From ec3fc5db881d93617328ebec37f7ac5fa10377e4 Mon Sep 17 00:00:00 2001 From: Marc Fiuczynski Date: Fri, 21 Jan 2005 03:33:53 +0000 Subject: [PATCH] kernel.org linux-2.6.9 --- CREDITS | 156 +- Documentation/CodingStyle | 4 +- Documentation/DMA-API.txt | 79 + Documentation/DocBook/Makefile | 4 +- Documentation/DocBook/gadget.tmpl | 245 +- Documentation/DocBook/kernel-hacking.tmpl | 4 +- Documentation/DocBook/mousedrivers.tmpl | 1 - Documentation/DocBook/usb.tmpl | 1 + Documentation/IPMI.txt | 30 + Documentation/ManagementStyle | 276 + Documentation/RCU/RTFP.txt | 387 + Documentation/RCU/UP.txt | 64 + Documentation/RCU/arrayRCU.txt | 141 + Documentation/RCU/checklist.txt | 157 + Documentation/RCU/listRCU.txt | 307 + Documentation/RCU/rcu.txt | 67 + Documentation/arm/IXP2000 | 69 + .../arm/Samsung-S3C24XX/EB2410ITX.txt | 44 + Documentation/arm/Samsung-S3C24XX/GPIO.txt | 122 + .../arm/Samsung-S3C24XX/Overview.txt | 97 + Documentation/cachetlb.txt | 4 - Documentation/cdrom/cdrom-standard.tex | 12 +- Documentation/crypto/api-intro.txt | 4 + Documentation/devices.txt | 120 +- Documentation/driver-model/bus.txt | 74 +- Documentation/filesystems/Locking | 29 +- Documentation/filesystems/ext2.txt | 34 +- Documentation/filesystems/ext3.txt | 72 +- Documentation/filesystems/ntfs.txt | 33 +- Documentation/filesystems/proc.txt | 45 +- Documentation/filesystems/tmpfs.txt | 12 +- Documentation/filesystems/vfs.txt | 2 +- Documentation/filesystems/xfs.txt | 29 +- .../firmware_sample_firmware_class.c | 3 +- Documentation/firmware_class/hotplug-script | 4 +- Documentation/i2c/sysfs-interface | 2 +- Documentation/i2o/README | 63 + Documentation/i2o/ioctl | 394 + Documentation/input/joystick-parport.txt | 13 +- Documentation/ioctl-number.txt | 1 + Documentation/kbuild/makefiles.txt | 145 +- Documentation/kernel-parameters.txt | 85 +- Documentation/laptop-mode.txt | 2 +- Documentation/networking/gen_stats.txt | 117 + Documentation/networking/ip-sysctl.txt | 5 + Documentation/networking/netdevices.txt | 13 + Documentation/pci.txt | 11 +- Documentation/power/swsusp.txt | 32 +- Documentation/powerpc/hvcs.txt | 39 +- Documentation/powerpc/mpc52xx.txt | 11 +- Documentation/sched-domains.txt | 27 +- Documentation/sched-stats.txt | 153 + Documentation/scsi/ChangeLog.megaraid | 241 +- Documentation/scsi/megaraid.txt | 70 + Documentation/scsi/scsi_mid_low_api.txt | 252 +- .../sound/alsa/ALSA-Configuration.txt | 31 +- .../sound/alsa/DocBook/alsa-driver-api.tmpl | 1 - .../alsa/DocBook/writing-an-alsa-driver.tmpl | 456 +- Documentation/sysctl/kernel.txt | 22 +- Documentation/sysctl/vm.txt | 2 +- Documentation/time_interpolators.txt | 40 + Documentation/tty.txt | 194 + Documentation/usb/sn9c102.txt | 55 +- Documentation/vm/overcommit-accounting | 8 +- Documentation/watchdog/pcwd-watchdog.txt | 3 +- Documentation/x86_64/boot-options.txt | 24 +- MAINTAINERS | 165 +- Makefile | 334 +- arch/alpha/Kconfig | 108 +- arch/alpha/Kconfig.debug | 59 + arch/alpha/Makefile | 16 +- arch/alpha/boot/Makefile | 2 +- arch/alpha/defconfig | 140 +- arch/alpha/kernel/Makefile | 4 +- arch/alpha/kernel/alpha_ksyms.c | 59 +- arch/alpha/kernel/core_cia.c | 4 +- arch/alpha/kernel/core_irongate.c | 20 +- arch/alpha/kernel/core_marvel.c | 227 +- arch/alpha/kernel/core_titan.c | 50 +- arch/alpha/kernel/err_titan.c | 2 +- arch/alpha/kernel/io.c | 630 ++ arch/alpha/kernel/irq.c | 44 +- arch/alpha/kernel/irq_impl.h | 29 - arch/alpha/kernel/machvec_impl.h | 101 +- arch/alpha/kernel/osf_sys.c | 142 +- arch/alpha/kernel/pci-noop.c | 75 +- arch/alpha/kernel/pci.c | 49 +- arch/alpha/kernel/pci_iommu.c | 39 + arch/alpha/kernel/process.c | 3 +- arch/alpha/kernel/ptrace.c | 19 +- arch/alpha/kernel/signal.c | 41 +- arch/alpha/kernel/smp.c | 21 +- arch/alpha/kernel/srmcons.c | 14 +- arch/alpha/kernel/sys_alcor.c | 6 +- arch/alpha/kernel/sys_cabriolet.c | 5 - arch/alpha/kernel/sys_dp264.c | 13 +- arch/alpha/kernel/sys_eb64p.c | 2 - arch/alpha/kernel/sys_eiger.c | 1 - arch/alpha/kernel/sys_jensen.c | 3 - arch/alpha/kernel/sys_marvel.c | 1 - arch/alpha/kernel/sys_miata.c | 1 - arch/alpha/kernel/sys_mikasa.c | 2 - arch/alpha/kernel/sys_nautilus.c | 1 - arch/alpha/kernel/sys_noritake.c | 2 - arch/alpha/kernel/sys_rawhide.c | 1 - arch/alpha/kernel/sys_ruffian.c | 1 - arch/alpha/kernel/sys_rx164.c | 1 - arch/alpha/kernel/sys_sable.c | 3 - arch/alpha/kernel/sys_sio.c | 5 - arch/alpha/kernel/sys_sx164.c | 1 - arch/alpha/kernel/sys_takara.c | 1 - arch/alpha/kernel/sys_titan.c | 18 +- arch/alpha/kernel/sys_wildfire.c | 1 - arch/alpha/kernel/systbls.S | 1 + arch/alpha/kernel/time.c | 6 +- arch/alpha/kernel/traps.c | 4 +- arch/alpha/kernel/vmlinux.lds.S | 6 +- arch/alpha/lib/Makefile | 1 - arch/alpha/lib/csum_partial_copy.c | 5 +- arch/alpha/mm/fault.c | 2 +- arch/alpha/mm/numa.c | 2 +- arch/arm/Kconfig | 199 +- arch/arm/Kconfig.debug | 115 + arch/arm/Makefile | 18 +- arch/arm/boot/Makefile | 10 + arch/arm/boot/compressed/Makefile | 13 +- arch/arm/boot/compressed/big-endian.S | 13 + arch/arm/boot/compressed/head-xscale.S | 31 +- arch/arm/boot/compressed/head.S | 39 + arch/arm/boot/compressed/misc.c | 24 +- arch/arm/common/dmabounce.c | 34 +- arch/arm/common/sa1111.c | 17 +- arch/arm/configs/ebsa110_defconfig | 1 - arch/arm/configs/enp2611_defconfig | 795 ++ arch/arm/configs/ep80219_defconfig | 849 +++ arch/arm/configs/h7201_defconfig | 511 ++ arch/arm/configs/h7202_defconfig | 652 ++ arch/arm/configs/iq31244_defconfig | 818 +++ arch/arm/configs/iq80321_defconfig | 433 +- arch/arm/configs/iq80331_defconfig | 753 ++ arch/arm/configs/ixdp2400_defconfig | 796 ++ arch/arm/configs/ixdp2401_defconfig | 797 ++ arch/arm/configs/ixdp2800_defconfig | 796 ++ arch/arm/configs/ixdp2801_defconfig | 797 ++ arch/arm/configs/ixp4xx_defconfig | 1 - arch/arm/configs/mx1ads_defconfig | 652 ++ arch/arm/configs/s3c2410_defconfig | 8 + arch/arm/kernel/Makefile | 5 +- arch/arm/kernel/apm.c | 362 +- arch/arm/kernel/armksyms.c | 93 +- arch/arm/kernel/asm-offsets.c | 16 +- arch/arm/kernel/bios32.c | 61 +- arch/arm/kernel/calls.S | 9 +- arch/arm/kernel/debug.S | 98 +- arch/arm/kernel/ecard.c | 82 +- arch/arm/kernel/entry-armv.S | 220 +- arch/arm/kernel/irq.c | 19 +- arch/arm/kernel/iwmmxt.S | 320 + arch/arm/kernel/process.c | 6 + arch/arm/kernel/ptrace.c | 7 +- arch/arm/kernel/semaphore.c | 8 +- arch/arm/kernel/setup.c | 3 +- arch/arm/kernel/signal.c | 152 +- arch/arm/kernel/sys_arm.c | 9 +- arch/arm/kernel/time.c | 76 +- arch/arm/kernel/traps.c | 6 +- arch/arm/kernel/vmlinux.lds.S | 4 +- arch/arm/lib/getuser.S | 57 +- arch/arm/lib/putuser.S | 59 +- arch/arm/mach-h720x/Kconfig | 27 + arch/arm/mach-h720x/Makefile | 16 + arch/arm/mach-h720x/common.c | 247 + arch/arm/mach-h720x/cpu-h7201.c | 59 + arch/arm/mach-h720x/cpu-h7202.c | 165 + arch/arm/mach-h720x/h7201-eval.c | 42 + arch/arm/mach-h720x/h7202-eval.c | 85 + arch/arm/mach-imx/Kconfig | 10 + arch/arm/mach-imx/Makefile | 19 + arch/arm/mach-imx/dma.c | 203 + arch/arm/mach-imx/generic.c | 274 + arch/arm/mach-imx/generic.h | 14 + arch/arm/mach-imx/irq.c | 252 + arch/arm/mach-imx/leds-mx1ads.c | 54 + arch/arm/mach-imx/leds.c | 31 + arch/arm/mach-imx/leds.h | 9 + arch/arm/mach-imx/mx1ads.c | 88 + arch/arm/mach-imx/time.c | 95 + arch/arm/mach-integrator/clock.c | 9 +- arch/arm/mach-integrator/cpu.c | 8 +- arch/arm/mach-integrator/impd1.c | 191 + arch/arm/mach-integrator/integrator_cp.c | 76 + arch/arm/mach-iop3xx/Kconfig | 61 +- arch/arm/mach-iop3xx/Makefile | 21 +- arch/arm/mach-iop3xx/arch.c | 58 +- arch/arm/mach-iop3xx/common.c | 75 + arch/arm/mach-iop3xx/iop321-irq.c | 3 +- arch/arm/mach-iop3xx/iop321-mm.c | 43 + arch/arm/mach-iop3xx/iop321-pci.c | 64 +- arch/arm/mach-iop3xx/iop321-setup.c | 63 + arch/arm/mach-iop3xx/iop321-time.c | 64 +- arch/arm/mach-iop3xx/iop331-irq.c | 127 + arch/arm/mach-iop3xx/iop331-mm.c | 43 + arch/arm/mach-iop3xx/iop331-pci.c | 217 + arch/arm/mach-iop3xx/iop331-setup.c | 102 + arch/arm/mach-iop3xx/iop331-time.c | 141 + arch/arm/mach-iop3xx/iq31244-mm.c | 44 + arch/arm/mach-iop3xx/iq31244-pci.c | 134 + arch/arm/mach-iop3xx/iq80321-mm.c | 44 + arch/arm/mach-iop3xx/iq80321-pci.c | 83 +- arch/arm/mach-iop3xx/iq80331-mm.c | 36 + arch/arm/mach-iop3xx/iq80331-pci.c | 138 + arch/arm/mach-ixp2000/Kconfig | 59 + arch/arm/mach-ixp2000/Makefile | 14 + arch/arm/mach-ixp2000/core.c | 426 ++ arch/arm/mach-ixp2000/enp2611.c | 210 + arch/arm/mach-ixp2000/ixdp2400.c | 177 + arch/arm/mach-ixp2000/ixdp2800.c | 178 + arch/arm/mach-ixp2000/ixdp2x00.c | 307 + arch/arm/mach-ixp2000/ixdp2x01.c | 381 + arch/arm/mach-ixp2000/pci.c | 233 + arch/arm/mach-ixp4xx/common.c | 2 +- arch/arm/mach-lh7a40x/arch-lpd7a40x.c | 11 +- arch/arm/mach-lh7a40x/time.c | 8 +- arch/arm/mach-omap/Makefile | 10 +- arch/arm/mach-omap/board-generic.c | 56 +- arch/arm/mach-omap/board-h2.c | 115 + arch/arm/mach-omap/board-h3.c | 90 + arch/arm/mach-omap/board-innovator.c | 58 +- arch/arm/mach-omap/board-osk.c | 4 +- arch/arm/mach-omap/board-perseus2.c | 15 +- arch/arm/mach-omap/clocks.c | 11 +- arch/arm/mach-omap/common.c | 53 +- arch/arm/mach-omap/common.h | 1 - arch/arm/mach-omap/dma.c | 156 +- arch/arm/mach-omap/fpga.c | 30 +- arch/arm/mach-omap/gpio.c | 28 +- arch/arm/mach-omap/irq.c | 20 +- arch/arm/mach-omap/leds-h2p2-debug.c | 104 + arch/arm/mach-omap/leds.c | 9 +- arch/arm/mach-omap/leds.h | 2 +- arch/arm/mach-omap/mcbsp.c | 669 ++ arch/arm/mach-omap/ocpi.c | 4 +- arch/arm/mach-omap/usb.c | 541 ++ arch/arm/mach-pxa/Kconfig | 7 +- arch/arm/mach-pxa/dma.c | 1 + arch/arm/mach-pxa/generic.c | 8 + arch/arm/mach-pxa/idp.c | 3 +- arch/arm/mach-pxa/irq.c | 103 +- arch/arm/mach-pxa/leds-lubbock.c | 1 + arch/arm/mach-pxa/leds-mainstone.c | 1 + arch/arm/mach-pxa/lubbock.c | 1 + arch/arm/mach-pxa/mainstone.c | 1 + arch/arm/mach-pxa/pm.c | 18 +- arch/arm/mach-pxa/pxa25x.c | 1 + arch/arm/mach-pxa/pxa27x.c | 1 + arch/arm/mach-pxa/sleep.S | 43 +- arch/arm/mach-pxa/time.c | 1 + arch/arm/mach-s3c2410/Kconfig | 42 +- arch/arm/mach-s3c2410/Makefile | 25 +- arch/arm/mach-s3c2410/clock.c | 310 + arch/arm/mach-s3c2410/clock.h | 20 + arch/arm/mach-s3c2410/cpu.c | 152 + arch/arm/mach-s3c2410/cpu.h | 41 + arch/arm/mach-s3c2410/devs.c | 442 ++ arch/arm/mach-s3c2410/devs.h | 36 + arch/arm/mach-s3c2410/dma.c | 1085 +++ arch/arm/mach-s3c2410/gpio.c | 118 +- arch/arm/mach-s3c2410/irq.c | 201 +- arch/arm/mach-s3c2410/mach-bast.c | 52 +- arch/arm/mach-s3c2410/mach-h1940.c | 46 +- arch/arm/mach-s3c2410/mach-smdk2410.c | 22 +- arch/arm/mach-s3c2410/mach-vr1000.c | 34 +- arch/arm/mach-s3c2410/s3c2410.c | 78 +- arch/arm/mach-s3c2410/s3c2410.h | 32 +- arch/arm/mach-s3c2410/s3c2440-dsc.c | 57 + arch/arm/mach-s3c2410/s3c2440.c | 192 + arch/arm/mach-s3c2410/s3c2440.h | 18 + arch/arm/mach-s3c2410/time.c | 19 +- arch/arm/mach-s3c2410/usb-simtec.c | 123 + arch/arm/mach-s3c2410/usb-simtec.h | 19 + arch/arm/mach-sa1100/cpu-sa1100.c | 4 +- arch/arm/mach-sa1100/cpu-sa1110.c | 4 +- arch/arm/mach-sa1100/pm.c | 19 +- arch/arm/mach-versatile/clock.c | 4 +- arch/arm/mach-versatile/core.c | 211 +- arch/arm/mm/Kconfig | 6 +- arch/arm/mm/Makefile | 3 +- arch/arm/mm/abort-ev5tj.S | 1 - arch/arm/mm/cache-v3.S | 14 + arch/arm/mm/cache-v4.S | 14 + arch/arm/mm/cache-v4wb.S | 14 + arch/arm/mm/cache-v4wt.S | 14 + arch/arm/mm/cache-v6.S | 17 + arch/arm/mm/consistent.c | 30 +- arch/arm/mm/copypage-v6.c | 92 +- arch/arm/mm/fault-armv.c | 67 +- arch/arm/mm/flush.c | 94 + arch/arm/mm/init.c | 13 +- arch/arm/mm/proc-arm1020.S | 14 + arch/arm/mm/proc-arm1020e.S | 15 +- arch/arm/mm/proc-arm1022.S | 16 +- arch/arm/mm/proc-arm1026.S | 15 +- arch/arm/mm/proc-arm920.S | 14 + arch/arm/mm/proc-arm922.S | 14 + arch/arm/mm/proc-arm925.S | 14 + arch/arm/mm/proc-arm926.S | 16 +- arch/arm/mm/proc-syms.c | 8 +- arch/arm/mm/proc-v6.S | 10 +- arch/arm/mm/proc-xscale.S | 105 +- arch/arm/nwfpe/fpa11_cpdt.c | 10 + arch/arm/oprofile/op_model_xscale.c | 29 +- arch/arm/tools/mach-types | 60 +- arch/arm26/Kconfig | 117 +- arch/arm26/Kconfig.debug | 60 + arch/arm26/Makefile | 4 +- arch/arm26/boot/Makefile | 4 +- arch/arm26/kernel/Makefile | 2 +- arch/arm26/kernel/armksyms.c | 98 +- arch/arm26/kernel/irq.c | 6 +- arch/arm26/kernel/ptrace.c | 7 +- arch/arm26/kernel/signal.c | 4 +- arch/arm26/kernel/sys_arm.c | 2 +- arch/arm26/kernel/time.c | 24 +- arch/arm26/kernel/vmlinux-arm26-xip.lds.in | 3 - arch/arm26/kernel/vmlinux-arm26.lds.in | 3 - arch/arm26/mm/init.c | 6 +- arch/cris/Kconfig | 56 +- arch/cris/Kconfig.debug | 28 + arch/cris/Makefile | 6 +- arch/cris/arch-v10/kernel/debugport.c | 2 +- arch/cris/arch-v10/kernel/process.c | 2 +- arch/cris/arch-v10/kernel/ptrace.c | 13 +- arch/cris/arch-v10/kernel/signal.c | 8 +- arch/cris/arch-v10/mm/init.c | 2 +- arch/cris/arch-v10/vmlinux.lds.S | 3 - arch/cris/kernel/Makefile | 2 +- arch/cris/kernel/crisksyms.c | 5 +- arch/cris/kernel/irq.c | 8 +- arch/h8300/Kconfig | 75 +- arch/h8300/Kconfig.debug | 68 + arch/h8300/kernel/Makefile | 2 +- arch/h8300/kernel/asm-offsets.c | 2 +- arch/h8300/kernel/h8300_ksyms.c | 59 +- arch/h8300/kernel/ints.c | 2 +- arch/h8300/kernel/process.c | 2 +- arch/h8300/kernel/ptrace.c | 15 +- arch/h8300/kernel/signal.c | 8 +- arch/h8300/kernel/time.c | 23 +- arch/h8300/kernel/vmlinux.lds.S | 3 - arch/h8300/lib/checksum.c | 1 + arch/h8300/platform/h8300h/generic/timer.c | 4 +- arch/h8300/platform/h8s/ints.c | 2 +- arch/i386/Kconfig | 154 +- arch/i386/Kconfig.debug | 80 + arch/i386/Makefile | 35 +- arch/i386/boot/Makefile | 4 +- arch/i386/boot/setup.S | 2 +- arch/i386/boot/video.S | 36 + arch/i386/kernel/Makefile | 6 +- arch/i386/kernel/acpi/boot.c | 20 +- arch/i386/kernel/acpi/sleep.c | 5 +- arch/i386/kernel/apic.c | 89 +- arch/i386/kernel/apm.c | 45 +- arch/i386/kernel/asm-offsets.c | 1 + arch/i386/kernel/cpu/centaur.c | 27 +- arch/i386/kernel/cpu/common.c | 23 +- arch/i386/kernel/cpu/cpufreq/Kconfig | 10 + arch/i386/kernel/cpu/cpufreq/acpi.c | 103 +- arch/i386/kernel/cpu/cpufreq/gx-suspmod.c | 1 + arch/i386/kernel/cpu/cpufreq/longhaul.c | 309 +- arch/i386/kernel/cpu/cpufreq/longrun.c | 42 +- arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 4 +- arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 74 +- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 16 +- arch/i386/kernel/cpu/cpufreq/powernow-k8.h | 2 +- .../kernel/cpu/cpufreq/speedstep-centrino.c | 250 +- arch/i386/kernel/cpu/cpufreq/speedstep-ich.c | 117 +- arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 7 +- arch/i386/kernel/cpu/intel.c | 73 +- arch/i386/kernel/cpu/mtrr/mtrr.h | 1 - arch/i386/kernel/cpu/proc.c | 4 +- arch/i386/kernel/dmi_scan.c | 86 +- arch/i386/kernel/doublefault.c | 2 +- arch/i386/kernel/entry.S | 35 +- arch/i386/kernel/head.S | 3 - arch/i386/kernel/i386_ksyms.c | 23 +- arch/i386/kernel/i8259.c | 72 +- arch/i386/kernel/init_task.c | 7 +- arch/i386/kernel/io_apic.c | 184 +- arch/i386/kernel/ioport.c | 36 +- arch/i386/kernel/irq.c | 50 +- arch/i386/kernel/kprobes.c | 349 + arch/i386/kernel/ldt.c | 9 +- arch/i386/kernel/microcode.c | 1 + arch/i386/kernel/nmi.c | 76 +- arch/i386/kernel/pci-dma.c | 111 +- arch/i386/kernel/process.c | 102 +- arch/i386/kernel/ptrace.c | 11 +- arch/i386/kernel/setup.c | 43 +- arch/i386/kernel/signal.c | 80 +- arch/i386/kernel/smp.c | 19 +- arch/i386/kernel/smpboot.c | 277 +- arch/i386/kernel/sysenter.c | 8 +- arch/i386/kernel/time.c | 17 +- arch/i386/kernel/time_hpet.c | 11 +- arch/i386/kernel/timers/timer_pit.c | 44 + arch/i386/kernel/timers/timer_tsc.c | 7 +- arch/i386/kernel/traps.c | 194 +- arch/i386/kernel/vm86.c | 4 +- arch/i386/kernel/vmlinux.lds.S | 7 +- arch/i386/kernel/vsyscall.lds.S | 65 + arch/i386/lib/memcpy.c | 6 +- arch/i386/lib/mmx.c | 2 +- arch/i386/lib/usercopy.c | 2 + arch/i386/mach-es7000/es7000.h | 9 +- arch/i386/mach-es7000/es7000plat.c | 83 +- arch/i386/mach-generic/bigsmp.c | 28 +- arch/i386/mach-voyager/voyager_smp.c | 32 +- arch/i386/math-emu/fpu_proto.h | 1 - arch/i386/mm/Makefile | 2 +- arch/i386/mm/discontig.c | 23 +- arch/i386/mm/fault.c | 12 +- arch/i386/mm/init.c | 6 +- arch/i386/mm/ioremap.c | 22 +- arch/i386/mm/mmap.c | 4 +- arch/i386/mm/pageattr.c | 2 +- arch/i386/oprofile/op_model_athlon.c | 4 +- arch/i386/oprofile/op_model_p4.c | 40 +- arch/i386/oprofile/op_model_ppro.c | 4 +- arch/i386/pci/common.c | 2 +- arch/i386/pci/fixup.c | 129 +- arch/i386/pci/i386.c | 10 +- arch/i386/pci/mmconfig.c | 9 +- arch/i386/pci/numa.c | 5 +- arch/i386/pci/pcbios.c | 2 +- arch/i386/power/Makefile | 1 - arch/i386/power/cpu.c | 4 +- arch/i386/power/swsusp.S | 76 +- arch/ia64/Kconfig | 127 +- arch/ia64/Kconfig.debug | 64 + arch/ia64/Makefile | 18 +- arch/ia64/configs/bigsur_defconfig | 1132 +++ arch/ia64/configs/generic_defconfig | 29 +- arch/ia64/configs/sn2_defconfig | 49 +- arch/ia64/configs/tiger_defconfig | 1028 +++ arch/ia64/configs/zx1_defconfig | 662 +- arch/ia64/hp/common/sba_iommu.c | 86 +- arch/ia64/hp/sim/simserial.c | 8 +- arch/ia64/ia32/binfmt_elf32.c | 41 +- arch/ia64/ia32/elfcore32.h | 14 +- arch/ia64/ia32/ia32_entry.S | 8 +- arch/ia64/ia32/ia32_ldt.c | 25 +- arch/ia64/ia32/ia32_signal.c | 182 +- arch/ia64/ia32/ia32_support.c | 38 +- arch/ia64/ia32/ia32priv.h | 19 +- arch/ia64/ia32/sys_ia32.c | 349 +- arch/ia64/kernel/Makefile | 12 +- arch/ia64/kernel/acpi-ext.c | 2 +- arch/ia64/kernel/acpi.c | 85 +- arch/ia64/kernel/asm-offsets.c | 29 +- arch/ia64/kernel/cyclone.c | 61 +- arch/ia64/kernel/efi.c | 14 +- arch/ia64/kernel/entry.S | 4 +- arch/ia64/kernel/fsys.S | 365 +- arch/ia64/kernel/head.S | 3 +- arch/ia64/kernel/iosapic.c | 73 +- arch/ia64/kernel/irq.c | 52 +- arch/ia64/kernel/irq_ia64.c | 7 +- arch/ia64/kernel/mca.c | 41 +- arch/ia64/kernel/mca_drv.c | 639 ++ arch/ia64/kernel/mca_drv.h | 113 + arch/ia64/kernel/mca_drv_asm.S | 45 + arch/ia64/kernel/minstate.h | 6 +- arch/ia64/kernel/module.c | 20 +- arch/ia64/kernel/palinfo.c | 4 +- arch/ia64/kernel/patch.c | 26 +- arch/ia64/kernel/perfmon.c | 64 +- arch/ia64/kernel/process.c | 38 +- arch/ia64/kernel/ptrace.c | 109 +- arch/ia64/kernel/sal.c | 38 + arch/ia64/kernel/salinfo.c | 13 +- arch/ia64/kernel/setup.c | 2 +- arch/ia64/kernel/sigframe.h | 2 +- arch/ia64/kernel/signal.c | 92 +- arch/ia64/kernel/smp.c | 2 +- arch/ia64/kernel/smpboot.c | 30 +- arch/ia64/kernel/sys_ia64.c | 4 +- arch/ia64/kernel/time.c | 221 +- arch/ia64/kernel/traps.c | 27 +- arch/ia64/kernel/unaligned.c | 18 +- arch/ia64/kernel/unwind.c | 45 +- arch/ia64/kernel/vmlinux.lds.S | 7 +- arch/ia64/lib/csum_partial_copy.c | 12 +- arch/ia64/lib/io.c | 22 +- arch/ia64/lib/swiotlb.c | 112 +- arch/ia64/mm/contig.c | 17 +- arch/ia64/mm/discontig.c | 60 +- arch/ia64/mm/extable.c | 2 +- arch/ia64/mm/fault.c | 4 +- arch/ia64/mm/init.c | 20 +- arch/ia64/mm/tlb.c | 2 +- arch/ia64/oprofile/Kconfig | 4 + arch/ia64/oprofile/Makefile | 1 + arch/ia64/oprofile/init.c | 9 +- arch/ia64/oprofile/perfmon.c | 105 + arch/ia64/pci/pci.c | 9 +- arch/ia64/sn/io/hwgfs/interface.c | 4 +- arch/ia64/sn/io/machvec/pci_bus_cvlink.c | 18 +- arch/ia64/sn/kernel/bte.c | 7 +- arch/ia64/sn/kernel/setup.c | 2 + arch/ia64/sn/kernel/sn2/Makefile | 2 +- arch/ia64/sn/kernel/sn2/prominfo_proc.c | 313 +- arch/ia64/sn/kernel/sn2/sn_hwperf.c | 652 ++ arch/ia64/sn/kernel/sn2/sn_proc_fs.c | 182 +- arch/ia64/sn/kernel/sn2/timer.c | 49 +- arch/m32r/Kconfig | 441 ++ arch/m32r/Makefile | 55 + arch/m32r/boot/Makefile | 19 + arch/m32r/boot/compressed/Makefile | 38 + arch/m32r/boot/compressed/boot.h | 59 + arch/m32r/boot/compressed/head.S | 115 + arch/m32r/boot/compressed/install.sh | 57 + arch/m32r/boot/compressed/m32r_sio.c | 53 + arch/m32r/boot/compressed/misc.c | 223 + arch/m32r/boot/compressed/vmlinux.lds.S | 23 + arch/m32r/boot/compressed/vmlinux.scr | 9 + arch/m32r/boot/setup.S | 162 + arch/m32r/defconfig | 635 ++ arch/m32r/kernel/Makefile | 20 + arch/m32r/kernel/align.c | 585 ++ arch/m32r/kernel/entry.S | 999 +++ arch/m32r/kernel/head.S | 287 + arch/m32r/kernel/init_task.c | 41 + arch/m32r/kernel/io_m32700ut.c | 455 ++ arch/m32r/kernel/io_mappi.c | 368 + arch/m32r/kernel/io_mappi2.c | 370 + arch/m32r/kernel/io_oaks32r.c | 243 + arch/m32r/kernel/io_opsput.c | 377 + arch/m32r/kernel/io_usrv.c | 247 + arch/m32r/kernel/irq.c | 1020 +++ arch/m32r/kernel/m32r_ksyms.c | 141 + arch/m32r/kernel/module.c | 253 + arch/m32r/kernel/process.c | 356 + arch/m32r/kernel/ptrace.c | 858 +++ arch/m32r/kernel/semaphore.c | 186 + arch/m32r/kernel/setup.c | 403 ++ arch/m32r/kernel/setup_m32700ut.c | 478 ++ arch/m32r/kernel/setup_mappi.c | 160 + arch/m32r/kernel/setup_mappi2.c | 212 + arch/m32r/kernel/setup_oaks32r.c | 143 + arch/m32r/kernel/setup_opsput.c | 482 ++ arch/m32r/kernel/setup_usrv.c | 256 + arch/m32r/kernel/signal.c | 621 ++ arch/m32r/kernel/smp.c | 965 +++ arch/m32r/kernel/smpboot.c | 635 ++ arch/m32r/kernel/sys_m32r.c | 217 + arch/m32r/kernel/time.c | 317 + arch/m32r/kernel/traps.c | 330 + arch/m32r/kernel/vmlinux.lds.S | 143 + arch/m32r/lib/Makefile | 7 + arch/m32r/lib/ashxdi3.S | 297 + arch/m32r/lib/checksum.S | 322 + arch/m32r/lib/csum_partial_copy.c | 58 + arch/m32r/lib/delay.c | 126 + arch/m32r/lib/getuser.S | 88 + arch/m32r/lib/memcpy.S | 95 + arch/m32r/lib/memset.S | 178 + arch/m32r/lib/putuser.S | 84 + arch/m32r/lib/strlen.S | 120 + arch/m32r/lib/usercopy.c | 391 + arch/m32r/m32700ut/defconfig.m32700ut.smp | 662 ++ arch/m32r/m32700ut/defconfig.m32700ut.up | 659 ++ arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB | 249 + arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB | 249 + arch/m32r/mappi/defconfig.nommu | 529 ++ arch/m32r/mappi/defconfig.smp | 646 ++ arch/m32r/mappi/defconfig.up | 642 ++ arch/m32r/mappi/dot.gdbinit | 242 + arch/m32r/mappi/dot.gdbinit.nommu | 245 + arch/m32r/mappi/dot.gdbinit.smp | 344 + arch/m32r/mm/Makefile | 12 + arch/m32r/mm/cache.c | 68 + arch/m32r/mm/discontig.c | 170 + arch/m32r/mm/extable.c | 22 + arch/m32r/mm/fault-nommu.c | 164 + arch/m32r/mm/fault.c | 572 ++ arch/m32r/mm/init.c | 250 + arch/m32r/mm/ioremap-nommu.c | 52 + arch/m32r/mm/ioremap.c | 192 + arch/m32r/mm/mmu.S | 350 + arch/m32r/mm/page.S | 82 + arch/m32r/oaks32r/defconfig.nommu | 521 ++ arch/m32r/oaks32r/dot.gdbinit.nommu | 155 + arch/m32r/oprofile/Kconfig | 23 + arch/m32r/oprofile/Makefile | 9 + arch/m32r/oprofile/init.c | 25 + arch/m32r/opsput/defconfig.opsput | 598 ++ arch/m32r/opsput/dot.gdbinit | 180 + arch/m68k/Kconfig | 43 +- arch/m68k/Kconfig.debug | 5 + arch/m68k/Makefile | 2 +- arch/m68k/kernel/Makefile | 2 +- arch/m68k/kernel/bios32.c | 5 - arch/m68k/kernel/m68k_ksyms.c | 25 +- arch/m68k/kernel/process.c | 2 +- arch/m68k/kernel/ptrace.c | 7 +- arch/m68k/kernel/signal.c | 8 +- arch/m68k/kernel/time.c | 22 +- arch/m68k/kernel/vmlinux-std.lds | 3 - arch/m68k/kernel/vmlinux-sun3.lds | 3 - arch/m68k/q40/q40ints.c | 2 +- arch/m68knommu/Kconfig | 66 +- arch/m68knommu/Kconfig.debug | 42 + arch/m68knommu/kernel/Makefile | 2 +- arch/m68knommu/kernel/asm-offsets.c | 2 +- arch/m68knommu/kernel/comempci.c | 2 - arch/m68knommu/kernel/m68k_ksyms.c | 49 +- arch/m68knommu/kernel/process.c | 2 +- arch/m68knommu/kernel/ptrace.c | 13 +- arch/m68knommu/kernel/signal.c | 8 +- arch/m68knommu/kernel/time.c | 23 +- arch/m68knommu/kernel/vmlinux.lds.S | 3 - arch/m68knommu/platform/5307/timers.c | 13 +- arch/mips/Kconfig | 146 +- arch/mips/Kconfig.debug | 76 + arch/mips/Makefile | 8 +- arch/mips/au1000/common/time.c | 2 +- arch/mips/baget/irq.c | 7 +- arch/mips/configs/jaguar-atx_defconfig | 8 +- arch/mips/configs/ocelot_c_defconfig | 2 +- arch/mips/configs/tb0226_defconfig | 1 - arch/mips/configs/tb0229_defconfig | 1 - arch/mips/kernel/Makefile | 2 +- arch/mips/kernel/irixsig.c | 4 +- arch/mips/kernel/irq.c | 45 +- arch/mips/kernel/mips_ksyms.c | 44 +- arch/mips/kernel/signal.c | 17 +- arch/mips/kernel/signal32.c | 8 +- arch/mips/kernel/signal_n32.c | 4 +- arch/mips/kernel/smp.c | 23 +- arch/mips/kernel/syscall.c | 2 +- arch/mips/kernel/sysirix.c | 4 +- arch/mips/kernel/time.c | 20 +- arch/mips/kernel/vmlinux.lds.S | 4 +- arch/mips/mips-boards/generic/time.c | 1 - arch/mips/mm/fault.c | 1 - arch/mips/momentum/jaguar_atx/prom.c | 4 +- arch/mips/momentum/ocelot_c/prom.c | 6 +- arch/mips/pci/fixup-atlas.c | 10 +- arch/mips/pci/fixup-au1000.c | 4 - arch/mips/pci/fixup-capcella.c | 4 - arch/mips/pci/fixup-cobalt.c | 12 +- arch/mips/pci/fixup-ddb5074.c | 7 +- arch/mips/pci/fixup-ddb5477.c | 16 +- arch/mips/pci/fixup-ip32.c | 4 - arch/mips/pci/fixup-jaguar.c | 4 - arch/mips/pci/fixup-lasat.c | 4 - arch/mips/pci/fixup-malta.c | 11 +- arch/mips/pci/fixup-mpc30x.c | 4 - arch/mips/pci/fixup-ocelot-c.c | 4 - arch/mips/pci/fixup-ocelot-g.c | 4 - arch/mips/pci/fixup-sni.c | 4 - arch/mips/pci/fixup-tb0219.c | 4 - arch/mips/pci/fixup-tb0226.c | 4 - arch/mips/pci/fixup-yosemite.c | 4 - arch/mips/pci/pci-ip27.c | 21 +- arch/mips/pci/pci-sb1250.c | 4 - arch/mips/pmc-sierra/yosemite/ht.c | 5 - arch/mips/sgi-ip27/ip27-memory.c | 2 +- arch/mips/vr41xx/common/giu.c | 7 +- arch/mips/vr41xx/common/icu.c | 222 +- arch/mips/vr41xx/common/serial.c | 4 +- arch/mips/vr41xx/common/vrc4173.c | 90 + arch/parisc/Kconfig | 70 +- arch/parisc/Kconfig.debug | 14 + arch/parisc/kernel/Makefile | 2 +- arch/parisc/kernel/asm-offsets.c | 4 +- arch/parisc/kernel/cache.c | 5 +- arch/parisc/kernel/hardware.c | 2 +- arch/parisc/kernel/pci.c | 9 - arch/parisc/kernel/process.c | 2 +- arch/parisc/kernel/ptrace.c | 7 +- arch/parisc/kernel/smp.c | 23 +- arch/parisc/kernel/time.c | 40 +- arch/parisc/kernel/vmlinux.lds.S | 4 +- arch/parisc/lib/debuglocks.c | 2 +- arch/parisc/mm/init.c | 2 +- arch/ppc/8260_io/fcc_enet.c | 4 +- arch/ppc/8xx_io/uart.c | 2 +- arch/ppc/Kconfig | 145 +- arch/ppc/Kconfig.debug | 84 + arch/ppc/Makefile | 34 +- arch/ppc/amiga/config.c | 3 - arch/ppc/boot/Makefile | 4 +- arch/ppc/boot/common/misc-common.c | 30 +- arch/ppc/boot/common/ns16550.c | 6 +- arch/ppc/boot/common/serial_stub.c | 5 - arch/ppc/boot/common/util.S | 16 +- arch/ppc/boot/include/nonstdio.h | 2 + arch/ppc/boot/include/serial.h | 46 + arch/ppc/boot/lib/Makefile | 4 +- arch/ppc/boot/openfirmware/coffmain.c | 1 - arch/ppc/boot/openfirmware/common.c | 106 +- arch/ppc/boot/openfirmware/misc.S | 2 +- arch/ppc/boot/simple/Makefile | 7 +- arch/ppc/boot/simple/chrpmap.c | 12 + arch/ppc/boot/simple/misc-embedded.c | 9 +- arch/ppc/boot/simple/misc-prep.c | 1 + arch/ppc/boot/simple/misc-spruce.c | 3 - arch/ppc/boot/simple/misc.c | 16 +- arch/ppc/boot/simple/pibs.c | 101 + arch/ppc/boot/simple/prepmap.c | 12 + arch/ppc/boot/simple/relocate.S | 6 +- arch/ppc/boot/utils/mkbugboot.c | 12 +- arch/ppc/boot/utils/mktree.c | 4 + arch/ppc/configs/mvme5100_defconfig | 448 +- arch/ppc/kernel/Makefile | 2 +- arch/ppc/kernel/align.c | 163 +- arch/ppc/kernel/asm-offsets.c | 7 + arch/ppc/kernel/cpu_setup_6xx.S | 42 +- arch/ppc/kernel/cpu_setup_power4.S | 8 +- arch/ppc/kernel/cputable.c | 115 +- arch/ppc/kernel/dma-mapping.c | 4 +- arch/ppc/kernel/entry.S | 4 +- arch/ppc/kernel/head.S | 16 +- arch/ppc/kernel/head_44x.S | 237 +- arch/ppc/kernel/head_booke.h | 240 + arch/ppc/kernel/head_e500.S | 236 +- arch/ppc/kernel/idle.c | 34 + arch/ppc/kernel/idle_6xx.S | 6 +- arch/ppc/kernel/idle_power4.S | 2 +- arch/ppc/kernel/irq.c | 44 +- arch/ppc/kernel/misc.S | 33 +- arch/ppc/kernel/pci.c | 63 +- arch/ppc/kernel/ppc_htab.c | 33 +- arch/ppc/kernel/ppc_ksyms.c | 4 + arch/ppc/kernel/process.c | 7 +- arch/ppc/kernel/setup.c | 8 +- arch/ppc/kernel/signal.c | 33 +- arch/ppc/kernel/smp.c | 10 +- arch/ppc/kernel/time.c | 43 +- arch/ppc/kernel/traps.c | 51 +- arch/ppc/kernel/vector.S | 4 +- arch/ppc/kernel/vmlinux.lds.S | 4 +- arch/ppc/lib/checksum.S | 12 +- arch/ppc/lib/rheap.c | 8 +- arch/ppc/math-emu/op-common.h | 1 - arch/ppc/mm/44x_mmu.c | 2 +- arch/ppc/mm/4xx_mmu.c | 5 + arch/ppc/mm/init.c | 5 + arch/ppc/mm/pgtable.c | 13 + arch/ppc/platforms/4xx/ebony.c | 168 +- arch/ppc/platforms/4xx/ebony.h | 18 +- arch/ppc/platforms/4xx/ocotea.c | 271 +- arch/ppc/platforms/4xx/ocotea.h | 15 +- arch/ppc/platforms/85xx/mpc8540_ads.c | 4 - arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 6 +- arch/ppc/platforms/85xx/sbc8560.c | 3 - arch/ppc/platforms/Makefile | 8 +- arch/ppc/platforms/chrp_setup.c | 9 +- arch/ppc/platforms/chrp_smp.c | 1 - arch/ppc/platforms/est8260.h | 3 + arch/ppc/platforms/k2.c | 4 - arch/ppc/platforms/lite5200.c | 55 +- arch/ppc/platforms/lopec.c | 410 ++ arch/ppc/platforms/lopec.h | 39 + arch/ppc/platforms/mcpn765.c | 6 - arch/ppc/platforms/mcpn765.h | 50 +- arch/ppc/platforms/mpc5200.c | 24 + arch/ppc/platforms/mvme5100.c | 349 + arch/ppc/platforms/mvme5100.h | 25 +- arch/ppc/platforms/pcore.c | 4 - arch/ppc/platforms/pmac_cpufreq.c | 12 +- arch/ppc/platforms/pmac_feature.c | 2 +- arch/ppc/platforms/pmac_pci.c | 23 +- arch/ppc/platforms/pmac_setup.c | 3 - arch/ppc/platforms/pmac_smp.c | 2 +- arch/ppc/platforms/pmac_time.c | 2 +- arch/ppc/platforms/powerpmc250.h | 18 +- arch/ppc/platforms/pplus.c | 2 - arch/ppc/platforms/pq2ads.c | 26 + arch/ppc/platforms/pq2ads.h | 4 + arch/ppc/platforms/prep_pci.c | 176 +- arch/ppc/platforms/prep_setup.c | 218 +- arch/ppc/platforms/prpmc750.c | 4 - arch/ppc/platforms/prpmc750.h | 26 +- arch/ppc/platforms/prpmc800.c | 4 - arch/ppc/platforms/prpmc800.h | 28 +- arch/ppc/platforms/residual.c | 133 +- arch/ppc/platforms/rpx8260.h | 7 + arch/ppc/platforms/sandpoint.c | 4 - arch/ppc/platforms/sbc82xx.c | 58 +- arch/ppc/platforms/sbc82xx.h | 4 + arch/ppc/platforms/spruce.c | 5 - arch/ppc/platforms/tqm8260.h | 4 + arch/ppc/platforms/tqm8260_setup.c | 41 +- arch/ppc/syslib/Makefile | 4 +- arch/ppc/syslib/cpm2_pic.c | 25 +- arch/ppc/syslib/cpm2_pic.h | 8 +- arch/ppc/syslib/hawk_common.c | 32 + arch/ppc/syslib/ibm44x_common.c | 165 + arch/ppc/syslib/ibm44x_common.h | 8 +- arch/ppc/syslib/m8260_pci.h | 1 + arch/ppc/syslib/m8260_setup.c | 84 +- arch/ppc/syslib/m8xx_setup.c | 6 + arch/ppc/syslib/m8xx_wdt.c | 99 + arch/ppc/syslib/m8xx_wdt.h | 16 + arch/ppc/syslib/mpc52xx_pic.c | 22 +- arch/ppc/syslib/mpc52xx_setup.c | 41 +- arch/ppc/syslib/open_pic.c | 10 +- arch/ppc/syslib/open_pic2.c | 2 +- arch/ppc/syslib/ppc4xx_pic.c | 2 +- arch/ppc/syslib/ppc4xx_setup.c | 4 - arch/ppc/syslib/ppc85xx_setup.c | 4 +- arch/ppc/syslib/prom_init.c | 24 +- arch/ppc/syslib/todc_time.c | 8 +- arch/ppc64/Kconfig | 146 +- arch/ppc64/Kconfig.debug | 59 + arch/ppc64/Makefile | 19 +- arch/ppc64/boot/Makefile | 39 +- arch/ppc64/boot/main.c | 170 +- arch/ppc64/boot/zImage.lds | 12 +- arch/ppc64/configs/g5_defconfig | 197 +- arch/ppc64/configs/iSeries_defconfig | 109 +- arch/ppc64/configs/pSeries_defconfig | 263 +- arch/ppc64/kernel/ItLpQueue.c | 2 +- arch/ppc64/kernel/Makefile | 17 +- arch/ppc64/kernel/asm-offsets.c | 19 +- arch/ppc64/kernel/btext.c | 231 +- arch/ppc64/kernel/eeh.c | 321 +- arch/ppc64/kernel/entry.S | 31 +- arch/ppc64/kernel/head.S | 264 +- arch/ppc64/kernel/hvconsole.c | 66 +- arch/ppc64/kernel/hvcserver.c | 86 +- arch/ppc64/kernel/iSeries_htab.c | 2 + arch/ppc64/kernel/iSeries_pci.c | 45 +- arch/ppc64/kernel/iSeries_pci_reset.c | 3 +- arch/ppc64/kernel/iSeries_setup.c | 178 +- arch/ppc64/kernel/iSeries_setup.h | 4 - arch/ppc64/kernel/idle.c | 226 +- arch/ppc64/kernel/idle_power4.S | 2 +- arch/ppc64/kernel/ioctl32.c | 2 - arch/ppc64/kernel/iomap.c | 119 + arch/ppc64/kernel/iommu.c | 2 +- arch/ppc64/kernel/irq.c | 72 +- arch/ppc64/kernel/lmb.c | 63 +- arch/ppc64/kernel/lparcfg.c | 224 +- arch/ppc64/kernel/mf_proc.c | 30 +- arch/ppc64/kernel/misc.S | 137 +- arch/ppc64/kernel/nvram.c | 4 +- arch/ppc64/kernel/open_pic.c | 5 - arch/ppc64/kernel/open_pic_u3.c | 2 +- arch/ppc64/kernel/pSeries_iommu.c | 200 +- arch/ppc64/kernel/pSeries_lpar.c | 266 +- arch/ppc64/kernel/pSeries_pci.c | 396 +- arch/ppc64/kernel/pSeries_setup.c | 579 ++ arch/ppc64/kernel/pacaData.c | 31 +- arch/ppc64/kernel/pci.c | 377 +- arch/ppc64/kernel/pci.h | 4 +- arch/ppc64/kernel/pci_dn.c | 4 +- arch/ppc64/kernel/pci_iommu.c | 4 +- arch/ppc64/kernel/pmac_feature.c | 11 +- arch/ppc64/kernel/pmac_low_i2c.c | 2 +- arch/ppc64/kernel/pmac_pci.c | 26 +- arch/ppc64/kernel/pmac_setup.c | 267 +- arch/ppc64/kernel/pmac_smp.c | 1 - arch/ppc64/kernel/pmac_time.c | 2 +- arch/ppc64/kernel/ppc_ksyms.c | 15 +- arch/ppc64/kernel/process.c | 29 +- arch/ppc64/kernel/prom.c | 2439 ++----- arch/ppc64/kernel/prom_init.c | 1714 +++++ arch/ppc64/kernel/ras.c | 8 +- arch/ppc64/kernel/rtas-proc.c | 2 +- arch/ppc64/kernel/rtas.c | 131 +- arch/ppc64/kernel/rtasd.c | 146 +- arch/ppc64/kernel/rtc.c | 2 +- arch/ppc64/kernel/setup.c | 909 ++- arch/ppc64/kernel/signal.c | 25 +- arch/ppc64/kernel/signal32.c | 40 +- arch/ppc64/kernel/smp.c | 380 +- arch/ppc64/kernel/sys_ppc32.c | 36 +- arch/ppc64/kernel/sysfs.c | 85 +- arch/ppc64/kernel/time.c | 103 +- arch/ppc64/kernel/traps.c | 241 +- arch/ppc64/kernel/u3_iommu.c | 321 + arch/ppc64/kernel/udbg.c | 56 +- arch/ppc64/kernel/vector.S | 4 +- arch/ppc64/kernel/vio.c | 4 + arch/ppc64/kernel/viopath.c | 2 +- arch/ppc64/kernel/vmlinux.lds.S | 12 +- arch/ppc64/kernel/xics.c | 2 +- arch/ppc64/lib/checksum.S | 14 +- arch/ppc64/lib/locks.c | 226 +- arch/ppc64/mm/Makefile | 4 +- arch/ppc64/mm/hash_low.S | 16 +- arch/ppc64/mm/hash_native.c | 419 ++ arch/ppc64/mm/hash_utils.c | 95 +- arch/ppc64/mm/hugetlbpage.c | 104 +- arch/ppc64/mm/imalloc.c | 77 +- arch/ppc64/mm/init.c | 247 +- arch/ppc64/mm/mmap.c | 9 +- arch/ppc64/mm/numa.c | 238 +- arch/ppc64/mm/slb.c | 85 +- arch/ppc64/mm/slb_low.S | 99 +- arch/ppc64/mm/stab.c | 240 + arch/ppc64/mm/tlb.c | 2 +- arch/ppc64/oprofile/common.c | 21 +- arch/ppc64/oprofile/op_impl.h | 15 +- arch/ppc64/oprofile/op_model_power4.c | 33 +- arch/ppc64/oprofile/op_model_rs64.c | 6 +- arch/ppc64/xmon/xmon.c | 42 +- arch/s390/Kconfig | 187 +- arch/s390/Kconfig.debug | 5 + arch/s390/Makefile | 34 +- arch/s390/appldata/appldata_mem.c | 8 +- arch/s390/defconfig | 34 +- arch/s390/kernel/Makefile | 4 +- arch/s390/kernel/asm-offsets.c | 4 + arch/s390/kernel/compat_exec.c | 2 +- arch/s390/kernel/compat_linux.c | 5 +- arch/s390/kernel/compat_signal.c | 45 +- arch/s390/kernel/debug.c | 13 +- arch/s390/kernel/ebcdic.c | 12 +- arch/s390/kernel/entry.S | 103 +- arch/s390/kernel/entry64.S | 107 +- arch/s390/kernel/head.S | 6 +- arch/s390/kernel/head64.S | 6 +- arch/s390/kernel/irq.c | 99 + arch/s390/kernel/process.c | 97 +- arch/s390/kernel/profile.c | 41 +- arch/s390/kernel/s390_ext.c | 1 + arch/s390/kernel/s390_ksyms.c | 21 +- arch/s390/kernel/setup.c | 51 +- arch/s390/kernel/signal.c | 25 +- arch/s390/kernel/smp.c | 30 +- arch/s390/kernel/time.c | 42 +- arch/s390/kernel/traps.c | 96 +- arch/s390/kernel/vmlinux.lds.S | 4 +- arch/s390/kernel/vtime.c | 2 +- arch/s390/lib/string.c | 34 +- arch/s390/mm/Makefile | 2 +- arch/s390/mm/fault.c | 8 +- arch/sh/Kconfig | 162 +- arch/sh/Kconfig.debug | 124 + arch/sh/Makefile | 4 +- arch/sh/boards/mpc1211/pci.c | 9 +- arch/sh/boards/overdrive/galileo.c | 8 +- arch/sh/boot/compressed/Makefile | 2 +- arch/sh/drivers/pci/fixups-dreamcast.c | 6 +- arch/sh/drivers/pci/pci-sh7751.c | 9 +- arch/sh/drivers/pci/pci-st40.c | 8 +- arch/sh/kernel/Makefile | 2 +- arch/sh/kernel/irq.c | 8 +- arch/sh/kernel/process.c | 2 +- arch/sh/kernel/sh_ksyms.c | 3 +- arch/sh/kernel/signal.c | 8 +- arch/sh/kernel/smp.c | 10 +- arch/sh/kernel/time.c | 35 +- arch/sh/kernel/vmlinux.lds.S | 4 +- arch/sh/mm/fault-nommu.c | 1 - arch/sh/mm/fault.c | 1 - arch/sh/mm/init.c | 6 +- arch/sh/mm/tlb-sh3.c | 1 - arch/sh/mm/tlb-sh4.c | 1 - arch/sh64/Kconfig | 50 +- arch/sh64/Kconfig.debug | 37 + arch/sh64/boot/compressed/Makefile | 6 +- arch/sh64/kernel/irq.c | 6 +- arch/sh64/kernel/pci_sh5.c | 7 +- arch/sh64/kernel/process.c | 4 +- arch/sh64/kernel/ptrace.c | 7 +- arch/sh64/kernel/sh_ksyms.c | 29 +- arch/sh64/kernel/signal.c | 8 +- arch/sh64/kernel/time.c | 34 +- arch/sh64/kernel/vmlinux.lds.S | 4 +- arch/sh64/mm/fault.c | 1 - arch/sh64/mm/init.c | 4 +- arch/sh64/mm/tlbmiss.c | 1 - arch/sparc/Kconfig | 80 +- arch/sparc/Kconfig.debug | 14 + arch/sparc/Makefile | 2 +- arch/sparc/boot/Makefile | 42 +- arch/sparc/kernel/Makefile | 2 +- arch/sparc/kernel/entry.S | 2 +- arch/sparc/kernel/init_task.c | 2 +- arch/sparc/kernel/irq.c | 1 - arch/sparc/kernel/pcic.c | 4 - arch/sparc/kernel/process.c | 2 - arch/sparc/kernel/ptrace.c | 7 +- arch/sparc/kernel/setup.c | 1 - arch/sparc/kernel/signal.c | 37 +- arch/sparc/kernel/smp.c | 1 - arch/sparc/kernel/sparc_ksyms.c | 8 +- arch/sparc/kernel/sun4d_smp.c | 18 +- arch/sparc/kernel/sun4m_smp.c | 18 +- arch/sparc/kernel/systbls.S | 2 +- arch/sparc/kernel/time.c | 53 +- arch/sparc/kernel/vmlinux.lds.S | 4 +- arch/sparc/mm/srmmu.c | 2 +- arch/sparc/mm/sun4c.c | 4 +- arch/sparc64/Kconfig | 113 +- arch/sparc64/Kconfig.debug | 54 + arch/sparc64/Makefile | 8 +- arch/sparc64/boot/Makefile | 2 +- arch/sparc64/defconfig | 63 +- arch/sparc64/kernel/Makefile | 3 +- arch/sparc64/kernel/auxio.c | 11 +- arch/sparc64/kernel/binfmt_elf32.c | 4 +- arch/sparc64/kernel/chmc.c | 2 +- arch/sparc64/kernel/etrap.S | 301 +- arch/sparc64/kernel/head.S | 5 +- arch/sparc64/kernel/irq.c | 20 +- arch/sparc64/kernel/kprobes.c | 373 + arch/sparc64/kernel/pci.c | 8 - arch/sparc64/kernel/pci_common.c | 122 +- arch/sparc64/kernel/pci_impl.h | 1 - arch/sparc64/kernel/pci_iommu.c | 60 +- arch/sparc64/kernel/pci_psycho.c | 28 +- arch/sparc64/kernel/pci_sabre.c | 25 +- arch/sparc64/kernel/pci_schizo.c | 24 +- arch/sparc64/kernel/power.c | 11 +- arch/sparc64/kernel/process.c | 2 - arch/sparc64/kernel/ptrace.c | 7 +- arch/sparc64/kernel/setup.c | 1 - arch/sparc64/kernel/signal.c | 37 +- arch/sparc64/kernel/signal32.c | 135 +- arch/sparc64/kernel/smp.c | 15 +- arch/sparc64/kernel/sparc64_ksyms.c | 40 +- arch/sparc64/kernel/sys32.S | 2 +- arch/sparc64/kernel/sys_sparc32.c | 38 +- arch/sparc64/kernel/systbls.S | 4 +- arch/sparc64/kernel/time.c | 180 +- arch/sparc64/kernel/traps.c | 141 +- arch/sparc64/kernel/ttable.S | 2 +- arch/sparc64/kernel/vmlinux.lds.S | 4 +- arch/sparc64/lib/Makefile | 11 +- arch/sparc64/lib/PeeCeeI.c | 12 +- arch/sparc64/lib/U1copy_from_user.S | 33 + arch/sparc64/lib/U1copy_to_user.S | 33 + arch/sparc64/lib/U1memcpy.S | 555 ++ arch/sparc64/lib/U3copy_from_user.S | 424 +- arch/sparc64/lib/U3copy_to_user.S | 424 +- arch/sparc64/lib/U3memcpy.S | 331 +- arch/sparc64/lib/U3patch.S | 32 + arch/sparc64/lib/atomic.S | 9 +- arch/sparc64/lib/bitops.S | 44 +- arch/sparc64/lib/copy_in_user.S | 119 + arch/sparc64/lib/copy_page.S | 3 + arch/sparc64/lib/debuglocks.c | 2 +- arch/sparc64/lib/delay.c | 49 + arch/sparc64/lib/iomap.c | 48 + arch/sparc64/lib/ipcsum.S | 6 +- arch/sparc64/lib/memmove.S | 33 + arch/sparc64/lib/strlen.S | 6 +- arch/sparc64/lib/strncmp.S | 7 +- arch/sparc64/lib/strncpy_from_user.S | 4 +- arch/sparc64/lib/user_fixup.c | 68 + arch/sparc64/lib/xor.S | 28 +- arch/sparc64/mm/fault.c | 11 +- arch/sparc64/mm/init.c | 19 +- arch/sparc64/solaris/misc.c | 69 +- arch/um/Kconfig | 125 +- arch/um/Kconfig.debug | 43 + arch/um/Kconfig_block | 5 + arch/um/Kconfig_char | 56 +- arch/um/Kconfig_net | 72 +- arch/um/Makefile | 169 +- arch/um/Makefile-i386 | 42 +- arch/um/Makefile-skas | 9 +- arch/um/Makefile-tt | 3 +- arch/um/config.release | 1 - arch/um/defconfig | 282 +- arch/um/drivers/Makefile | 18 +- arch/um/drivers/chan_kern.c | 67 +- arch/um/drivers/chan_user.c | 104 +- arch/um/drivers/cow.h | 16 +- arch/um/drivers/cow_sys.h | 48 + arch/um/drivers/cow_user.c | 46 +- arch/um/drivers/daemon_user.c | 26 +- arch/um/drivers/fd.c | 20 +- arch/um/drivers/harddog_user.c | 62 +- arch/um/drivers/hostaudio_kern.c | 145 +- arch/um/drivers/line.c | 159 +- arch/um/drivers/mcast_user.c | 16 +- arch/um/drivers/mconsole_kern.c | 154 +- arch/um/drivers/mconsole_user.c | 25 +- arch/um/drivers/mmapper_kern.c | 5 +- arch/um/drivers/net_kern.c | 123 +- arch/um/drivers/net_user.c | 49 +- arch/um/drivers/null.c | 1 - arch/um/drivers/port_kern.c | 17 +- arch/um/drivers/port_user.c | 42 +- arch/um/drivers/pty.c | 45 +- arch/um/drivers/slip_user.c | 75 +- arch/um/drivers/slirp_user.c | 23 +- arch/um/drivers/ssl.c | 49 +- arch/um/drivers/stdio_console.c | 62 +- arch/um/drivers/tty.c | 15 +- arch/um/drivers/ubd_kern.c | 658 +- arch/um/drivers/ubd_user.c | 498 +- arch/um/drivers/xterm.c | 37 +- arch/um/drivers/xterm_kern.c | 12 +- arch/um/include/2_5compat.h | 14 - arch/um/include/irq_kern.h | 4 +- arch/um/include/irq_user.h | 1 + arch/um/include/kern_util.h | 11 +- arch/um/include/line.h | 4 +- arch/um/include/mconsole.h | 6 +- arch/um/include/mem.h | 15 +- arch/um/include/mem_kern.h | 2 +- arch/um/include/mem_user.h | 31 +- arch/um/include/os.h | 55 +- arch/um/include/signal_user.h | 2 + arch/um/include/skas_ptrace.h | 2 +- arch/um/include/sysdep-i386/checksum.h | 4 +- arch/um/include/sysdep-i386/frame_user.h | 28 +- arch/um/include/sysdep-i386/sigcontext.h | 4 +- arch/um/include/sysdep-i386/syscalls.h | 59 +- arch/um/include/time_user.h | 1 + arch/um/include/ubd_user.h | 9 +- arch/um/include/um_uaccess.h | 51 + arch/um/include/user.h | 3 + arch/um/include/user_util.h | 13 +- arch/um/kernel/Makefile | 57 +- arch/um/kernel/config.c.in | 4 +- arch/um/kernel/dyn.lds.S | 171 + arch/um/kernel/exec_kern.c | 5 + arch/um/kernel/frame.c | 11 +- arch/um/kernel/frame_kern.c | 6 +- arch/um/kernel/helper.c | 62 +- arch/um/kernel/init_task.c | 17 +- arch/um/kernel/initrd_user.c | 13 +- arch/um/kernel/irq.c | 154 +- arch/um/kernel/irq_user.c | 51 +- arch/um/kernel/ksyms.c | 60 +- arch/um/kernel/main.c | 249 + arch/um/kernel/mem.c | 657 +- arch/um/kernel/mem_user.c | 224 +- arch/um/kernel/physmem.c | 130 +- arch/um/kernel/process.c | 106 +- arch/um/kernel/process_kern.c | 63 +- arch/um/kernel/ptrace.c | 25 +- arch/um/kernel/reboot.c | 2 + arch/um/kernel/sigio_kern.c | 17 +- arch/um/kernel/sigio_user.c | 106 +- arch/um/kernel/signal_kern.c | 79 +- arch/um/kernel/signal_user.c | 11 + arch/um/kernel/skas/Makefile | 16 +- arch/um/kernel/skas/exec_user.c | 6 +- arch/um/kernel/skas/include/mode.h | 6 +- arch/um/kernel/skas/include/ptrace-skas.h | 10 + arch/um/kernel/skas/include/skas.h | 4 +- arch/um/kernel/skas/include/uaccess.h | 207 +- arch/um/kernel/skas/mem_user.c | 32 +- arch/um/kernel/skas/mmu.c | 8 +- arch/um/kernel/skas/process.c | 192 +- arch/um/kernel/skas/process_kern.c | 115 +- arch/um/kernel/skas/sys-i386/Makefile | 2 - arch/um/kernel/skas/sys-i386/sigcontext.c | 15 +- arch/um/kernel/skas/syscall_kern.c | 2 +- arch/um/kernel/skas/syscall_user.c | 4 +- arch/um/kernel/skas/tlb.c | 2 +- arch/um/kernel/skas/trap_user.c | 9 +- arch/um/kernel/skas/uaccess.c | 71 +- arch/um/kernel/skas/util/Makefile | 12 +- arch/um/kernel/skas/util/mk_ptregs.c | 1 + arch/um/kernel/smp.c | 112 +- arch/um/kernel/sys_call_table.c | 685 +- arch/um/kernel/syscall_kern.c | 65 +- arch/um/kernel/sysrq.c | 5 + arch/um/kernel/tempfile.c | 7 +- arch/um/kernel/time.c | 41 +- arch/um/kernel/time_kern.c | 87 +- arch/um/kernel/trap_kern.c | 51 +- arch/um/kernel/trap_user.c | 20 +- arch/um/kernel/tt/Makefile | 6 +- arch/um/kernel/tt/exec_kern.c | 13 +- arch/um/kernel/tt/exec_user.c | 9 +- arch/um/kernel/tt/include/mode.h | 2 + arch/um/kernel/tt/include/uaccess.h | 60 +- arch/um/kernel/tt/mem.c | 2 +- arch/um/kernel/tt/mem_user.c | 7 +- arch/um/kernel/tt/process_kern.c | 140 +- arch/um/kernel/tt/ptproxy/Makefile | 2 - arch/um/kernel/tt/ptproxy/proxy.c | 29 +- arch/um/kernel/tt/ptproxy/sysdep.c | 1 + arch/um/kernel/tt/ptproxy/wait.c | 12 +- arch/um/kernel/tt/sys-i386/Makefile | 2 - arch/um/kernel/tt/syscall_kern.c | 2 +- arch/um/kernel/tt/syscall_user.c | 4 +- arch/um/kernel/tt/tlb.c | 1 + arch/um/kernel/tt/tracer.c | 32 +- arch/um/kernel/tt/trap_user.c | 9 +- arch/um/kernel/tt/uaccess.c | 10 +- arch/um/kernel/tt/uaccess_user.c | 24 +- arch/um/kernel/tt/unmap.c | 3 - arch/um/kernel/tty_log.c | 136 +- arch/um/kernel/uaccess_user.c | 4 +- arch/um/kernel/um_arch.c | 92 +- arch/um/kernel/umid.c | 87 +- arch/um/kernel/uml.lds.S | 96 + arch/um/kernel/user_util.c | 65 +- arch/um/os-Linux/Makefile | 8 +- arch/um/os-Linux/drivers/ethertap_kern.c | 1 - arch/um/os-Linux/drivers/ethertap_user.c | 58 +- arch/um/os-Linux/drivers/tuntap_user.c | 60 +- arch/um/os-Linux/file.c | 461 +- arch/um/os-Linux/process.c | 72 +- arch/um/os-Linux/time.c | 21 + arch/um/os-Linux/tty.c | 10 +- arch/um/os-Linux/user_syms.c | 4 +- arch/um/sys-i386/Makefile | 30 +- arch/um/sys-i386/bugs.c | 147 +- arch/um/sys-i386/fault.c | 16 +- arch/um/sys-i386/ldt.c | 2 + arch/um/sys-i386/ptrace_user.c | 9 +- arch/um/sys-i386/syscalls.c | 22 + arch/um/sys-i386/util/Makefile | 19 +- arch/um/sys-i386/util/mk_sc.c | 1 + arch/um/sys-ia64/Makefile | 15 +- arch/um/sys-ppc/Makefile | 11 +- arch/um/util/Makefile | 27 +- arch/um/util/mk_constants_kern.c | 4 + arch/v850/Kconfig | 32 +- arch/v850/Kconfig.debug | 10 + arch/v850/kernel/Makefile | 2 +- arch/v850/kernel/asm-consts.c | 2 +- arch/v850/kernel/irq.c | 6 +- arch/v850/kernel/ptrace.c | 17 +- arch/v850/kernel/rte_mb_a_pci.c | 2 - arch/v850/kernel/setup.c | 4 +- arch/v850/kernel/signal.c | 8 +- arch/v850/kernel/time.c | 23 +- arch/v850/kernel/v850_ksyms.c | 53 +- arch/v850/kernel/vmlinux.lds.S | 3 - arch/x86_64/Kconfig | 155 +- arch/x86_64/Kconfig.debug | 59 + arch/x86_64/Makefile | 11 +- arch/x86_64/boot/Makefile | 2 +- arch/x86_64/boot/video.S | 86 +- arch/x86_64/defconfig | 60 +- arch/x86_64/ia32/ia32_binfmt.c | 5 +- arch/x86_64/ia32/ia32_ioctl.c | 15 - arch/x86_64/ia32/ia32_signal.c | 64 +- arch/x86_64/ia32/ia32entry.S | 34 +- arch/x86_64/ia32/ptrace32.c | 6 +- arch/x86_64/ia32/sys_ia32.c | 50 +- arch/x86_64/ia32/syscall32.c | 25 +- arch/x86_64/kernel/Makefile | 3 +- arch/x86_64/kernel/aperture.c | 23 +- arch/x86_64/kernel/apic.c | 62 +- arch/x86_64/kernel/asm-offsets.c | 2 +- arch/x86_64/kernel/cpufreq/Kconfig | 54 + arch/x86_64/kernel/cpufreq/Makefile | 8 +- arch/x86_64/kernel/early_printk.c | 19 +- arch/x86_64/kernel/entry.S | 19 +- arch/x86_64/kernel/i8259.c | 55 +- arch/x86_64/kernel/init_task.c | 3 +- arch/x86_64/kernel/io_apic.c | 228 +- arch/x86_64/kernel/ioport.c | 40 +- arch/x86_64/kernel/irq.c | 45 +- arch/x86_64/kernel/ldt.c | 10 +- arch/x86_64/kernel/mce.c | 132 +- arch/x86_64/kernel/msr.c | 325 +- arch/x86_64/kernel/nmi.c | 3 +- arch/x86_64/kernel/pci-dma.c | 21 +- arch/x86_64/kernel/pci-gart.c | 290 +- arch/x86_64/kernel/pci-nommu.c | 62 +- arch/x86_64/kernel/process.c | 85 +- arch/x86_64/kernel/ptrace.c | 21 +- arch/x86_64/kernel/setup.c | 65 +- arch/x86_64/kernel/setup64.c | 39 +- arch/x86_64/kernel/signal.c | 58 +- arch/x86_64/kernel/smp.c | 57 +- arch/x86_64/kernel/smpboot.c | 28 +- arch/x86_64/kernel/suspend.c | 2 +- arch/x86_64/kernel/suspend_asm.S | 82 +- arch/x86_64/kernel/time.c | 160 +- arch/x86_64/kernel/traps.c | 77 +- arch/x86_64/kernel/vmlinux.lds.S | 4 +- arch/x86_64/kernel/x8664_ksyms.c | 92 +- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/bitops.c | 140 + arch/x86_64/lib/bitstr.c | 3 + arch/x86_64/lib/csum-wrappers.c | 2 + arch/x86_64/lib/memmove.c | 16 +- arch/x86_64/lib/usercopy.c | 2 + arch/x86_64/mm/fault.c | 100 +- arch/x86_64/mm/init.c | 22 +- arch/x86_64/mm/ioremap.c | 12 +- arch/x86_64/mm/k8topology.c | 4 +- arch/x86_64/mm/numa.c | 57 +- arch/x86_64/pci/Makefile | 4 +- arch/x86_64/pci/Makefile-BUS | 22 + arch/x86_64/pci/k8-bus.c | 74 + crypto/Kconfig | 14 +- crypto/Makefile | 1 + crypto/aes.c | 14 +- crypto/api.c | 6 +- crypto/arc4.c | 4 +- crypto/blowfish.c | 6 +- crypto/internal.h | 1 - crypto/scatterwalk.c | 2 +- crypto/tcrypt.c | 22 +- crypto/tcrypt.h | 255 +- crypto/tea.c | 2 +- crypto/twofish.c | 4 +- crypto/wp512.c | 1208 ++++ drivers/Makefile | 12 +- drivers/acpi/Kconfig | 26 + drivers/acpi/Makefile | 2 +- drivers/acpi/acpi_ksyms.c | 2 + drivers/acpi/asus_acpi.c | 184 +- drivers/acpi/blacklist.c | 58 +- drivers/acpi/bus.c | 50 +- drivers/acpi/button.c | 9 + drivers/acpi/debug.c | 105 +- drivers/acpi/dispatcher/dsmethod.c | 70 +- drivers/acpi/dispatcher/dsmthdat.c | 8 +- drivers/acpi/dispatcher/dsopcode.c | 7 +- drivers/acpi/dispatcher/dsutils.c | 53 +- drivers/acpi/dispatcher/dswload.c | 22 + drivers/acpi/dispatcher/dswstate.c | 18 +- drivers/acpi/ec.c | 13 +- drivers/acpi/events/evevent.c | 12 +- drivers/acpi/events/evgpe.c | 397 +- drivers/acpi/events/evgpeblk.c | 181 +- drivers/acpi/events/evmisc.c | 45 +- drivers/acpi/events/evregion.c | 388 +- drivers/acpi/events/evrgnini.c | 12 +- drivers/acpi/events/evxface.c | 191 +- drivers/acpi/events/evxfevnt.c | 173 +- drivers/acpi/events/evxfregn.c | 203 +- drivers/acpi/executer/exconfig.c | 47 +- drivers/acpi/executer/exfldio.c | 200 +- drivers/acpi/executer/exmisc.c | 149 +- drivers/acpi/executer/exmutex.c | 46 +- drivers/acpi/executer/exoparg2.c | 48 +- drivers/acpi/executer/exresolv.c | 8 +- drivers/acpi/executer/exstore.c | 17 +- drivers/acpi/hardware/hwgpe.c | 341 +- drivers/acpi/hardware/hwregs.c | 104 +- drivers/acpi/hardware/hwsleep.c | 57 +- drivers/acpi/hardware/hwtimer.c | 28 +- drivers/acpi/motherboard.c | 177 + drivers/acpi/namespace/nsaccess.c | 2 +- drivers/acpi/namespace/nsalloc.c | 2 +- drivers/acpi/namespace/nseval.c | 90 +- drivers/acpi/namespace/nsinit.c | 42 +- drivers/acpi/namespace/nsparse.c | 5 +- drivers/acpi/namespace/nsxfeval.c | 52 +- drivers/acpi/namespace/nsxfname.c | 4 +- drivers/acpi/numa.c | 16 +- drivers/acpi/osl.c | 74 +- drivers/acpi/parser/psopcode.c | 8 +- drivers/acpi/parser/psxface.c | 51 +- drivers/acpi/pci_link.c | 80 +- drivers/acpi/power.c | 80 + drivers/acpi/processor.c | 81 +- drivers/acpi/resources/rsutils.c | 7 +- drivers/acpi/resources/rsxface.c | 3 +- drivers/acpi/scan.c | 193 +- drivers/acpi/sleep/Makefile | 2 +- drivers/acpi/sleep/main.c | 36 +- drivers/acpi/sleep/proc.c | 86 + drivers/acpi/sleep/sleep.h | 3 + drivers/acpi/sleep/wakeup.c | 181 + drivers/acpi/tables.c | 4 +- drivers/acpi/tables/tbxfroot.c | 205 +- drivers/acpi/thermal.c | 88 +- drivers/acpi/utilities/utalloc.c | 13 +- drivers/acpi/utilities/uteval.c | 18 +- drivers/acpi/utilities/utglobal.c | 88 +- drivers/acpi/utilities/utxface.c | 41 +- drivers/atm/Makefile | 2 +- drivers/atm/ambassador.c | 5 +- drivers/atm/eni.c | 73 +- drivers/atm/eni.h | 20 +- drivers/atm/firestream.c | 5 +- drivers/atm/firestream.h | 2 +- drivers/atm/fore200e.h | 2 +- drivers/atm/he.c | 17 +- drivers/atm/he.h | 2 +- drivers/atm/idt77252.c | 81 +- drivers/atm/idt77252.h | 4 +- drivers/atm/lanai.c | 12 +- drivers/atm/nicstar.c | 5 +- drivers/atm/nicstar.h | 2 +- drivers/atm/nicstarmac.c | 2 +- drivers/atm/nicstarmac.h | 2 +- drivers/base/class.c | 9 +- drivers/base/firmware_class.c | 4 +- drivers/base/node.c | 13 +- drivers/block/DAC960.c | 41 +- drivers/block/DAC960.h | 188 +- drivers/block/Kconfig | 11 +- drivers/block/Makefile | 1 + drivers/block/amiflop.c | 16 +- drivers/block/cciss.c | 71 +- drivers/block/cciss.h | 6 +- drivers/block/cpqarray.c | 14 +- drivers/block/cpqarray.h | 2 +- drivers/block/genhd.c | 4 + drivers/block/ioctl.c | 3 +- drivers/block/ll_rw_blk.c | 279 +- drivers/block/nbd.c | 39 +- drivers/block/rd.c | 9 +- drivers/block/scsi_ioctl.c | 30 +- drivers/block/sx8.c | 96 +- drivers/block/ub.c | 2097 ++++++ drivers/block/umem.c | 10 +- drivers/bluetooth/hci_ldisc.c | 8 +- drivers/bluetooth/hci_usb.c | 2 +- drivers/cdrom/cdrom.c | 177 +- drivers/cdrom/cdu31a.c | 6 +- drivers/cdrom/mcd.c | 7 +- drivers/cdrom/viocd.c | 63 +- drivers/char/Kconfig | 53 +- drivers/char/Makefile | 9 +- drivers/char/agp/Kconfig | 4 +- drivers/char/agp/agp.h | 2 +- drivers/char/agp/amd-k7-agp.c | 31 +- drivers/char/agp/amd64-agp.c | 8 +- drivers/char/agp/ati-agp.c | 31 +- drivers/char/agp/generic.c | 16 +- drivers/char/agp/hp-agp.c | 16 +- drivers/char/agp/intel-agp.c | 127 +- drivers/char/agp/intel-mch-agp.c | 8 +- drivers/char/agp/nvidia-agp.c | 25 +- drivers/char/agp/sis-agp.c | 4 + drivers/char/agp/sworks-agp.c | 43 +- drivers/char/agp/via-agp.c | 33 +- drivers/char/amiserial.c | 22 +- drivers/char/applicom.c | 28 +- drivers/char/cyclades.c | 648 +- drivers/char/drm/Kconfig | 27 +- drivers/char/drm/Makefile | 2 + drivers/char/drm/drmP.h | 233 +- drivers/char/drm/drm_agpsupport.h | 5 +- drivers/char/drm/drm_bufs.h | 137 +- drivers/char/drm/drm_context.h | 20 +- drivers/char/drm/drm_core.h | 40 + drivers/char/drm/drm_dma.h | 53 +- drivers/char/drm/drm_drv.h | 532 +- drivers/char/drm/drm_fops.h | 15 +- drivers/char/drm/drm_ioctl.h | 6 +- drivers/char/drm/drm_irq.h | 81 +- drivers/char/drm/drm_memory.h | 38 +- drivers/char/drm/drm_memory_debug.h | 2 +- drivers/char/drm/drm_os_linux.h | 42 +- drivers/char/drm/drm_pciids.h | 8 + drivers/char/drm/drm_scatter.h | 6 + drivers/char/drm/drm_vm.h | 44 +- drivers/char/drm/ffb.h | 4 - drivers/char/drm/ffb_context.c | 30 +- drivers/char/drm/ffb_drv.c | 214 +- drivers/char/drm/ffb_drv.h | 10 + drivers/char/drm/gamma.h | 39 +- drivers/char/drm/gamma_context.h | 4 +- drivers/char/drm/gamma_dma.c | 78 +- drivers/char/drm/gamma_drv.c | 1 + drivers/char/drm/gamma_drv.h | 5 +- drivers/char/drm/i810.h | 47 - drivers/char/drm/i810_dma.c | 51 +- drivers/char/drm/i810_drv.c | 17 +- drivers/char/drm/i810_drv.h | 1 - drivers/char/drm/i830.h | 50 - drivers/char/drm/i830_dma.c | 62 +- drivers/char/drm/i830_drv.c | 18 +- drivers/char/drm/i830_drv.h | 5 +- drivers/char/drm/i830_irq.c | 12 +- drivers/char/drm/i915.h | 53 + drivers/char/drm/i915_dma.c | 755 ++ drivers/char/drm/i915_drm.h | 154 + drivers/char/drm/i915_drv.c | 17 + drivers/char/drm/i915_drv.h | 219 + drivers/char/drm/i915_irq.c | 165 + drivers/char/drm/i915_mem.c | 347 + drivers/char/drm/mga.h | 35 - drivers/char/drm/mga_dma.c | 59 +- drivers/char/drm/mga_drv.c | 17 +- drivers/char/drm/mga_drv.h | 6 + drivers/char/drm/mga_irq.c | 4 +- drivers/char/drm/r128.h | 45 - drivers/char/drm/r128_cce.c | 45 +- drivers/char/drm/r128_drv.c | 18 +- drivers/char/drm/r128_drv.h | 7 +- drivers/char/drm/r128_irq.c | 4 +- drivers/char/drm/r128_state.c | 36 +- drivers/char/drm/radeon.h | 61 - drivers/char/drm/radeon_cp.c | 54 +- drivers/char/drm/radeon_drv.c | 18 +- drivers/char/drm/radeon_drv.h | 9 +- drivers/char/drm/radeon_irq.c | 4 +- drivers/char/drm/radeon_state.c | 83 +- drivers/char/drm/sis.h | 17 - drivers/char/drm/sis_drv.c | 16 +- drivers/char/drm/sis_drv.h | 2 - drivers/char/drm/sis_mm.c | 18 +- drivers/char/drm/tdfx.h | 2 - drivers/char/drm/tdfx_drv.c | 20 +- drivers/char/ds1620.c | 3 +- drivers/char/dsp56k.c | 14 +- drivers/char/ec3104_keyb.c | 2 +- drivers/char/efirtc.c | 19 +- drivers/char/epca.c | 29 +- drivers/char/esp.c | 21 +- drivers/char/ftape/lowlevel/ftape-calibr.c | 71 +- drivers/char/generic_serial.c | 14 +- drivers/char/hpet.c | 99 +- drivers/char/hvc_console.c | 754 +- drivers/char/hvcs.c | 443 +- drivers/char/hvsi.c | 1319 ++++ drivers/char/ip2/ip2types.h | 3 + drivers/char/ip2main.c | 17 +- drivers/char/ipmi/Kconfig | 7 + drivers/char/ipmi/Makefile | 1 + drivers/char/ipmi/ipmi_bt_sm.c | 2 +- drivers/char/ipmi/ipmi_devintf.c | 2 +- drivers/char/ipmi/ipmi_kcs_sm.c | 2 +- drivers/char/ipmi/ipmi_msghandler.c | 58 +- drivers/char/ipmi/ipmi_poweroff.c | 543 ++ drivers/char/ipmi/ipmi_si_intf.c | 360 +- drivers/char/ipmi/ipmi_si_sm.h | 3 + drivers/char/ipmi/ipmi_smic_sm.c | 2 +- drivers/char/ipmi/ipmi_watchdog.c | 71 +- drivers/char/isicom.c | 32 +- drivers/char/istallion.c | 40 +- drivers/char/keyboard.c | 33 +- drivers/char/mem.c | 10 +- drivers/char/mmtimer.c | 216 + drivers/char/moxa.c | 16 +- drivers/char/mxser.c | 150 +- drivers/char/n_tty.c | 382 +- drivers/char/nwflash.c | 19 +- drivers/char/pcmcia/synclink_cs.c | 637 +- drivers/char/pcxx.c | 58 +- drivers/char/pty.c | 171 +- drivers/char/random.c | 234 +- drivers/char/rio/linux_compat.h | 2 +- drivers/char/rio/rio_linux.c | 6 +- drivers/char/riscom8.c | 32 +- drivers/char/rocket.c | 38 +- drivers/char/rocket_int.h | 4 - drivers/char/selection.c | 11 +- drivers/char/ser_a2232.c | 5 +- drivers/char/serial167.c | 40 +- drivers/char/serial_tx3912.c | 5 +- drivers/char/snsc.c | 456 ++ drivers/char/snsc.h | 50 + drivers/char/sonypi.c | 5 +- drivers/char/sonypi.h | 2 - drivers/char/specialix.c | 29 +- drivers/char/stallion.c | 13 +- drivers/char/sx.c | 5 +- drivers/char/synclink.c | 647 +- drivers/char/synclinkmp.c | 783 +- drivers/char/tty_io.c | 819 ++- drivers/char/tty_ioctl.c | 63 +- drivers/char/viocons.c | 5 +- drivers/char/vme_scc.c | 8 +- drivers/char/vt.c | 52 +- drivers/char/vt_ioctl.c | 3 +- drivers/char/watchdog/Kconfig | 6 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/cpu5wdt.c | 3 +- drivers/char/watchdog/ib700wdt.c | 1 + drivers/char/watchdog/indydog.c | 1 + drivers/char/watchdog/ixp4xx_wdt.c | 1 + drivers/char/watchdog/machzwd.c | 1 + drivers/char/watchdog/mixcomwd.c | 1 + drivers/char/watchdog/mpc8xx_wdt.c | 164 + drivers/char/watchdog/pcwd.c | 3 +- drivers/char/watchdog/sa1100_wdt.c | 5 + drivers/char/watchdog/sc1200wdt.c | 1 + drivers/char/watchdog/scx200_wdt.c | 1 + drivers/char/watchdog/wdt285.c | 1 + drivers/char/watchdog/wdt977.c | 1 + drivers/char/watchdog/wdt_pci.c | 2 +- drivers/cpufreq/Kconfig | 15 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq.c | 172 +- drivers/cpufreq/cpufreq_ondemand.c | 437 ++ drivers/cpufreq/cpufreq_userspace.c | 27 + drivers/cpufreq/proc_intf.c | 17 + drivers/fc4/soc.h | 20 +- drivers/fc4/socal.c | 4 +- drivers/fc4/socal.h | 6 +- drivers/firmware/Kconfig | 5 +- drivers/i2c/Makefile | 3 + drivers/i2c/algos/Kconfig | 11 + drivers/i2c/algos/Makefile | 1 + drivers/i2c/algos/i2c-algo-bit.c | 4 +- drivers/i2c/algos/i2c-algo-ite.c | 14 +- drivers/i2c/algos/i2c-algo-pca.c | 395 + drivers/i2c/algos/i2c-algo-pca.h | 26 + drivers/i2c/algos/i2c-algo-pcf.c | 12 +- drivers/i2c/busses/Kconfig | 34 + drivers/i2c/busses/Makefile | 3 + drivers/i2c/busses/i2c-ali1563.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 6 +- drivers/i2c/busses/i2c-amd756.c | 2 +- drivers/i2c/busses/i2c-amd8111.c | 2 +- drivers/i2c/busses/i2c-elektor.c | 10 +- drivers/i2c/busses/i2c-hydra.c | 2 +- drivers/i2c/busses/i2c-i801.c | 6 +- drivers/i2c/busses/i2c-i810.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.c | 8 +- drivers/i2c/busses/i2c-ite.c | 24 +- drivers/i2c/busses/i2c-ixp2000.c | 171 + drivers/i2c/busses/i2c-keywest.c | 9 +- drivers/i2c/busses/i2c-mpc.c | 392 + drivers/i2c/busses/i2c-nforce2.c | 5 +- drivers/i2c/busses/i2c-parport-light.c | 4 +- drivers/i2c/busses/i2c-parport.h | 2 +- drivers/i2c/busses/i2c-pca-isa.c | 184 + drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-prosavage.c | 2 +- drivers/i2c/busses/i2c-savage4.c | 2 +- drivers/i2c/busses/i2c-sis5595.c | 6 +- drivers/i2c/busses/i2c-sis630.c | 17 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- drivers/i2c/busses/i2c-viapro.c | 8 +- drivers/i2c/busses/i2c-voodoo3.c | 2 +- drivers/i2c/busses/scx200_acb.c | 6 +- drivers/i2c/busses/scx200_i2c.c | 10 +- drivers/i2c/chips/Kconfig | 27 +- drivers/i2c/chips/Makefile | 3 + drivers/i2c/chips/adm1021.c | 2 +- drivers/i2c/chips/adm1025.c | 2 +- drivers/i2c/chips/asb100.c | 9 +- drivers/i2c/chips/ds1621.c | 2 +- drivers/i2c/chips/eeprom.c | 2 +- drivers/i2c/chips/isp1301_omap.c | 1660 +++++ drivers/i2c/chips/it87.c | 60 +- drivers/i2c/chips/lm78.c | 4 +- drivers/i2c/chips/lm83.c | 23 +- drivers/i2c/chips/lm85.c | 9 +- drivers/i2c/chips/pcf8591.c | 2 +- drivers/i2c/chips/rtc8564.c | 4 +- drivers/i2c/chips/smsc47m1.c | 579 ++ drivers/i2c/chips/via686a.c | 4 +- drivers/i2c/chips/w83627hf.c | 16 +- drivers/i2c/chips/w83781d.c | 13 +- drivers/i2c/i2c-sensor-detect.c | 169 + drivers/i2c/i2c-sensor-vid.c | 99 + drivers/ide/Kconfig | 12 +- drivers/ide/arm/Makefile | 1 + drivers/ide/arm/bast-ide.c | 71 + drivers/ide/arm/icside.c | 5 - drivers/ide/ide-cd.c | 14 +- drivers/ide/ide-disk.c | 179 +- drivers/ide/ide-dma.c | 13 +- drivers/ide/ide-io.c | 267 +- drivers/ide/ide-iops.c | 26 +- drivers/ide/ide-lib.c | 4 - drivers/ide/ide-probe.c | 43 +- drivers/ide/ide-proc.c | 27 +- drivers/ide/ide-tape.c | 74 - drivers/ide/ide-taskfile.c | 202 +- drivers/ide/ide.c | 218 +- drivers/ide/legacy/Makefile | 1 - drivers/ide/legacy/ide-cs.c | 6 - drivers/ide/legacy/pdc4030.c | 116 +- drivers/ide/legacy/qd65xx.h | 6 +- drivers/ide/pci/aec62xx.c | 49 +- drivers/ide/pci/aec62xx.h | 7 - drivers/ide/pci/alim15x3.c | 6 +- drivers/ide/pci/amd74xx.c | 5 +- drivers/ide/pci/atiixp.c | 2 +- drivers/ide/pci/cmd640.c | 6 +- drivers/ide/pci/cmd64x.c | 19 +- drivers/ide/pci/cmd64x.h | 4 - drivers/ide/pci/cs5520.c | 7 +- drivers/ide/pci/cy82c693.c | 2 +- drivers/ide/pci/generic.c | 2 +- drivers/ide/pci/hpt34x.c | 70 +- drivers/ide/pci/hpt34x.h | 2 - drivers/ide/pci/hpt366.c | 15 +- drivers/ide/pci/it8172.c | 2 +- drivers/ide/pci/ns87415.c | 2 +- drivers/ide/pci/opti621.c | 2 +- drivers/ide/pci/pdc202xx_new.c | 2 +- drivers/ide/pci/pdc202xx_old.c | 13 +- drivers/ide/pci/pdc202xx_old.h | 71 - drivers/ide/pci/piix.c | 45 +- drivers/ide/pci/rz1000.c | 2 +- drivers/ide/pci/sc1200.c | 2 +- drivers/ide/pci/serverworks.c | 2 +- drivers/ide/pci/sgiioc4.c | 7 +- drivers/ide/pci/siimage.c | 52 +- drivers/ide/pci/sis5513.c | 12 +- drivers/ide/pci/sl82c105.c | 2 +- drivers/ide/pci/slc90e66.c | 2 +- drivers/ide/pci/triflex.c | 64 +- drivers/ide/pci/trm290.c | 2 +- drivers/ide/pci/via82cxxx.c | 2 +- drivers/ide/ppc/pmac.c | 83 +- drivers/ieee1394/eth1394.c | 4 +- drivers/ieee1394/eth1394.h | 7 + drivers/ieee1394/ohci1394.h | 2 +- drivers/input/gameport/cs461x.c | 2 +- drivers/input/gameport/emu10k1-gp.c | 5 +- drivers/input/gameport/fm801-gp.c | 2 +- drivers/input/gameport/vortex.c | 6 +- drivers/input/joydev.c | 6 +- drivers/input/joystick/Kconfig | 4 +- drivers/input/joystick/gamecon.c | 194 +- drivers/input/joystick/grip_mp.c | 3 +- drivers/input/joystick/iforce/iforce-main.c | 4 +- drivers/input/joystick/iforce/iforce-serio.c | 18 +- drivers/input/joystick/iforce/iforce.h | 2 +- drivers/input/joystick/magellan.c | 24 +- drivers/input/joystick/spaceball.c | 24 +- drivers/input/joystick/spaceorb.c | 24 +- drivers/input/joystick/stinger.c | 24 +- drivers/input/joystick/tmdc.c | 2 +- drivers/input/joystick/twidjoy.c | 20 +- drivers/input/joystick/warrior.c | 24 +- drivers/input/keyboard/atkbd.c | 285 +- drivers/input/keyboard/lkkbd.c | 24 +- drivers/input/keyboard/newtonkbd.c | 24 +- drivers/input/keyboard/sunkbd.c | 24 +- drivers/input/keyboard/xtkbd.c | 24 +- drivers/input/misc/Kconfig | 2 +- drivers/input/misc/uinput.c | 3 + drivers/input/mouse/Kconfig | 2 - drivers/input/mouse/logips2pp.c | 2 +- drivers/input/mouse/pc110pad.c | 6 +- drivers/input/mouse/psmouse-base.c | 312 +- drivers/input/mouse/psmouse.h | 40 +- drivers/input/mouse/sermouse.c | 24 +- drivers/input/mouse/synaptics.c | 54 +- drivers/input/mouse/vsxxxaa.c | 24 +- drivers/input/mousedev.c | 237 +- drivers/input/serio/Kconfig | 18 +- drivers/input/serio/Makefile | 1 + drivers/input/serio/ambakmi.c | 44 +- drivers/input/serio/ct82c710.c | 104 +- drivers/input/serio/gscps2.c | 64 +- drivers/input/serio/i8042-io.h | 31 + drivers/input/serio/i8042-sparcio.h | 8 +- drivers/input/serio/i8042.c | 353 +- drivers/input/serio/i8042.h | 7 + drivers/input/serio/maceps2.c | 86 +- drivers/input/serio/parkbd.c | 48 +- drivers/input/serio/pcips2.c | 54 +- drivers/input/serio/q40kbd.c | 117 +- drivers/input/serio/rpckbd.c | 48 +- drivers/input/serio/sa1111ps2.c | 41 +- drivers/input/serio/serio.c | 576 +- drivers/input/serio/serio_raw.c | 390 + drivers/input/serio/serport.c | 49 +- drivers/input/touchscreen/gunze.c | 24 +- drivers/input/touchscreen/h3600_ts_input.c | 24 +- drivers/input/tsdev.c | 301 +- drivers/isdn/act2000/act2000_isa.c | 5 +- drivers/isdn/capi/capi.c | 90 +- drivers/isdn/capi/capidrv.c | 3 +- drivers/isdn/hardware/avm/b1.c | 8 +- drivers/isdn/hardware/avm/b1dma.c | 2 - drivers/isdn/hardware/avm/c4.c | 2 - drivers/isdn/hardware/avm/t1isa.c | 7 +- drivers/isdn/hardware/eicon/capifunc.c | 5 +- drivers/isdn/hardware/eicon/capifunc.h | 4 +- drivers/isdn/hardware/eicon/debug.c | 488 +- drivers/isdn/hardware/eicon/debug_if.h | 6 + drivers/isdn/hardware/eicon/debuglib.h | 6 +- drivers/isdn/hardware/eicon/diddfunc.c | 4 +- drivers/isdn/hardware/eicon/diva_didd.c | 10 +- drivers/isdn/hardware/eicon/divamnt.c | 236 +- drivers/isdn/hardware/eicon/divasfunc.c | 12 +- drivers/isdn/hardware/eicon/divasync.h | 21 +- drivers/isdn/hardware/eicon/idifunc.c | 4 +- drivers/isdn/hardware/eicon/io.c | 50 +- drivers/isdn/hardware/eicon/io.h | 63 +- drivers/isdn/hardware/eicon/maintidi.c | 51 +- drivers/isdn/hardware/eicon/maintidi.h | 4 +- drivers/isdn/hardware/eicon/mntfunc.c | 103 +- drivers/isdn/hardware/eicon/pc.h | 87 + drivers/isdn/hardware/eicon/platform.h | 37 +- drivers/isdn/hisax/avm_pci.c | 106 +- drivers/isdn/hisax/bkm_a4t.c | 4 +- drivers/isdn/hisax/bkm_a8.c | 4 +- drivers/isdn/hisax/diva.c | 2 +- drivers/isdn/hisax/elsa.c | 2 +- drivers/isdn/hisax/enternow_pci.c | 2 +- drivers/isdn/hisax/gazel.c | 2 +- drivers/isdn/hisax/hfc_pci.c | 4 +- drivers/isdn/hisax/niccy.c | 2 +- drivers/isdn/hisax/nj_s.c | 2 +- drivers/isdn/hisax/nj_u.c | 4 +- drivers/isdn/hisax/sedlbauer.c | 2 +- drivers/isdn/hisax/st5481_usb.c | 3 - drivers/isdn/hisax/telespci.c | 2 +- drivers/isdn/hisax/w6692.c | 2 +- drivers/isdn/i4l/isdn_net.c | 2 +- drivers/isdn/i4l/isdn_tty.c | 21 +- drivers/isdn/tpam/tpam_main.c | 47 +- drivers/macintosh/adbhid.c | 146 +- drivers/macintosh/ans-lcd.c | 6 +- drivers/macintosh/macserial.c | 22 +- drivers/macintosh/therm_adt746x.c | 80 +- drivers/macintosh/therm_windtunnel.c | 3 +- drivers/macintosh/via-pmu.c | 22 +- drivers/md/Kconfig | 18 + drivers/md/Makefile | 3 +- drivers/md/dm-log.c | 110 +- drivers/md/dm-log.h | 6 + drivers/md/dm-raid1.c | 29 +- drivers/md/dm-stripe.c | 9 +- drivers/md/dm-table.c | 25 +- drivers/md/dm.c | 142 +- drivers/md/dm.h | 4 + drivers/md/linear.c | 25 +- drivers/md/md.c | 207 +- drivers/md/multipath.c | 43 +- drivers/md/raid0.c | 29 +- drivers/md/raid1.c | 124 +- drivers/md/raid10.c | 1780 +++++ drivers/md/raid5.c | 41 +- drivers/md/raid6main.c | 41 +- drivers/media/common/saa7146_i2c.c | 21 +- drivers/media/dvb/b2c2/skystar2.c | 2 +- drivers/media/dvb/bt8xx/bt878.c | 12 +- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 27 +- drivers/media/dvb/dvb-core/dvb_net.c | 4 +- drivers/media/dvb/frontends/alps_tdlb7.c | 3 - drivers/media/dvb/frontends/dst.c | 6 +- drivers/media/dvb/frontends/sp887x.c | 2 - drivers/media/dvb/frontends/stv0299.c | 12 +- drivers/media/dvb/frontends/tda1004x.c | 2 - drivers/media/dvb/ttpci/Kconfig | 8 +- drivers/media/dvb/ttpci/Makefile | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 2 +- drivers/media/radio/miropcm20-rds.c | 4 +- drivers/media/radio/radio-aimslab.c | 7 +- drivers/media/radio/radio-cadet.c | 6 +- drivers/media/radio/radio-maestro.c | 54 +- drivers/media/radio/radio-maxiradio.c | 9 +- drivers/media/radio/radio-sf16fmi.c | 6 +- drivers/media/radio/radio-sf16fmr2.c | 15 +- drivers/media/video/Kconfig | 2 +- drivers/media/video/adv7175.c | 28 + drivers/media/video/bttv-cards.c | 90 +- drivers/media/video/bttv-driver.c | 13 +- drivers/media/video/bttv-gpio.c | 14 + drivers/media/video/bttv-i2c.c | 12 + drivers/media/video/bttv-risc.c | 30 +- drivers/media/video/bttv.h | 6 + drivers/media/video/bttvp.h | 1 + drivers/media/video/cpia.c | 38 +- drivers/media/video/dpc7146.c | 1 + drivers/media/video/meye.c | 2 +- drivers/media/video/msp3400.c | 7 +- drivers/media/video/saa7134/saa6752hs.c | 7 +- drivers/media/video/saa7134/saa7134-cards.c | 132 +- drivers/media/video/saa7134/saa7134-core.c | 7 +- drivers/media/video/saa7134/saa7134-i2c.c | 2 + drivers/media/video/saa7134/saa7134-oss.c | 2 - drivers/media/video/saa7134/saa7134-tvaudio.c | 8 +- drivers/media/video/saa7134/saa7134-video.c | 48 +- drivers/media/video/saa7134/saa7134.h | 8 +- drivers/media/video/tda7432.c | 8 +- drivers/media/video/tda9875.c | 7 +- drivers/media/video/tda9887.c | 67 +- drivers/media/video/tuner.c | 21 +- drivers/media/video/tvaudio.c | 8 +- drivers/media/video/tvmixer.c | 8 +- drivers/media/video/videodev.c | 2 +- drivers/media/video/zoran_device.c | 3 +- drivers/media/video/zoran_driver.c | 4 +- drivers/message/fusion/Kconfig | 33 - drivers/message/fusion/Makefile | 3 +- drivers/message/fusion/mptbase.c | 1056 ++- drivers/message/fusion/mptbase.h | 170 +- drivers/message/fusion/mptctl.c | 169 +- drivers/message/fusion/mptlan.c | 154 +- drivers/message/fusion/mptscsih.c | 1831 ++--- drivers/message/i2o/Makefile | 1 + drivers/message/i2o/debug.c | 571 ++ drivers/message/i2o/device.c | 674 ++ drivers/message/i2o/driver.c | 367 + drivers/message/i2o/exec-osm.c | 505 ++ drivers/message/i2o/i2o_block.c | 2321 +++--- drivers/message/i2o/i2o_block.h | 99 + drivers/message/i2o/i2o_config.c | 1371 ++-- drivers/message/i2o/i2o_proc.c | 4032 ++++------- drivers/message/i2o/i2o_scsi.c | 1401 ++-- drivers/message/i2o/iop.c | 1258 ++++ drivers/message/i2o/pci.c | 528 ++ drivers/misc/ibmasm/module.c | 12 +- drivers/mmc/Kconfig | 52 + drivers/mmc/Makefile | 21 + drivers/mmc/mmc.c | 913 +++ drivers/mmc/mmc.h | 16 + drivers/mmc/mmc_block.c | 495 ++ drivers/mmc/mmc_queue.c | 222 + drivers/mmc/mmc_queue.h | 32 + drivers/mmc/mmc_sysfs.c | 241 + drivers/mmc/mmci.c | 679 ++ drivers/mmc/mmci.h | 183 + drivers/mmc/pxamci.c | 604 ++ drivers/mmc/pxamci.h | 94 + drivers/mtd/chips/cfi_cmdset_0001.c | 5 +- drivers/mtd/chips/jedec_probe.c | 44 +- drivers/mtd/maps/Kconfig | 9 + drivers/mtd/maps/Makefile | 1 + drivers/mtd/maps/amd76xrom.c | 15 +- drivers/mtd/maps/ceiva.c | 4 +- drivers/mtd/maps/edb7312.c | 8 +- drivers/mtd/maps/impa7.c | 4 +- drivers/mtd/maps/ixp2000.c | 281 + drivers/mtd/maps/ixp4xx.c | 28 +- drivers/mtd/maps/lubbock-flash.c | 10 +- drivers/mtd/maps/nettel.c | 2 +- drivers/mtd/maps/sa1100-flash.c | 4 +- drivers/mtd/maps/tqm8xxl.c | 8 +- drivers/mtd/maps/uclinux.c | 7 +- drivers/mtd/nftlmount.c | 6 +- drivers/net/3c507.c | 2 +- drivers/net/3c527.c | 13 +- drivers/net/3c59x.c | 90 +- drivers/net/8139cp.c | 2 +- drivers/net/8139too.c | 70 +- drivers/net/8390.c | 46 +- drivers/net/8390.h | 12 +- drivers/net/Kconfig | 69 +- drivers/net/Makefile | 5 + drivers/net/acenic.c | 156 +- drivers/net/acenic.h | 2 +- drivers/net/amd8111e.c | 2 +- drivers/net/arcnet/arc-rimi.c | 12 +- drivers/net/arcnet/arcnet.c | 3 +- drivers/net/arcnet/com90xx.c | 4 +- drivers/net/b44.c | 199 +- drivers/net/b44.h | 5 +- drivers/net/bonding/bond_alb.c | 2 +- drivers/net/cs89x0.c | 29 +- drivers/net/cs89x0.h | 19 +- drivers/net/defxx.c | 22 +- drivers/net/dl2k.h | 2 +- drivers/net/e100.c | 89 +- drivers/net/e1000/e1000.h | 24 +- drivers/net/e1000/e1000_ethtool.c | 146 +- drivers/net/e1000/e1000_hw.c | 16 +- drivers/net/e1000/e1000_hw.h | 3 +- drivers/net/e1000/e1000_main.c | 526 +- drivers/net/e1000/e1000_param.c | 48 +- drivers/net/eepro100.c | 17 - drivers/net/epic100.c | 432 +- drivers/net/forcedeth.c | 78 +- drivers/net/gianfar.c | 584 +- drivers/net/gianfar.h | 46 +- drivers/net/gianfar_ethtool.c | 221 +- drivers/net/gianfar_phy.c | 899 +-- drivers/net/gianfar_phy.h | 295 +- drivers/net/gt64240eth.h | 402 ++ drivers/net/gt96100eth.c | 119 +- drivers/net/hamachi.c | 2 +- drivers/net/hamradio/bpqether.c | 2 +- drivers/net/hamradio/dmascc.c | 290 +- drivers/net/hamradio/mkiss.c | 2 - drivers/net/hp100.c | 21 +- drivers/net/ibm_emac/ibm_emac.h | 32 +- drivers/net/ibm_emac/ibm_emac_core.c | 74 +- drivers/net/ibm_emac/ibm_emac_core.h | 2 +- drivers/net/ibm_emac/ibm_emac_mal.c | 4 - drivers/net/ibmveth.c | 28 +- drivers/net/ibmveth.h | 2 + drivers/net/ioc3-eth.c | 4 +- drivers/net/irda/irda-usb.c | 3 - drivers/net/irda/irtty-sir.c | 7 - drivers/net/ixgb/ixgb_main.c | 132 +- drivers/net/lasi_82596.c | 2 - drivers/net/loopback.c | 13 + drivers/net/mv643xx_eth.c | 2646 +++++++ drivers/net/mv643xx_eth.h | 601 ++ drivers/net/myri_sbus.c | 69 +- drivers/net/myri_sbus.h | 17 +- drivers/net/natsemi.c | 282 +- drivers/net/ne.c | 30 +- drivers/net/plip.c | 2 +- drivers/net/ppp_async.c | 18 +- drivers/net/ppp_generic.c | 1 + drivers/net/ppp_synctty.c | 2 + drivers/net/pppoe.c | 4 +- drivers/net/r8169.c | 669 +- drivers/net/rrunner.c | 86 +- drivers/net/s2io.c | 8 +- drivers/net/sis900.c | 1 + drivers/net/sk98lin/h/skdrv2nd.h | 54 - drivers/net/sk98lin/skaddr.c | 4 +- drivers/net/sk98lin/skge.c | 746 +- drivers/net/skfp/skfddi.c | 20 +- drivers/net/slip.c | 24 +- drivers/net/smc9194.c | 255 +- drivers/net/smc91x.c | 31 +- drivers/net/smc91x.h | 22 +- drivers/net/sunbmac.c | 40 +- drivers/net/sunbmac.h | 8 +- drivers/net/sundance.c | 2 +- drivers/net/sungem.c | 246 +- drivers/net/sungem.h | 7 +- drivers/net/sunhme.c | 77 +- drivers/net/sunhme.h | 14 +- drivers/net/sunlance.c | 64 +- drivers/net/sunqe.c | 14 +- drivers/net/sunqe.h | 6 +- drivers/net/tg3.c | 910 +-- drivers/net/tg3.h | 17 +- drivers/net/tokenring/Kconfig | 3 +- drivers/net/tokenring/ibmtr.c | 2 +- drivers/net/tokenring/olympic.c | 117 +- drivers/net/tokenring/olympic.h | 4 +- drivers/net/tulip/Kconfig | 4 +- drivers/net/tulip/de4x5.c | 16 +- drivers/net/tulip/dmfe.c | 30 +- drivers/net/typhoon.c | 53 +- drivers/net/via-rhine.c | 739 +- drivers/net/via-velocity.c | 640 +- drivers/net/via-velocity.h | 16 +- drivers/net/wan/cycx_x25.c | 6 +- drivers/net/wan/dscc4.c | 33 +- drivers/net/wan/hd6457x.c | 6 +- drivers/net/wan/lmc/lmc_debug.c | 2 +- drivers/net/wan/pc300.h | 14 +- drivers/net/wan/pc300_drv.c | 153 +- drivers/net/wan/pc300_tty.c | 54 +- drivers/net/wan/sdla_chdlc.c | 20 +- drivers/net/wan/sdla_fr.c | 4 +- drivers/net/wan/sdladrv.c | 6 +- drivers/net/wan/sdlamain.c | 2 +- drivers/net/wan/syncppp.c | 8 +- drivers/net/wireless/airo.c | 140 +- drivers/net/wireless/airport.c | 52 +- drivers/net/wireless/atmel.c | 5 +- drivers/net/wireless/hermes.c | 12 +- drivers/net/wireless/hermes.h | 133 +- drivers/net/wireless/hermes_rid.h | 99 +- drivers/net/wireless/ieee802_11.h | 1 - drivers/net/wireless/orinoco.c | 2805 ++++---- drivers/net/wireless/orinoco.h | 36 +- drivers/net/wireless/orinoco_cs.c | 70 +- drivers/net/wireless/orinoco_pci.c | 52 +- drivers/net/wireless/orinoco_plx.c | 204 +- drivers/net/wireless/orinoco_tmd.c | 56 +- drivers/net/wireless/prism54/isl_38xx.c | 12 +- drivers/net/wireless/prism54/isl_38xx.h | 14 +- drivers/net/wireless/prism54/isl_ioctl.c | 5 +- drivers/net/wireless/prism54/islpci_dev.c | 8 +- drivers/net/wireless/prism54/islpci_dev.h | 2 +- drivers/net/wireless/ray_cs.c | 157 +- drivers/net/wireless/ray_cs.h | 6 +- drivers/net/wireless/strip.c | 25 +- drivers/net/wireless/wavelan.c | 11 +- drivers/oprofile/buffer_sync.c | 279 +- drivers/oprofile/buffer_sync.h | 3 + drivers/oprofile/cpu_buffer.c | 101 +- drivers/oprofile/cpu_buffer.h | 11 +- drivers/oprofile/oprofile_stats.c | 13 +- drivers/oprofile/timer_int.c | 2 +- drivers/parisc/lasi.c | 2 +- drivers/parisc/superio.c | 3 +- drivers/parport/parport_pc.c | 84 +- drivers/pci/Makefile | 2 +- drivers/pci/hotplug/Kconfig | 12 + drivers/pci/hotplug/Makefile | 1 + drivers/pci/hotplug/acpiphp.h | 16 + drivers/pci/hotplug/acpiphp_core.c | 127 +- drivers/pci/hotplug/acpiphp_glue.c | 14 - drivers/pci/hotplug/acpiphp_ibm.c | 474 ++ drivers/pci/hotplug/cpci_hotplug_core.c | 18 +- drivers/pci/hotplug/cpcihp_zt5550.c | 4 +- drivers/pci/hotplug/cpqphp_core.c | 4 +- drivers/pci/hotplug/ibmphp.h | 6 - drivers/pci/hotplug/ibmphp_core.c | 4 +- drivers/pci/hotplug/ibmphp_hpc.c | 20 +- drivers/pci/hotplug/pci_hotplug_core.c | 2 +- drivers/pci/hotplug/pciehp_core.c | 6 +- drivers/pci/hotplug/pciehp_hpc.c | 4 +- drivers/pci/hotplug/pcihp_skeleton.c | 2 +- drivers/pci/hotplug/rpaphp_core.c | 10 +- drivers/pci/hotplug/rpaphp_pci.c | 27 +- drivers/pci/hotplug/rpaphp_slot.c | 12 +- drivers/pci/hotplug/shpchp_core.c | 6 +- drivers/pci/hotplug/shpchp_ctrl.c | 4 +- drivers/pci/hotplug/shpchp_hpc.c | 4 +- drivers/pci/pci-driver.c | 22 +- drivers/pci/pci.c | 7 +- drivers/pci/pci.ids | 572 +- drivers/pci/probe.c | 13 +- drivers/pci/quirks.c | 372 +- drivers/pci/remove.c | 20 +- drivers/pci/setup-bus.c | 5 +- drivers/pcmcia/au1000_generic.c | 15 +- drivers/pcmcia/cardbus.c | 2 +- drivers/pcmcia/cistpl.c | 12 +- drivers/pcmcia/cs.c | 37 +- drivers/pcmcia/ds.c | 6 +- drivers/pcmcia/hd64465_ss.c | 11 +- drivers/pcmcia/i82092.c | 20 +- drivers/pcmcia/i82365.c | 17 +- drivers/pcmcia/pd6729.c | 14 +- drivers/pcmcia/pxa2xx_base.c | 34 +- drivers/pcmcia/pxa2xx_lubbock.c | 32 +- drivers/pcmcia/pxa2xx_mainstone.c | 24 + drivers/pcmcia/rsrc_mgr.c | 71 +- drivers/pcmcia/sa1100_h3600.c | 4 +- drivers/pcmcia/soc_common.c | 14 +- drivers/pcmcia/tcic.c | 12 +- drivers/pcmcia/yenta_socket.c | 10 +- drivers/pcmcia/yenta_socket.h | 2 +- drivers/pnp/interface.c | 10 +- drivers/pnp/isapnp/core.c | 4 +- drivers/pnp/pnpbios/bioscalls.c | 14 +- drivers/pnp/pnpbios/core.c | 4 +- drivers/pnp/pnpbios/proc.c | 8 +- drivers/pnp/pnpbios/rsparser.c | 9 +- drivers/pnp/system.c | 6 +- drivers/s390/block/dasd_diag.c | 7 +- drivers/s390/block/dasd_eckd.c | 20 +- drivers/s390/block/dcssblk.c | 56 + drivers/s390/char/con3215.c | 10 +- drivers/s390/char/sclp.c | 43 +- drivers/s390/char/sclp_tty.c | 5 +- drivers/s390/char/sclp_vt220.c | 5 +- drivers/s390/cio/blacklist.c | 4 +- drivers/s390/cio/ccwgroup.c | 16 +- drivers/s390/cio/cio.c | 15 +- drivers/s390/cio/cmf.c | 95 +- drivers/s390/cio/css.c | 5 +- drivers/s390/cio/device.c | 26 +- drivers/s390/cio/device_fsm.c | 1 + drivers/s390/cio/device_id.c | 4 +- drivers/s390/cio/qdio.c | 4 +- drivers/s390/net/ctctty.c | 12 +- drivers/s390/net/lcs.c | 452 +- drivers/s390/net/lcs.h | 17 +- drivers/s390/net/qeth_main.c | 61 +- drivers/s390/s390mach.h | 4 - drivers/s390/scsi/zfcp_aux.c | 512 +- drivers/s390/scsi/zfcp_def.h | 188 +- drivers/s390/scsi/zfcp_erp.c | 276 +- drivers/s390/scsi/zfcp_ext.h | 30 +- drivers/s390/scsi/zfcp_fsf.c | 344 +- drivers/s390/scsi/zfcp_fsf.h | 11 +- drivers/s390/scsi/zfcp_scsi.c | 31 +- drivers/s390/scsi/zfcp_sysfs_adapter.c | 45 +- drivers/s390/scsi/zfcp_sysfs_driver.c | 4 +- drivers/s390/scsi/zfcp_sysfs_port.c | 37 +- drivers/s390/scsi/zfcp_sysfs_unit.c | 29 +- drivers/sbus/char/aurora.c | 13 +- drivers/sbus/char/bbc_envctrl.c | 5 +- drivers/sbus/char/bbc_i2c.c | 4 +- drivers/sbus/char/cpwatchdog.c | 82 +- drivers/sbus/char/display7seg.c | 2 +- drivers/sbus/char/envctrl.c | 65 +- drivers/sbus/char/flash.c | 3 +- drivers/sbus/dvma.c | 11 - drivers/scsi/3w-xxxx.c | 6 +- drivers/scsi/BusLogic.c | 6396 ++++++++--------- drivers/scsi/BusLogic.h | 1468 ++-- drivers/scsi/Kconfig | 27 +- drivers/scsi/Makefile | 4 +- drivers/scsi/NCR5380.c | 222 +- drivers/scsi/NCR5380.h | 3 +- drivers/scsi/NCR53C9x.c | 16 +- drivers/scsi/NCR53c406a.c | 11 +- drivers/scsi/NCR_Q720.c | 21 +- drivers/scsi/aacraid/README | 14 +- drivers/scsi/aacraid/aachba.c | 71 +- drivers/scsi/aacraid/aacraid.h | 25 +- drivers/scsi/aacraid/commctrl.c | 2 +- drivers/scsi/aacraid/commsup.c | 2 +- drivers/scsi/aacraid/linit.c | 179 +- drivers/scsi/advansys.c | 20 +- drivers/scsi/advansys.h | 26 - drivers/scsi/aha1542.c | 4 +- drivers/scsi/aha1542.h | 10 +- drivers/scsi/aic7xxx/Kconfig.aic79xx | 2 +- drivers/scsi/aic7xxx/Kconfig.aic7xxx | 2 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 41 +- drivers/scsi/aic7xxx/aic79xx_pci.c | 4 +- drivers/scsi/aic7xxx/aic7xxx_osm.c | 12 +- drivers/scsi/aic7xxx/aic7xxx_pci.c | 4 +- drivers/scsi/aic7xxx/aicasm/Makefile | 6 +- drivers/scsi/aic7xxx_old.c | 9 +- drivers/scsi/arm/cumana_1.c | 1 + drivers/scsi/arm/ecoscsi.c | 1 + drivers/scsi/arm/eesox.c | 30 +- drivers/scsi/arm/fas216.c | 4 +- drivers/scsi/arm/oak.c | 1 + drivers/scsi/ata_piix.c | 174 +- drivers/scsi/atp870u.c | 6 +- drivers/scsi/cpqfcTScontrol.c | 1 - drivers/scsi/cpqfcTSinit.c | 51 +- drivers/scsi/dc395x.c | 46 +- drivers/scsi/dmx3191d.c | 3 +- drivers/scsi/dtc.c | 1 + drivers/scsi/eata_pio.c | 5 +- drivers/scsi/esp.h | 4 +- drivers/scsi/fd_mcs.c | 11 +- drivers/scsi/fdomain.c | 51 +- drivers/scsi/g_NCR5380.c | 6 +- drivers/scsi/gdth.c | 120 +- drivers/scsi/gdth.h | 2 +- drivers/scsi/hosts.c | 2 +- drivers/scsi/ibmvscsi/Makefile | 5 + drivers/scsi/ibmvscsi/ibmvscsi.c | 1393 ++++ drivers/scsi/ibmvscsi/ibmvscsi.h | 108 + drivers/scsi/ibmvscsi/iseries_vscsi.c | 144 + drivers/scsi/ibmvscsi/rpa_vscsi.c | 260 + drivers/scsi/ibmvscsi/srp.h | 225 + drivers/scsi/ibmvscsi/viosrp.h | 126 + drivers/scsi/imm.c | 2 +- drivers/scsi/ipr.c | 240 +- drivers/scsi/ipr.h | 24 +- drivers/scsi/ips.c | 136 +- drivers/scsi/libata-core.c | 1201 ++-- drivers/scsi/libata-scsi.c | 426 +- drivers/scsi/libata.h | 3 +- drivers/scsi/mac_scsi.c | 1 + drivers/scsi/mca_53c9x.c | 14 +- drivers/scsi/megaraid.c | 10 +- drivers/scsi/megaraid/Kconfig.megaraid | 77 + drivers/scsi/megaraid/Makefile | 2 + drivers/scsi/megaraid/mbox_defs.h | 790 ++ drivers/scsi/megaraid/mega_common.h | 283 + drivers/scsi/megaraid/megaraid_ioctl.h | 291 + drivers/scsi/megaraid/megaraid_mbox.c | 3891 ++++++++++ drivers/scsi/megaraid/megaraid_mbox.h | 268 + drivers/scsi/megaraid/megaraid_mm.c | 1160 +++ drivers/scsi/megaraid/megaraid_mm.h | 102 + drivers/scsi/nsp32.c | 8 +- drivers/scsi/pas16.c | 1 + drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/scsi/qla1280.c | 1024 +-- drivers/scsi/qla1280.h | 57 +- drivers/scsi/qla2xxx/ql2100.c | 1 + drivers/scsi/qla2xxx/ql2200.c | 1 + drivers/scsi/qla2xxx/ql2300.c | 1 + drivers/scsi/qla2xxx/ql2322.c | 1 + drivers/scsi/qla2xxx/ql6312.c | 1 + drivers/scsi/qla2xxx/ql6322.c | 1 + drivers/scsi/qla2xxx/qla_init.c | 14 +- drivers/scsi/qla2xxx/qla_iocb.c | 16 +- drivers/scsi/qla2xxx/qla_os.c | 7 +- drivers/scsi/qla2xxx/qla_version.h | 4 +- drivers/scsi/qlogicpti.c | 2 +- drivers/scsi/qlogicpti.h | 4 +- drivers/scsi/sata_nv.c | 96 +- drivers/scsi/sata_promise.c | 87 +- drivers/scsi/sata_sil.c | 23 +- drivers/scsi/sata_sis.c | 61 +- drivers/scsi/sata_svw.c | 78 +- drivers/scsi/sata_sx4.c | 171 +- drivers/scsi/sata_via.c | 54 +- drivers/scsi/sata_vsc.c | 11 +- drivers/scsi/scsi.c | 17 +- drivers/scsi/scsi_error.c | 63 +- drivers/scsi/scsi_ioctl.c | 23 +- drivers/scsi/scsi_lib.c | 47 +- drivers/scsi/scsi_scan.c | 25 +- drivers/scsi/scsi_syms.c | 4 +- drivers/scsi/scsi_sysfs.c | 8 +- drivers/scsi/scsiiom.c | 172 +- drivers/scsi/sd.c | 178 +- drivers/scsi/sg.c | 43 +- drivers/scsi/sr.c | 14 +- drivers/scsi/sr_ioctl.c | 3 +- drivers/scsi/sym53c8xx_2/sym_defs.h | 3 + drivers/scsi/sym53c8xx_2/sym_glue.c | 122 +- drivers/scsi/sym53c8xx_2/sym_glue.h | 42 +- drivers/scsi/sym53c8xx_2/sym_hipd.c | 126 +- drivers/scsi/sym53c8xx_2/sym_hipd.h | 40 +- drivers/scsi/sym53c8xx_2/sym_misc.c | 118 - drivers/scsi/sym53c8xx_2/sym_nvram.c | 16 - drivers/scsi/t128.c | 1 + drivers/scsi/tmscsim.c | 615 +- drivers/scsi/tmscsim.h | 1 - drivers/scsi/wd7000.c | 47 +- drivers/serial/68328serial.c | 17 +- drivers/serial/68360serial.c | 18 +- drivers/serial/8250.c | 187 +- drivers/serial/8250.h | 14 + drivers/serial/8250_pci.c | 60 +- drivers/serial/Kconfig | 15 +- drivers/serial/amba-pl011.c | 1 - drivers/serial/bast_sio.c | 31 +- drivers/serial/icom.c | 1702 +++++ drivers/serial/icom.h | 290 + drivers/serial/mcfserial.c | 17 +- drivers/serial/pxa.c | 1 + drivers/serial/s3c2410.c | 4 +- drivers/serial/serial_core.c | 29 +- drivers/serial/serial_cs.c | 45 +- drivers/serial/sn_console.c | 66 +- drivers/serial/sunsab.c | 20 +- drivers/serial/sunsu.c | 89 +- drivers/serial/sunzilog.c | 79 +- drivers/tc/zs.c | 49 +- drivers/telephony/ixj.c | 53 +- drivers/telephony/ixj.h | 4 +- drivers/usb/class/audio.c | 12 +- drivers/usb/class/bluetty.c | 12 +- drivers/usb/class/cdc-acm.c | 39 +- drivers/usb/class/cdc-acm.h | 2 +- drivers/usb/class/usb-midi.c | 26 +- drivers/usb/class/usblp.c | 14 +- drivers/usb/core/Kconfig | 37 + drivers/usb/core/config.c | 7 +- drivers/usb/core/devices.c | 5 +- drivers/usb/core/devio.c | 16 +- drivers/usb/core/hcd-pci.c | 4 +- drivers/usb/core/hcd.c | 49 +- drivers/usb/core/hcd.h | 5 +- drivers/usb/core/hub.c | 702 +- drivers/usb/core/hub.h | 14 +- drivers/usb/core/inode.c | 19 +- drivers/usb/core/message.c | 65 +- drivers/usb/core/otg_whitelist.h | 112 + drivers/usb/core/urb.c | 11 +- drivers/usb/core/usb.c | 2 + drivers/usb/core/usb.h | 1 + drivers/usb/gadget/Kconfig | 51 +- drivers/usb/gadget/Makefile | 4 +- drivers/usb/gadget/dummy_hcd.c | 9 +- drivers/usb/gadget/ether.c | 19 +- drivers/usb/gadget/file_storage.c | 171 +- drivers/usb/gadget/gadget_chips.h | 6 + drivers/usb/gadget/inode.c | 145 +- drivers/usb/gadget/lh7a40x_udc.c | 2168 ++++++ drivers/usb/gadget/lh7a40x_udc.h | 261 + drivers/usb/gadget/net2280.c | 113 +- drivers/usb/gadget/net2280.h | 23 +- drivers/usb/gadget/omap_udc.c | 2695 +++++++ drivers/usb/gadget/omap_udc.h | 199 + drivers/usb/gadget/pxa2xx_udc.c | 7 +- drivers/usb/gadget/serial.c | 293 +- drivers/usb/gadget/zero.c | 13 +- drivers/usb/host/Kconfig | 1 + drivers/usb/host/ehci-dbg.c | 43 +- drivers/usb/host/ehci-hcd.c | 22 +- drivers/usb/host/ehci-hub.c | 6 +- drivers/usb/host/ehci-mem.c | 8 +- drivers/usb/host/ehci-q.c | 18 +- drivers/usb/host/ehci-sched.c | 19 +- drivers/usb/host/ehci.h | 81 +- drivers/usb/host/hc_simple.c | 5 - drivers/usb/host/hc_sl811.c | 8 +- drivers/usb/host/ohci-dbg.c | 18 +- drivers/usb/host/ohci-hcd.c | 5 +- drivers/usb/host/ohci-hub.c | 98 +- drivers/usb/host/ohci-omap.c | 557 +- drivers/usb/host/ohci-pci.c | 3 +- drivers/usb/host/ohci-q.c | 36 +- drivers/usb/host/ohci.h | 35 +- drivers/usb/host/uhci-hcd.c | 25 +- drivers/usb/host/uhci-hcd.h | 14 +- drivers/usb/host/uhci-hub.c | 6 +- drivers/usb/image/microtek.c | 4 +- drivers/usb/input/aiptek.c | 20 +- drivers/usb/input/ati_remote.c | 4 +- drivers/usb/input/hid-core.c | 132 +- drivers/usb/input/hiddev.c | 35 +- drivers/usb/input/kbtab.c | 11 +- drivers/usb/input/wacom.c | 14 +- drivers/usb/media/Kconfig | 48 +- drivers/usb/media/Makefile | 4 +- drivers/usb/media/dabusb.c | 4 +- drivers/usb/media/dsbr100.c | 2 +- drivers/usb/media/ibmcam.c | 30 +- drivers/usb/media/konicawc.c | 20 +- drivers/usb/media/ov511.c | 75 +- drivers/usb/media/se401.c | 4 +- drivers/usb/media/sn9c102.h | 6 +- drivers/usb/media/sn9c102_core.c | 95 +- drivers/usb/media/sn9c102_pas106b.c | 76 +- drivers/usb/media/sn9c102_pas202bcb.c | 238 + drivers/usb/media/sn9c102_sensor.h | 133 +- drivers/usb/media/sn9c102_tas5110c1b.c | 47 +- drivers/usb/media/sn9c102_tas5130d1b.c | 56 +- drivers/usb/media/stv680.c | 7 +- drivers/usb/media/ultracam.c | 16 +- drivers/usb/media/usbvideo.c | 2 +- drivers/usb/misc/auerswald.c | 12 +- drivers/usb/misc/legousbtower.c | 65 +- drivers/usb/misc/phidgetservo.c | 16 +- drivers/usb/misc/tiglusb.c | 2 +- drivers/usb/misc/usbtest.c | 31 +- drivers/usb/net/catc.c | 4 +- drivers/usb/net/kaweth.c | 10 +- drivers/usb/net/pegasus.c | 16 +- drivers/usb/net/rtl8150.c | 6 +- drivers/usb/net/usbnet.c | 13 +- drivers/usb/serial/cyberjack.c | 34 +- drivers/usb/serial/digi_acceleport.c | 19 +- drivers/usb/serial/empeg.c | 4 - drivers/usb/serial/ftdi_sio.c | 122 +- drivers/usb/serial/ftdi_sio.h | 17 + drivers/usb/serial/io_edgeport.c | 25 +- drivers/usb/serial/io_edgeport.h | 4 +- drivers/usb/serial/io_fw_down.h | 1968 ++--- drivers/usb/serial/io_fw_down3.h | 1532 ++-- drivers/usb/serial/io_tables.h | 67 +- drivers/usb/serial/io_ti.c | 23 +- drivers/usb/serial/io_usbvend.h | 377 +- drivers/usb/serial/ipaq.c | 2 + drivers/usb/serial/ipaq.h | 1 + drivers/usb/serial/ir-usb.c | 4 + drivers/usb/serial/keyspan_pda.c | 8 +- drivers/usb/serial/mct_u232.c | 6 +- drivers/usb/serial/pl2303.c | 2 +- drivers/usb/serial/usb-serial.c | 137 +- drivers/usb/serial/whiteheat.c | 3 +- drivers/usb/storage/datafab.c | 25 +- drivers/usb/storage/datafab.h | 2 +- drivers/usb/storage/debug.c | 8 +- drivers/usb/storage/debug.h | 6 +- drivers/usb/storage/dpcm.c | 6 +- drivers/usb/storage/dpcm.h | 2 +- drivers/usb/storage/freecom.c | 24 +- drivers/usb/storage/freecom.h | 2 +- drivers/usb/storage/isd200.c | 90 +- drivers/usb/storage/isd200.h | 2 +- drivers/usb/storage/jumpshot.c | 24 +- drivers/usb/storage/jumpshot.h | 2 +- drivers/usb/storage/protocol.c | 27 +- drivers/usb/storage/protocol.h | 20 +- drivers/usb/storage/scsiglue.c | 47 +- drivers/usb/storage/scsiglue.h | 8 +- drivers/usb/storage/sddr09.c | 27 +- drivers/usb/storage/sddr09.h | 2 +- drivers/usb/storage/sddr55.c | 48 +- drivers/usb/storage/sddr55.h | 2 +- drivers/usb/storage/shuttle_usbat.c | 42 +- drivers/usb/storage/shuttle_usbat.h | 2 +- drivers/usb/storage/transport.c | 44 +- drivers/usb/storage/transport.h | 19 +- drivers/usb/storage/unusual_devs.h | 33 +- drivers/usb/storage/usb.c | 30 +- drivers/usb/storage/usb.h | 13 +- drivers/usb/usb-skeleton.c | 622 +- drivers/video/68328fb.c | 25 +- drivers/video/Kconfig | 56 +- drivers/video/Makefile | 122 +- drivers/video/acornfb.c | 9 +- drivers/video/amba-clcd.c | 515 ++ drivers/video/amifb.c | 19 +- drivers/video/asiliantfb.c | 7 +- drivers/video/aty/aty128fb.c | 11 +- drivers/video/aty/atyfb_base.c | 22 +- drivers/video/aty/radeon_base.c | 192 +- drivers/video/aty/radeon_monitor.c | 18 +- drivers/video/aty/radeonfb.h | 8 +- drivers/video/bw2.c | 14 +- drivers/video/cfbcopyarea.c | 13 +- drivers/video/cfbfillrect.c | 16 +- drivers/video/cfbimgblt.c | 32 +- drivers/video/cg14.c | 8 +- drivers/video/cg3.c | 8 +- drivers/video/cg6.c | 9 +- drivers/video/chipsfb.c | 7 +- drivers/video/cirrusfb.c | 17 +- drivers/video/clps711xfb.c | 7 +- drivers/video/console/Kconfig | 6 +- drivers/video/console/fbcon.c | 501 +- drivers/video/console/fbcon.h | 21 +- drivers/video/controlfb.c | 8 +- drivers/video/cyber2000fb.c | 18 +- drivers/video/dnfb.c | 8 + drivers/video/epson1355fb.c | 1012 ++- drivers/video/fbmem.c | 763 +- drivers/video/fbmon.c | 113 +- drivers/video/ffb.c | 155 +- drivers/video/fm2fb.c | 11 +- drivers/video/g364fb.c | 6 +- drivers/video/gbefb.c | 13 +- drivers/video/hgafb.c | 7 +- drivers/video/hitfb.c | 8 +- drivers/video/hpfb.c | 6 +- drivers/video/i810/i810_dvt.c | 14 +- drivers/video/i810/i810_main.c | 78 +- drivers/video/igafb.c | 6 +- drivers/video/imsttfb.c | 15 +- drivers/video/kyro/fbdev.c | 12 +- drivers/video/leo.c | 7 +- drivers/video/macfb.c | 11 +- drivers/video/matrox/matroxfb_base.c | 8 + drivers/video/matrox/matroxfb_base.h | 31 +- drivers/video/matrox/matroxfb_crtc2.c | 3 + drivers/video/matrox/matroxfb_crtc2.h | 2 +- drivers/video/matrox/matroxfb_misc.c | 12 +- drivers/video/maxinefb.c | 7 +- drivers/video/modedb.c | 265 +- drivers/video/neofb.c | 451 +- drivers/video/offb.c | 33 +- drivers/video/p9100.c | 8 +- drivers/video/platinumfb.c | 11 +- drivers/video/pm2fb.c | 15 +- drivers/video/pmag-ba-fb.c | 6 +- drivers/video/pmagb-b-fb.c | 6 +- drivers/video/pvr2fb.c | 11 +- drivers/video/pxafb.c | 23 +- drivers/video/q40fb.c | 6 +- drivers/video/radeonfb.c | 57 +- drivers/video/riva/fbdev.c | 491 +- drivers/video/riva/nv_driver.c | 2 + drivers/video/riva/riva_hw.c | 12 +- drivers/video/riva/riva_hw.h | 4 +- drivers/video/riva/rivafb-i2c.c | 36 +- drivers/video/riva/rivafb.h | 7 +- drivers/video/sa1100fb.c | 6 +- drivers/video/sgivwfb.c | 135 +- drivers/video/sis/sis.h | 14 +- drivers/video/sis/sis_main.c | 58 +- drivers/video/sis/sis_main.h | 2 +- drivers/video/skeletonfb.c | 13 +- drivers/video/softcursor.c | 18 +- drivers/video/sstfb.c | 11 +- drivers/video/stifb.c | 15 +- drivers/video/tcx.c | 8 +- drivers/video/tdfxfb.c | 156 +- drivers/video/tgafb.c | 25 +- drivers/video/tridentfb.c | 24 +- drivers/video/tx3912fb.c | 13 +- drivers/video/valkyriefb.c | 8 +- drivers/video/vesafb.c | 67 +- drivers/video/vfb.c | 11 +- drivers/video/vga16fb.c | 9 +- drivers/video/vgastate.c | 12 +- drivers/w1/Kconfig | 26 + drivers/w1/Makefile | 7 + drivers/w1/ds_w1_bridge.c | 174 + drivers/w1/dscore.c | 783 ++ drivers/w1/dscore.h | 173 + drivers/w1/matrox_w1.c | 2 +- drivers/w1/w1.c | 276 +- drivers/w1/w1.h | 19 + drivers/w1/w1_family.c | 11 + drivers/w1/w1_family.h | 2 +- drivers/w1/w1_int.c | 16 +- drivers/w1/w1_io.c | 69 +- drivers/w1/w1_io.h | 3 + drivers/w1/w1_netlink.h | 15 +- drivers/w1/w1_smem.c | 118 + drivers/w1/w1_therm.c | 87 +- drivers/zorro/Makefile | 2 +- fs/Kconfig | 40 +- fs/Makefile | 2 + fs/adfs/adfs.h | 11 +- fs/adfs/dir.c | 3 +- fs/adfs/dir_f.c | 16 +- fs/adfs/dir_fplus.h | 28 +- fs/adfs/inode.c | 11 +- fs/adfs/map.c | 10 +- fs/adfs/super.c | 10 +- fs/affs/amigaffs.c | 26 +- fs/affs/bitmap.c | 44 +- fs/affs/inode.c | 11 +- fs/affs/namei.c | 2 +- fs/affs/super.c | 8 +- fs/afs/cmservice.c | 2 +- fs/afs/dir.c | 16 +- fs/afs/fsclient.c | 6 +- fs/afs/inode.c | 5 +- fs/afs/main.c | 3 +- fs/afs/mntpt.c | 16 +- fs/afs/vlclient.c | 17 +- fs/afs/vlclient.h | 3 - fs/afs/vlocation.c | 3 +- fs/afs/vnode.c | 6 +- fs/afs/volume.h | 1 - fs/aio.c | 667 +- fs/autofs/root.c | 10 +- fs/autofs4/autofs_i.h | 1 - fs/autofs4/expire.c | 8 +- fs/befs/befs.h | 1 - fs/befs/debug.c | 2 + fs/befs/linuxvfs.c | 18 +- fs/bfs/inode.c | 9 +- fs/binfmt_aout.c | 2 +- fs/binfmt_elf.c | 144 +- fs/bio.c | 151 +- fs/buffer.c | 71 +- fs/cifs/AUTHORS | 5 +- fs/cifs/CHANGES | 4 +- fs/cifs/asn1.c | 27 +- fs/cifs/cifs_debug.c | 16 +- fs/cifs/cifsencrypt.c | 14 +- fs/cifs/cifsfs.c | 28 +- fs/cifs/cifsfs.h | 1 + fs/cifs/cifsglob.h | 18 +- fs/cifs/cifspdu.h | 879 +-- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 727 +- fs/cifs/connect.c | 519 +- fs/cifs/file.c | 131 +- fs/cifs/inode.c | 45 +- fs/cifs/link.c | 50 +- fs/cifs/misc.c | 28 +- fs/cifs/netmisc.c | 15 +- fs/cifs/ntlmssp.h | 26 +- fs/cifs/transport.c | 66 +- fs/coda/coda_linux.c | 2 +- fs/coda/file.c | 18 + fs/coda/inode.c | 2 +- fs/coda/psdev.c | 2 +- fs/coda/upcall.c | 10 +- fs/compat.c | 142 +- fs/compat_ioctl.c | 12 +- fs/dcache.c | 78 +- fs/devpts/inode.c | 8 +- fs/direct-io.c | 75 +- fs/dquot.c | 3 +- fs/efs/inode.c | 4 +- fs/efs/super.c | 18 +- fs/eventpoll.c | 6 +- fs/exec.c | 122 +- fs/exportfs/expfs.c | 22 +- fs/ext2/acl.h | 12 +- fs/ext2/balloc.c | 4 +- fs/ext2/dir.c | 11 +- fs/ext2/ext2.h | 7 +- fs/ext2/ialloc.c | 4 +- fs/ext2/inode.c | 38 +- fs/ext2/super.c | 81 +- fs/ext2/xattr.c | 2 +- fs/ext2/xattr.h | 16 +- fs/ext3/acl.h | 12 +- fs/ext3/balloc.c | 4 +- fs/ext3/fsync.c | 4 - fs/ext3/ialloc.c | 7 +- fs/ext3/inode.c | 65 +- fs/ext3/namei.c | 37 +- fs/ext3/super.c | 116 +- fs/ext3/xattr.c | 2 +- fs/ext3/xattr.h | 16 +- fs/fat/cache.c | 11 +- fs/fat/dir.c | 33 +- fs/fat/file.c | 6 - fs/fat/inode.c | 39 +- fs/fat/misc.c | 13 +- fs/fcntl.c | 12 +- fs/file_table.c | 47 +- fs/freevxfs/vxfs_extern.h | 2 +- fs/freevxfs/vxfs_inode.c | 11 +- fs/freevxfs/vxfs_super.c | 2 +- fs/fs-writeback.c | 33 +- fs/hfs/bfind.c | 3 +- fs/hfs/bitmap.c | 35 +- fs/hfs/bnode.c | 10 +- fs/hfs/brec.c | 8 +- fs/hfs/btree.c | 2 +- fs/hfs/btree.h | 28 +- fs/hfs/catalog.c | 2 +- fs/hfs/extent.c | 6 +- fs/hfs/hfs.h | 134 +- fs/hfs/hfs_fs.h | 15 +- fs/hfs/inode.c | 26 +- fs/hfs/mdb.c | 4 +- fs/hfs/part_tbl.c | 20 +- fs/hfs/super.c | 7 +- fs/hfsplus/bfind.c | 3 +- fs/hfsplus/bitmap.c | 33 +- fs/hfsplus/bnode.c | 12 +- fs/hfsplus/brec.c | 8 +- fs/hfsplus/btree.c | 2 +- fs/hfsplus/catalog.c | 8 +- fs/hfsplus/extents.c | 4 +- fs/hfsplus/hfsplus_fs.h | 3 +- fs/hfsplus/hfsplus_raw.h | 172 +- fs/hfsplus/inode.c | 10 +- fs/hfsplus/part_tbl.c | 20 +- fs/hfsplus/super.c | 9 +- fs/hfsplus/wrapper.c | 10 +- fs/hostfs/Makefile | 4 +- fs/hostfs/hostfs.h | 22 +- fs/hostfs/hostfs_kern.c | 124 +- fs/hostfs/hostfs_user.c | 62 +- fs/hpfs/super.c | 2 +- fs/hppfs/Makefile | 4 +- fs/hppfs/hppfs_kern.c | 92 +- fs/hugetlbfs/inode.c | 37 +- fs/inode.c | 9 +- fs/isofs/compress.c | 4 +- fs/isofs/inode.c | 3 +- fs/isofs/rock.c | 18 +- fs/jbd/commit.c | 50 +- fs/jbd/journal.c | 51 +- fs/jbd/recovery.c | 32 +- fs/jbd/revoke.c | 13 +- fs/jffs2/super.c | 7 +- fs/jfs/acl.c | 13 +- fs/jfs/inode.c | 22 +- fs/jfs/jfs_dtree.c | 65 +- fs/jfs/jfs_extent.c | 26 +- fs/jfs/jfs_imap.c | 27 +- fs/jfs/jfs_inode.c | 14 +- fs/jfs/jfs_metapage.c | 1 + fs/jfs/jfs_mount.c | 3 - fs/jfs/jfs_txnmgr.c | 3 - fs/jfs/jfs_xtree.c | 61 +- fs/jfs/namei.c | 39 +- fs/jfs/resize.c | 5 +- fs/jfs/super.c | 4 +- fs/jfs/xattr.c | 51 +- fs/libfs.c | 72 +- fs/lockd/clntlock.c | 4 +- fs/lockd/clntproc.c | 174 +- fs/lockd/host.c | 18 +- fs/lockd/svc.c | 8 +- fs/lockd/svc4proc.c | 3 +- fs/lockd/svclock.c | 50 +- fs/lockd/svcproc.c | 3 +- fs/lockd/svcsubs.c | 10 +- fs/locks.c | 181 +- fs/minix/inode.c | 7 +- fs/minix/itree_common.c | 2 +- fs/mpage.c | 33 +- fs/namei.c | 61 +- fs/namespace.c | 32 +- fs/ncpfs/dir.c | 30 +- fs/ncpfs/file.c | 21 +- fs/ncpfs/inode.c | 35 +- fs/ncpfs/ioctl.c | 4 +- fs/ncpfs/mmap.c | 10 +- fs/ncpfs/ncplib_kernel.c | 192 +- fs/ncpfs/ncplib_kernel.h | 42 +- fs/ncpfs/sock.c | 2 +- fs/ncpfs/symlink.c | 15 +- fs/nfs/Makefile | 3 +- fs/nfs/callback.c | 325 + fs/nfs/callback.h | 70 + fs/nfs/callback_proc.c | 85 + fs/nfs/callback_xdr.c | 481 ++ fs/nfs/delegation.c | 342 + fs/nfs/delegation.h | 57 + fs/nfs/dir.c | 144 +- fs/nfs/direct.c | 47 +- fs/nfs/file.c | 147 +- fs/nfs/inode.c | 382 +- fs/nfs/mount_clnt.c | 2 - fs/nfs/nfs2xdr.c | 70 +- fs/nfs/nfs3proc.c | 111 +- fs/nfs/nfs3xdr.c | 48 +- fs/nfs/nfs4proc.c | 1272 +++- fs/nfs/nfs4state.c | 371 +- fs/nfs/nfs4xdr.c | 563 +- fs/nfs/pagelist.c | 62 +- fs/nfs/proc.c | 63 +- fs/nfs/read.c | 62 +- fs/nfs/symlink.c | 75 +- fs/nfs/write.c | 170 +- fs/nfsd/Makefile | 3 +- fs/nfsd/export.c | 5 + fs/nfsd/lockd.c | 11 +- fs/nfsd/nfs3proc.c | 12 +- fs/nfsd/nfs3xdr.c | 10 +- fs/nfsd/nfs4acl.c | 974 +++ fs/nfsd/nfs4proc.c | 17 +- fs/nfsd/nfs4state.c | 148 +- fs/nfsd/nfs4xdr.c | 127 +- fs/nfsd/nfsctl.c | 96 +- fs/nfsd/nfsfh.c | 25 +- fs/nfsd/nfsproc.c | 1 + fs/nfsd/nfssvc.c | 2 + fs/nfsd/vfs.c | 287 +- fs/nls/nls_cp932.c | 43 +- fs/ntfs/ChangeLog | 147 +- fs/ntfs/Makefile | 4 +- fs/ntfs/aops.c | 127 +- fs/ntfs/attrib.c | 904 ++- fs/ntfs/attrib.h | 36 +- fs/ntfs/bitmap.c | 191 + fs/ntfs/bitmap.h | 118 + fs/ntfs/collate.c | 20 +- fs/ntfs/collate.h | 12 +- fs/ntfs/compress.c | 38 +- fs/ntfs/debug.c | 19 +- fs/ntfs/debug.h | 2 +- fs/ntfs/dir.c | 195 +- fs/ntfs/endian.h | 72 +- fs/ntfs/file.c | 99 +- fs/ntfs/index.c | 36 +- fs/ntfs/index.h | 2 +- fs/ntfs/inode.c | 492 +- fs/ntfs/inode.h | 20 +- fs/ntfs/layout.h | 767 +- fs/ntfs/lcnalloc.c | 1001 +++ fs/ntfs/lcnalloc.h | 83 + fs/ntfs/logfile.c | 8 +- fs/ntfs/logfile.h | 76 +- fs/ntfs/mft.c | 27 +- fs/ntfs/mst.c | 23 +- fs/ntfs/namei.c | 46 +- fs/ntfs/ntfs.h | 3 +- fs/ntfs/quota.c | 2 +- fs/ntfs/super.c | 380 +- fs/ntfs/time.h | 6 +- fs/ntfs/types.h | 26 +- fs/ntfs/unistr.c | 12 +- fs/ntfs/upcase.c | 3 +- fs/ntfs/volume.h | 18 +- fs/openpromfs/inode.c | 48 +- fs/partitions/acorn.c | 42 +- fs/partitions/amiga.c | 42 +- fs/partitions/atari.h | 4 +- fs/partitions/efi.h | 36 +- fs/partitions/ldm.c | 16 +- fs/partitions/ldm.h | 6 +- fs/partitions/mac.h | 36 +- fs/partitions/msdos.c | 3 + fs/partitions/osf.c | 46 +- fs/partitions/sgi.c | 32 +- fs/partitions/sun.c | 33 +- fs/proc/array.c | 52 +- fs/proc/base.c | 138 +- fs/proc/inode.c | 2 +- fs/proc/proc_misc.c | 74 +- fs/proc/proc_tty.c | 12 +- fs/proc/root.c | 5 +- fs/proc/task_mmu.c | 56 +- fs/proc/task_nommu.c | 8 +- fs/qnx4/inode.c | 11 +- fs/quota_v1.c | 4 +- fs/quota_v2.c | 10 +- fs/ramfs/inode.c | 8 +- fs/reiserfs/file.c | 13 +- fs/reiserfs/inode.c | 5 +- fs/reiserfs/journal.c | 94 +- fs/reiserfs/super.c | 33 +- fs/reiserfs/xattr.c | 21 +- fs/reiserfs/xattr_acl.c | 28 +- fs/reiserfs/xattr_security.c | 10 +- fs/reiserfs/xattr_trusted.c | 10 +- fs/reiserfs/xattr_user.c | 10 +- fs/romfs/inode.c | 33 +- fs/select.c | 19 +- fs/smbfs/inode.c | 2 +- fs/smbfs/proc.c | 17 +- fs/super.c | 26 +- fs/sysfs/symlink.c | 41 +- fs/sysfs/sysfs.h | 2 +- fs/sysv/balloc.c | 31 +- fs/sysv/ialloc.c | 2 +- fs/sysv/inode.c | 5 +- fs/sysv/itree.c | 36 +- fs/sysv/super.c | 36 +- fs/sysv/sysv.h | 72 +- fs/udf/balloc.c | 22 +- fs/udf/dir.c | 4 +- fs/udf/directory.c | 16 +- fs/udf/ecma_167.h | 294 +- fs/udf/fsync.c | 4 +- fs/udf/inode.c | 114 +- fs/udf/misc.c | 14 +- fs/udf/namei.c | 36 +- fs/udf/osta_udf.h | 86 +- fs/udf/partition.c | 12 +- fs/udf/super.c | 59 +- fs/udf/truncate.c | 14 +- fs/udf/udfdecl.h | 35 +- fs/udf/udfend.h | 22 +- fs/udf/udftime.c | 8 +- fs/ufs/balloc.c | 33 +- fs/ufs/dir.c | 10 +- fs/ufs/inode.c | 22 +- fs/ufs/super.c | 24 +- fs/ufs/swab.h | 72 +- fs/ufs/truncate.c | 16 +- fs/ufs/util.h | 38 +- fs/umsdos/inode.c | 6 +- fs/vfat/namei.c | 40 +- fs/xfs/Makefile | 3 +- fs/xfs/linux-2.6/xfs_aops.c | 74 +- fs/xfs/linux-2.6/xfs_buf.c | 54 +- fs/xfs/linux-2.6/xfs_buf.h | 2 +- fs/xfs/linux-2.6/xfs_file.c | 46 +- fs/xfs/linux-2.6/xfs_fs_subr.h | 1 - fs/xfs/linux-2.6/xfs_globals.c | 1 + fs/xfs/linux-2.6/xfs_ioctl.c | 133 +- fs/xfs/linux-2.6/xfs_ioctl32.c | 162 + fs/xfs/linux-2.6/xfs_ioctl32.h | 41 + fs/xfs/linux-2.6/xfs_iops.c | 30 +- fs/xfs/linux-2.6/xfs_iops.h | 2 +- fs/xfs/linux-2.6/xfs_linux.h | 2 + fs/xfs/linux-2.6/xfs_lrw.c | 276 +- fs/xfs/linux-2.6/xfs_lrw.h | 6 +- fs/xfs/linux-2.6/xfs_stats.c | 4 +- fs/xfs/linux-2.6/xfs_super.c | 217 +- fs/xfs/linux-2.6/xfs_sysctl.c | 7 +- fs/xfs/linux-2.6/xfs_sysctl.h | 2 + fs/xfs/linux-2.6/xfs_vfs.c | 2 + fs/xfs/linux-2.6/xfs_vfs.h | 21 +- fs/xfs/linux-2.6/xfs_vnode.c | 66 +- fs/xfs/linux-2.6/xfs_vnode.h | 16 +- fs/xfs/quota/xfs_dquot.c | 108 +- fs/xfs/quota/xfs_dquot.h | 2 + fs/xfs/quota/xfs_qm.c | 61 +- fs/xfs/quota/xfs_qm.h | 8 +- fs/xfs/quota/xfs_qm_stats.c | 4 +- fs/xfs/quota/xfs_qm_syscalls.c | 40 +- fs/xfs/quota/xfs_trans_dquot.c | 41 +- fs/xfs/support/ktrace.c | 9 +- fs/xfs/support/move.c | 8 +- fs/xfs/xfs_acl.h | 4 +- fs/xfs/xfs_alloc.c | 20 +- fs/xfs/xfs_alloc_btree.c | 2 +- fs/xfs/xfs_attr.c | 33 +- fs/xfs/xfs_attr_leaf.h | 1 - fs/xfs/xfs_bmap.c | 75 +- fs/xfs/xfs_bmap.h | 2 +- fs/xfs/xfs_bmap_btree.c | 2 +- fs/xfs/xfs_bmap_btree.h | 11 +- fs/xfs/xfs_buf_item.c | 2 - fs/xfs/xfs_da_btree.c | 2 +- fs/xfs/xfs_dfrag.c | 2 +- fs/xfs/xfs_dfrag.h | 2 +- fs/xfs/xfs_dinode.h | 12 + fs/xfs/xfs_dir2_trace.c | 2 +- fs/xfs/xfs_fs.h | 60 +- fs/xfs/xfs_fsops.c | 20 +- fs/xfs/xfs_iget.c | 7 +- fs/xfs/xfs_inode.c | 60 +- fs/xfs/xfs_inode.h | 1 - fs/xfs/xfs_iomap.c | 100 +- fs/xfs/xfs_iomap.h | 5 +- fs/xfs/xfs_itable.c | 12 +- fs/xfs/xfs_itable.h | 10 +- fs/xfs/xfs_log.c | 57 +- fs/xfs/xfs_log_priv.h | 1 - fs/xfs/xfs_log_recover.c | 23 +- fs/xfs/xfs_mount.c | 32 +- fs/xfs/xfs_mount.h | 2 +- fs/xfs/xfs_quota.h | 18 +- fs/xfs/xfs_rtalloc.c | 14 +- fs/xfs/xfs_sb.h | 6 +- fs/xfs/xfs_trans.c | 5 +- fs/xfs/xfs_trans_item.c | 2 +- fs/xfs/xfs_types.h | 2 +- fs/xfs/xfs_vfsops.c | 118 +- fs/xfs/xfs_vnodeops.c | 116 +- include/acpi/acconfig.h | 25 +- include/acpi/acdebug.h | 8 + include/acpi/acdisasm.h | 15 + include/acpi/acdispat.h | 3 +- include/acpi/acevents.h | 54 +- include/acpi/acexcep.h | 8 +- include/acpi/acglobal.h | 44 +- include/acpi/achware.h | 36 +- include/acpi/acinterp.h | 15 +- include/acpi/aclocal.h | 39 +- include/acpi/acmacros.h | 23 +- include/acpi/acnamesp.h | 18 +- include/acpi/acobject.h | 13 +- include/acpi/acparser.h | 4 +- include/acpi/acpi_bus.h | 28 +- include/acpi/acpi_drivers.h | 58 +- include/acpi/acpiosxf.h | 19 +- include/acpi/acpixf.h | 10 +- include/acpi/acstruct.h | 23 +- include/acpi/actbl.h | 29 +- include/acpi/actypes.h | 78 +- include/acpi/platform/acenv.h | 8 +- include/acpi/platform/aclinux.h | 2 - include/asm-alpha/a.out.h | 2 +- include/asm-alpha/bitops.h | 5 +- include/asm-alpha/bug.h | 12 +- include/asm-alpha/cache.h | 2 +- include/asm-alpha/compiler.h | 16 +- include/asm-alpha/core_apecs.h | 224 +- include/asm-alpha/core_cia.h | 303 +- include/asm-alpha/core_irongate.h | 134 +- include/asm-alpha/core_lca.h | 223 +- include/asm-alpha/core_marvel.h | 243 +- include/asm-alpha/core_mcpcia.h | 267 +- include/asm-alpha/core_polaris.h | 146 +- include/asm-alpha/core_t2.h | 110 +- include/asm-alpha/core_titan.h | 146 +- include/asm-alpha/core_tsunami.h | 149 +- include/asm-alpha/core_wildfire.h | 149 +- include/asm-alpha/dma-mapping.h | 64 +- include/asm-alpha/hardirq.h | 41 - include/asm-alpha/io.h | 687 +- include/asm-alpha/io_trivial.h | 127 + include/asm-alpha/jensen.h | 99 +- include/asm-alpha/machvec.h | 42 +- include/asm-alpha/mmu_context.h | 1 + include/asm-alpha/page.h | 1 + include/asm-alpha/pci.h | 4 +- include/asm-alpha/pgtable.h | 2 +- include/asm-alpha/ptrace.h | 1 + include/asm-alpha/resource.h | 2 +- include/asm-alpha/semaphore.h | 23 +- include/asm-alpha/socket.h | 16 - include/asm-alpha/spinlock.h | 27 +- include/asm-alpha/sysinfo.h | 1 + include/asm-alpha/system.h | 6 +- include/asm-alpha/thread_info.h | 2 +- include/asm-alpha/tlbflush.h | 3 +- include/asm-alpha/uaccess.h | 6 +- include/asm-alpha/unistd.h | 5 +- include/asm-alpha/vga.h | 18 +- include/asm-arm/apm.h | 49 +- include/asm-arm/arch-cl7500/uncompress.h | 2 +- include/asm-arm/arch-clps711x/uncompress.h | 2 +- include/asm-arm/arch-ebsa110/param.h | 2 +- include/asm-arm/arch-ebsa110/uncompress.h | 2 +- include/asm-arm/arch-ebsa285/uncompress.h | 2 +- include/asm-arm/arch-epxa10db/uncompress.h | 2 +- include/asm-arm/arch-h720x/boards.h | 53 + include/asm-arm/arch-h720x/dma.h | 26 + include/asm-arm/arch-h720x/h7201-regs.h | 67 + include/asm-arm/arch-h720x/h7202-regs.h | 151 + include/asm-arm/arch-h720x/hardware.h | 182 + include/asm-arm/arch-h720x/io.h | 24 + include/asm-arm/arch-h720x/irq.h | 14 + include/asm-arm/arch-h720x/irqs.h | 116 + include/asm-arm/arch-h720x/memory.h | 31 + include/asm-arm/arch-h720x/param.h | 10 + include/asm-arm/arch-h720x/serial.h | 101 + include/asm-arm/arch-h720x/system.h | 31 + include/asm-arm/arch-h720x/timex.h | 15 + include/asm-arm/arch-h720x/uncompress.h | 39 + include/asm-arm/arch-h720x/vmalloc.h | 21 + include/asm-arm/arch-imx/dma.h | 71 + include/asm-arm/arch-imx/hardware.h | 101 + include/asm-arm/arch-imx/imx-regs.h | 548 ++ include/asm-arm/arch-imx/io.h | 28 + include/asm-arm/arch-imx/irq.h | 20 + include/asm-arm/arch-imx/irqs.h | 116 + include/asm-arm/arch-imx/memory.h | 38 + include/asm-arm/arch-imx/mx1ads.h | 36 + include/asm-arm/arch-imx/param.h | 19 + include/asm-arm/arch-imx/serial.h | 26 + include/asm-arm/arch-imx/system.h | 40 + include/asm-arm/arch-imx/timex.h | 27 + include/asm-arm/arch-imx/uncompress.h | 78 + include/asm-arm/arch-imx/vmalloc.h | 32 + include/asm-arm/arch-integrator/uncompress.h | 2 +- include/asm-arm/arch-iop3xx/dma.h | 103 +- include/asm-arm/arch-iop3xx/hardware.h | 51 +- include/asm-arm/arch-iop3xx/iop321-irqs.h | 26 +- include/asm-arm/arch-iop3xx/iop321.h | 95 +- include/asm-arm/arch-iop3xx/iop331-irqs.h | 113 + include/asm-arm/arch-iop3xx/iop331.h | 342 + include/asm-arm/arch-iop3xx/iq31244.h | 36 + include/asm-arm/arch-iop3xx/iq80321.h | 32 +- include/asm-arm/arch-iop3xx/iq80331.h | 38 + include/asm-arm/arch-iop3xx/irqs.h | 18 +- include/asm-arm/arch-iop3xx/memory.h | 26 +- include/asm-arm/arch-iop3xx/param.h | 2 +- include/asm-arm/arch-iop3xx/serial.h | 53 +- include/asm-arm/arch-iop3xx/system.h | 10 +- include/asm-arm/arch-iop3xx/timex.h | 16 +- include/asm-arm/arch-iop3xx/uncompress.h | 36 +- include/asm-arm/arch-iop3xx/vmalloc.h | 1 + include/asm-arm/arch-ixp2000/dma.h | 18 + include/asm-arm/arch-ixp2000/enp2611.h | 28 + include/asm-arm/arch-ixp2000/gpio.h | 55 + include/asm-arm/arch-ixp2000/hardware.h | 44 + include/asm-arm/arch-ixp2000/io.h | 150 + include/asm-arm/arch-ixp2000/irq.h | 13 + include/asm-arm/arch-ixp2000/irqs.h | 190 + include/asm-arm/arch-ixp2000/ixdp2x00.h | 93 + include/asm-arm/arch-ixp2000/ixdp2x01.h | 53 + include/asm-arm/arch-ixp2000/ixp2000-regs.h | 337 + include/asm-arm/arch-ixp2000/memory.h | 34 + include/asm-arm/arch-ixp2000/param.h | 3 + include/asm-arm/arch-ixp2000/platform.h | 165 + include/asm-arm/arch-ixp2000/serial.h | 27 + include/asm-arm/arch-ixp2000/system.h | 35 + include/asm-arm/arch-ixp2000/timex.h | 13 + include/asm-arm/arch-ixp2000/uncompress.h | 52 + include/asm-arm/arch-ixp2000/vmalloc.h | 23 + include/asm-arm/arch-ixp4xx/io.h | 14 +- include/asm-arm/arch-ixp4xx/uncompress.h | 2 +- include/asm-arm/arch-l7200/param.h | 2 +- include/asm-arm/arch-l7200/uncompress.h | 2 +- include/asm-arm/arch-lh7a40x/uncompress.h | 2 +- include/asm-arm/arch-omap/board-h2.h | 10 + include/asm-arm/arch-omap/board-h3.h | 84 +- include/asm-arm/arch-omap/board-innovator.h | 119 +- include/asm-arm/arch-omap/board-perseus2.h | 57 +- include/asm-arm/arch-omap/board.h | 51 +- include/asm-arm/arch-omap/fpga.h | 159 +- include/asm-arm/arch-omap/hardware.h | 48 +- include/asm-arm/arch-omap/mcbsp.h | 253 + include/asm-arm/arch-omap/memory.h | 2 +- include/asm-arm/arch-omap/mux.h | 36 +- include/asm-arm/arch-omap/omap1510.h | 19 +- include/asm-arm/arch-omap/omap1610.h | 9 + include/asm-arm/arch-omap/omap5912.h | 9 + include/asm-arm/arch-omap/omap730.h | 6 - include/asm-arm/arch-omap/tps65010.h | 80 + include/asm-arm/arch-omap/uncompress.h | 2 +- include/asm-arm/arch-omap/usb.h | 108 + include/asm-arm/arch-pxa/dma.h | 2 +- include/asm-arm/arch-pxa/hardware.h | 9 +- include/asm-arm/arch-pxa/irqs.h | 54 +- include/asm-arm/arch-pxa/mmc.h | 19 + include/asm-arm/arch-pxa/pxa-regs.h | 56 +- include/asm-arm/arch-pxa/serial.h | 1 + include/asm-arm/arch-pxa/system.h | 1 + include/asm-arm/arch-pxa/uncompress.h | 2 +- include/asm-arm/arch-rpc/io.h | 38 +- include/asm-arm/arch-rpc/uncompress.h | 6 +- include/asm-arm/arch-s3c2410/bast-cpld.h | 35 +- include/asm-arm/arch-s3c2410/bast-irq.h | 3 +- include/asm-arm/arch-s3c2410/dma.h | 299 +- include/asm-arm/arch-s3c2410/hardware.h | 35 + include/asm-arm/arch-s3c2410/nand.h | 48 + include/asm-arm/arch-s3c2410/param.h | 2 +- include/asm-arm/arch-s3c2410/regs-clock.h | 58 +- include/asm-arm/arch-s3c2410/regs-dsc.h | 183 + include/asm-arm/arch-s3c2410/regs-gpio.h | 31 +- include/asm-arm/arch-s3c2410/regs-gpioj.h | 100 + include/asm-arm/arch-s3c2410/regs-iic.h | 50 + include/asm-arm/arch-s3c2410/regs-mem.h | 190 + include/asm-arm/arch-s3c2410/regs-nand.h | 43 + include/asm-arm/arch-s3c2410/regs-sdi.h | 112 + include/asm-arm/arch-s3c2410/regs-spi.h | 56 + include/asm-arm/arch-s3c2410/regs-timer.h | 2 + include/asm-arm/arch-s3c2410/regs-udc.h | 162 + include/asm-arm/arch-s3c2410/uncompress.h | 2 +- include/asm-arm/arch-s3c2410/usb-control.h | 45 + include/asm-arm/arch-sa1100/uncompress.h | 2 +- include/asm-arm/arch-shark/uncompress.h | 2 +- include/asm-arm/arch-versatile/uncompress.h | 2 +- include/asm-arm/atomic.h | 54 +- include/asm-arm/bitops.h | 2 +- include/asm-arm/bug.h | 14 +- include/asm-arm/cacheflush.h | 26 +- include/asm-arm/checksum.h | 2 +- include/asm-arm/elf.h | 27 + include/asm-arm/fpstate.h | 19 +- include/asm-arm/hardirq.h | 48 +- include/asm-arm/hardware.h | 9 - include/asm-arm/hardware/amba_clcd.h | 259 + include/asm-arm/hardware/clock.h | 8 +- include/asm-arm/io.h | 2 + include/asm-arm/mach/mmc.h | 16 + include/asm-arm/mach/pci.h | 8 +- include/asm-arm/mach/time.h | 7 +- include/asm-arm/memory.h | 21 +- include/asm-arm/page.h | 2 +- include/asm-arm/param.h | 11 +- include/asm-arm/ptrace.h | 6 + include/asm-arm/resource.h | 2 +- include/asm-arm/semaphore.h | 30 +- include/asm-arm/socket.h | 16 - include/asm-arm/system.h | 43 +- include/asm-arm/thread_info.h | 29 +- include/asm-arm/uaccess.h | 3 + include/asm-arm/unistd.h | 52 +- include/asm-arm26/bug.h | 17 +- include/asm-arm26/hardirq.h | 35 - include/asm-arm26/ptrace.h | 1 + include/asm-arm26/resource.h | 2 +- include/asm-arm26/semaphore.h | 37 +- include/asm-arm26/socket.h | 16 - include/asm-arm26/uaccess.h | 3 + include/asm-cris/arch-v10/ptrace.h | 1 + include/asm-cris/bug.h | 19 +- include/asm-cris/hardirq.h | 36 - include/asm-cris/resource.h | 2 +- include/asm-cris/semaphore.h | 33 +- include/asm-cris/socket.h | 15 - include/asm-cris/uaccess.h | 2 + include/asm-generic/bug.h | 34 + include/asm-generic/ide_iops.h | 8 +- include/asm-generic/iomap.h | 63 + include/asm-generic/local.h | 2 +- include/asm-generic/pgtable.h | 8 + include/asm-generic/siginfo.h | 1 + include/asm-generic/uaccess.h | 26 + include/asm-generic/vmlinux.lds.h | 22 + include/asm-h8300/bitops.h | 2 + include/asm-h8300/bug.h | 19 +- include/asm-h8300/hardirq.h | 40 - include/asm-h8300/ptrace.h | 1 + include/asm-h8300/resource.h | 2 +- include/asm-h8300/semaphore.h | 33 +- include/asm-h8300/socket.h | 16 - include/asm-h8300/uaccess.h | 2 + include/asm-i386/acpi.h | 13 + include/asm-i386/apic.h | 27 +- include/asm-i386/bitops.h | 12 +- include/asm-i386/bug.h | 14 +- include/asm-i386/checksum.h | 7 +- include/asm-i386/cpufeature.h | 13 +- include/asm-i386/desc.h | 10 +- include/asm-i386/dma-mapping.h | 13 +- include/asm-i386/elf.h | 2 +- include/asm-i386/fixmap.h | 21 +- include/asm-i386/hardirq.h | 42 +- include/asm-i386/hw_irq.h | 40 - include/asm-i386/io.h | 65 +- include/asm-i386/kdebug.h | 50 + include/asm-i386/kprobes.h | 60 + include/asm-i386/linkage.h | 4 + include/asm-i386/mach-bigsmp/mach_ipi.h | 2 +- include/asm-i386/mach-default/do_timer.h | 2 +- include/asm-i386/mach-default/mach_ipi.h | 4 +- include/asm-i386/mach-es7000/mach_ipi.h | 2 +- include/asm-i386/mach-es7000/mach_mpparse.h | 3 +- include/asm-i386/mach-es7000/mach_mpspec.h | 2 +- include/asm-i386/mach-numaq/mach_ipi.h | 2 +- include/asm-i386/mach-summit/mach_apic.h | 8 +- include/asm-i386/mach-summit/mach_ipi.h | 2 +- include/asm-i386/mach-visws/do_timer.h | 2 +- include/asm-i386/mach-visws/mach_apic.h | 1 + include/asm-i386/mmu_context.h | 12 +- include/asm-i386/mtrr.h | 2 - include/asm-i386/page.h | 8 +- include/asm-i386/pgtable-2level.h | 7 + include/asm-i386/pgtable-3level.h | 8 + include/asm-i386/pgtable.h | 7 - include/asm-i386/processor.h | 23 +- include/asm-i386/ptrace.h | 5 + include/asm-i386/resource.h | 2 +- include/asm-i386/rwlock.h | 32 +- include/asm-i386/semaphore.h | 34 +- include/asm-i386/smp.h | 1 + include/asm-i386/socket.h | 16 - include/asm-i386/spinlock.h | 18 +- include/asm-i386/thread_info.h | 2 +- include/asm-i386/timer.h | 1 + include/asm-i386/timex.h | 13 +- include/asm-i386/tlbflush.h | 2 +- include/asm-i386/topology.h | 2 +- include/asm-i386/uaccess.h | 42 +- include/asm-i386/unistd.h | 3 +- include/asm-ia64/acpi.h | 4 +- include/asm-ia64/bug.h | 13 +- include/asm-ia64/compat.h | 8 +- include/asm-ia64/dma-mapping.h | 2 +- include/asm-ia64/elf.h | 6 +- include/asm-ia64/gcc_intrin.h | 24 +- include/asm-ia64/hardirq.h | 41 +- include/asm-ia64/hw_irq.h | 2 - include/asm-ia64/ia32.h | 4 +- include/asm-ia64/io.h | 85 +- include/asm-ia64/iosapic.h | 11 +- include/asm-ia64/mca.h | 7 + include/asm-ia64/mca_asm.h | 3 - include/asm-ia64/mmu_context.h | 51 +- include/asm-ia64/mmzone.h | 6 - include/asm-ia64/numa.h | 2 +- include/asm-ia64/page.h | 18 +- include/asm-ia64/pgtable.h | 12 +- include/asm-ia64/processor.h | 30 +- include/asm-ia64/ptrace.h | 9 + include/asm-ia64/resource.h | 2 +- include/asm-ia64/sal.h | 12 +- include/asm-ia64/semaphore.h | 30 +- include/asm-ia64/siginfo.h | 2 +- include/asm-ia64/signal.h | 4 +- include/asm-ia64/smp.h | 8 +- include/asm-ia64/sn/sn2/shubio.h | 2 +- include/asm-ia64/sn/sn2/sn_hwperf.h | 218 + include/asm-ia64/sn/sn_cpuid.h | 8 +- include/asm-ia64/sn/sn_sal.h | 196 +- include/asm-ia64/sn/xtalk/xtalk.h | 2 +- include/asm-ia64/sn/xtalk/xwidget.h | 2 +- include/asm-ia64/socket.h | 16 - include/asm-ia64/spinlock.h | 4 +- include/asm-ia64/system.h | 4 +- include/asm-ia64/thread_info.h | 8 - include/asm-ia64/tlb.h | 1 + include/asm-ia64/tlbflush.h | 7 +- include/asm-ia64/uaccess.h | 120 +- include/asm-ia64/unistd.h | 4 +- include/asm-m32r/a.out.h | 28 + include/asm-m32r/addrspace.h | 58 + include/asm-m32r/assembler.h | 212 + include/asm-m32r/atomic.h | 305 + include/asm-m32r/bitops.h | 716 ++ include/asm-m32r/bug.h | 22 + include/asm-m32r/bugs.h | 21 + include/asm-m32r/byteorder.h | 19 + include/asm-m32r/cache.h | 12 + include/asm-m32r/cachectl.h | 26 + include/asm-m32r/cacheflush.h | 68 + include/asm-m32r/checksum.h | 206 + include/asm-m32r/current.h | 18 + include/asm-m32r/delay.h | 28 + include/asm-m32r/div64.h | 38 + include/asm-m32r/dma-mapping.h | 23 + include/asm-m32r/dma.h | 14 + include/asm-m32r/elf.h | 172 + include/asm-m32r/errno.h | 9 + include/asm-m32r/fcntl.h | 92 + include/asm-m32r/flat.h | 145 + include/asm-m32r/hardirq.h | 65 + include/asm-m32r/hdreg.h | 1 + include/asm-m32r/hw_irq.h | 9 + include/asm-m32r/ide.h | 82 + include/asm-m32r/io.h | 216 + include/asm-m32r/ioctl.h | 78 + include/asm-m32r/ioctls.h | 88 + include/asm-m32r/ipc.h | 35 + include/asm-m32r/ipcbuf.h | 33 + include/asm-m32r/irq.h | 86 + include/asm-m32r/kmap_types.h | 34 + include/asm-m32r/linkage.h | 7 + include/asm-m32r/local.h | 6 + include/asm-m32r/m32102.h | 266 + include/asm-m32r/m32102peri.h | 468 ++ include/asm-m32r/m32700ut/m32700ut_lan.h | 107 + include/asm-m32r/m32700ut/m32700ut_lcd.h | 59 + include/asm-m32r/m32700ut/m32700ut_pld.h | 265 + include/asm-m32r/m32r.h | 134 + include/asm-m32r/m32r_mp_fpga.h | 313 + include/asm-m32r/mappi2/mappi2_pld.h | 151 + include/asm-m32r/mc146818rtc.h | 32 + include/asm-m32r/mman.h | 45 + include/asm-m32r/mmu.h | 35 + include/asm-m32r/mmu_context.h | 169 + include/asm-m32r/mmzone.h | 80 + include/asm-m32r/module.h | 13 + include/asm-m32r/msgbuf.h | 35 + include/asm-m32r/namei.h | 21 + include/asm-m32r/numnodes.h | 15 + include/asm-m32r/opsput/opsput_lan.h | 56 + include/asm-m32r/opsput/opsput_lcd.h | 59 + include/asm-m32r/opsput/opsput_pld.h | 259 + include/asm-m32r/page.h | 112 + include/asm-m32r/param.h | 27 + include/asm-m32r/pci.h | 10 + include/asm-m32r/percpu.h | 6 + include/asm-m32r/pgalloc.h | 87 + include/asm-m32r/pgtable-2level.h | 77 + include/asm-m32r/pgtable.h | 422 ++ include/asm-m32r/poll.h | 31 + include/asm-m32r/posix_types.h | 126 + include/asm-m32r/processor.h | 157 + include/asm-m32r/ptrace.h | 165 + include/asm-m32r/resource.h | 55 + include/asm-m32r/rtc.h | 70 + include/asm-m32r/scatterlist.h | 18 + include/asm-m32r/sections.h | 8 + include/asm-m32r/segment.h | 14 + include/asm-m32r/semaphore.h | 214 + include/asm-m32r/sembuf.h | 29 + include/asm-m32r/serial.h | 151 + include/asm-m32r/setup.h | 33 + include/asm-m32r/shmbuf.h | 46 + include/asm-m32r/shmparam.h | 8 + include/asm-m32r/sigcontext.h | 50 + include/asm-m32r/siginfo.h | 8 + include/asm-m32r/signal.h | 200 + include/asm-m32r/smp.h | 119 + include/asm-m32r/socket.h | 50 + include/asm-m32r/sockios.h | 14 + include/asm-m32r/spinlock.h | 382 + include/asm-m32r/stat.h | 91 + include/asm-m32r/statfs.h | 6 + include/asm-m32r/string.h | 15 + include/asm-m32r/syscall.h | 11 + include/asm-m32r/system.h | 301 + include/asm-m32r/termbits.h | 175 + include/asm-m32r/termios.h | 109 + include/asm-m32r/thread_info.h | 149 + include/asm-m32r/timex.h | 36 + include/asm-m32r/tlb.h | 20 + include/asm-m32r/tlbflush.h | 102 + include/asm-m32r/topology.h | 53 + include/asm-m32r/types.h | 64 + include/asm-m32r/uaccess.h | 752 ++ include/asm-m32r/ucontext.h | 14 + include/asm-m32r/unaligned.h | 25 + include/asm-m32r/unistd.h | 483 ++ include/asm-m32r/user.h | 59 + include/asm-m32r/vga.h | 22 + include/asm-m32r/xor.h | 8 + include/asm-m68k/bug.h | 17 +- include/asm-m68k/cacheflush.h | 12 +- include/asm-m68k/hardirq.h | 36 - include/asm-m68k/ptrace.h | 1 + include/asm-m68k/resource.h | 2 +- include/asm-m68k/semaphore.h | 33 +- include/asm-m68k/socket.h | 16 - include/asm-m68k/system.h | 2 +- include/asm-m68k/uaccess.h | 3 + include/asm-m68knommu/bug.h | 22 +- include/asm-m68knommu/hardirq.h | 46 - include/asm-m68knommu/ptrace.h | 1 + include/asm-m68knommu/semaphore.h | 33 +- include/asm-m68knommu/uaccess.h | 2 + include/asm-mips/bug.h | 10 +- include/asm-mips/dma-mapping.h | 1 - include/asm-mips/hardirq.h | 40 - include/asm-mips/ptrace.h | 1 + include/asm-mips/resource.h | 2 +- include/asm-mips/semaphore.h | 36 +- include/asm-mips/siginfo.h | 2 +- include/asm-mips/socket.h | 41 +- include/asm-mips/uaccess.h | 4 + include/asm-mips/vr41xx/vrc4173.h | 106 + include/asm-parisc/bug.h | 27 +- include/asm-parisc/cacheflush.h | 12 +- include/asm-parisc/hardirq.h | 42 - include/asm-parisc/ptrace.h | 1 + include/asm-parisc/resource.h | 2 +- include/asm-parisc/semaphore.h | 31 +- include/asm-parisc/socket.h | 14 - include/asm-parisc/uaccess.h | 2 + include/asm-ppc/8253pit.h | 10 + include/asm-ppc/bug.h | 7 +- include/asm-ppc/checksum.h | 2 +- include/asm-ppc/dma-mapping.h | 1 - include/asm-ppc/fsl_ocp.h | 2 +- include/asm-ppc/hardirq.h | 44 - include/asm-ppc/ibm44x.h | 4 +- include/asm-ppc/ide.h | 8 +- include/asm-ppc/io.h | 74 +- include/asm-ppc/mpc52xx.h | 374 +- include/asm-ppc/mpc52xx_psc.h | 162 +- include/asm-ppc/mpc8260.h | 4 + include/asm-ppc/open_pic.h | 2 +- include/asm-ppc/ppcboot.h | 36 +- include/asm-ppc/ptrace.h | 6 + include/asm-ppc/reg_booke.h | 6 +- include/asm-ppc/residual.h | 16 + include/asm-ppc/resource.h | 2 +- include/asm-ppc/semaphore.h | 36 +- include/asm-ppc/serial.h | 12 +- include/asm-ppc/socket.h | 16 - include/asm-ppc/thread_info.h | 10 - include/asm-ppc/uaccess.h | 2 + include/asm-ppc64/8253pit.h | 10 + include/asm-ppc64/bitops.h | 88 +- include/asm-ppc64/btext.h | 19 +- include/asm-ppc64/bug.h | 8 +- include/asm-ppc64/checksum.h | 4 +- include/asm-ppc64/dma-mapping.h | 1 - include/asm-ppc64/eeh.h | 152 +- include/asm-ppc64/hardirq.h | 45 - include/asm-ppc64/hvcall.h | 8 +- include/asm-ppc64/hvconsole.h | 18 +- include/asm-ppc64/hvcserver.h | 25 +- include/asm-ppc64/iSeries/iSeries_io.h | 18 +- include/asm-ppc64/io.h | 107 +- include/asm-ppc64/iommu.h | 13 +- include/asm-ppc64/lmb.h | 10 +- include/asm-ppc64/machdep.h | 8 +- include/asm-ppc64/memory.h | 10 - include/asm-ppc64/mmu.h | 244 +- include/asm-ppc64/mmu_context.h | 218 +- include/asm-ppc64/mmzone.h | 4 +- include/asm-ppc64/naca.h | 3 - include/asm-ppc64/paca.h | 19 +- include/asm-ppc64/page.h | 26 +- include/asm-ppc64/pci-bridge.h | 9 +- include/asm-ppc64/pgalloc.h | 1 + include/asm-ppc64/pgtable.h | 33 +- include/asm-ppc64/plpar_wrappers.h | 109 + include/asm-ppc64/ppc32.h | 30 +- include/asm-ppc64/processor.h | 58 +- include/asm-ppc64/prom.h | 71 +- include/asm-ppc64/ptrace.h | 8 +- include/asm-ppc64/resource.h | 2 +- include/asm-ppc64/rtas.h | 143 +- include/asm-ppc64/semaphore.h | 36 +- include/asm-ppc64/smp.h | 24 +- include/asm-ppc64/socket.h | 16 - include/asm-ppc64/spinlock.h | 278 +- include/asm-ppc64/system.h | 3 + include/asm-ppc64/systemcfg.h | 49 +- include/asm-ppc64/tlb.h | 17 +- include/asm-ppc64/uaccess.h | 6 + include/asm-ppc64/unistd.h | 6 +- include/asm-s390/bug.h | 19 +- include/asm-s390/dma-mapping.h | 13 +- include/asm-s390/hardirq.h | 43 +- include/asm-s390/idals.h | 2 +- include/asm-s390/irq.h | 2 +- include/asm-s390/lowcore.h | 8 +- include/asm-s390/page.h | 19 + include/asm-s390/pgtable.h | 23 +- include/asm-s390/processor.h | 21 + include/asm-s390/ptrace.h | 1 + include/asm-s390/resource.h | 2 +- include/asm-s390/socket.h | 16 - include/asm-s390/thread_info.h | 38 +- include/asm-s390/timer.h | 2 - include/asm-s390/uaccess.h | 6 + include/asm-sh/bug.h | 17 +- include/asm-sh/cacheflush.h | 14 +- include/asm-sh/dma-mapping.h | 1 - include/asm-sh/hardirq.h | 41 +- include/asm-sh/ptrace.h | 9 + include/asm-sh/resource.h | 2 +- include/asm-sh/semaphore.h | 35 +- include/asm-sh/socket.h | 16 - include/asm-sh/uaccess.h | 4 + include/asm-sh64/cacheflush.h | 14 +- include/asm-sh64/dma-mapping.h | 1 - include/asm-sh64/ptrace.h | 1 + include/asm-sh64/semaphore.h | 35 +- include/asm-sh64/uaccess.h | 3 + include/asm-sparc/bug.h | 17 +- include/asm-sparc/cacheflush.h | 10 +- include/asm-sparc/dma-mapping.h | 1 - include/asm-sparc/hardirq.h | 41 - include/asm-sparc/ptrace.h | 1 + include/asm-sparc/resource.h | 2 +- include/asm-sparc/semaphore.h | 36 +- include/asm-sparc/sigcontext.h | 14 - include/asm-sparc/socket.h | 16 - include/asm-sparc/uaccess.h | 3 + include/asm-sparc/unistd.h | 11 +- include/asm-sparc/vaddrs.h | 4 +- include/asm-sparc64/bitops.h | 35 +- include/asm-sparc64/bug.h | 19 +- include/asm-sparc64/cacheflush.h | 11 +- include/asm-sparc64/checksum.h | 37 +- include/asm-sparc64/delay.h | 69 +- include/asm-sparc64/dma.h | 2 +- include/asm-sparc64/ebus.h | 2 +- include/asm-sparc64/elf.h | 4 +- include/asm-sparc64/hardirq.h | 41 - include/asm-sparc64/ide.h | 12 +- include/asm-sparc64/io.h | 162 +- include/asm-sparc64/kdebug.h | 49 +- include/asm-sparc64/kprobes.h | 24 + include/asm-sparc64/parport.h | 6 +- include/asm-sparc64/pbm.h | 9 + include/asm-sparc64/ptrace.h | 5 + include/asm-sparc64/resource.h | 2 +- include/asm-sparc64/sigcontext.h | 12 - include/asm-sparc64/siginfo.h | 54 +- include/asm-sparc64/socket.h | 16 - include/asm-sparc64/spinlock.h | 180 +- include/asm-sparc64/string.h | 109 +- include/asm-sparc64/ttable.h | 6 + include/asm-sparc64/uaccess.h | 53 +- include/asm-sparc64/unistd.h | 12 +- include/asm-sparc64/vga.h | 3 + include/asm-um/archparam-i386.h | 89 +- include/asm-um/bug.h | 28 +- include/asm-um/common.lds.S | 52 +- include/asm-um/current.h | 6 +- include/asm-um/dma-mapping.h | 122 +- include/asm-um/elf.h | 13 + include/asm-um/fixmap.h | 8 + include/asm-um/irq.h | 18 - include/asm-um/mmu_context.h | 4 +- include/asm-um/module-i386.h | 13 + include/asm-um/page.h | 34 +- include/asm-um/pgtable.h | 109 +- include/asm-um/processor-generic.h | 47 +- include/asm-um/processor-i386.h | 11 +- include/asm-um/ptrace-generic.h | 2 + include/asm-um/smp.h | 6 +- include/asm-um/spinlock.h | 4 - include/asm-um/system-generic.h | 9 +- include/asm-um/system-i386.h | 31 - include/asm-um/thread_info.h | 16 +- include/asm-um/timex.h | 2 - include/asm-um/uaccess.h | 7 +- include/asm-um/unistd.h | 5 +- include/asm-v850/bug.h | 12 +- include/asm-v850/hardirq.h | 40 - include/asm-v850/ptrace.h | 1 + include/asm-v850/resource.h | 2 +- include/asm-v850/socket.h | 16 - include/asm-v850/uaccess.h | 3 + include/asm-x86_64/acpi.h | 7 + include/asm-x86_64/apic.h | 28 +- include/asm-x86_64/apicdef.h | 2 +- include/asm-x86_64/atomic.h | 160 + include/asm-x86_64/bitops.h | 143 +- include/asm-x86_64/bug.h | 25 +- include/asm-x86_64/cpufeature.h | 15 +- include/asm-x86_64/desc.h | 4 +- include/asm-x86_64/dma-mapping.h | 134 +- include/asm-x86_64/elf.h | 7 + include/asm-x86_64/hardirq.h | 43 +- include/asm-x86_64/hw_irq.h | 35 +- include/asm-x86_64/i387.h | 24 +- include/asm-x86_64/ia32.h | 10 +- include/asm-x86_64/ia32_unistd.h | 3 +- include/asm-x86_64/io.h | 59 +- include/asm-x86_64/mpspec.h | 3 +- include/asm-x86_64/msi.h | 3 +- include/asm-x86_64/mtrr.h | 2 - include/asm-x86_64/pci.h | 253 +- include/asm-x86_64/processor.h | 17 +- include/asm-x86_64/proto.h | 4 +- include/asm-x86_64/ptrace.h | 1 + include/asm-x86_64/resource.h | 2 +- include/asm-x86_64/semaphore.h | 35 +- include/asm-x86_64/smp.h | 14 +- include/asm-x86_64/socket.h | 16 - include/asm-x86_64/spinlock.h | 4 +- include/asm-x86_64/swiotlb.h | 36 + include/asm-x86_64/system.h | 8 +- include/asm-x86_64/topology.h | 9 +- include/asm-x86_64/uaccess.h | 6 + include/asm-x86_64/unistd.h | 4 +- include/linux/acct.h | 23 +- include/linux/acpi.h | 7 +- include/linux/adfs_fs.h | 16 +- include/linux/adfs_fs_i.h | 2 +- include/linux/adfs_fs_sb.h | 2 +- include/linux/affs_fs.h | 3 +- include/linux/affs_hardblocks.h | 14 +- include/linux/aio.h | 28 +- include/linux/amigaffs.h | 112 +- include/linux/arcdevice.h | 2 +- include/linux/ata.h | 31 +- include/linux/atalk.h | 29 +- include/linux/bio.h | 3 + include/linux/bitmap.h | 3 + include/linux/blkdev.h | 24 + include/linux/bootmem.h | 3 + include/linux/buffer_head.h | 26 +- include/linux/byteorder/big_endian.h | 118 +- include/linux/byteorder/generic.h | 8 +- include/linux/byteorder/little_endian.h | 118 +- include/linux/cdrom.h | 3 +- include/linux/coda.h | 10 +- include/linux/compat.h | 12 + include/linux/compat_ioctl.h | 24 +- include/linux/compiler-gcc+.h | 6 +- include/linux/compiler-gcc3.h | 12 +- include/linux/compiler.h | 8 + include/linux/cpu.h | 2 +- include/linux/cpufreq.h | 7 - include/linux/cpumask.h | 5 +- include/linux/cyclades.h | 10 +- include/linux/dcache.h | 4 +- include/linux/delay.h | 6 + include/linux/device.h | 4 +- include/linux/dma-mapping.h | 30 + include/linux/dqblk_xfs.h | 63 +- include/linux/efs_dir.h | 4 +- include/linux/efs_fs.h | 4 +- include/linux/efs_fs_i.h | 24 +- include/linux/efs_fs_sb.h | 52 +- include/linux/efs_vh.h | 20 +- include/linux/elf.h | 7 +- include/linux/err.h | 4 +- include/linux/errno.h | 1 + include/linux/ext2_fs.h | 144 +- include/linux/ext3_fs.h | 139 +- include/linux/ext3_fs_i.h | 2 +- include/linux/fb.h | 180 +- include/linux/fs.h | 120 +- include/linux/gen_stats.h | 62 + include/linux/genhd.h | 111 +- include/linux/gfp.h | 5 + include/linux/hardirq.h | 46 + include/linux/hdreg.h | 5 +- include/linux/hiddev.h | 8 +- include/linux/highmem.h | 4 + include/linux/highuid.h | 8 +- include/linux/hpet.h | 4 +- include/linux/i2c-algo-pca.h | 17 + include/linux/i2c-id.h | 4 + include/linux/i2c-vid.h | 5 +- include/linux/i2c.h | 4 +- include/linux/i2o-dev.h | 262 +- include/linux/i2o.h | 746 +- include/linux/ide.h | 62 +- include/linux/if_bridge.h | 2 +- include/linux/if_ether.h | 14 +- include/linux/if_fddi.h | 36 +- include/linux/if_tr.h | 9 + include/linux/if_vlan.h | 12 +- include/linux/inetdevice.h | 20 +- include/linux/input.h | 2 + include/linux/interrupt.h | 2 +- include/linux/ioctl32.h | 25 +- include/linux/ip6_tunnel.h | 2 + include/linux/ipmi.h | 6 + include/linux/ipv6.h | 11 +- include/linux/isicom.h | 1 - include/linux/iso_fs.h | 12 +- include/linux/jbd.h | 39 +- include/linux/kernel.h | 6 + include/linux/kmod.h | 1 + include/linux/kobject.h | 11 +- include/linux/kprobes.h | 134 + include/linux/kref.h | 14 +- include/linux/libata.h | 88 +- include/linux/linkage.h | 4 + include/linux/list.h | 42 +- include/linux/lockd/bind.h | 2 +- include/linux/lockd/lockd.h | 23 +- include/linux/mempolicy.h | 3 - include/linux/mii.h | 3 +- include/linux/miscdevice.h | 1 + include/linux/mm.h | 126 +- include/linux/mman.h | 3 + include/linux/mmc/card.h | 92 + include/linux/mmc/host.h | 108 + include/linux/mmc/mmc.h | 98 + include/linux/mmc/protocol.h | 203 + include/linux/mmtimer.h | 56 + include/linux/mmzone.h | 14 +- include/linux/moduleparam.h | 7 +- include/linux/msdos_fs.h | 57 +- include/linux/mtd/map.h | 2 +- include/linux/mv643xx.h | 1039 +++ include/linux/ncp.h | 92 +- include/linux/ncp_fs.h | 10 +- include/linux/ncp_fs_i.h | 8 +- include/linux/ncp_no.h | 26 +- include/linux/net.h | 30 + include/linux/netdevice.h | 9 +- include/linux/netfilter.h | 2 +- include/linux/netfilter_bridge/ebt_802_3.h | 9 + include/linux/netfilter_ipv4/ip_conntrack.h | 65 +- .../linux/netfilter_ipv4/ip_conntrack_core.h | 32 +- .../linux/netfilter_ipv4/ip_conntrack_ftp.h | 5 - .../linux/netfilter_ipv4/ip_conntrack_irc.h | 5 - .../netfilter_ipv4/ip_conntrack_protocol.h | 43 +- .../linux/netfilter_ipv4/ip_conntrack_sctp.h | 25 + .../linux/netfilter_ipv4/ip_conntrack_tcp.h | 37 +- .../linux/netfilter_ipv4/ip_conntrack_tuple.h | 6 + include/linux/netfilter_ipv4/ip_nat.h | 15 +- include/linux/netfilter_ipv4/ip_nat_core.h | 6 - include/linux/netfilter_ipv4/ip_nat_helper.h | 8 +- .../linux/netfilter_ipv4/ip_nat_protocol.h | 16 +- include/linux/netfilter_ipv4/ip_tables.h | 1 - include/linux/netfilter_ipv4/ipt_comment.h | 10 + include/linux/netfilter_ipv4/ipt_sctp.h | 107 + include/linux/netfilter_ipv6.h | 2 + include/linux/netfilter_ipv6/ip6_tables.h | 4 - include/linux/netfilter_ipv6/ip6t_physdev.h | 24 + include/linux/netlink.h | 8 +- include/linux/nfs.h | 17 + include/linux/nfs4.h | 62 +- include/linux/nfs4_acl.h | 59 + include/linux/nfs_fs.h | 116 +- include/linux/nfs_fs_i.h | 4 +- include/linux/nfs_fs_sb.h | 1 + include/linux/nfs_page.h | 37 +- include/linux/nfs_xdr.h | 76 +- include/linux/nfsd/nfsd.h | 13 +- include/linux/nfsd/state.h | 2 +- include/linux/nfsd/xdr4.h | 6 +- include/linux/nls.h | 25 + include/linux/node.h | 1 - include/linux/notifier.h | 4 + include/linux/page-flags.h | 10 +- include/linux/pagemap.h | 1 + include/linux/pci.h | 24 +- include/linux/pci_ids.h | 21 +- include/linux/percpu.h | 26 +- include/linux/personality.h | 12 +- include/linux/pfkeyv2.h | 1 + include/linux/pid.h | 43 +- include/linux/pkt_sched.h | 20 + include/linux/pm.h | 11 +- include/linux/poll.h | 8 +- include/linux/prctl.h | 2 + include/linux/prio_tree.h | 12 + include/linux/proc_fs.h | 11 +- include/linux/profile.h | 58 +- include/linux/quota.h | 1 - include/linux/quotaio_v2.h | 44 +- include/linux/raid/md.h | 2 - include/linux/raid/md_k.h | 11 +- include/linux/raid/raid10.h | 103 + include/linux/ramfs.h | 11 + include/linux/random.h | 2 - include/linux/rbtree.h | 1 + include/linux/rcupdate.h | 142 +- include/linux/reiserfs_fs.h | 11 +- include/linux/reiserfs_fs_i.h | 2 +- include/linux/reiserfs_fs_sb.h | 4 + include/linux/resource.h | 6 + include/linux/rmap.h | 18 +- include/linux/romfs_fs.h | 18 +- include/linux/rtnetlink.h | 151 +- include/linux/sched.h | 273 +- include/linux/serial_core.h | 1 + include/linux/serio.h | 66 +- include/linux/shm.h | 2 + include/linux/shmem_fs.h | 14 +- include/linux/signal.h | 2 +- include/linux/skbuff.h | 43 +- include/linux/slab.h | 7 +- include/linux/socket.h | 1 - include/linux/spinlock.h | 244 +- include/linux/stddef.h | 6 + include/linux/sunrpc/auth_gss.h | 2 - include/linux/sunrpc/cache.h | 5 +- include/linux/sunrpc/gss_asn1.h | 1 - include/linux/sunrpc/gss_spkm3.h | 61 + include/linux/sunrpc/sched.h | 2 + include/linux/sunrpc/svc.h | 10 + include/linux/suspend.h | 20 - include/linux/swap.h | 22 +- include/linux/syscalls.h | 10 +- include/linux/sysctl.h | 16 + include/linux/sysv_fs.h | 131 +- include/linux/tc_act/tc_gact.h | 34 + include/linux/tcp.h | 28 +- include/linux/time.h | 15 + include/linux/times.h | 20 + include/linux/timex.h | 121 +- include/linux/topology.h | 2 +- include/linux/tty.h | 40 +- include/linux/tty_ldisc.h | 10 + include/linux/types.h | 13 + include/linux/udf_fs_i.h | 2 +- include/linux/ufs_fs.h | 539 +- include/linux/ufs_fs_i.h | 4 +- include/linux/umem.h | 14 +- include/linux/usb.h | 13 +- include/linux/usb_ch9.h | 8 +- include/linux/usb_gadget.h | 6 - include/linux/usb_otg.h | 118 + include/linux/videodev.h | 1 + include/linux/vt_kern.h | 2 +- include/linux/wait.h | 41 + include/linux/workqueue.h | 2 + include/linux/writeback.h | 24 +- include/linux/xfrm.h | 1 + include/math-emu/op-common.h | 6 +- include/media/id.h | 1 - include/media/tuner.h | 17 + include/net/addrconf.h | 4 +- include/net/af_unix.h | 7 +- include/net/dn_neigh.h | 1 - include/net/gen_stats.h | 45 + include/net/if_inet6.h | 2 + include/net/inet_ecn.h | 43 +- include/net/ip.h | 1 + include/net/ip6_fib.h | 1 + include/net/ip6_route.h | 12 + include/net/ip_fib.h | 39 +- include/net/ipcomp.h | 3 +- include/net/ipv6.h | 2 +- include/net/llc_pdu.h | 10 +- include/net/neighbour.h | 100 +- include/net/pkt_act.h | 13 +- include/net/pkt_sched.h | 3 +- include/net/route.h | 5 - include/net/sctp/sctp.h | 1 + include/net/sock.h | 13 +- include/net/tc_act/tc_gact.h | 17 + include/net/tcp.h | 246 +- include/net/tcp_ecn.h | 2 +- include/net/xfrm.h | 109 +- include/pcmcia/ss.h | 6 +- include/rxrpc/call.h | 6 +- include/rxrpc/connection.h | 12 +- include/rxrpc/packet.h | 26 +- include/rxrpc/peer.h | 2 +- include/rxrpc/rxrpc.h | 9 +- include/rxrpc/transport.h | 2 - include/rxrpc/types.h | 2 + include/scsi/scsi.h | 10 +- include/scsi/scsi_device.h | 42 +- include/scsi/scsi_driver.h | 1 + include/scsi/scsi_eh.h | 1 - include/sound/ac97_codec.h | 42 +- include/sound/asequencer.h | 4 +- include/sound/asound.h | 1 - include/sound/control.h | 3 +- include/sound/core.h | 19 +- include/sound/cs46xx.h | 21 +- include/sound/driver.h | 2 - include/sound/emu10k1.h | 27 +- include/sound/es1688.h | 2 - include/sound/info.h | 5 +- include/sound/initval.h | 33 - include/sound/memalloc.h | 21 +- include/sound/pcm-indirect.h | 177 + include/sound/pcm.h | 58 +- include/sound/pcm_oss.h | 10 +- include/sound/seq_kernel.h | 7 +- include/sound/soundfont.h | 1 + include/sound/timer.h | 3 +- include/sound/trident.h | 1 - include/sound/version.h | 4 +- include/sound/vx_core.h | 8 + include/sound/ymfpci.h | 1 - include/video/epson1355.h | 64 + include/video/neomagic.h | 3 + include/video/tdfx.h | 1 + include/video/vga.h | 46 +- init/Kconfig | 27 +- init/do_mounts_rd.c | 20 +- init/main.c | 144 +- ipc/mqueue.c | 2 +- ipc/msg.c | 246 +- ipc/sem.c | 98 +- ipc/shm.c | 48 +- ipc/util.c | 105 +- ipc/util.h | 12 +- kernel/Makefile | 3 +- kernel/acct.c | 10 +- kernel/audit.c | 15 +- kernel/auditsc.c | 9 +- kernel/capability.c | 6 +- kernel/compat.c | 189 +- kernel/cpu.c | 7 +- kernel/exec_domain.c | 121 +- kernel/exit.c | 378 +- kernel/fork.c | 189 +- kernel/kmod.c | 4 +- kernel/kprobes.c | 149 + kernel/module.c | 53 +- kernel/panic.c | 8 +- kernel/params.c | 10 + kernel/pid.c | 105 +- kernel/posix-timers.c | 22 +- kernel/power/Kconfig | 42 +- kernel/power/Makefile | 7 +- kernel/power/console.c | 3 + kernel/power/disk.c | 85 +- kernel/power/main.c | 17 +- kernel/power/power.h | 19 +- kernel/power/process.c | 4 +- kernel/power/swsusp.c | 1386 ++-- kernel/printk.c | 16 +- kernel/profile.c | 241 +- kernel/ptrace.c | 63 +- kernel/rcupdate.c | 311 +- kernel/resource.c | 22 +- kernel/sched.c | 1590 ++-- kernel/signal.c | 305 +- kernel/softirq.c | 7 +- kernel/spinlock.c | 308 + kernel/sys.c | 168 +- kernel/sysctl.c | 57 +- kernel/time.c | 102 +- kernel/timer.c | 154 +- kernel/user.c | 4 +- kernel/workqueue.c | 22 +- lib/Kconfig.debug | 100 + lib/Makefile | 8 +- lib/bitmap.c | 82 + lib/idr.c | 168 +- lib/iomap.c | 206 + lib/kobject.c | 57 +- lib/kref.c | 29 +- lib/rbtree.c | 13 + lib/rwsem.c | 8 +- lib/zlib_inflate/Makefile | 2 +- lib/zlib_inflate/infblock.c | 2 +- lib/zlib_inflate/inflate.c | 143 - lib/zlib_inflate/inflate_sync.c | 148 + lib/zlib_inflate/inftrees.c | 34 +- lib/zlib_inflate/inftrees.h | 1 + mm/Makefile | 7 +- mm/bootmem.c | 25 +- mm/filemap.c | 425 +- mm/fremap.c | 4 +- mm/highmem.c | 6 +- mm/hugetlb.c | 6 +- mm/memory.c | 9 +- mm/mempolicy.c | 80 +- mm/mempool.c | 1 + mm/mlock.c | 65 +- mm/mmap.c | 209 +- mm/mprotect.c | 2 + mm/mremap.c | 9 +- mm/nommu.c | 2 +- mm/oom_kill.c | 23 +- mm/page_alloc.c | 358 +- mm/prio_tree.c | 69 +- mm/readahead.c | 42 +- mm/rmap.c | 289 +- mm/shmem.c | 316 +- mm/slab.c | 334 +- mm/swap_state.c | 2 +- mm/swapfile.c | 23 +- mm/thrash.c | 98 + mm/tiny-shmem.c | 124 + mm/truncate.c | 1 + mm/vmalloc.c | 27 +- mm/vmscan.c | 113 +- net/8021q/vlan.c | 2 +- net/8021q/vlan_dev.c | 6 +- net/Kconfig | 13 + net/Makefile | 3 +- net/appletalk/Makefile | 3 +- net/appletalk/atalk_proc.c | 13 - net/appletalk/ddp.c | 10 - net/appletalk/sysctl_net_atalk.c | 18 +- net/atm/br2684.c | 2 +- net/atm/clip.c | 319 +- net/atm/common.h | 11 - net/atm/ipcommon.h | 3 - net/atm/lec.h | 1 - net/atm/mpoa_proc.c | 2 +- net/ax25/af_ax25.c | 9 +- net/ax25/ax25_in.c | 1 - net/bluetooth/bnep/core.c | 2 +- net/bluetooth/l2cap.c | 19 +- net/bridge/br_input.c | 62 +- net/bridge/br_netfilter.c | 447 +- net/bridge/br_notify.c | 4 +- net/bridge/br_private.h | 2 +- net/bridge/netfilter/ebt_802_3.c | 2 +- net/bridge/netfilter/ebt_among.c | 61 +- net/bridge/netfilter/ebt_arp.c | 55 +- net/bridge/netfilter/ebt_arpreply.c | 34 +- net/bridge/netfilter/ebt_dnat.c | 3 +- net/bridge/netfilter/ebt_ip.c | 33 +- net/bridge/netfilter/ebt_log.c | 66 +- net/bridge/netfilter/ebt_redirect.c | 7 +- net/bridge/netfilter/ebt_snat.c | 3 +- net/bridge/netfilter/ebt_stp.c | 22 +- net/bridge/netfilter/ebt_vlan.c | 16 +- net/bridge/netfilter/ebtables.c | 2 +- net/compat.c | 6 +- net/core/Makefile | 2 +- net/core/dev.c | 139 +- net/core/dv.c | 7 +- net/core/filter.c | 21 +- net/core/gen_estimator.c | 204 + net/core/gen_stats.c | 132 + net/core/neighbour.c | 886 ++- net/core/net-sysfs.c | 1 - net/core/netfilter.c | 14 +- net/core/netpoll.c | 84 +- net/core/pktgen.c | 116 +- net/core/rtnetlink.c | 157 +- net/core/skbuff.c | 2 + net/core/sock.c | 21 + net/core/utils.c | 112 +- net/decnet/dn_dev.c | 125 +- net/decnet/dn_neigh.c | 225 +- net/decnet/dn_route.c | 43 +- net/econet/af_econet.c | 10 +- net/ethernet/eth.c | 6 +- net/ipv4/Kconfig | 40 +- net/ipv4/Makefile | 4 +- net/ipv4/af_inet.c | 113 +- net/ipv4/ah4.c | 17 +- net/ipv4/arp.c | 249 +- net/ipv4/devinet.c | 111 +- net/ipv4/esp4.c | 55 +- net/ipv4/fib_frontend.c | 4 +- net/ipv4/fib_hash.c | 841 +-- net/ipv4/fib_lookup.h | 34 + net/ipv4/fib_rules.c | 25 +- net/ipv4/fib_semantics.c | 407 +- net/ipv4/icmp.c | 48 +- net/ipv4/igmp.c | 92 +- net/ipv4/ip_fragment.c | 52 +- net/ipv4/ip_gre.c | 33 +- net/ipv4/ip_input.c | 3 +- net/ipv4/ip_output.c | 108 +- net/ipv4/ipcomp.c | 221 +- net/ipv4/ipconfig.c | 5 + net/ipv4/ipip.c | 14 +- net/ipv4/ipvs/ip_vs_core.c | 118 +- net/ipv4/ipvs/ip_vs_proto.c | 42 +- net/ipv4/ipvs/ip_vs_proto_ah.c | 9 +- net/ipv4/ipvs/ip_vs_proto_esp.c | 9 +- net/ipv4/ipvs/ip_vs_proto_icmp.c | 35 +- net/ipv4/ipvs/ip_vs_proto_tcp.c | 44 +- net/ipv4/ipvs/ip_vs_proto_udp.c | 42 +- net/ipv4/ipvs/ip_vs_sync.c | 28 +- net/ipv4/ipvs/ip_vs_xmit.c | 30 +- net/ipv4/netfilter/Kconfig | 239 +- net/ipv4/netfilter/Makefile | 11 +- net/ipv4/netfilter/arp_tables.c | 19 +- net/ipv4/netfilter/ip_conntrack_amanda.c | 17 +- net/ipv4/netfilter/ip_conntrack_core.c | 417 +- net/ipv4/netfilter/ip_conntrack_ftp.c | 46 +- net/ipv4/netfilter/ip_conntrack_irc.c | 47 +- .../netfilter/ip_conntrack_proto_generic.c | 28 +- net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 187 +- net/ipv4/netfilter/ip_conntrack_proto_sctp.c | 656 ++ net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 1055 ++- net/ipv4/netfilter/ip_conntrack_proto_udp.c | 96 +- net/ipv4/netfilter/ip_conntrack_standalone.c | 486 +- net/ipv4/netfilter/ip_conntrack_tftp.c | 20 +- net/ipv4/netfilter/ip_fw_compat_masq.c | 11 +- net/ipv4/netfilter/ip_nat_core.c | 131 +- net/ipv4/netfilter/ip_nat_ftp.c | 52 +- net/ipv4/netfilter/ip_nat_helper.c | 30 +- net/ipv4/netfilter/ip_nat_irc.c | 45 +- net/ipv4/netfilter/ip_nat_proto_icmp.c | 2 +- net/ipv4/netfilter/ip_nat_proto_tcp.c | 2 +- net/ipv4/netfilter/ip_nat_proto_udp.c | 2 +- net/ipv4/netfilter/ip_nat_proto_unknown.c | 4 +- net/ipv4/netfilter/ip_nat_rule.c | 3 +- net/ipv4/netfilter/ip_nat_snmp_basic.c | 6 +- net/ipv4/netfilter/ip_nat_standalone.c | 27 +- net/ipv4/netfilter/ip_nat_tftp.c | 35 +- net/ipv4/netfilter/ip_queue.c | 2 + net/ipv4/netfilter/ip_tables.c | 58 +- net/ipv4/netfilter/ipchains_core.c | 44 +- net/ipv4/netfilter/ipfwadm_core.c | 44 +- net/ipv4/netfilter/ipt_ECN.c | 29 +- net/ipv4/netfilter/ipt_LOG.c | 170 +- net/ipv4/netfilter/ipt_MASQUERADE.c | 4 +- net/ipv4/netfilter/ipt_NOTRACK.c | 3 +- net/ipv4/netfilter/ipt_REJECT.c | 27 +- net/ipv4/netfilter/ipt_ULOG.c | 35 +- net/ipv4/netfilter/ipt_ah.c | 11 +- net/ipv4/netfilter/ipt_comment.c | 59 + net/ipv4/netfilter/ipt_conntrack.c | 2 +- net/ipv4/netfilter/ipt_ecn.c | 17 +- net/ipv4/netfilter/ipt_esp.c | 11 +- net/ipv4/netfilter/ipt_helper.c | 1 + net/ipv4/netfilter/ipt_mac.c | 2 +- net/ipv4/netfilter/ipt_multiport.c | 19 +- net/ipv4/netfilter/ipt_recent.c | 11 +- net/ipv4/netfilter/ipt_sctp.c | 203 + net/ipv4/netfilter/ipt_state.c | 4 +- net/ipv4/netfilter/ipt_tcpmss.c | 30 +- net/ipv4/netfilter/iptable_filter.c | 3 +- net/ipv4/proc.c | 2 +- net/ipv4/raw.c | 49 + net/ipv4/route.c | 164 +- net/ipv4/sysctl_net_ipv4.c | 12 +- net/ipv4/tcp.c | 14 +- net/ipv4/tcp_diag.c | 77 +- net/ipv4/tcp_input.c | 407 +- net/ipv4/tcp_ipv4.c | 18 +- net/ipv4/tcp_minisocks.c | 15 +- net/ipv4/tcp_output.c | 316 +- net/ipv4/tcp_timer.c | 8 +- net/ipv4/udp.c | 1 + net/ipv4/xfrm4_input.c | 5 +- net/ipv4/xfrm4_output.c | 6 +- net/ipv4/xfrm4_policy.c | 21 +- net/ipv4/xfrm4_tunnel.c | 14 +- net/ipv6/Kconfig | 13 + net/ipv6/Makefile | 3 +- net/ipv6/addrconf.c | 168 +- net/ipv6/af_inet6.c | 156 +- net/ipv6/ah6.c | 29 +- net/ipv6/anycast.c | 63 +- net/ipv6/datagram.c | 13 +- net/ipv6/esp6.c | 52 +- net/ipv6/exthdrs.c | 3 + net/ipv6/exthdrs_core.c | 27 +- net/ipv6/icmp.c | 25 +- net/ipv6/ip6_fib.c | 29 +- net/ipv6/ip6_flowlabel.c | 3 +- net/ipv6/ip6_input.c | 3 +- net/ipv6/ip6_output.c | 94 +- net/ipv6/ip6_tunnel.c | 18 + net/ipv6/ipcomp6.c | 229 +- net/ipv6/mcast.c | 17 +- net/ipv6/ndisc.c | 91 +- net/ipv6/netfilter/Kconfig | 9 + net/ipv6/netfilter/Makefile | 1 + net/ipv6/netfilter/ip6_tables.c | 1 + net/ipv6/netfilter/ip6t_LOG.c | 7 +- net/ipv6/netfilter/ip6t_eui64.c | 6 +- net/ipv6/netfilter/ip6t_mac.c | 2 +- net/ipv6/netfilter/ip6t_physdev.c | 136 + net/ipv6/netfilter/ip6table_filter.c | 3 +- net/ipv6/raw.c | 60 +- net/ipv6/reassembly.c | 39 +- net/ipv6/route.c | 184 +- net/ipv6/sit.c | 16 +- net/ipv6/tcp_ipv6.c | 84 +- net/ipv6/udp.c | 12 +- net/ipv6/xfrm6_input.c | 21 +- net/ipv6/xfrm6_output.c | 14 +- net/ipv6/xfrm6_policy.c | 26 +- net/ipv6/xfrm6_tunnel.c | 72 +- net/ipx/af_ipx.c | 2 + net/irda/irlan/irlan_common.c | 5 +- net/irda/irlan/irlan_eth.c | 10 +- net/irda/irqueue.c | 8 +- net/key/af_key.c | 24 +- net/llc/af_llc.c | 1 - net/llc/llc_input.c | 2 +- net/llc/llc_output.c | 7 +- net/netlink/af_netlink.c | 22 +- net/netrom/af_netrom.c | 2 - net/packet/af_packet.c | 37 +- net/rose/af_rose.c | 2 - net/rxrpc/call.c | 65 +- net/rxrpc/connection.c | 37 +- net/rxrpc/main.c | 2 +- net/rxrpc/peer.c | 4 +- net/rxrpc/transport.c | 12 +- net/sched/Kconfig | 18 +- net/sched/Makefile | 5 +- net/sched/act_api.c | 10 +- net/sched/cls_api.c | 16 +- net/sched/cls_fw.c | 2 +- net/sched/cls_u32.c | 7 +- net/sched/estimator.c | 10 +- net/sched/gact.c | 265 + net/sched/sch_api.c | 46 +- net/sched/sch_atm.c | 2 +- net/sched/sch_cbq.c | 21 +- net/sched/sch_dsmark.c | 2 - net/sched/sch_generic.c | 73 +- net/sched/sch_hfsc.c | 315 +- net/sched/sch_htb.c | 1 - net/sched/sch_ingress.c | 14 +- net/sched/sch_netem.c | 810 +-- net/sched/sch_red.c | 8 +- net/sched/sch_sfq.c | 1 - net/sched/sch_teql.c | 3 +- net/sctp/ipv6.c | 24 +- net/sctp/protocol.c | 36 +- net/sctp/socket.c | 26 +- net/sunrpc/auth_gss/Makefile | 4 + net/sunrpc/auth_gss/auth_gss.c | 4 +- net/sunrpc/auth_gss/gss_generic_token.c | 2 +- net/sunrpc/auth_gss/gss_krb5_unseal.c | 2 +- net/sunrpc/auth_gss/gss_spkm3_mech.c | 296 + net/sunrpc/auth_gss/gss_spkm3_seal.c | 132 + net/sunrpc/auth_gss/gss_spkm3_token.c | 266 + net/sunrpc/auth_gss/gss_spkm3_unseal.c | 128 + net/sunrpc/auth_gss/svcauth_gss.c | 2 - net/sunrpc/cache.c | 5 +- net/sunrpc/clnt.c | 41 +- net/sunrpc/sched.c | 4 +- net/sunrpc/sunrpc_syms.c | 1 + net/sunrpc/svc.c | 9 +- net/sunrpc/svcauth.c | 62 +- net/sunrpc/svcauth_unix.c | 32 +- net/sunrpc/xprt.c | 8 +- net/unix/af_unix.c | 2 +- net/wanrouter/af_wanpipe.c | 1 - net/x25/af_x25.c | 2 - net/xfrm/xfrm_export.c | 2 - net/xfrm/xfrm_policy.c | 26 +- net/xfrm/xfrm_state.c | 36 +- net/xfrm/xfrm_user.c | 56 +- scripts/Makefile | 17 +- scripts/Makefile.build | 121 +- scripts/Makefile.clean | 44 +- scripts/Makefile.host | 155 + scripts/Makefile.lib | 52 +- scripts/Makefile.modinst | 2 +- scripts/Makefile.modpost | 5 +- scripts/basic/Makefile | 4 +- scripts/basic/fixdep.c | 11 +- scripts/binoffset.c | 12 +- scripts/genksyms/Makefile | 4 +- scripts/genksyms/genksyms.c | 15 + scripts/kconfig/Makefile | 2 +- scripts/kconfig/confdata.c | 17 +- scripts/kconfig/gconf.c | 5 +- scripts/kconfig/lkc.h | 3 - scripts/kconfig/mconf.c | 161 +- scripts/kconfig/menu.c | 1 - scripts/kconfig/zconf.tab.c_shipped | 2 + scripts/kconfig/zconf.y | 2 + scripts/lxdialog/Makefile | 4 +- scripts/lxdialog/menubox.c | 9 + scripts/mksysmap | 44 + scripts/mod/Makefile | 4 +- scripts/mod/modpost.c | 36 +- scripts/mod/modpost.h | 2 + scripts/mod/sumversion.c | 4 + scripts/namespace.pl | 449 ++ scripts/package/Makefile | 6 +- scripts/package/builddeb | 2 +- scripts/package/mkspec | 20 +- scripts/patch-kernel | 113 +- scripts/ver_linux | 7 +- security/Kconfig | 4 +- security/commoncap.c | 9 +- security/dummy.c | 4 +- security/security.c | 4 +- security/selinux/Kconfig | 15 + security/selinux/hooks.c | 211 +- security/selinux/include/avc.h | 1 - security/selinux/selinuxfs.c | 266 +- security/selinux/ss/avtab.c | 12 +- security/selinux/ss/avtab.h | 2 + security/selinux/ss/policydb.h | 1 - security/selinux/ss/services.c | 1 + sound/arm/sa11xx-uda1341.c | 19 +- sound/core/control.c | 51 +- sound/core/device.c | 4 +- sound/core/hwdep.c | 40 +- sound/core/info.c | 63 +- sound/core/info_oss.c | 12 - sound/core/init.c | 4 +- sound/core/ioctl32/ioctl32.c | 2 +- sound/core/ioctl32/pcm32.c | 55 +- sound/core/memalloc.c | 412 +- sound/core/memory.c | 76 +- sound/core/oss/mixer_oss.c | 53 +- sound/core/oss/pcm_oss.c | 50 +- sound/core/oss/pcm_plugin.c | 133 +- sound/core/oss/pcm_plugin.h | 2 +- sound/core/oss/route.c | 2 +- sound/core/pcm.c | 23 +- sound/core/pcm_lib.c | 78 +- sound/core/pcm_memory.c | 122 +- sound/core/pcm_misc.c | 708 +- sound/core/pcm_native.c | 390 +- sound/core/pcm_timer.c | 13 +- sound/core/rawmidi.c | 62 +- sound/core/seq/Makefile | 58 +- sound/core/seq/instr/Makefile | 34 +- sound/core/seq/instr/ainstr_fm.c | 2 - sound/core/seq/instr/ainstr_gf1.c | 4 +- sound/core/seq/instr/ainstr_iw.c | 8 +- sound/core/seq/instr/ainstr_simple.c | 2 - sound/core/seq/oss/seq_oss.c | 9 +- sound/core/seq/oss/seq_oss_init.c | 4 +- sound/core/seq/oss/seq_oss_ioctl.c | 74 +- sound/core/seq/oss/seq_oss_midi.c | 2 +- sound/core/seq/oss/seq_oss_readq.c | 49 +- sound/core/seq/oss/seq_oss_readq.h | 9 +- sound/core/seq/oss/seq_oss_rw.c | 116 +- sound/core/seq/oss/seq_oss_synth.c | 8 +- sound/core/seq/oss/seq_oss_timer.c | 4 +- sound/core/seq/oss/seq_oss_writeq.c | 2 +- sound/core/seq/seq.c | 3 +- sound/core/seq/seq_clientmgr.c | 80 +- sound/core/seq/seq_device.c | 14 +- sound/core/seq/seq_dummy.c | 23 +- sound/core/seq/seq_fifo.c | 2 +- sound/core/seq/seq_instr.c | 11 +- sound/core/seq/seq_memory.c | 6 +- sound/core/seq/seq_midi.c | 6 +- sound/core/seq/seq_midi_emul.c | 2 - sound/core/seq/seq_midi_event.c | 2 +- sound/core/seq/seq_ports.c | 4 +- sound/core/seq/seq_prioq.c | 2 +- sound/core/seq/seq_queue.c | 2 +- sound/core/seq/seq_timer.c | 2 +- sound/core/seq/seq_virmidi.c | 46 +- sound/core/sgbuf.c | 11 +- sound/core/sound.c | 42 +- sound/core/timer.c | 67 +- sound/drivers/dummy.c | 102 +- sound/drivers/mpu401/mpu401.c | 21 +- sound/drivers/mpu401/mpu401_uart.c | 22 +- sound/drivers/mtpav.c | 16 +- sound/drivers/opl3/opl3_lib.c | 10 +- sound/drivers/opl3/opl3_midi.c | 14 +- sound/drivers/opl3/opl3_oss.c | 16 +- sound/drivers/opl3/opl3_seq.c | 9 +- sound/drivers/opl3/opl3_synth.c | 6 +- sound/drivers/opl4/Makefile | 2 +- sound/drivers/opl4/opl4_lib.c | 59 +- sound/drivers/opl4/opl4_local.h | 1 - sound/drivers/opl4/opl4_mixer.c | 12 +- sound/drivers/opl4/opl4_proc.c | 8 +- sound/drivers/opl4/opl4_seq.c | 10 +- sound/drivers/opl4/opl4_synth.c | 35 +- sound/drivers/serial-u16550.c | 34 +- sound/drivers/virmidi.c | 9 +- sound/drivers/vx/vx_core.c | 11 +- sound/drivers/vx/vx_hwdep.c | 4 +- sound/drivers/vx/vx_mixer.c | 53 +- sound/drivers/vx/vx_pcm.c | 37 +- sound/drivers/vx/vx_uer.c | 15 +- sound/i2c/cs8427.c | 26 +- sound/i2c/i2c.c | 10 +- sound/i2c/l3/uda1341.c | 24 +- sound/i2c/other/ak4117.c | 10 +- sound/i2c/other/ak4xxx-adda.c | 12 +- sound/i2c/tea6330t.c | 14 +- sound/isa/Kconfig | 8 + sound/isa/ad1816a/ad1816a.c | 15 +- sound/isa/ad1816a/ad1816a_lib.c | 18 +- sound/isa/ad1848/ad1848.c | 12 +- sound/isa/ad1848/ad1848_lib.c | 16 +- sound/isa/als100.c | 15 +- sound/isa/azt2320.c | 16 +- sound/isa/cmi8330.c | 18 +- sound/isa/cs423x/cs4231.c | 14 +- sound/isa/cs423x/cs4231_lib.c | 22 +- sound/isa/cs423x/cs4236.c | 20 +- sound/isa/cs423x/cs4236_lib.c | 26 +- sound/isa/dt019x.c | 14 +- sound/isa/es1688/es1688.c | 11 +- sound/isa/es1688/es1688_lib.c | 15 +- sound/isa/es18xx.c | 31 +- sound/isa/gus/Makefile | 6 +- sound/isa/gus/gus_dram.c | 10 +- sound/isa/gus/gus_instr.c | 18 +- sound/isa/gus/gus_irq.c | 4 +- sound/isa/gus/gus_main.c | 10 +- sound/isa/gus/gus_mem.c | 2 +- sound/isa/gus/gus_mem_proc.c | 12 +- sound/isa/gus/gus_mixer.c | 10 +- sound/isa/gus/gus_pcm.c | 38 +- sound/isa/gus/gus_synth.c | 2 +- sound/isa/gus/gus_timer.c | 6 +- sound/isa/gus/gus_uart.c | 12 +- sound/isa/gus/gusclassic.c | 13 +- sound/isa/gus/gusextreme.c | 17 +- sound/isa/gus/gusmax.c | 13 +- sound/isa/gus/interwave.c | 60 +- sound/isa/opl3sa2.c | 39 +- sound/isa/opti9xx/opti92x-ad1848.c | 57 +- sound/isa/sb/emu8000.c | 18 +- sound/isa/sb/emu8000_callback.c | 20 +- sound/isa/sb/emu8000_local.h | 2 - sound/isa/sb/emu8000_patch.c | 2 +- sound/isa/sb/emu8000_pcm.c | 4 +- sound/isa/sb/emu8000_synth.c | 1 - sound/isa/sb/es968.c | 13 +- sound/isa/sb/sb16.c | 21 +- sound/isa/sb/sb16_csp.c | 17 +- sound/isa/sb/sb16_main.c | 18 +- sound/isa/sb/sb8.c | 13 +- sound/isa/sb/sb8_main.c | 2 - sound/isa/sb/sb8_midi.c | 16 +- sound/isa/sb/sb_common.c | 9 +- sound/isa/sb/sb_mixer.c | 2 - sound/isa/sgalaxy.c | 9 +- sound/isa/sscape.c | 24 +- sound/isa/wavefront/wavefront.c | 19 +- sound/isa/wavefront/wavefront_fx.c | 54 +- sound/isa/wavefront/wavefront_synth.c | 6 + sound/oss/Kconfig | 11 +- sound/oss/Makefile | 2 +- sound/oss/ad1848.c | 56 +- sound/oss/ad1848.h | 8 +- sound/oss/ad1889.c | 79 +- sound/oss/ad1889.h | 6 +- sound/oss/ali5455.c | 1 - sound/oss/au1000.c | 2 +- sound/oss/awe_wave.c | 4 +- sound/oss/btaudio.c | 4 +- sound/oss/cmpci.c | 83 +- sound/oss/cs4232.c | 46 +- sound/oss/cs4232.h | 2 - sound/oss/cs46xx.c | 13 +- sound/oss/dmasound/Kconfig | 2 +- sound/oss/emu10k1/midi.c | 3 +- sound/oss/forte.c | 1 - sound/oss/gus_card.c | 24 +- sound/oss/gus_wave.c | 14 +- sound/oss/harmony.c | 138 +- sound/oss/i810_audio.c | 13 +- sound/oss/ite8172.c | 2 +- sound/oss/kahlua.c | 4 + sound/oss/mad16.c | 220 +- sound/oss/maui.c | 63 +- sound/oss/mpu401.c | 26 +- sound/oss/mpu401.h | 2 +- sound/oss/msnd.c | 28 +- sound/oss/msnd.h | 9 +- sound/oss/msnd_pinnacle.c | 42 +- sound/oss/nec_vrc5477.c | 1 - sound/oss/opl3sa.c | 59 +- sound/oss/opl3sa2.c | 59 +- sound/oss/pss.c | 142 +- sound/oss/rme96xx.c | 2 +- sound/oss/sb_card.c | 9 +- sound/oss/sb_common.c | 24 +- sound/oss/sgalaxy.c | 42 +- sound/oss/sscape.c | 215 +- sound/oss/swarm_cs4297a.c | 2 +- sound/oss/trident.c | 1 - sound/oss/trix.c | 221 +- sound/oss/v_midi.c | 5 +- sound/oss/waveartist.c | 6 +- sound/oss/wavfront.c | 6 +- sound/oss/wf_midi.c | 5 +- sound/parisc/harmony.c | 75 +- sound/pci/Kconfig | 14 +- sound/pci/Makefile | 2 + sound/pci/ac97/ac97_codec.c | 417 +- sound/pci/ac97/ac97_id.h | 7 + sound/pci/ac97/ac97_local.h | 14 +- sound/pci/ac97/ac97_patch.c | 257 +- sound/pci/ac97/ac97_patch.h | 1 + sound/pci/ac97/ac97_pcm.c | 9 +- sound/pci/ac97/ac97_proc.c | 18 +- sound/pci/ac97/ak4531_codec.c | 26 +- sound/pci/ali5451/ali5451.c | 78 +- sound/pci/als4000.c | 64 +- sound/pci/atiixp.c | 127 +- sound/pci/atiixp_modem.c | 1351 ++++ sound/pci/au88x0/au88x0.c | 16 +- sound/pci/au88x0/au88x0.h | 2 - sound/pci/au88x0/au88x0_a3d.c | 14 +- sound/pci/au88x0/au88x0_core.c | 2 +- sound/pci/au88x0/au88x0_eq.c | 160 +- sound/pci/au88x0/au88x0_game.c | 2 +- sound/pci/au88x0/au88x0_mixer.c | 13 +- sound/pci/au88x0/au88x0_mpu401.c | 2 +- sound/pci/au88x0/au88x0_pcm.c | 7 +- sound/pci/au88x0/au88x0_xtalk.c | 6 + sound/pci/au88x0/au88x0_xtalk.h | 3 +- sound/pci/azt3328.c | 115 +- sound/pci/bt87x.c | 96 +- sound/pci/cmipci.c | 223 +- sound/pci/cs4281.c | 151 +- sound/pci/cs46xx/cs46xx.c | 9 +- sound/pci/cs46xx/cs46xx_lib.c | 346 +- sound/pci/cs46xx/cs46xx_lib.h | 2 - sound/pci/cs46xx/dsp_spos.c | 41 +- sound/pci/cs46xx/dsp_spos_scb_lib.c | 2 +- sound/pci/emu10k1/emu10k1.c | 19 +- sound/pci/emu10k1/emu10k1_callback.c | 16 +- sound/pci/emu10k1/emu10k1_main.c | 57 +- sound/pci/emu10k1/emu10k1_patch.c | 4 +- sound/pci/emu10k1/emu10k1_synth.c | 4 +- sound/pci/emu10k1/emufx.c | 374 +- sound/pci/emu10k1/emumixer.c | 21 +- sound/pci/emu10k1/emupcm.c | 321 +- sound/pci/emu10k1/emuproc.c | 126 +- sound/pci/emu10k1/io.c | 4 +- sound/pci/emu10k1/irq.c | 2 +- sound/pci/emu10k1/memory.c | 14 +- sound/pci/ens1370.c | 140 +- sound/pci/es1938.c | 224 +- sound/pci/es1968.c | 208 +- sound/pci/fm801.c | 79 +- sound/pci/ice1712/Makefile | 2 +- sound/pci/ice1712/ak4xxx.c | 1 - sound/pci/ice1712/aureon.c | 307 +- sound/pci/ice1712/delta.c | 4 +- sound/pci/ice1712/ews.c | 26 +- sound/pci/ice1712/ews.h | 4 +- sound/pci/ice1712/ice1712.c | 125 +- sound/pci/ice1712/ice1712.h | 6 - sound/pci/ice1712/ice1724.c | 381 +- sound/pci/ice1712/pontis.c | 849 +++ sound/pci/ice1712/pontis.h | 33 + sound/pci/ice1712/revo.c | 4 +- sound/pci/ice1712/vt1720_mobo.c | 106 + sound/pci/ice1712/vt1720_mobo.h | 37 + sound/pci/intel8x0.c | 330 +- sound/pci/intel8x0m.c | 187 +- sound/pci/korg1212/korg1212.c | 202 +- sound/pci/maestro3.c | 97 +- sound/pci/mixart/mixart.c | 126 +- sound/pci/mixart/mixart.h | 1 - sound/pci/mixart/mixart_core.c | 4 +- sound/pci/mixart/mixart_hwdep.c | 4 +- sound/pci/mixart/mixart_mixer.c | 2 - sound/pci/nm256/nm256.c | 97 +- sound/pci/rme32.c | 844 +-- sound/pci/rme96.c | 375 +- sound/pci/rme9652/hdsp.c | 481 +- sound/pci/rme9652/rme9652.c | 311 +- sound/pci/sonicvibes.c | 130 +- sound/pci/trident/trident.c | 8 +- sound/pci/trident/trident_main.c | 165 +- sound/pci/trident/trident_memory.c | 14 +- sound/pci/trident/trident_synth.c | 33 +- sound/pci/via82xx.c | 206 +- sound/pci/vx222/vx222.c | 42 +- sound/pci/vx222/vx222.h | 2 +- sound/pci/vx222/vx222_ops.c | 2 - sound/pci/ymfpci/ymfpci.c | 10 +- sound/pci/ymfpci/ymfpci_main.c | 186 +- sound/pcmcia/pdaudiocf/pdaudiocf.c | 16 +- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 12 +- sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | 4 +- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 4 +- sound/pcmcia/vx/vx_entry.c | 10 +- sound/pcmcia/vx/vxp_mixer.c | 2 - sound/pcmcia/vx/vxp_ops.c | 2 - sound/pcmcia/vx/vxpocket.c | 7 +- sound/ppc/Kconfig | 5 +- sound/ppc/Makefile | 2 +- sound/ppc/awacs.c | 35 +- sound/ppc/beep.c | 262 + sound/ppc/burgundy.c | 6 +- sound/ppc/daca.c | 6 +- sound/ppc/pmac.c | 93 +- sound/ppc/pmac.h | 14 +- sound/ppc/powermac.c | 24 +- sound/ppc/tumbler.c | 71 +- sound/sparc/amd7930.c | 24 +- sound/sparc/cs4231.c | 49 +- sound/synth/emux/emux.c | 6 +- sound/synth/emux/emux_effect.c | 2 +- sound/synth/emux/emux_hwdep.c | 2 +- sound/synth/emux/emux_nrpn.c | 18 +- sound/synth/emux/emux_oss.c | 14 +- sound/synth/emux/emux_proc.c | 2 +- sound/synth/emux/emux_seq.c | 20 +- sound/synth/emux/emux_synth.c | 12 +- sound/synth/emux/soundfont.c | 60 +- sound/synth/util_mem.c | 2 +- sound/usb/Kconfig | 10 + sound/usb/Makefile | 8 +- sound/usb/usbaudio.c | 108 +- sound/usb/usbaudio.h | 7 +- sound/usb/usbmidi.c | 86 +- sound/usb/usbmixer.c | 62 +- sound/usb/usbmixer_maps.c | 2 +- sound/usb/usbquirks.h | 89 +- sound/usb/usx2y/Makefile | 3 + sound/usb/usx2y/usX2Yhwdep.c | 282 + sound/usb/usx2y/usX2Yhwdep.h | 6 + sound/usb/usx2y/usbus428ctldefs.h | 108 + sound/usb/usx2y/usbusx2y.c | 434 ++ sound/usb/usx2y/usbusx2y.h | 61 + sound/usb/usx2y/usbusx2yaudio.c | 1027 +++ sound/usb/usx2y/usx2y.h | 49 + usr/Makefile | 2 +- 4603 files changed, 254568 insertions(+), 101340 deletions(-) create mode 100644 Documentation/ManagementStyle create mode 100644 Documentation/RCU/RTFP.txt create mode 100644 Documentation/RCU/UP.txt create mode 100644 Documentation/RCU/arrayRCU.txt create mode 100644 Documentation/RCU/checklist.txt create mode 100644 Documentation/RCU/listRCU.txt create mode 100644 Documentation/RCU/rcu.txt create mode 100644 Documentation/arm/IXP2000 create mode 100644 Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt create mode 100644 Documentation/arm/Samsung-S3C24XX/GPIO.txt create mode 100644 Documentation/arm/Samsung-S3C24XX/Overview.txt create mode 100644 Documentation/i2o/README create mode 100644 Documentation/i2o/ioctl create mode 100644 Documentation/networking/gen_stats.txt create mode 100644 Documentation/sched-stats.txt create mode 100644 Documentation/scsi/megaraid.txt create mode 100644 Documentation/time_interpolators.txt create mode 100644 Documentation/tty.txt create mode 100644 arch/alpha/Kconfig.debug create mode 100644 arch/alpha/kernel/io.c create mode 100644 arch/arm/Kconfig.debug create mode 100644 arch/arm/boot/compressed/big-endian.S create mode 100644 arch/arm/configs/enp2611_defconfig create mode 100644 arch/arm/configs/ep80219_defconfig create mode 100644 arch/arm/configs/h7201_defconfig create mode 100644 arch/arm/configs/h7202_defconfig create mode 100644 arch/arm/configs/iq31244_defconfig create mode 100644 arch/arm/configs/iq80331_defconfig create mode 100644 arch/arm/configs/ixdp2400_defconfig create mode 100644 arch/arm/configs/ixdp2401_defconfig create mode 100644 arch/arm/configs/ixdp2800_defconfig create mode 100644 arch/arm/configs/ixdp2801_defconfig create mode 100644 arch/arm/configs/mx1ads_defconfig create mode 100644 arch/arm/kernel/iwmmxt.S create mode 100644 arch/arm/mach-h720x/Kconfig create mode 100644 arch/arm/mach-h720x/Makefile create mode 100644 arch/arm/mach-h720x/common.c create mode 100644 arch/arm/mach-h720x/cpu-h7201.c create mode 100644 arch/arm/mach-h720x/cpu-h7202.c create mode 100644 arch/arm/mach-h720x/h7201-eval.c create mode 100644 arch/arm/mach-h720x/h7202-eval.c create mode 100644 arch/arm/mach-imx/Kconfig create mode 100644 arch/arm/mach-imx/Makefile create mode 100644 arch/arm/mach-imx/dma.c create mode 100644 arch/arm/mach-imx/generic.c create mode 100644 arch/arm/mach-imx/generic.h create mode 100644 arch/arm/mach-imx/irq.c create mode 100644 arch/arm/mach-imx/leds-mx1ads.c create mode 100644 arch/arm/mach-imx/leds.c create mode 100644 arch/arm/mach-imx/leds.h create mode 100644 arch/arm/mach-imx/mx1ads.c create mode 100644 arch/arm/mach-imx/time.c create mode 100644 arch/arm/mach-iop3xx/common.c create mode 100644 arch/arm/mach-iop3xx/iop321-mm.c create mode 100644 arch/arm/mach-iop3xx/iop321-setup.c create mode 100644 arch/arm/mach-iop3xx/iop331-irq.c create mode 100644 arch/arm/mach-iop3xx/iop331-mm.c create mode 100644 arch/arm/mach-iop3xx/iop331-pci.c create mode 100644 arch/arm/mach-iop3xx/iop331-setup.c create mode 100644 arch/arm/mach-iop3xx/iop331-time.c create mode 100644 arch/arm/mach-iop3xx/iq31244-mm.c create mode 100644 arch/arm/mach-iop3xx/iq31244-pci.c create mode 100644 arch/arm/mach-iop3xx/iq80321-mm.c create mode 100644 arch/arm/mach-iop3xx/iq80331-mm.c create mode 100644 arch/arm/mach-iop3xx/iq80331-pci.c create mode 100644 arch/arm/mach-ixp2000/Kconfig create mode 100644 arch/arm/mach-ixp2000/Makefile create mode 100644 arch/arm/mach-ixp2000/core.c create mode 100644 arch/arm/mach-ixp2000/enp2611.c create mode 100644 arch/arm/mach-ixp2000/ixdp2400.c create mode 100644 arch/arm/mach-ixp2000/ixdp2800.c create mode 100644 arch/arm/mach-ixp2000/ixdp2x00.c create mode 100644 arch/arm/mach-ixp2000/ixdp2x01.c create mode 100644 arch/arm/mach-ixp2000/pci.c create mode 100644 arch/arm/mach-omap/board-h2.c create mode 100644 arch/arm/mach-omap/board-h3.c create mode 100644 arch/arm/mach-omap/leds-h2p2-debug.c create mode 100644 arch/arm/mach-omap/mcbsp.c create mode 100644 arch/arm/mach-omap/usb.c create mode 100644 arch/arm/mach-s3c2410/clock.c create mode 100644 arch/arm/mach-s3c2410/clock.h create mode 100644 arch/arm/mach-s3c2410/cpu.c create mode 100644 arch/arm/mach-s3c2410/cpu.h create mode 100644 arch/arm/mach-s3c2410/devs.c create mode 100644 arch/arm/mach-s3c2410/devs.h create mode 100644 arch/arm/mach-s3c2410/dma.c create mode 100644 arch/arm/mach-s3c2410/s3c2440-dsc.c create mode 100644 arch/arm/mach-s3c2410/s3c2440.c create mode 100644 arch/arm/mach-s3c2410/s3c2440.h create mode 100644 arch/arm/mach-s3c2410/usb-simtec.c create mode 100644 arch/arm/mach-s3c2410/usb-simtec.h create mode 100644 arch/arm/mm/flush.c create mode 100644 arch/arm26/Kconfig.debug create mode 100644 arch/cris/Kconfig.debug create mode 100644 arch/h8300/Kconfig.debug create mode 100644 arch/i386/Kconfig.debug create mode 100644 arch/i386/kernel/kprobes.c create mode 100644 arch/i386/kernel/vsyscall.lds.S create mode 100644 arch/ia64/Kconfig.debug create mode 100644 arch/ia64/configs/bigsur_defconfig create mode 100644 arch/ia64/configs/tiger_defconfig create mode 100644 arch/ia64/kernel/mca_drv.c create mode 100644 arch/ia64/kernel/mca_drv.h create mode 100644 arch/ia64/kernel/mca_drv_asm.S create mode 100644 arch/ia64/oprofile/perfmon.c create mode 100644 arch/ia64/sn/kernel/sn2/sn_hwperf.c create mode 100644 arch/m32r/Kconfig create mode 100644 arch/m32r/Makefile create mode 100644 arch/m32r/boot/Makefile create mode 100644 arch/m32r/boot/compressed/Makefile create mode 100644 arch/m32r/boot/compressed/boot.h create mode 100644 arch/m32r/boot/compressed/head.S create mode 100644 arch/m32r/boot/compressed/install.sh create mode 100644 arch/m32r/boot/compressed/m32r_sio.c create mode 100644 arch/m32r/boot/compressed/misc.c create mode 100644 arch/m32r/boot/compressed/vmlinux.lds.S create mode 100644 arch/m32r/boot/compressed/vmlinux.scr create mode 100644 arch/m32r/boot/setup.S create mode 100644 arch/m32r/defconfig create mode 100644 arch/m32r/kernel/Makefile create mode 100644 arch/m32r/kernel/align.c create mode 100644 arch/m32r/kernel/entry.S create mode 100644 arch/m32r/kernel/head.S create mode 100644 arch/m32r/kernel/init_task.c create mode 100644 arch/m32r/kernel/io_m32700ut.c create mode 100644 arch/m32r/kernel/io_mappi.c create mode 100644 arch/m32r/kernel/io_mappi2.c create mode 100644 arch/m32r/kernel/io_oaks32r.c create mode 100644 arch/m32r/kernel/io_opsput.c create mode 100644 arch/m32r/kernel/io_usrv.c create mode 100644 arch/m32r/kernel/irq.c create mode 100644 arch/m32r/kernel/m32r_ksyms.c create mode 100644 arch/m32r/kernel/module.c create mode 100644 arch/m32r/kernel/process.c create mode 100644 arch/m32r/kernel/ptrace.c create mode 100644 arch/m32r/kernel/semaphore.c create mode 100644 arch/m32r/kernel/setup.c create mode 100644 arch/m32r/kernel/setup_m32700ut.c create mode 100644 arch/m32r/kernel/setup_mappi.c create mode 100644 arch/m32r/kernel/setup_mappi2.c create mode 100644 arch/m32r/kernel/setup_oaks32r.c create mode 100644 arch/m32r/kernel/setup_opsput.c create mode 100644 arch/m32r/kernel/setup_usrv.c create mode 100644 arch/m32r/kernel/signal.c create mode 100644 arch/m32r/kernel/smp.c create mode 100644 arch/m32r/kernel/smpboot.c create mode 100644 arch/m32r/kernel/sys_m32r.c create mode 100644 arch/m32r/kernel/time.c create mode 100644 arch/m32r/kernel/traps.c create mode 100644 arch/m32r/kernel/vmlinux.lds.S create mode 100644 arch/m32r/lib/Makefile create mode 100644 arch/m32r/lib/ashxdi3.S create mode 100644 arch/m32r/lib/checksum.S create mode 100644 arch/m32r/lib/csum_partial_copy.c create mode 100644 arch/m32r/lib/delay.c create mode 100644 arch/m32r/lib/getuser.S create mode 100644 arch/m32r/lib/memcpy.S create mode 100644 arch/m32r/lib/memset.S create mode 100644 arch/m32r/lib/putuser.S create mode 100644 arch/m32r/lib/strlen.S create mode 100644 arch/m32r/lib/usercopy.c create mode 100644 arch/m32r/m32700ut/defconfig.m32700ut.smp create mode 100644 arch/m32r/m32700ut/defconfig.m32700ut.up create mode 100644 arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB create mode 100644 arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB create mode 100644 arch/m32r/mappi/defconfig.nommu create mode 100644 arch/m32r/mappi/defconfig.smp create mode 100644 arch/m32r/mappi/defconfig.up create mode 100644 arch/m32r/mappi/dot.gdbinit create mode 100644 arch/m32r/mappi/dot.gdbinit.nommu create mode 100644 arch/m32r/mappi/dot.gdbinit.smp create mode 100644 arch/m32r/mm/Makefile create mode 100644 arch/m32r/mm/cache.c create mode 100644 arch/m32r/mm/discontig.c create mode 100644 arch/m32r/mm/extable.c create mode 100644 arch/m32r/mm/fault-nommu.c create mode 100644 arch/m32r/mm/fault.c create mode 100644 arch/m32r/mm/init.c create mode 100644 arch/m32r/mm/ioremap-nommu.c create mode 100644 arch/m32r/mm/ioremap.c create mode 100644 arch/m32r/mm/mmu.S create mode 100644 arch/m32r/mm/page.S create mode 100644 arch/m32r/oaks32r/defconfig.nommu create mode 100644 arch/m32r/oaks32r/dot.gdbinit.nommu create mode 100644 arch/m32r/oprofile/Kconfig create mode 100644 arch/m32r/oprofile/Makefile create mode 100644 arch/m32r/oprofile/init.c create mode 100644 arch/m32r/opsput/defconfig.opsput create mode 100644 arch/m32r/opsput/dot.gdbinit create mode 100644 arch/m68k/Kconfig.debug create mode 100644 arch/m68knommu/Kconfig.debug create mode 100644 arch/mips/Kconfig.debug create mode 100644 arch/parisc/Kconfig.debug create mode 100644 arch/ppc/Kconfig.debug create mode 100644 arch/ppc/boot/include/serial.h create mode 100644 arch/ppc/boot/simple/chrpmap.c create mode 100644 arch/ppc/boot/simple/pibs.c create mode 100644 arch/ppc/boot/simple/prepmap.c create mode 100644 arch/ppc/kernel/head_booke.h create mode 100644 arch/ppc/platforms/lopec.c create mode 100644 arch/ppc/platforms/lopec.h create mode 100644 arch/ppc/platforms/mvme5100.c create mode 100644 arch/ppc/platforms/pq2ads.c create mode 100644 arch/ppc/syslib/m8xx_wdt.c create mode 100644 arch/ppc/syslib/m8xx_wdt.h create mode 100644 arch/ppc64/Kconfig.debug create mode 100644 arch/ppc64/kernel/iomap.c create mode 100644 arch/ppc64/kernel/pSeries_setup.c create mode 100644 arch/ppc64/kernel/prom_init.c create mode 100644 arch/ppc64/kernel/u3_iommu.c create mode 100644 arch/ppc64/mm/hash_native.c create mode 100644 arch/ppc64/mm/stab.c create mode 100644 arch/s390/Kconfig.debug create mode 100644 arch/s390/kernel/irq.c create mode 100644 arch/sh/Kconfig.debug create mode 100644 arch/sh64/Kconfig.debug create mode 100644 arch/sparc/Kconfig.debug create mode 100644 arch/sparc64/Kconfig.debug create mode 100644 arch/sparc64/kernel/kprobes.c create mode 100644 arch/sparc64/lib/U1copy_from_user.S create mode 100644 arch/sparc64/lib/U1copy_to_user.S create mode 100644 arch/sparc64/lib/U1memcpy.S create mode 100644 arch/sparc64/lib/U3patch.S create mode 100644 arch/sparc64/lib/copy_in_user.S create mode 100644 arch/sparc64/lib/delay.c create mode 100644 arch/sparc64/lib/iomap.c create mode 100644 arch/sparc64/lib/memmove.S create mode 100644 arch/sparc64/lib/user_fixup.c create mode 100644 arch/um/Kconfig.debug create mode 100644 arch/um/drivers/cow_sys.h create mode 100644 arch/um/kernel/dyn.lds.S create mode 100644 arch/um/kernel/main.c create mode 100644 arch/um/kernel/uml.lds.S create mode 100644 arch/um/os-Linux/time.c create mode 100644 arch/v850/Kconfig.debug create mode 100644 arch/x86_64/Kconfig.debug create mode 100644 arch/x86_64/lib/bitops.c create mode 100644 arch/x86_64/pci/Makefile-BUS create mode 100644 arch/x86_64/pci/k8-bus.c create mode 100644 crypto/wp512.c create mode 100644 drivers/acpi/motherboard.c create mode 100644 drivers/acpi/sleep/wakeup.c create mode 100644 drivers/block/ub.c create mode 100644 drivers/char/drm/drm_core.h create mode 100644 drivers/char/drm/i915.h create mode 100644 drivers/char/drm/i915_dma.c create mode 100644 drivers/char/drm/i915_drm.h create mode 100644 drivers/char/drm/i915_drv.c create mode 100644 drivers/char/drm/i915_drv.h create mode 100644 drivers/char/drm/i915_irq.c create mode 100644 drivers/char/drm/i915_mem.c create mode 100644 drivers/char/hvsi.c create mode 100644 drivers/char/ipmi/ipmi_poweroff.c create mode 100644 drivers/char/mmtimer.c create mode 100644 drivers/char/snsc.c create mode 100644 drivers/char/snsc.h create mode 100644 drivers/char/watchdog/mpc8xx_wdt.c create mode 100644 drivers/cpufreq/cpufreq_ondemand.c create mode 100644 drivers/i2c/algos/i2c-algo-pca.c create mode 100644 drivers/i2c/algos/i2c-algo-pca.h create mode 100644 drivers/i2c/busses/i2c-ixp2000.c create mode 100644 drivers/i2c/busses/i2c-mpc.c create mode 100644 drivers/i2c/busses/i2c-pca-isa.c create mode 100644 drivers/i2c/chips/isp1301_omap.c create mode 100644 drivers/i2c/chips/smsc47m1.c create mode 100644 drivers/i2c/i2c-sensor-detect.c create mode 100644 drivers/i2c/i2c-sensor-vid.c create mode 100644 drivers/ide/arm/bast-ide.c create mode 100644 drivers/input/serio/serio_raw.c create mode 100644 drivers/md/raid10.c create mode 100644 drivers/message/i2o/debug.c create mode 100644 drivers/message/i2o/device.c create mode 100644 drivers/message/i2o/driver.c create mode 100644 drivers/message/i2o/exec-osm.c create mode 100644 drivers/message/i2o/i2o_block.h create mode 100644 drivers/message/i2o/iop.c create mode 100644 drivers/message/i2o/pci.c create mode 100644 drivers/mmc/Kconfig create mode 100644 drivers/mmc/Makefile create mode 100644 drivers/mmc/mmc.c create mode 100644 drivers/mmc/mmc.h create mode 100644 drivers/mmc/mmc_block.c create mode 100644 drivers/mmc/mmc_queue.c create mode 100644 drivers/mmc/mmc_queue.h create mode 100644 drivers/mmc/mmc_sysfs.c create mode 100644 drivers/mmc/mmci.c create mode 100644 drivers/mmc/mmci.h create mode 100644 drivers/mmc/pxamci.c create mode 100644 drivers/mmc/pxamci.h create mode 100644 drivers/mtd/maps/ixp2000.c create mode 100644 drivers/net/gt64240eth.h create mode 100644 drivers/net/mv643xx_eth.c create mode 100644 drivers/net/mv643xx_eth.h create mode 100644 drivers/pci/hotplug/acpiphp_ibm.c create mode 100644 drivers/scsi/ibmvscsi/Makefile create mode 100644 drivers/scsi/ibmvscsi/ibmvscsi.c create mode 100644 drivers/scsi/ibmvscsi/ibmvscsi.h create mode 100644 drivers/scsi/ibmvscsi/iseries_vscsi.c create mode 100644 drivers/scsi/ibmvscsi/rpa_vscsi.c create mode 100644 drivers/scsi/ibmvscsi/srp.h create mode 100644 drivers/scsi/ibmvscsi/viosrp.h create mode 100644 drivers/scsi/megaraid/Kconfig.megaraid create mode 100644 drivers/scsi/megaraid/Makefile create mode 100644 drivers/scsi/megaraid/mbox_defs.h create mode 100644 drivers/scsi/megaraid/mega_common.h create mode 100644 drivers/scsi/megaraid/megaraid_ioctl.h create mode 100644 drivers/scsi/megaraid/megaraid_mbox.c create mode 100644 drivers/scsi/megaraid/megaraid_mbox.h create mode 100644 drivers/scsi/megaraid/megaraid_mm.c create mode 100644 drivers/scsi/megaraid/megaraid_mm.h create mode 100644 drivers/serial/icom.c create mode 100644 drivers/serial/icom.h create mode 100644 drivers/usb/core/otg_whitelist.h create mode 100644 drivers/usb/gadget/lh7a40x_udc.c create mode 100644 drivers/usb/gadget/lh7a40x_udc.h create mode 100644 drivers/usb/gadget/omap_udc.c create mode 100644 drivers/usb/gadget/omap_udc.h create mode 100644 drivers/usb/media/sn9c102_pas202bcb.c create mode 100644 drivers/video/amba-clcd.c create mode 100644 drivers/w1/ds_w1_bridge.c create mode 100644 drivers/w1/dscore.c create mode 100644 drivers/w1/dscore.h create mode 100644 drivers/w1/w1_smem.c create mode 100644 fs/nfs/callback.c create mode 100644 fs/nfs/callback.h create mode 100644 fs/nfs/callback_proc.c create mode 100644 fs/nfs/callback_xdr.c create mode 100644 fs/nfs/delegation.c create mode 100644 fs/nfs/delegation.h create mode 100644 fs/nfsd/nfs4acl.c create mode 100644 fs/ntfs/bitmap.c create mode 100644 fs/ntfs/bitmap.h create mode 100644 fs/ntfs/lcnalloc.c create mode 100644 fs/ntfs/lcnalloc.h create mode 100644 fs/xfs/linux-2.6/xfs_ioctl32.c create mode 100644 fs/xfs/linux-2.6/xfs_ioctl32.h create mode 100644 include/asm-alpha/io_trivial.h create mode 100644 include/asm-arm/arch-h720x/boards.h create mode 100644 include/asm-arm/arch-h720x/dma.h create mode 100644 include/asm-arm/arch-h720x/h7201-regs.h create mode 100644 include/asm-arm/arch-h720x/h7202-regs.h create mode 100644 include/asm-arm/arch-h720x/hardware.h create mode 100644 include/asm-arm/arch-h720x/io.h create mode 100644 include/asm-arm/arch-h720x/irq.h create mode 100644 include/asm-arm/arch-h720x/irqs.h create mode 100644 include/asm-arm/arch-h720x/memory.h create mode 100644 include/asm-arm/arch-h720x/param.h create mode 100644 include/asm-arm/arch-h720x/serial.h create mode 100644 include/asm-arm/arch-h720x/system.h create mode 100644 include/asm-arm/arch-h720x/timex.h create mode 100644 include/asm-arm/arch-h720x/uncompress.h create mode 100644 include/asm-arm/arch-h720x/vmalloc.h create mode 100644 include/asm-arm/arch-imx/dma.h create mode 100644 include/asm-arm/arch-imx/hardware.h create mode 100644 include/asm-arm/arch-imx/imx-regs.h create mode 100644 include/asm-arm/arch-imx/io.h create mode 100644 include/asm-arm/arch-imx/irq.h create mode 100644 include/asm-arm/arch-imx/irqs.h create mode 100644 include/asm-arm/arch-imx/memory.h create mode 100644 include/asm-arm/arch-imx/mx1ads.h create mode 100644 include/asm-arm/arch-imx/param.h create mode 100644 include/asm-arm/arch-imx/serial.h create mode 100644 include/asm-arm/arch-imx/system.h create mode 100644 include/asm-arm/arch-imx/timex.h create mode 100644 include/asm-arm/arch-imx/uncompress.h create mode 100644 include/asm-arm/arch-imx/vmalloc.h create mode 100644 include/asm-arm/arch-iop3xx/iop331-irqs.h create mode 100644 include/asm-arm/arch-iop3xx/iop331.h create mode 100644 include/asm-arm/arch-iop3xx/iq31244.h create mode 100644 include/asm-arm/arch-iop3xx/iq80331.h create mode 100644 include/asm-arm/arch-ixp2000/dma.h create mode 100644 include/asm-arm/arch-ixp2000/enp2611.h create mode 100644 include/asm-arm/arch-ixp2000/gpio.h create mode 100644 include/asm-arm/arch-ixp2000/hardware.h create mode 100644 include/asm-arm/arch-ixp2000/io.h create mode 100644 include/asm-arm/arch-ixp2000/irq.h create mode 100644 include/asm-arm/arch-ixp2000/irqs.h create mode 100644 include/asm-arm/arch-ixp2000/ixdp2x00.h create mode 100644 include/asm-arm/arch-ixp2000/ixdp2x01.h create mode 100644 include/asm-arm/arch-ixp2000/ixp2000-regs.h create mode 100644 include/asm-arm/arch-ixp2000/memory.h create mode 100644 include/asm-arm/arch-ixp2000/param.h create mode 100644 include/asm-arm/arch-ixp2000/platform.h create mode 100644 include/asm-arm/arch-ixp2000/serial.h create mode 100644 include/asm-arm/arch-ixp2000/system.h create mode 100644 include/asm-arm/arch-ixp2000/timex.h create mode 100644 include/asm-arm/arch-ixp2000/uncompress.h create mode 100644 include/asm-arm/arch-ixp2000/vmalloc.h create mode 100644 include/asm-arm/arch-omap/mcbsp.h create mode 100644 include/asm-arm/arch-omap/tps65010.h create mode 100644 include/asm-arm/arch-omap/usb.h create mode 100644 include/asm-arm/arch-pxa/mmc.h create mode 100644 include/asm-arm/arch-s3c2410/nand.h create mode 100644 include/asm-arm/arch-s3c2410/regs-dsc.h create mode 100644 include/asm-arm/arch-s3c2410/regs-gpioj.h create mode 100644 include/asm-arm/arch-s3c2410/regs-iic.h create mode 100644 include/asm-arm/arch-s3c2410/regs-mem.h create mode 100644 include/asm-arm/arch-s3c2410/regs-nand.h create mode 100644 include/asm-arm/arch-s3c2410/regs-sdi.h create mode 100644 include/asm-arm/arch-s3c2410/regs-spi.h create mode 100644 include/asm-arm/arch-s3c2410/regs-udc.h create mode 100644 include/asm-arm/arch-s3c2410/usb-control.h create mode 100644 include/asm-arm/hardware/amba_clcd.h create mode 100644 include/asm-arm/mach/mmc.h create mode 100644 include/asm-generic/bug.h create mode 100644 include/asm-generic/iomap.h create mode 100644 include/asm-generic/uaccess.h create mode 100644 include/asm-i386/kdebug.h create mode 100644 include/asm-i386/kprobes.h create mode 100644 include/asm-ia64/sn/sn2/sn_hwperf.h create mode 100644 include/asm-m32r/a.out.h create mode 100644 include/asm-m32r/addrspace.h create mode 100644 include/asm-m32r/assembler.h create mode 100644 include/asm-m32r/atomic.h create mode 100644 include/asm-m32r/bitops.h create mode 100644 include/asm-m32r/bug.h create mode 100644 include/asm-m32r/bugs.h create mode 100644 include/asm-m32r/byteorder.h create mode 100644 include/asm-m32r/cache.h create mode 100644 include/asm-m32r/cachectl.h create mode 100644 include/asm-m32r/cacheflush.h create mode 100644 include/asm-m32r/checksum.h create mode 100644 include/asm-m32r/current.h create mode 100644 include/asm-m32r/delay.h create mode 100644 include/asm-m32r/div64.h create mode 100644 include/asm-m32r/dma-mapping.h create mode 100644 include/asm-m32r/dma.h create mode 100644 include/asm-m32r/elf.h create mode 100644 include/asm-m32r/errno.h create mode 100644 include/asm-m32r/fcntl.h create mode 100644 include/asm-m32r/flat.h create mode 100644 include/asm-m32r/hardirq.h create mode 100644 include/asm-m32r/hdreg.h create mode 100644 include/asm-m32r/hw_irq.h create mode 100644 include/asm-m32r/ide.h create mode 100644 include/asm-m32r/io.h create mode 100644 include/asm-m32r/ioctl.h create mode 100644 include/asm-m32r/ioctls.h create mode 100644 include/asm-m32r/ipc.h create mode 100644 include/asm-m32r/ipcbuf.h create mode 100644 include/asm-m32r/irq.h create mode 100644 include/asm-m32r/kmap_types.h create mode 100644 include/asm-m32r/linkage.h create mode 100644 include/asm-m32r/local.h create mode 100644 include/asm-m32r/m32102.h create mode 100644 include/asm-m32r/m32102peri.h create mode 100644 include/asm-m32r/m32700ut/m32700ut_lan.h create mode 100644 include/asm-m32r/m32700ut/m32700ut_lcd.h create mode 100644 include/asm-m32r/m32700ut/m32700ut_pld.h create mode 100644 include/asm-m32r/m32r.h create mode 100644 include/asm-m32r/m32r_mp_fpga.h create mode 100644 include/asm-m32r/mappi2/mappi2_pld.h create mode 100644 include/asm-m32r/mc146818rtc.h create mode 100644 include/asm-m32r/mman.h create mode 100644 include/asm-m32r/mmu.h create mode 100644 include/asm-m32r/mmu_context.h create mode 100644 include/asm-m32r/mmzone.h create mode 100644 include/asm-m32r/module.h create mode 100644 include/asm-m32r/msgbuf.h create mode 100644 include/asm-m32r/namei.h create mode 100644 include/asm-m32r/numnodes.h create mode 100644 include/asm-m32r/opsput/opsput_lan.h create mode 100644 include/asm-m32r/opsput/opsput_lcd.h create mode 100644 include/asm-m32r/opsput/opsput_pld.h create mode 100644 include/asm-m32r/page.h create mode 100644 include/asm-m32r/param.h create mode 100644 include/asm-m32r/pci.h create mode 100644 include/asm-m32r/percpu.h create mode 100644 include/asm-m32r/pgalloc.h create mode 100644 include/asm-m32r/pgtable-2level.h create mode 100644 include/asm-m32r/pgtable.h create mode 100644 include/asm-m32r/poll.h create mode 100644 include/asm-m32r/posix_types.h create mode 100644 include/asm-m32r/processor.h create mode 100644 include/asm-m32r/ptrace.h create mode 100644 include/asm-m32r/resource.h create mode 100644 include/asm-m32r/rtc.h create mode 100644 include/asm-m32r/scatterlist.h create mode 100644 include/asm-m32r/sections.h create mode 100644 include/asm-m32r/segment.h create mode 100644 include/asm-m32r/semaphore.h create mode 100644 include/asm-m32r/sembuf.h create mode 100644 include/asm-m32r/serial.h create mode 100644 include/asm-m32r/setup.h create mode 100644 include/asm-m32r/shmbuf.h create mode 100644 include/asm-m32r/shmparam.h create mode 100644 include/asm-m32r/sigcontext.h create mode 100644 include/asm-m32r/siginfo.h create mode 100644 include/asm-m32r/signal.h create mode 100644 include/asm-m32r/smp.h create mode 100644 include/asm-m32r/socket.h create mode 100644 include/asm-m32r/sockios.h create mode 100644 include/asm-m32r/spinlock.h create mode 100644 include/asm-m32r/stat.h create mode 100644 include/asm-m32r/statfs.h create mode 100644 include/asm-m32r/string.h create mode 100644 include/asm-m32r/syscall.h create mode 100644 include/asm-m32r/system.h create mode 100644 include/asm-m32r/termbits.h create mode 100644 include/asm-m32r/termios.h create mode 100644 include/asm-m32r/thread_info.h create mode 100644 include/asm-m32r/timex.h create mode 100644 include/asm-m32r/tlb.h create mode 100644 include/asm-m32r/tlbflush.h create mode 100644 include/asm-m32r/topology.h create mode 100644 include/asm-m32r/types.h create mode 100644 include/asm-m32r/uaccess.h create mode 100644 include/asm-m32r/ucontext.h create mode 100644 include/asm-m32r/unaligned.h create mode 100644 include/asm-m32r/unistd.h create mode 100644 include/asm-m32r/user.h create mode 100644 include/asm-m32r/vga.h create mode 100644 include/asm-m32r/xor.h create mode 100644 include/asm-ppc/8253pit.h create mode 100644 include/asm-ppc64/8253pit.h create mode 100644 include/asm-ppc64/plpar_wrappers.h create mode 100644 include/asm-sparc64/kprobes.h create mode 100644 include/asm-um/module-i386.h create mode 100644 include/asm-x86_64/swiotlb.h create mode 100644 include/linux/gen_stats.h create mode 100644 include/linux/hardirq.h create mode 100644 include/linux/i2c-algo-pca.h create mode 100644 include/linux/kprobes.h create mode 100644 include/linux/mmc/card.h create mode 100644 include/linux/mmc/host.h create mode 100644 include/linux/mmc/mmc.h create mode 100644 include/linux/mmc/protocol.h create mode 100644 include/linux/mmtimer.h create mode 100644 include/linux/mv643xx.h create mode 100644 include/linux/netfilter_ipv4/ip_conntrack_sctp.h create mode 100644 include/linux/netfilter_ipv4/ipt_comment.h create mode 100644 include/linux/netfilter_ipv4/ipt_sctp.h create mode 100644 include/linux/netfilter_ipv6/ip6t_physdev.h create mode 100644 include/linux/nfs4_acl.h create mode 100644 include/linux/raid/raid10.h create mode 100644 include/linux/ramfs.h create mode 100644 include/linux/sunrpc/gss_spkm3.h create mode 100644 include/linux/tc_act/tc_gact.h create mode 100644 include/linux/usb_otg.h create mode 100644 include/net/gen_stats.h create mode 100644 include/net/tc_act/tc_gact.h create mode 100644 include/sound/pcm-indirect.h create mode 100644 include/video/epson1355.h create mode 100644 kernel/kprobes.c create mode 100644 kernel/spinlock.c create mode 100644 lib/Kconfig.debug create mode 100644 lib/iomap.c create mode 100644 lib/zlib_inflate/inflate_sync.c create mode 100644 mm/thrash.c create mode 100644 mm/tiny-shmem.c create mode 100644 net/core/gen_estimator.c create mode 100644 net/core/gen_stats.c create mode 100644 net/ipv4/fib_lookup.h create mode 100644 net/ipv4/netfilter/ip_conntrack_proto_sctp.c create mode 100644 net/ipv4/netfilter/ipt_comment.c create mode 100644 net/ipv4/netfilter/ipt_sctp.c create mode 100644 net/ipv6/netfilter/ip6t_physdev.c create mode 100644 net/sched/gact.c create mode 100644 net/sunrpc/auth_gss/gss_spkm3_mech.c create mode 100644 net/sunrpc/auth_gss/gss_spkm3_seal.c create mode 100644 net/sunrpc/auth_gss/gss_spkm3_token.c create mode 100644 net/sunrpc/auth_gss/gss_spkm3_unseal.c create mode 100644 scripts/Makefile.host create mode 100644 scripts/mksysmap create mode 100644 scripts/namespace.pl create mode 100644 sound/pci/atiixp_modem.c create mode 100644 sound/pci/ice1712/pontis.c create mode 100644 sound/pci/ice1712/pontis.h create mode 100644 sound/pci/ice1712/vt1720_mobo.c create mode 100644 sound/pci/ice1712/vt1720_mobo.h create mode 100644 sound/ppc/beep.c create mode 100644 sound/usb/usx2y/Makefile create mode 100644 sound/usb/usx2y/usX2Yhwdep.c create mode 100644 sound/usb/usx2y/usX2Yhwdep.h create mode 100644 sound/usb/usx2y/usbus428ctldefs.h create mode 100644 sound/usb/usx2y/usbusx2y.c create mode 100644 sound/usb/usx2y/usbusx2y.h create mode 100644 sound/usb/usx2y/usbusx2yaudio.c create mode 100644 sound/usb/usx2y/usx2y.h diff --git a/CREDITS b/CREDITS index cc0cffd96..22252bdf5 100644 --- a/CREDITS +++ b/CREDITS @@ -281,6 +281,11 @@ S: Code 930.5, Goddard Space Flight Center S: Greenbelt, Maryland 20771 S: USA +N: Adam Belay +E: ambx1@neo.rr.com +D: Linux Plug and Play Support +S: USA + N: Daniele Bellucci E: bellucda@tiscali.it D: Various Janitor work. @@ -513,6 +518,14 @@ S: 25-29 St Giles S: Oxford S: United Kingdom +N: Luiz Fernando N. Capitulino +E: lcapitulino@terra.com.br +E: lcapitulino@prefeitura.sp.gov.br +W: http://www.telecentros.sp.gov.br +D: Little fixes and a lot of janitorial work +S: E-GOV Telecentros SP +S: Brazil + N: Remy Card E: Remy.Card@masi.ibp.fr E: Remy.Card@linux.org @@ -625,6 +638,14 @@ E: nconway.list@ukaea.org.uk D: Assorted sched/mm titbits S: Oxfordshire, UK. +N: Kees Cook +E: kees@outflux.net +W: http://outflux.net/ +P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D +D: Minor updates to SCSI code for the Communications type +S: (ask for current address) +S: USA + N: Mark Corner E: mcorner@umich.edu W: http://www.eecs.umich.edu/~mcorner/ @@ -639,14 +660,6 @@ D: Kernel module SMART utilities S: Santa Cruz, California S: USA -N: Kees Cook -E: kees@outflux.net -W: http://outflux.net/ -P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D -D: Minor updates to SCSI code for the Communications type -S: (ask for current address) -S: USA - N: Alan Cox W: http://www.linux.org.uk/diary/ D: Linux Networking (0.99.10->2.0.29) @@ -735,6 +748,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 +773,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 @@ -905,6 +924,10 @@ S: Brevia 1043 S: S-114 79 Stockholm S: Sweden +N: David Engebretsen +E: engebret@us.ibm.com +D: Linux port to 64-bit PowerPC architecture + N: Michael Engel E: engel@unix-ag.org D: DECstation framebuffer drivers @@ -1049,6 +1072,12 @@ S: R. Tocantins, 89 - Cristo Rei S: 80050-430 - Curitiba - Paraná S: Brazil +N: Kumar Gala +E: kumar.gala@freescale.com +D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support +S: Austin, Texas 78729 +S: USA + N: Nigel Gamble E: nigel@nrg.org D: Interrupt-driven printer driver @@ -1060,12 +1089,6 @@ S: USA N: Jeff Garzik E: jgarzik@pobox.com -N: Kumar Gala -E: kumar.gala@freescale.com -D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support -S: Austin, Texas 78729 -S: USA - N: Jacques Gelinas E: jacques@solucorp.qc.ca D: Author of the Umsdos file system @@ -1563,10 +1586,37 @@ D: Backport/Forwardport merge monkey. D: Various Janitor work. S: United Kingdom +N: Martin Josfsson +E: gandalf@wlug.westbo.se +P: 1024D/F6B6D3B1 7610 7CED 5C34 4AA6 DBA2 8BE1 5A6D AF95 F6B6 D3B1 +D: netfilter: SAME target +D: netfilter: helper target +D: netfilter: various other hacks +S: Ronneby +S: Sweden + N: Ani Joshi E: ajoshi@shell.unixbox.com D: fbdev hacking +N: Jesper Juhl +E: juhl-lkml@dif.dk +D: Various small janitor fixes, cleanups etc. +S: Lemnosvej 1, 3.tv +S: 2300 Copenhagen S +S: Denmark + +N: Jozsef Kadlecsik +E: kadlec@blackhole.kfki.hu +P: 1024D/470DB964 4CB3 1A05 713E 9BF7 FAC5 5809 DD8C B7B1 470D B964 +D: netfilter: TCP window tracking code +D: netfilter: raw table +D: netfilter: iprange match +D: netfilter: new logging interfaces +D: netfilter: various other hacks +S: Tata +S: Hungary + N: Bernhard Kaindl E: bkaindl@netway.at E: edv@bartelt.via.at @@ -1818,11 +1868,6 @@ S: Sindlovy Dvory 117 S: 370 01 Ceske Budejovice S: Czech Republic -N: Adam Belay -E: ambx1@neo.rr.com -D: Linux Plug and Play Support -S: USA - N: Bas Laarhoven E: sjml@xs4all.nl D: Loadable modules and ftape driver @@ -1954,12 +1999,6 @@ S: 8786 Niwot Road S: Niwot, Colorado 80503 S: USA -N: Pete Popov -E: pete_popov@yahoo.com -D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging -S: San Jose, CA 95134 -S: USA - N: Robert M. Love E: rml@tech9.net E: rml@novell.com @@ -2127,6 +2166,16 @@ D: OV511 driver S: (address available on request) S: USA +N: Patrick McHardy +E: kaber@trash.net +P: 1024D/12155E80 B128 7DE6 FF0A C2B2 48BE AB4C C9D4 964E 1215 5E80 +D: netfilter: endless number of bugfixes +D: netfilter: CLASSIFY target +D: netfilter: addrtype match +D: tc: HFSC scheduler +S: Freiburg +S: Germany + N: Mike McLagan E: mike.mclagan@linux.org W: http://www.invlogic.com/~mmclagan @@ -2214,14 +2263,13 @@ S: 7546 JA Enschede S: Netherlands N: David S. Miller -E: davem@redhat.com +E: davem@davemloft.net D: Sparc and blue box hacker D: Vger Linux mailing list co-maintainer D: Linux Emacs elf/qmagic support + other libc/gcc things D: Yee bore de yee bore! ;-) -S: 750 N. Shoreline Blvd. -S: Apt. #111 -S: Mountain View, California 94043 +S: 575 Harrison St. #103 +S: San Francisco, CA 94105 S: USA N: Rick Miller @@ -2570,6 +2618,7 @@ N: Nicolas Pitre E: nico@cam.org D: StrongARM SA1100 support integrator & hacker D: Xscale PXA architecture +D: unified SMC 91C9x/91C11x ethernet driver (smc91x) S: Montreal, Quebec, Canada N: Ken Pizzini @@ -2582,6 +2631,12 @@ P: 1024D/EDBB6147 7B36 0E07 04BC 11DC A7A0 D3F7 7185 9E7A EDBB 6147 D: sonypi, meye drivers, mct_u232 usb serial hacks S: Paris, France +N: Pete Popov +E: pete_popov@yahoo.com +D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging +S: San Jose, CA 95134 +S: USA + N: Matt Porter E: mporter@kernel.crashing.org D: Motorola PowerPC PReP support @@ -2797,7 +2852,7 @@ S: Germany N: Paul `Rusty' Russell E: rusty@rustcorp.com.au -W: http://www.samba.org/netfilter +W: http://ozlabs.org/~rusty D: Ruggedly handsome. D: netfilter, ipchains with Michael Neuling. S: 52 Moore St @@ -2821,7 +2876,6 @@ S: I/3 Walter St S: Wellington S: New Zealand - N: Sampo Saaristo E: sambo@cs.tut.fi D: Co-author of Multi-Protocol Over ATM (MPOA) @@ -2838,6 +2892,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 @@ -3289,14 +3346,6 @@ S: Chudenicka 8 S: 10200 Prague 10, Hostivar S: Czech Republic -N: James R. Van Zandt -E: jrv@vanzandt.mv.com -P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C -D: Author and maintainer of the Double Talk speech synthesizer driver -S: 27 Spencer Drive -S: Nashua, New Hampshire 03062 -S: USA - N: Heikki Vatiainen E: hessu@cs.tut.fi D: Co-author of Multi-Protocol Over ATM (MPOA), some LANE hacks @@ -3387,6 +3436,18 @@ S: UC Berkeley S: Berkeley, CA 94720-1776 S: USA +N: Harald Welte +E: laforge@netfilter.org +P: 1024D/30F48BFF DBDE 6912 8831 9A53 879B 9190 5DA5 C655 30F4 8BFF +W: http://gnumonks.org/users/laforge +D: netfilter: new nat helper infrastructure +D: netfilter: ULOG, ECN, DSCP target +D: netfilter: TTL match +D: netfilter: IPv6 mangle table +D: netfilter: various other hacks +S: Berlin +S: Germany + N: Bill Wendling E: wendling@ganymede.isdn.uiuc.edu W: http://www.ncsa.uiuc.edu/~wendling/ @@ -3578,6 +3639,14 @@ S: ARCO Tower 1-8-1 Shimomeguro Meguro-ku S: Tokyo 153 S: Japan +N: James R. Van Zandt +E: jrv@vanzandt.mv.com +P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C +D: Author and maintainer of the Double Talk speech synthesizer driver +S: 27 Spencer Drive +S: Nashua, New Hampshire 03062 +S: USA + N: Orest Zborowski E: orestz@eskimo.com D: XFree86 and kernel development @@ -3619,13 +3688,6 @@ D: MD driver D: EISA/sysfs subsystem S: France -N: Luiz Fernando N. Capitulino -E: lcapitulino@terra.com.br -E: lcapitulino@prefeitura.sp.gov.br -W: http://www.telecentros.sp.gov.br -D: Little fixes and a lot of janitorial work -S: E-GOV Telecentros SP -S: Brazil # Don't add your name here, unless you really _are_ after Marc # alphabetically. Leonard used to be very proud of being the diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 7b256c12a..f25b3953f 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/DMA-API.txt b/Documentation/DMA-API.txt index 11caa2d64..8787c4d09 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -444,4 +444,83 @@ dma_alloc_noncoherent(), starting at virtual address vaddr and continuing on for size. Again, you *must* observe the cache line boundaries when doing this. +int +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int + flags) + + +Declare region of memory to be handed out by dma_alloc_coherent when +it's asked for coherent memory for this device. + +bus_addr is the physical address to which the memory is currently +assigned in the bus responding region (this will be used by the +platform to perform the mapping) + +device_addr is the physical address the device needs to be programmed +with actually to address this memory (this will be handed out as the +dma_addr_t in dma_alloc_coherent()) + +size is the size of the area (must be multiples of PAGE_SIZE). + +flags can be or'd together and are + +DMA_MEMORY_MAP - request that the memory returned from +dma_alloc_coherent() be directly writeable. + +DMA_MEMORY_IO - request that the memory returned from +dma_alloc_coherent() be addressable using read/write/memcpy_toio etc. + +One or both of these flags must be present + +DMA_MEMORY_INCLUDES_CHILDREN - make the declared memory be allocated by +dma_alloc_coherent of any child devices of this one (for memory residing +on a bridge). + +DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions. +Do not allow dma_alloc_coherent() to fall back to system memory when +it's out of memory in the declared region. + +The return value will be either DMA_MEMORY_MAP or DMA_MEMORY_IO and +must correspond to a passed in flag (i.e. no returning DMA_MEMORY_IO +if only DMA_MEMORY_MAP were passed in) for success or zero for +failure. + +Note, for DMA_MEMORY_IO returns, all subsequent memory returned by +dma_alloc_coherent() may no longer be accessed directly, but instead +must be accessed using the correct bus functions. If your driver +isn't prepared to handle this contingency, it should not specify +DMA_MEMORY_IO in the input flags. + +As a simplification for the platforms, only *one* such region of +memory may be declared per device. + +For reasons of efficiency, most platforms choose to track the declared +region only at the granularity of a page. For smaller allocations, +you should use the dma_pool() API. + +void +dma_release_declared_memory(struct device *dev) + +Remove the memory region previously declared from the system. This +API performs *no* in-use checking for this region and will return +unconditionally having removed all the required structures. It is the +drivers job to ensure that no parts of this memory region are +currently in use. + +void * +dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) + +This is used to occupy specific regions of the declared space +(dma_alloc_coherent() will hand out the first free region it finds). + +device_addr is the *device* address of the region requested + +size is the size (and should be a page sized multiple). + +The return value will be either a pointer to the processor virtual +address of the memory, or an error (via PTR_ERR()) if any part of the +region is occupied. + diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index bf212c021..9a23eab00 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -185,9 +185,7 @@ clean-files := $(DOCBOOKS) \ $(patsubst %.sgml, %.9, $(DOCBOOKS)) \ $(C-procfs-example) -ifneq ($(wildcard $(patsubst %.html,%,$(HTML))),) -clean-rule := rm -rf $(wildcard $(patsubst %.html,%,$(HTML))) -endif +clean-dirs := $(patsubst %.sgml,%,$(DOCBOOKS)) #man put files in man subdir - traverse down subdir- := man/ diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index f07e73a41..0c28a966c 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -2,8 +2,8 @@ USB Gadget API for Linux - 02 June 2003 - 02 June 2003 + 20 August 2004 + 20 August 2004 @@ -34,7 +34,7 @@ - 2003 + 2003-2004 David Brownell @@ -73,9 +73,13 @@ a number of important problems, including: composite devices, and alternate interface settings. + USB "On-The-Go" (OTG) support, in conjunction + with updates to the Linux-USB host side. + Sharing data structures and API models with the - Linux-USB host side API. This looks forward to USB "On-The-Go" - (OTG) and similar more-symmetric frameworks. + Linux-USB host side API. This helps the OTG support, and + looks forward to more-symmetric frameworks (where the same + I/O model is used by both host and device side drivers). Minimalist, so it's easier to support new device controller hardware. I/O processing doesn't imply large @@ -153,6 +157,7 @@ with the lowest level (which directly handles hardware). the SA-11x0 or PXA-25x UDC (found within many PDAs), and a variety of other products. + @@ -162,10 +167,14 @@ with the lowest level (which directly handles hardware). The lower boundary of this driver implements hardware-neutral USB functions, using calls to the controller driver. Because such hardware varies widely in capabilities and restrictions, - the gadget driver is normally configured at compile time + and is used in embedded environments where space is at a premium, + the gadget driver is often configured at compile time to work with endpoints supported by one particular controller. Gadget drivers may be portable to several different controllers, using conditional compilation. + (Recent kernels substantially simplify the work involved in + supporting new hardware, by autoconfiguring + endpoints automatically for many bulk-oriented drivers.) Gadget driver responsibilities include: @@ -178,8 +187,9 @@ with the lowest level (which directly handles hardware). altsettings, including enabling and configuring endpoints handling life cycle events, such as managing - bindings - to hardware, and disconnection from the USB host. + bindings to hardware, + USB suspend/resume, remote wakeup, + and disconnection from the USB host. managing IN and OUT transfers on all currently enabled endpoints @@ -244,15 +254,38 @@ with the lowest level (which directly handles hardware). -Over time, reusable utilities should evolve to help make some -gadget driver tasks simpler. An example of particular interest +OTG-capable systems will also need to include a standard Linux-USB +host side stack, +with usbcore, +one or more Host Controller Drivers (HCDs), +USB Device Drivers to support +the OTG "Targeted Peripheral List", +and so forth. +There will also be an OTG Controller Driver, +which is visible to gadget and device driver developers only indirectly. +That helps the host and device side USB controllers implement the +two new OTG protocols (HNP and SRP). +Roles switch (host to peripheral, or vice versa) using HNP +during USB suspend processing, and SRP can be viewed as a +more battery-friendly kind of device wakeup protocol. + + +Over time, reusable utilities are evolving to help make some +gadget driver tasks simpler. +For example, building configuration descriptors from vectors of +descriptors for the configurations interfaces and endpoints is +now automated, and many drivers now use autoconfiguration to +choose hardware endpoints and initialize their descriptors. + +A potential example of particular interest is code implementing standard USB-IF protocols for HID, networking, storage, or audio classes. Some developers are interested in KDB or KGDB hooks, to let target hardware be remotely debugged. Most such USB protocol code doesn't need to be hardware-specific, any more than network protocols like X11, HTTP, or NFS are. -Such interface drivers might be combined, to support composite devices. +Such gadget-side interface drivers should eventually be combined, +to implement composite devices. @@ -284,7 +317,7 @@ data types and functions are described here. However, docproc does not understand all the C constructs that are used, so some relevant information is likely omitted from what you are reading. -One example of such information is several per-request flags. +One example of such information is endpoint autoconfiguration. You'll have to read the header file, and use example source code (such as that for "Gadget Zero"), to fully understand the API. @@ -292,7 +325,7 @@ code (such as that for "Gadget Zero"), to fully understand the API. The part of the API implementing some basic driver capabilities is specific to the version of the Linux kernel that's in use. -The 2.5 kernel includes a driver model +The 2.6 kernel includes a driver model framework that has no analogue on earlier kernels; so those parts of the gadget API are not fully portable. (They are implemented on 2.4 kernels, but in a different way.) @@ -308,17 +341,21 @@ There are significant hardware features, such as device-to-device DMA that would be added using hardware-specific APIs. -This API expects drivers to use conditional compilation to handle -endpoint capabilities of different hardware. -Those tend to have arbitrary restrictions, relating to +This API allows drivers to use conditional compilation to handle +endpoint capabilities of different hardware, but doesn't require that. +Hardware tends to have arbitrary restrictions, relating to transfer types, addressing, packet sizes, buffering, and availability. As a rule, such differences only matter for "endpoint zero" logic that handles device configuration and management. -The API only supports limited run-time +The API supports limited run-time detection of capabilities, through naming conventions for endpoints. -Although a gadget driver could scan the endpoints available to it and -choose to map those capabilities onto driver functionality in some way, -few drivers will want to reconfigure themselves at run-time. +Many drivers will be able to at least partially autoconfigure +themselves. +In particular, driver init sections will often have endpoint +autoconfiguration logic that scans the hardware's list of endpoints +to find ones matching the driver requirements +(relying on those conventions), to eliminate some of the most +common reasons for conditional compilation. Like the Linux-USB host side API, this API exposes @@ -355,10 +392,14 @@ and so on. At this point the device is logically in the USB ch9 initial state ("attached"), drawing no power and not usable (since it does not yet support enumeration). +Any host should not see the device, since it's not +activated the data line pullup used by the host to +detect a device, even if VBUS power is available. Register a gadget driver that implements some higher level -device function. That will then bind() to a usb_gadget. +device function. That will then bind() to a usb_gadget, which +activates the data line pullup sometime after detecting VBUS. The hardware driver can now start enumerating. @@ -373,6 +414,8 @@ based both on what the bus interface hardware provides and on the functionality being implemented. That can involve alternate settings or configurations, unless the hardware prevents such operation. +For OTG devices, each configuration descriptor includes +an OTG descriptor. The gadget driver handles the last step of enumeration, @@ -381,13 +424,18 @@ It enables all endpoints used in that configuration, with all interfaces in their default settings. That involves using a list of the hardware's endpoints, enabling each endpoint according to its descriptor. +It may also involve using usb_gadget_vbus_draw +to let more power be drawn from VBUS, as allowed by that configuration. +For OTG devices, setting a configuration may also involve reporting +HNP capabilities through a user interface. Do real work and perform data transfers, possibly involving changes to interface settings or switching to new configurations, until the device is disconnect()ed from the host. Queue any number of transfer requests to each endpoint. -The drivers then go back to step 3 (above). +It may be suspended and resumed several times before being disconnected. +On disconnect, the drivers go back to step 3 (above). When the gadget driver module is being unloaded, @@ -399,7 +447,9 @@ driver be unloaded. Drivers will normally be arranged so that just loading the gadget driver module (or statically linking it into a Linux kernel) -allows the peripheral device to be enumerated. +allows the peripheral device to be enumerated, but some drivers +will defer enumeration until some higher level component (like +a user mode daemon) enables it. Note that at this lowest level there are no policies about how ep0 configuration logic is implemented, except that it should obey USB specifications. @@ -410,6 +460,18 @@ or understanding that composite devices might happen to be built by integrating reusable components. +Note that the lifecycle above can be slightly different +for OTG devices. +Other than providing an additional OTG descriptor in each +configuration, only the HNP-related differences are particularly +visible to driver code. +They involve reporting requirements during the SET_CONFIGURATION +request, and the option to invoke HNP during some suspend callbacks. +Also, SRP changes the semantics of +usb_gadget_wakeup +slightly. + + USB 2.0 Chapter 9 Types and Constants @@ -418,9 +480,9 @@ be built by integrating reusable components. rely on common USB structures and constants defined in the <linux/usb_ch9.h> -header file, which is standard in Linux 2.5 kernels. +header file, which is standard in Linux 2.6 kernels. These are the same types and constants used by host -side drivers. +side drivers (and usbcore). !Iinclude/linux/usb_ch9.h @@ -451,26 +513,38 @@ USB peripheral controller drivers. The core API is sufficient for writing a USB Gadget Driver, but some optional utilities are provided to simplify common tasks. +These utilities include endpoint autoconfiguration. !Edrivers/usb/gadget/usbstring.c !Edrivers/usb/gadget/config.c + Peripheral Controller Drivers -The first hardware supporting this API is the NetChip 2280 +The first hardware supporting this API was the NetChip 2280 controller, which supports USB 2.0 high speed and is based on PCI. This is the net2280 driver module. -The driver supports Linux kernel versions 2.4 and 2.5; +The driver supports Linux kernel versions 2.4 and 2.6; contact NetChip Technologies for development boards and product information. -For users of Intel's PXA 2xx series processors, -a pxa2xx_udc driver is available. +Other hardware working in the "gadget" framework includes: +Intel's PXA 25x and IXP42x series processors +(pxa2xx_udc), +Toshiba TC86c001 "Goku-S" (goku_udc), +Renesas SH7705/7727 (sh_udc), +MediaQ 11xx (mq11xx_udc), +Hynix HMS30C7202 (h7202_udc), +National 9303/4 (n9604_udc), +Texas Instruments OMAP (omap_udc), +Sharp LH7A40x (lh7a40x_udc), +and more. +Most of those are full speed controllers. At this writing, there are people at work on drivers in @@ -526,6 +600,15 @@ subset of CDC Ethernet. to avoid creating problems.) +Support for Microsoft's RNDIS +protocol has been contributed by Pengutronix and Auerswald GmbH. +This is like CDC Ethernet, but it runs on more slightly USB hardware +(but less than the CDC subset). +However, its main claim to fame is being able to connect directly to +recent versions of Windows, using drivers that Microsoft bundles +and supports, making it much simpler to network with Windows. + + There is also support for user mode gadget drivers, using gadgetfs. This provides a User Mode API that presents @@ -535,6 +618,10 @@ Familiar tools like GDB and pthreads can be used to develop and debug user mode drivers, so that once a robust controller driver is available many applications for it won't require new kernel mode software. +Linux 2.6 Async I/O (AIO) +support is available, so that user mode software +can stream data with only slightly more overhead +than a kernel driver. There's a USB Mass Storage class driver, which provides @@ -548,6 +635,16 @@ storage class specification, using transparent SCSI commands to access the data from the backing store. +There's a "serial line" driver, useful for TTY style +operation over USB. +The latest version of that driver supports CDC ACM style +operation, like a USB modem, and so on most hardware it can +interoperate easily with MS-Windows. +One interesting use of that driver is in boot firmware (like a BIOS), +which can sometimes use that model with very small systems without +real serial lines. + + Support for other kinds of gadget is expected to be developed and contributed over time, as this driver framework evolves. @@ -555,6 +652,96 @@ over time, as this driver framework evolves. +USB On-The-GO (OTG) + +USB OTG support on Linux 2.6 was initially developed +by Texas Instruments for +OMAP 16xx and 17xx +series processors. +Other OTG systems should work in similar ways, but the +hardware level details could be very different. + + +Systems need specialized hardware support to implement OTG, +notably including a special Mini-AB jack +and associated transciever to support Dual-Role +operation: +they can act either as a host, using the standard +Linux-USB host side driver stack, +or as a peripheral, using this "gadget" framework. +To do that, the system software relies on small additions +to those programming interfaces, +and on a new internal component (here called an "OTG Controller") +affecting which driver stack connects to the OTG port. +In each role, the system can re-use the existing pool of +hardware-neutral drivers, layered on top of the controller +driver interfaces (usb_bus or +usb_gadget). +Such drivers need at most minor changes, and most of the calls +added to support OTG can also benefit non-OTG products. + + + + Gadget drivers test the is_otg + flag, and use it to determine whether or not to include + an OTG descriptor in each of their configurations. + + Gadget drivers may need changes to support the + two new OTG protocols, exposed in new gadget attributes + such as b_hnp_enable flag. + HNP support should be reported through a user interface + (two LEDs could suffice), and is triggered in some cases + when the host suspends the peripheral. + SRP support can be user-initiated just like remote wakeup, + probably by pressing the same button. + + On the host side, USB device drivers need + to be taught to trigger HNP at appropriate moments, using + usb_suspend_device(). + That also conserves battery power, which is useful even + for non-OTG configurations. + + Also on the host side, a driver must support the + OTG "Targeted Peripheral List". That's just a whitelist, + used to reject peripherals not supported with a given + Linux OTG host. + This whitelist is product-specific; + each product must modify otg_whitelist.h + to match its interoperability specification. + + + Non-OTG Linux hosts, like PCs and workstations, + normally have some solution for adding drivers, so that + peripherals that aren't recognized can eventually be supported. + That approach is unreasonable for consumer products that may + never have their firmware upgraded, and where it's usually + unrealistic to expect traditional PC/workstation/server kinds + of support model to work. + For example, it's often impractical to change device firmware + once the product has been distributed, so driver bugs can't + normally be fixed if they're found after shipment. + + + + +Additional changes are needed below those hardware-neutral +usb_bus and usb_gadget +driver interfaces; those aren't discussed here in any detail. +Those affect the hardware-specific code for each USB Host or Peripheral +controller, and how the HCD initializes (since OTG can be active only +on a single port). +They also involve what may be called an OTG Controller +Driver, managing the OTG transceiver and the OTG state +machine logic as well as much of the root hub behavior for the +OTG port. +The OTG controller driver needs to activate and deactivate USB +controllers depending on the relevant device role. +Some related changes were needed inside usbcore, so that it +can identify OTG-capable devices and respond appropriately +to HNP or SRP protocols. + + + Slave NPU + * | + * | + * P2P + * | + * + * Bus 1 | + * <--+------+---------+---------+------+--> + * | | | | | + * | | | | | + * ... Dev PMC Media Eth0 Eth1 ... + * + * The master controlls all but Eth1, which is controlled by the + * slave. What this measn is that the both the master and the slave + * have to scan the bus, but only one of them can enumerate the bus. + * In addition, after the bus is scaned, each kernel must remove + * the device(s) it does not control from the PCI dev list otherwise + * a driver on each NPU will try to manage it and we will have horrible + * conflicts. Oh..and the slave NPU needs to see the master NPU + * for Intel's drivers to work properly. Closed source drivers... + * + * The way we deal with this is fairly simple but ugly: + * + * 1) Let master scan and enumerate the bus completely. + * 2) Master deletes Eth1 from device list. + * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave) + * from device list. + * 4) Find HW designers and LART them. + * + * The boards also do not do normal PCI IRQ routing, or any sort of + * sensical swizzling, so we just need to check where on the bus a + * device sits and figure out to which CPLD pin the interrupt is routed. + * See ixdp2[48]00.c files. + * + *************************************************************************/ +void ixdp2x00_slave_pci_postinit(void) +{ + struct pci_dev *dev; + + /* + * Remove PMC device is there is one + */ + if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN))) + pci_remove_bus_device(dev); + + dev = pci_find_slot(0, IXDP2X00_21555_DEVFN); + pci_remove_bus_device(dev); +} + +/************************************************************************** + * IXDP2x00 Machine Setup + *************************************************************************/ +static struct flash_platform_data ixdp2x00_platform_data = { + .map_name = "cfi_probe", + .width = 1, +}; + +static struct ixp2000_flash_data ixdp2x00_flash_data = { + .platform_data = &ixdp2x00_platform_data, + .nr_banks = 1 +}; + +static struct resource ixdp2x00_flash_resource = { + .start = 0xc4000000, + .end = 0xc4000000 + 0x00ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ixdp2x00_flash = { + .name = "IXP2000-Flash", + .id = 0, + .dev = { + .platform_data = &ixdp2x00_flash_data, + }, + .num_resources = 1, + .resource = &ixdp2x00_flash_resource, +}; + +static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = { + .sda_pin = IXDP2X00_GPIO_SDA, + .scl_pin = IXDP2X00_GPIO_SCL, +}; + +static struct platform_device ixdp2x00_i2c_controller = { + .name = "IXP2000-I2C", + .id = 0, + .dev = { + .platform_data = &ixdp2x00_i2c_gpio_pins, + }, + .num_resources = 0 +}; + +static struct platform_device *ixdp2x00_devices[] __initdata = { + &ixdp2x00_flash, + &ixdp2x00_i2c_controller +}; + +void __init ixdp2x00_init_machine(void) +{ + gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1); + gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT); + + platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices)); +} + diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c new file mode 100644 index 000000000..176114aad --- /dev/null +++ b/arch/arm/mach-ixp2000/ixdp2x01.c @@ -0,0 +1,381 @@ +/* + * arch/arm/mach-ixp2000/ixdp2x01.c + * + * Code common to Intel IXDP2401 and IXDP2801 platforms + * + * Original Author: Andrzej Mialwoski + * Maintainer: Deepak Saxena + * + * Copyright (C) 2002-2003 Intel Corp. + * Copyright (C) 2003-2004 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/************************************************************************* + * IXDP2x01 IRQ Handling + *************************************************************************/ +static void ixdp2x01_irq_mask(unsigned int irq) +{ + *IXDP2X01_INT_MASK_SET_REG = IXP2000_BOARD_IRQ_MASK(irq); +} + +static void ixdp2x01_irq_unmask(unsigned int irq) +{ + *IXDP2X01_INT_MASK_CLR_REG = IXP2000_BOARD_IRQ_MASK(irq); +} + +static u32 valid_irq_mask; + +static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + u32 ex_interrupt; + int i; + + desc->chip->mask(irq); + + ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask; + + if (!ex_interrupt) { + printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n"); + return; + } + + for (i = 0; i < IXP2000_BOARD_IRQS; i++) { + if (ex_interrupt & (1 << i)) { + struct irqdesc *cpld_desc; + int cpld_irq = IXP2000_BOARD_IRQ(0) + i; + cpld_desc = irq_desc + cpld_irq; + cpld_desc->handle(cpld_irq, cpld_desc, regs); + } + } + + desc->chip->unmask(irq); +} + +static struct irqchip ixdp2x01_irq_chip = { + .mask = ixdp2x01_irq_mask, + .ack = ixdp2x01_irq_mask, + .unmask = ixdp2x01_irq_unmask +}; + +/* + * We only do anything if we are the master NPU on the board. + * The slave NPU only has the ethernet chip going directly to + * the PCIB interrupt input. + */ +void __init ixdp2x01_init_irq(void) +{ + int irq = 0; + + /* initialize chip specific interrupts */ + ixp2000_init_irq(); + + if (machine_is_ixdp2401()) + valid_irq_mask = IXDP2401_VALID_IRQ_MASK; + else + valid_irq_mask = IXDP2801_VALID_IRQ_MASK; + + /* Mask all interrupts from CPLD, disable simulation */ + *IXDP2X01_INT_MASK_SET_REG = 0xffffffff; + *IXDP2X01_INT_SIM_REG = 0; + + for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { + if (irq & valid_irq_mask) { + set_irq_chip(irq, &ixdp2x01_irq_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } else { + set_irq_flags(irq, 0); + } + } + + /* Hook into PCI interrupts */ + set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler); +} + + +/************************************************************************* + * IXDP2x01 memory map and serial ports + *************************************************************************/ +static struct map_desc ixdp2x01_io_desc __initdata = { + .virtual = IXDP2X01_VIRT_CPLD_BASE, + .physical = IXDP2X01_PHYS_CPLD_BASE, + .length = IXDP2X01_CPLD_REGION_SIZE, + .type = MT_DEVICE +}; + +static struct uart_port ixdp2x01_serial_ports[2] = { + { + .membase = (char *)(IXDP2X01_UART1_VIRT_BASE), + .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE, + .irq = IRQ_IXDP2X01_UART1, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM32, + .regshift = 2, + .uartclk = IXDP2X01_UART_CLK, + .line = 1, + .type = PORT_16550A, + .fifosize = 16 + }, { + .membase = (char *)(IXDP2X01_UART2_VIRT_BASE), + .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE, + .irq = IRQ_IXDP2X01_UART2, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM32, + .regshift = 2, + .uartclk = IXDP2X01_UART_CLK, + .line = 2, + .type = PORT_16550A, + .fifosize = 16 + }, +}; + +static void __init ixdp2x01_map_io(void) +{ + ixp2000_map_io(); + + iotable_init(&ixdp2x01_io_desc, 1); + + early_serial_setup(&ixdp2x01_serial_ports[0]); + early_serial_setup(&ixdp2x01_serial_ports[1]); +} + + +/************************************************************************* + * IXDP2x01 timer tick configuration + *************************************************************************/ +static unsigned int ixdp2x01_clock; + +static int __init ixdp2x01_clock_setup(char *str) +{ + ixdp2x01_clock = simple_strtoul(str, NULL, 10); + + return 1; +} + +__setup("ixdp2x01_clock=", ixdp2x01_clock_setup); + +static void __init ixdp2x01_init_time(void) +{ + if (!ixdp2x01_clock) + ixdp2x01_clock = 50000000; + + ixp2000_init_time(ixdp2x01_clock); +} + +/************************************************************************* + * IXDP2x01 PCI + *************************************************************************/ +void __init ixdp2x01_pci_preinit(void) +{ + ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000); + ixp2000_pci_preinit(); +} + +#define DEVPIN(dev, pin) ((pin) | ((dev) << 3)) + +static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + u8 bus = dev->bus->number; + u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin); + struct pci_bus *tmp_bus = dev->bus; + + /* Primary bus, no interrupts here */ + if (bus == 0) { + return -1; + } + + /* Lookup first leaf in bus tree */ + while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) { + tmp_bus = tmp_bus->parent; + } + + /* Select between known bridges */ + switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) { + /* Device is located after first MB bridge */ + case 0x0008: + if (tmp_bus == dev->bus) { + /* Device is located directy after first MB bridge */ + switch (devpin) { + case DEVPIN(1, 1): /* Onboard 82546 ch 0 */ + if (machine_is_ixdp2401()) + return IRQ_IXDP2401_INTA_82546; + return -1; + case DEVPIN(1, 2): /* Onboard 82546 ch 1 */ + if (machine_is_ixdp2401()) + return IRQ_IXDP2401_INTB_82546; + return -1; + case DEVPIN(0, 1): /* PMC INTA# */ + return IRQ_IXDP2X01_SPCI_PMC_INTA; + case DEVPIN(0, 2): /* PMC INTB# */ + return IRQ_IXDP2X01_SPCI_PMC_INTB; + case DEVPIN(0, 3): /* PMC INTC# */ + return IRQ_IXDP2X01_SPCI_PMC_INTC; + case DEVPIN(0, 4): /* PMC INTD# */ + return IRQ_IXDP2X01_SPCI_PMC_INTD; + } + } + break; + case 0x0010: + if (tmp_bus == dev->bus) { + /* Device is located directy after second MB bridge */ + /* Secondary bus of second bridge */ + switch (devpin) { + case DEVPIN(0, 1): /* DB#0 */ + return IRQ_IXDP2X01_SPCI_DB_0; + case DEVPIN(1, 1): /* DB#1 */ + return IRQ_IXDP2X01_SPCI_DB_1; + } + } else { + /* Device is located indirectly after second MB bridge */ + /* Not supported now */ + } + break; + } + + return -1; +} + + +static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys) +{ + sys->mem_offset = 0xe0000000; + + if (machine_is_ixdp2801()) + sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16); + + return ixp2000_pci_setup(nr, sys); +} + +struct hw_pci ixdp2x01_pci __initdata = { + .nr_controllers = 1, + .setup = ixdp2x01_pci_setup, + .preinit = ixdp2x01_pci_preinit, + .scan = ixp2000_pci_scan_bus, + .map_irq = ixdp2x01_pci_map_irq, +}; + +int __init ixdp2x01_pci_init(void) +{ + + pci_common_init(&ixdp2x01_pci); + return 0; +} + +subsys_initcall(ixdp2x01_pci_init); + +/************************************************************************* + * IXDP2x01 Machine Intialization + *************************************************************************/ +static struct flash_platform_data ixdp2x01_flash_platform_data = { + .map_name = "cfi_probe", + .width = 1, +}; + +static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) +{ + *IXDP2X01_CPLD_FLASH_REG = + ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN); + return (ofs & IXDP2X01_FLASH_WINDOW_MASK); +} + +static struct ixp2000_flash_data ixdp2x01_flash_data = { + .platform_data = &ixdp2x01_flash_platform_data, + .bank_setup = ixdp2x01_flash_bank_setup +}; + +static struct resource ixdp2x01_flash_resource = { + .start = 0xc4000000, + .end = 0xc4000000 + 0x01ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ixdp2x01_flash = { + .name = "IXP2000-Flash", + .id = 0, + .dev = { + .platform_data = &ixdp2x01_flash_data, + }, + .num_resources = 1, + .resource = &ixdp2x01_flash_resource, +}; + +static struct platform_device *ixdp2x01_devices[] __initdata = { + &ixdp2x01_flash +}; + +static void __init ixdp2x01_init_machine(void) +{ + *IXDP2X01_CPLD_FLASH_REG = + (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN); + + ixdp2x01_flash_data.nr_banks = + ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1); + + platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices)); +} + + +#ifdef CONFIG_ARCH_IXDP2401 +MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE) + BOOT_PARAMS(0x00000100) + MAPIO(ixdp2x01_map_io) + INITIRQ(ixdp2x01_init_irq) + INITTIME(ixdp2x01_init_time) + INIT_MACHINE(ixdp2x01_init_machine) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_IXDP2801 +MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE) + BOOT_PARAMS(0x00000100) + MAPIO(ixdp2x01_map_io) + INITIRQ(ixdp2x01_init_irq) + INITTIME(ixdp2x01_init_time) + INIT_MACHINE(ixdp2x01_init_machine) +MACHINE_END +#endif + + diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c new file mode 100644 index 000000000..d08cebe00 --- /dev/null +++ b/arch/arm/mach-ixp2000/pci.c @@ -0,0 +1,233 @@ +/* + * arch/arm/mach-ixp2000/pci.c + * + * PCI routines for IXDP2400/IXDP2800 boards + * + * Original Author: Naeem Afzal + * Maintained by: Deepak Saxena + * + * Copyright 2002 Intel Corp. + * Copyright (C) 2003-2004 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static int pci_master_aborts = 0; + +static int clear_master_aborts(void); + +static u32 * +ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where) +{ + u32 *paddress; + + if (PCI_SLOT(devfn) > 7) + return 0; + + /* Must be dword aligned */ + where &= ~3; + + /* + * For top bus, generate type 0, else type 1 + */ + if (!bus_nr) { + /* only bits[23:16] are used for IDSEL */ + paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE + | (1 << (PCI_SLOT(devfn) + 16)) + | (PCI_FUNC(devfn) << 8) | where); + } else { + paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE + | (bus_nr << 16) + | (PCI_SLOT(devfn) << 11) + | (PCI_FUNC(devfn) << 8) | where); + } + + return paddress; +} + +/* + * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes. + * 0 and 3 are not valid indexes... + */ +static u32 bytemask[] = { + /*0*/ 0, + /*1*/ 0xff, + /*2*/ 0xffff, + /*3*/ 0, + /*4*/ 0xffffffff, +}; + + +int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + u32 n; + u32 *addr; + + n = where % 4; + + addr = ixp2000_pci_config_addr(bus->number, devfn, where); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + pci_master_aborts = 0; + *value = (*addr >> (8*n)) & bytemask[size]; + if (pci_master_aborts) { + pci_master_aborts = 0; + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +/* + * We don't do error checks by callling clear_master_aborts() b/c the + * assumption is that the caller did a read first to make sure a device + * exists. + */ +int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + u32 mask; + u32 *addr; + u32 temp; + + mask = ~(bytemask[size] << ((where % 0x4) * 8)); + addr = ixp2000_pci_config_addr(bus->number, devfn, where); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + temp = (u32) (value) << ((where % 0x4) * 8); + *addr = (*addr & mask) | temp; + + clear_master_aborts(); + + return PCIBIOS_SUCCESSFUL; +} + + +static struct pci_ops ixp2000_pci_ops = { + .read = ixp2000_pci_read_config, + .write = ixp2000_pci_write_config +}; + +struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata) +{ + return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata); +} + + +int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + + volatile u32 temp; + + pci_master_aborts = 1; + + cli(); + temp = *(IXP2000_PCI_CONTROL); + if (temp & ((1 << 8) | (1 << 5))) { + *(IXP2000_PCI_CONTROL) = temp; + } + + temp = *(IXP2000_PCI_CMDSTAT); + if (temp & (1 << 29)) { + while (temp & (1 << 29)) { + *(IXP2000_PCI_CMDSTAT) = temp; + temp = *(IXP2000_PCI_CMDSTAT); + } + } + sti(); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +int +clear_master_aborts(void) +{ + volatile u32 temp; + + cli(); + temp = *(IXP2000_PCI_CONTROL); + if (temp & ((1 << 8) | (1 << 5))) { + *(IXP2000_PCI_CONTROL) = temp; + } + + temp = *(IXP2000_PCI_CMDSTAT); + if (temp & (1 << 29)) { + while (temp & (1 << 29)) { + *(IXP2000_PCI_CMDSTAT) = temp; + temp = *(IXP2000_PCI_CMDSTAT); + } + } + sti(); + + return 0; +} + +void __init +ixp2000_pci_preinit(void) +{ + hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, + "PCI config cycle to non-existent device"); +} + + +/* + * IXP2000 systems often have large resource requirements, so we just + * use our own resource space. + */ +static struct resource ixp2000_pci_mem_space = { + .start = 0x00000000, + .end = 0xffffffff, + .flags = IORESOURCE_MEM, + .name = "PCI Mem Space" +}; + +static struct resource ixp2000_pci_io_space = { + .start = 0x00000000, + .end = 0xffffffff, + .flags = IORESOURCE_IO, + .name = "PCI I/O Space" +}; + +int ixp2000_pci_setup(int nr, struct pci_sys_data *sys) +{ + if (nr >= 1) + return 0; + + sys->resource[0] = &ixp2000_pci_io_space; + sys->resource[1] = &ixp2000_pci_mem_space; + sys->resource[2] = NULL; + + return 1; +} + diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index a4edbe0eb..24ffa3238 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -207,7 +207,7 @@ void __init ixp4xx_init_irq(void) static unsigned volatile last_jiffy_time; -#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC) +#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) /* IRQs are disabled before entering here from do_gettimeofday() */ static unsigned long ixp4xx_gettimeoffset(void) diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index 9e0bf6c18..bd82bebce 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -45,7 +45,6 @@ static struct platform_device smc91x_device = { .resource = smc91x_resources, }; -#if 0 static struct resource lh7a40x_usbclient_resources[] = { [0] = { .start = USB_PHYS, @@ -53,8 +52,8 @@ static struct resource lh7a40x_usbclient_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_USB, - .end = IRQ_USB, + .start = IRQ_USBINTR, + .end = IRQ_USBINTR, .flags = IORESOURCE_IRQ, }, }; @@ -62,7 +61,7 @@ static struct resource lh7a40x_usbclient_resources[] = { static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL; static struct platform_device lh7a40x_usbclient_device = { - .name = "lh7a40x-udc", + .name = "lh7a40x_udc", .id = 0, .dev = { .dma_mask = &lh7a40x_usbclient_dma_mask, @@ -71,7 +70,6 @@ static struct platform_device lh7a40x_usbclient_device = { .num_resources = ARRAY_SIZE (lh7a40x_usbclient_resources), .resource = lh7a40x_usbclient_resources, }; -#endif #if defined (CONFIG_ARCH_LH7A404) @@ -105,8 +103,7 @@ static struct platform_device lh7a404_usbhost_device = { static struct platform_device *lpd7a40x_devs[] __initdata = { &smc91x_device, -/* &lh7a40x_usbclient_device, */ - + &lh7a40x_usbclient_device, #if defined (CONFIG_ARCH_LH7A404) &lh7a404_usbhost_device, #endif diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c index 61ada24c7..f4943cacb 100644 --- a/arch/arm/mach-lh7a40x/time.c +++ b/arch/arm/mach-lh7a40x/time.c @@ -22,12 +22,12 @@ #include #if HZ < 100 -# define TIMER_CONTROL TIMER_CONTROL1 -# define TIMER_LOAD TIMER_LOAD1 +# define TIMER_CONTROL TIMER_CONTROL2 +# define TIMER_LOAD TIMER_LOAD2 # define TIMER_CONSTANT (508469/HZ) # define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC | TIMER_C_508KHZ) -# define TIMER_EOI TIMER_EOI1 -# define TIMER_IRQ IRQ_T1UI +# define TIMER_EOI TIMER_EOI2 +# define TIMER_IRQ IRQ_T2UI #else # define TIMER_CONTROL TIMER_CONTROL3 # define TIMER_LOAD TIMER_LOAD3 diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index 5fcb1e5c7..b483092dd 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -3,25 +3,29 @@ # # Common support -obj-y := common.o irq.o dma.o clocks.o mux.o bus.o gpio.o time.o +obj-y := common.o time.o irq.o dma.o clocks.o mux.o gpio.o mcbsp.o obj-m := obj-n := obj- := led-y := leds.o # Specific board support +obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o +obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o -# OCPI interconnect support for 1610 and 5912 +# OCPI interconnect support for 1710, 1610 and 5912 +obj-$(CONFIG_ARCH_OMAP1710) += ocpi.o obj-$(CONFIG_ARCH_OMAP1610) += ocpi.o obj-$(CONFIG_ARCH_OMAP5912) += ocpi.o # LEDs support +led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o -led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-perseus2.o +led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o obj-$(CONFIG_LEDS) += $(led-y) # Power Management diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c index 447046b24..03da924c7 100644 --- a/arch/arm/mach-omap/board-generic.c +++ b/arch/arm/mach-omap/board-generic.c @@ -25,9 +25,13 @@ #include #include #include +#include +#include #include "common.h" +extern void __init omap_init_time(void); + static void __init omap_generic_init_irq(void) { omap_init_irq(); @@ -36,17 +40,49 @@ static void __init omap_generic_init_irq(void) /* * Muxes the serial ports on */ +#ifdef CONFIG_ARCH_OMAP1510 static void __init omap_early_serial_init(void) { +#ifdef CONFIG_OMAP_LL_DEBUG_UART1 omap_cfg_reg(UART1_TX); omap_cfg_reg(UART1_RTS); +#endif +#ifdef CONFIG_OMAP_LL_DEBUG_UART2 omap_cfg_reg(UART2_TX); omap_cfg_reg(UART2_RTS); +#endif +#ifdef CONFIG_OMAP_LL_DEBUG_UART1 omap_cfg_reg(UART3_TX); omap_cfg_reg(UART3_RX); +#endif } +#endif + +/* assume no Mini-AB port */ + +#ifdef CONFIG_ARCH_OMAP1510 +static struct omap_usb_config generic1510_usb_config __initdata = { + .register_host = 1, + .register_dev = 1, + .hmc_mode = 16, + .pins[0] = 3, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1610 +static struct omap_usb_config generic1610_usb_config __initdata = { + .register_host = 1, + .register_dev = 1, + .hmc_mode = 16, + .pins[0] = 6, +}; +#endif + +static struct omap_board_config_kernel generic_config[] = { + { OMAP_TAG_USB, NULL }, +}; static void __init omap_generic_init(void) { @@ -55,9 +91,19 @@ static void __init omap_generic_init(void) * You have to mux them off in device drivers later on * if not needed. */ +#ifdef CONFIG_ARCH_OMAP1510 if (cpu_is_omap1510()) { omap_early_serial_init(); + generic_config[0].data = &generic1510_usb_config; } +#endif +#ifdef CONFIG_ARCH_OMAP1610 + if (!cpu_is_omap1510()) { + generic_config[0].data = &generic1610_usb_config; + } +#endif + omap_board_config = generic_config; + omap_board_config_size = ARRAY_SIZE(generic_config); } static void __init omap_generic_map_io(void) @@ -65,18 +111,12 @@ static void __init omap_generic_map_io(void) omap_map_io(); } -static void __init omap_generic_init_time(void) -{ - omap_init_time(); -} - -MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610/1710") +MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710") MAINTAINER("Tony Lindgren ") BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) BOOT_PARAMS(0x10000100) MAPIO(omap_generic_map_io) INITIRQ(omap_generic_init_irq) INIT_MACHINE(omap_generic_init) - INITTIME(omap_generic_init_time) + INITTIME(omap_init_time) MACHINE_END - diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c new file mode 100644 index 000000000..1441089d9 --- /dev/null +++ b/arch/arm/mach-omap/board-h2.c @@ -0,0 +1,115 @@ +/* + * linux/arch/arm/mach-omap/board-h2.c + * + * Board specific inits for OMAP-1610 H2 + * + * Copyright (C) 2001 RidgeRun, Inc. + * Author: Greg Lonnon + * + * Copyright (C) 2002 MontaVista Software, Inc. + * + * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 + * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen + * + * H2 specific changes and cleanup + * Copyright (C) 2004 Nokia Corporation by Imre Deak + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "common.h" + +extern void __init omap_init_time(void); + +static struct map_desc h2_io_desc[] __initdata = { +{ OMAP1610_ETHR_BASE, OMAP1610_ETHR_START, OMAP1610_ETHR_SIZE,MT_DEVICE }, +{ OMAP1610_NOR_FLASH_BASE, OMAP1610_NOR_FLASH_START, OMAP1610_NOR_FLASH_SIZE, + MT_DEVICE }, +}; + +static struct resource h2_smc91x_resources[] = { + [0] = { + .start = OMAP1610_ETHR_START, /* Physical */ + .end = OMAP1610_ETHR_START + SZ_4K, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0, /* Really GPIO 0 */ + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device h2_smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(h2_smc91x_resources), + .resource = h2_smc91x_resources, +}; + +static struct platform_device *h2_devices[] __initdata = { + &h2_smc91x_device, +}; + +void h2_init_irq(void) +{ + omap_init_irq(); +} + +static struct omap_usb_config h2_usb_config __initdata = { + /* usb1 has a Mini-AB port and external isp1301 transceiver */ + .otg = 2, + +#ifdef CONFIG_USB_GADGET_OMAP + .hmc_mode = 19, // 0:host(off) 1:dev|otg 2:disabled + // .hmc_mode = 21, // 0:host(off) 1:dev(loopback) 2:host(loopback) +#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ + .hmc_mode = 20, // 1:dev|otg(off) 1:host 2:disabled +#endif + + .pins[1] = 3, +}; + +static struct omap_board_config_kernel h2_config[] = { + { OMAP_TAG_USB, &h2_usb_config }, +}; + +static void __init h2_init(void) +{ + platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); + omap_board_config = h2_config; + omap_board_config_size = ARRAY_SIZE(h2_config); +} + +static void __init h2_map_io(void) +{ + omap_map_io(); + iotable_init(h2_io_desc, ARRAY_SIZE(h2_io_desc)); +} + +MACHINE_START(OMAP_H2, "TI-H2") + MAINTAINER("Imre Deak ") + BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) + BOOT_PARAMS(0x10000100) + MAPIO(h2_map_io) + INITIRQ(h2_init_irq) + INIT_MACHINE(h2_init) + INITTIME(omap_init_time) +MACHINE_END diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c new file mode 100644 index 000000000..d573b0cdf --- /dev/null +++ b/arch/arm/mach-omap/board-h3.c @@ -0,0 +1,90 @@ +/* + * linux/arch/arm/mach-omap/board-h3.c + * + * This file contains OMAP1710 H3 specific code. + * + * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2002 MontaVista Software, Inc. + * Copyright (C) 2001 RidgeRun, Inc. + * Author: RidgeRun, Inc. + * Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +extern void __init omap_init_time(void); + +void h3_init_irq(void) +{ + omap_init_irq(); +} + +static struct resource smc91x_resources[] = { + [0] = { + .start = OMAP1710_ETHR_START, /* Physical */ + .end = OMAP1710_ETHR_START + OMAP1710_ETHR_SIZE, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *devices[] __initdata = { + &smc91x_device, +}; + +static void __init h3_init(void) +{ + (void) platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static struct map_desc h3_io_desc[] __initdata = { +{ OMAP1710_ETHR_BASE, OMAP1710_ETHR_START, OMAP1710_ETHR_SIZE, MT_DEVICE }, +{ OMAP_NOR_FLASH_BASE, OMAP_NOR_FLASH_START, OMAP_NOR_FLASH_SIZE, MT_DEVICE }, +}; + +static void __init h3_map_io(void) +{ + omap_map_io(); + iotable_init(h3_io_desc, ARRAY_SIZE(h3_io_desc)); +} + +MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board") + MAINTAINER("Texas Instruments, Inc.") + BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) + BOOT_PARAMS(0x10000100) + MAPIO(h3_map_io) + INITIRQ(h3_init_irq) + INIT_MACHINE(h3_init) + INITTIME(omap_init_time) +MACHINE_END diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c index 6ef4d8dcf..8fd97e7af 100644 --- a/arch/arm/mach-omap/board-innovator.c +++ b/arch/arm/mach-omap/board-innovator.c @@ -29,9 +29,12 @@ #include #include #include +#include #include "common.h" +extern void __init omap_init_time(void); + #ifdef CONFIG_ARCH_OMAP1510 extern int omap_gpio_init(void); @@ -49,8 +52,8 @@ static struct resource innovator1510_smc91x_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = INT_ETHER, - .end = INT_ETHER, + .start = OMAP1510_INT_ETHER, + .end = OMAP1510_INT_ETHER, .flags = IORESOURCE_IRQ, }, }; @@ -108,11 +111,43 @@ void innovator_init_irq(void) #ifdef CONFIG_ARCH_OMAP1510 if (cpu_is_omap1510()) { omap_gpio_init(); - fpga_init_irq(); + omap1510_fpga_init_irq(); } #endif } +#ifdef CONFIG_ARCH_OMAP1510 +static struct omap_usb_config innovator1510_usb_config __initdata = { + /* has usb host and device, but no Mini-AB port */ + .register_host = 1, + .register_dev = 1, + /* Assume bad Innovator wiring; Use internal host only with custom cable */ + .hmc_mode = 16, + .pins[0] = 2, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1610 +static struct omap_usb_config h2_usb_config __initdata = { + /* usb1 has a Mini-AB port and external isp1301 transceiver */ + .otg = 2, + +#ifdef CONFIG_USB_GADGET_OMAP + .hmc_mode = 19, // 0:host(off) 1:dev|otg 2:disabled + // .hmc_mode = 21, // 0:host(off) 1:dev(loopback) 2:host(loopback) +#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ + .hmc_mode = 20, // 1:dev|otg(off) 1:host 2:disabled +#endif + + .pins[1] = 3, +}; +#endif + +static struct omap_board_config_kernel innovator_config[] = { + { OMAP_TAG_USB, NULL }, +}; + static void __init innovator_init(void) { #ifdef CONFIG_ARCH_OMAP1510 @@ -121,10 +156,21 @@ static void __init innovator_init(void) } #endif #ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { + if (!cpu_is_omap1510()) { platform_add_devices(innovator1610_devices, ARRAY_SIZE(innovator1610_devices)); } #endif + +#ifdef CONFIG_ARCH_OMAP1510 + if (cpu_is_omap1510()) + innovator_config[0].data = &innovator1510_usb_config; +#endif +#ifdef CONFIG_ARCH_OMAP1610 + if (cpu_is_omap1610()) + innovator_config[0].data = &h2_usb_config; +#endif + omap_board_config = innovator_config; + omap_board_config_size = ARRAY_SIZE(innovator_config); } static void __init innovator_map_io(void) @@ -144,7 +190,7 @@ static void __init innovator_map_io(void) } #endif #ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { + if (!cpu_is_omap1510()) { iotable_init(innovator1610_io_desc, ARRAY_SIZE(innovator1610_io_desc)); } #endif @@ -156,6 +202,6 @@ MACHINE_START(OMAP_INNOVATOR, "TI-Innovator") BOOT_PARAMS(0x10000100) MAPIO(innovator_map_io) INITIRQ(innovator_init_irq) - INITTIME(omap_init_time) INIT_MACHINE(innovator_init) + INITTIME(omap_init_time) MACHINE_END diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c index 16ecd6be5..85d9a0ac3 100644 --- a/arch/arm/mach-omap/board-osk.c +++ b/arch/arm/mach-omap/board-osk.c @@ -41,6 +41,8 @@ #include "common.h" +extern void __init omap_init_time(void); + static struct map_desc osk5912_io_desc[] __initdata = { { OMAP_OSK_ETHR_BASE, OMAP_OSK_ETHR_START, OMAP_OSK_ETHR_SIZE,MT_DEVICE }, { OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE, @@ -94,6 +96,6 @@ MACHINE_START(OMAP_OSK, "TI-OSK") BOOT_PARAMS(0x10000100) MAPIO(osk_map_io) INITIRQ(osk_init_irq) - INITTIME(omap_init_time) INIT_MACHINE(osk_init) + INITTIME(omap_init_time) MACHINE_END diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c index 8015d10fc..95833f3b9 100644 --- a/arch/arm/mach-omap/board-perseus2.c +++ b/arch/arm/mach-omap/board-perseus2.c @@ -23,9 +23,12 @@ #include #include #include +#include #include "common.h" +extern void __init omap_init_time(void); + void omap_perseus2_init_irq(void) { omap_init_irq(); @@ -33,14 +36,14 @@ void omap_perseus2_init_irq(void) static struct resource smc91x_resources[] = { [0] = { - .start = OMAP730_FPGA_ETHR_START, /* Physical */ - .end = OMAP730_FPGA_ETHR_START + SZ_4K, + .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ + .end = H2P2_DBG_FPGA_ETHR_START + SZ_4K, .flags = IORESOURCE_MEM, }, [1] = { - .start = 0, + .start = INT_730_MPU_EXT_NIRQ, .end = 0, - .flags = INT_ETHER, + .flags = IORESOURCE_IRQ, }, }; @@ -62,7 +65,7 @@ static void __init omap_perseus2_init(void) /* Only FPGA needs to be mapped here. All others are done with ioremap */ static struct map_desc omap_perseus2_io_desc[] __initdata = { - {OMAP730_FPGA_BASE, OMAP730_FPGA_START, OMAP730_FPGA_SIZE, + {H2P2_DBG_FPGA_BASE, H2P2_DBG_FPGA_START, H2P2_DBG_FPGA_SIZE, MT_DEVICE}, }; @@ -111,6 +114,6 @@ MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") BOOT_PARAMS(0x10000100) MAPIO(omap_perseus2_map_io) INITIRQ(omap_perseus2_init_irq) - INITTIME(omap_init_time) INIT_MACHINE(omap_perseus2_init) + INITTIME(omap_init_time) MACHINE_END diff --git a/arch/arm/mach-omap/clocks.c b/arch/arm/mach-omap/clocks.c index bda7c6f38..b50785659 100644 --- a/arch/arm/mach-omap/clocks.c +++ b/arch/arm/mach-omap/clocks.c @@ -36,6 +36,8 @@ #include #include +extern void start_mputimer1(unsigned long load_val); + /* Input clock in MHz */ static unsigned int source_clock = 12; @@ -239,7 +241,7 @@ int ck_auto_unclock = 1; int ck_debug = 0; #define CK_MAX_PLL_FREQ OMAP_CK_MAX_RATE -static __u8 ck_valid_table[CK_MAX_PLL_FREQ / 8 + 1]; +static __u32 ck_valid_table[CK_MAX_PLL_FREQ / 32 + 1]; static __u8 ck_lookup_table[CK_MAX_PLL_FREQ]; int @@ -615,11 +617,11 @@ __ck_make_lookup_table(void) int __init init_ck(void) { - const struct omap_clock_info *info; + const struct omap_clock_config *info; int crystal_type = 0; /* Default 12 MHz */ __ck_make_lookup_table(); - info = omap_get_per_info(OMAP_TAG_CLOCK, struct omap_clock_info); + info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); if (info != NULL) { if (!cpu_is_omap1510()) crystal_type = info->system_clock_type; @@ -645,7 +647,8 @@ init_ck(void) #elif defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730) omap_writew(0x250E, ARM_CKCTL); omap_writew(0x2710, DPLL_CTL); -#elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)) +#elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \ + || defined(CONFIG_ARCH_OMAP1710)) omap_writew(0x150f, ARM_CKCTL); if (crystal_type == 2) { source_clock = 13; /* MHz */ diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c index 43aaa1c6c..17d82a7f3 100644 --- a/arch/arm/mach-omap/common.c +++ b/arch/arm/mach-omap/common.c @@ -104,7 +104,7 @@ static struct map_desc omap1510_io_desc[] __initdata = { }; #endif -#ifdef CONFIG_ARCH_OMAP1610 +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) static struct map_desc omap1610_io_desc[] __initdata = { { OMAP1610_DSP_BASE, OMAP1610_DSP_START, OMAP1610_DSP_SIZE, MT_DEVICE }, { OMAP1610_DSPREG_BASE, OMAP1610_DSPREG_START, OMAP1610_DSPREG_SIZE, MT_DEVICE }, @@ -147,8 +147,8 @@ static void __init _omap_map_io(void) iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); } #endif -#ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap1710()) { iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc)); } #endif @@ -181,13 +181,18 @@ void omap_map_io(void) extern int omap_bootloader_tag_len; extern u8 omap_bootloader_tag[]; -const void *__omap_get_per_info(u16 tag, size_t len) +struct omap_board_config_kernel *omap_board_config; +int omap_board_config_size = 0; + +const void *__omap_get_config(u16 tag, size_t len) { - struct omap_board_info_entry *info = NULL; + struct omap_board_config_entry *info = NULL; + struct omap_board_config_kernel *kinfo = NULL; + int i; #ifdef CONFIG_OMAP_BOOT_TAG if (omap_bootloader_tag_len > 4) - info = (struct omap_board_info_entry *) omap_bootloader_tag; + info = (struct omap_board_config_entry *) omap_bootloader_tag; while (info != NULL) { u8 *next; @@ -198,26 +203,38 @@ const void *__omap_get_per_info(u16 tag, size_t len) if (next >= omap_bootloader_tag + omap_bootloader_tag_len) info = NULL; else - info = (struct omap_board_info_entry *) next; + info = (struct omap_board_config_entry *) next; + } + if (info != NULL) { + /* Check the length as a lame attempt to check for + * binary inconsistancy. */ + if (info->len != len) { + printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n", + tag, len, info->len); + return NULL; + } + return info->data; } #endif - if (info == NULL) - return NULL; - if (info->len != len) { - printk(KERN_ERR "OMAP per_info: Length mismatch with tag %x (want %d, got %d)\n", - tag, len, info->len); - return NULL; + /* Try to find the config from the board-specific structures + * in the kernel. */ + for (i = 0; i < omap_board_config_size; i++) { + if (omap_board_config[i].tag == tag) { + kinfo = &omap_board_config[i]; + break; + } } - - return info->data; + if (kinfo == NULL) + return NULL; + return kinfo->data; } -EXPORT_SYMBOL(__omap_get_per_info); +EXPORT_SYMBOL(__omap_get_config); static int __init omap_add_serial_console(void) { - const struct omap_uart_info *info; + const struct omap_uart_config *info; - info = omap_get_per_info(OMAP_TAG_UART, struct omap_uart_info); + info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); if (info != NULL && info->console_uart) { static char speed[11], *opt = NULL; diff --git a/arch/arm/mach-omap/common.h b/arch/arm/mach-omap/common.h index 96dcb3c53..1cc559dd2 100644 --- a/arch/arm/mach-omap/common.h +++ b/arch/arm/mach-omap/common.h @@ -28,7 +28,6 @@ #define __ARCH_ARM_MACH_OMAP_COMMON_H extern void omap_map_io(void); -extern void omap_init_time(void); #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c index 385b4d1cc..cfb23d894 100644 --- a/arch/arm/mach-omap/dma.c +++ b/arch/arm/mach-omap/dma.c @@ -118,7 +118,7 @@ void omap_set_dma_constant_fill(int lch, u32 color) u16 w; #ifdef CONFIG_DEBUG_KERNEL - if (omap_dma_in_1510_mode) { + if (omap_dma_in_1510_mode()) { printk(KERN_ERR "OMAP DMA constant fill not available in 1510 mode."); BUG(); return; @@ -141,7 +141,7 @@ void omap_set_dma_transparent_copy(int lch, u32 color) u16 w; #ifdef CONFIG_DEBUG_KERNEL - if (omap_dma_in_1510_mode) { + if (omap_dma_in_1510_mode()) { printk(KERN_ERR "OMAP DMA transparent copy not available in 1510 mode."); BUG(); } @@ -266,46 +266,78 @@ void omap_set_dma_dest_burst_mode(int lch, int burst_mode) omap_writew(w, OMAP_DMA_CSDP(lch)); } -void omap_start_dma(int lch) +static inline void init_intr(int lch) { u16 w; - if (!omap_dma_in_1510_mode()) { - int next_lch; - - next_lch = dma_chan[lch].next_lch; - - /* Enable the queue, if needed so. */ - if (next_lch != -1) { - /* Clear the STOP_LNK bits */ - w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); - w &= ~(1 << 14); - omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); - w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch)); - w &= ~(1 << 14); - omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch)); - - /* And set the ENABLE_LNK bits */ - omap_writew(next_lch | (1 << 15), - OMAP_DMA_CLNK_CTRL(lch)); - /* The loop case */ - if (dma_chan[next_lch].next_lch == lch) - omap_writew(lch | (1 << 15), - OMAP_DMA_CLNK_CTRL(next_lch)); - - /* Read CSR to make sure it's cleared. */ - w = omap_readw(OMAP_DMA_CSR(next_lch)); - /* Enable some nice interrupts. */ - omap_writew(dma_chan[next_lch].enabled_irqs, - OMAP_DMA_CICR(next_lch)); - dma_chan[next_lch].flags |= OMAP_DMA_ACTIVE; - } - } - /* Read CSR to make sure it's cleared. */ w = omap_readw(OMAP_DMA_CSR(lch)); /* Enable some nice interrupts. */ omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch)); + dma_chan[lch].flags |= OMAP_DMA_ACTIVE; +} + +static inline void enable_lnk(int lch) +{ + u16 w; + + /* Clear the STOP_LNK bits */ + w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); + w &= ~(1 << 14); + omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); + + /* And set the ENABLE_LNK bits */ + if (dma_chan[lch].next_lch != -1) + omap_writew(dma_chan[lch].next_lch | (1 << 15), + OMAP_DMA_CLNK_CTRL(lch)); +} + +static inline void disable_lnk(int lch) +{ + u16 w; + + /* Disable interrupts */ + omap_writew(0, OMAP_DMA_CICR(lch)); + + /* Set the STOP_LNK bit */ + w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); + w |= (1 << 14); + w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); + + dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; +} + +void omap_start_dma(int lch) +{ + u16 w; + + if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { + int next_lch, cur_lch; + char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; + + dma_chan_link_map[lch] = 1; + /* Set the link register of the first channel */ + enable_lnk(lch); + + memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map)); + cur_lch = dma_chan[lch].next_lch; + do { + next_lch = dma_chan[cur_lch].next_lch; + + /* The loop case: we've been here already */ + if (dma_chan_link_map[cur_lch]) + break; + /* Mark the current channel */ + dma_chan_link_map[cur_lch] = 1; + + enable_lnk(cur_lch); + init_intr(cur_lch); + + cur_lch = next_lch; + } while (next_lch != -1); + } + + init_intr(lch); w = omap_readw(OMAP_DMA_CCR(lch)); w |= OMAP_DMA_CCR_EN; @@ -316,37 +348,34 @@ void omap_start_dma(int lch) void omap_stop_dma(int lch) { u16 w; - int next_lch; - /* Disable all interrupts on the channel */ - omap_writew(0, OMAP_DMA_CICR(lch)); + if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { + int next_lch, cur_lch = lch; + char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; - if (omap_dma_in_1510_mode()) { - w = omap_readw(OMAP_DMA_CCR(lch)); - w &= ~OMAP_DMA_CCR_EN; - omap_writew(w, OMAP_DMA_CCR(lch)); - dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; - return; - } + memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map)); + do { + /* The loop case: we've been here already */ + if (dma_chan_link_map[cur_lch]) + break; + /* Mark the current channel */ + dma_chan_link_map[cur_lch] = 1; - next_lch = dma_chan[lch].next_lch; + disable_lnk(cur_lch); - /* - * According to thw HW spec, enabling the STOP_LNK bit - * resets the CCR_EN bit at the same time. - */ - w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); - w |= (1 << 14); - w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); - dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; + next_lch = dma_chan[cur_lch].next_lch; + cur_lch = next_lch; + } while (next_lch != -1); - if (next_lch != -1) { - omap_writew(0, OMAP_DMA_CICR(next_lch)); - w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch)); - w |= (1 << 14); - w = omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch)); - dma_chan[next_lch].flags &= ~OMAP_DMA_ACTIVE; + return; } + /* Disable all interrupts on the channel */ + omap_writew(0, OMAP_DMA_CICR(lch)); + + w = omap_readw(OMAP_DMA_CCR(lch)); + w &= ~OMAP_DMA_CCR_EN; + omap_writew(w, OMAP_DMA_CCR(lch)); + dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; } void omap_enable_dma_irq(int lch, u16 bits) @@ -445,7 +474,7 @@ int omap_request_dma(int dev_id, const char *dev_name, chan->data = data; chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; - if (cpu_is_omap1610() || cpu_is_omap5912()) { + if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) { /* If the sync device is set, configure it dynamically. */ if (dev_id != 0) { set_gdma_dev(free_ch + 1, dev_id); @@ -533,7 +562,6 @@ void omap_dma_unlink_lch (int lch_head, int lch_queue) } dma_chan[lch_head].next_lch = -1; - dma_chan[lch_queue].next_lch = -1; } @@ -713,7 +741,7 @@ static int __init omap_init_dma(void) printk(KERN_INFO "DMA support for OMAP1510 initialized\n"); dma_chan_count = 9; enable_1510_mode = 1; - } else if (cpu_is_omap1610() || cpu_is_omap5912()) { + } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) { printk(KERN_INFO "OMAP DMA hardware version %d\n", omap_readw(OMAP_DMA_HW_ID)); printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", @@ -771,6 +799,8 @@ EXPORT_SYMBOL(omap_request_dma); EXPORT_SYMBOL(omap_free_dma); EXPORT_SYMBOL(omap_start_dma); EXPORT_SYMBOL(omap_stop_dma); +EXPORT_SYMBOL(omap_enable_dma_irq); +EXPORT_SYMBOL(omap_disable_dma_irq); EXPORT_SYMBOL(omap_set_dma_transfer_params); EXPORT_SYMBOL(omap_set_dma_constant_fill); diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c index d9246b1dc..f0ce5c12a 100644 --- a/arch/arm/mach-omap/fpga.c +++ b/arch/arm/mach-omap/fpga.c @@ -31,19 +31,9 @@ #include #include -unsigned char fpga_read(int reg) -{ - return __raw_readb(reg); -} - -void fpga_write(unsigned char val, int reg) -{ - __raw_writeb(val, reg); -} - static void fpga_mask_irq(unsigned int irq) { - irq -= IH_FPGA_BASE; + irq -= OMAP1510_IH_FPGA_BASE; if (irq < 8) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) @@ -76,7 +66,7 @@ static void fpga_ack_irq(unsigned int irq) static void fpga_unmask_irq(unsigned int irq) { - irq -= IH_FPGA_BASE; + irq -= OMAP1510_IH_FPGA_BASE; if (irq < 8) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)), @@ -114,8 +104,8 @@ void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc, break; } - for (fpga_irq = IH_FPGA_BASE; - (fpga_irq < (IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; + for (fpga_irq = OMAP1510_IH_FPGA_BASE; + (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; fpga_irq++, stat >>= 1) { if (stat & 1) { d = irq_desc + fpga_irq; @@ -162,7 +152,7 @@ static struct irqchip omap_fpga_irq = { * interrupts at the interrupt controller via disable_irq/enable_irq * could pose a problem. */ -void fpga_init_irq(void) +void omap1510_fpga_init_irq(void) { int i; @@ -170,9 +160,9 @@ void fpga_init_irq(void) __raw_writeb(0, OMAP1510_FPGA_IMR_HI); __raw_writeb(0, INNOVATOR_FPGA_IMR2); - for (i = IH_FPGA_BASE; i < (IH_FPGA_BASE + NR_FPGA_IRQS); i++) { + for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) { - if (i == INT_FPGA_TS) { + if (i == OMAP1510_INT_FPGA_TS) { /* * The touchscreen interrupt is level-sensitive, so * we'll use the regular mask_ack routine for it. @@ -201,9 +191,7 @@ void fpga_init_irq(void) omap_request_gpio(13); omap_set_gpio_direction(13, 1); omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); - set_irq_chained_handler(INT_FPGA, innovator_fpga_IRQ_demux); + set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); } -EXPORT_SYMBOL(fpga_init_irq); -EXPORT_SYMBOL(fpga_read); -EXPORT_SYMBOL(fpga_write); +EXPORT_SYMBOL(omap1510_fpga_init_irq); diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c index 2f052a959..206bee968 100644 --- a/arch/arm/mach-omap/gpio.c +++ b/arch/arm/mach-omap/gpio.c @@ -94,7 +94,7 @@ struct gpio_bank { #define METHOD_GPIO_1610 2 #define METHOD_GPIO_730 3 -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) static struct gpio_bank gpio_bank_1610[5] = { { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO}, { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 }, @@ -113,7 +113,7 @@ static struct gpio_bank gpio_bank_1510[2] = { #ifdef CONFIG_ARCH_OMAP730 static struct gpio_bank gpio_bank_730[7] = { - { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, + { OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, { OMAP730_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 }, { OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 }, { OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 }, @@ -135,8 +135,8 @@ static inline struct gpio_bank *get_gpio_bank(int gpio) return &gpio_bank[1]; } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if (cpu_is_omap1610() || cpu_is_omap5912()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) + if (cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1 + (gpio >> 4)]; @@ -172,8 +172,8 @@ static inline int gpio_valid(int gpio) if (cpu_is_omap1510() && gpio < 16) return 0; #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if ((cpu_is_omap1610() || cpu_is_omap5912()) && gpio < 64) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) + if ((cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) && gpio < 64) return 0; #endif #ifdef CONFIG_ARCH_OMAP730 @@ -554,7 +554,7 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, if (bank->method == METHOD_GPIO_1510) isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1; #endif @@ -588,7 +588,7 @@ static void gpio_ack_irq(unsigned int irq) if (bank->method == METHOD_GPIO_1510) __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS); #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1); #endif @@ -629,7 +629,7 @@ static void mpuio_mask_irq(unsigned int irq) unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, gpio, 0); + _set_gpio_irqenable(bank, get_gpio_index(gpio), 0); } static void mpuio_unmask_irq(unsigned int irq) @@ -637,7 +637,7 @@ static void mpuio_unmask_irq(unsigned int irq) unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, gpio, 1); + _set_gpio_irqenable(bank, get_gpio_index(gpio), 1); } static struct irqchip gpio_irq_chip = { @@ -668,8 +668,8 @@ static int __init _omap_gpio_init(void) gpio_bank = gpio_bank_1510; } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if (cpu_is_omap1610() || cpu_is_omap5912()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) + if (cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) { int rev; gpio_bank_count = 5; @@ -702,7 +702,7 @@ static int __init _omap_gpio_init(void) __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) { __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); @@ -731,7 +731,7 @@ static int __init _omap_gpio_init(void) /* Enable system clock for GPIO module. * The CAM_CLK_CTRL *is* really the right place. */ - if (cpu_is_omap1610()) + if (cpu_is_omap1610() || cpu_is_omap1710()) omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); return 0; diff --git a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap/irq.c index 18da117f6..3eec2986b 100644 --- a/arch/arm/mach-omap/irq.c +++ b/arch/arm/mach-omap/irq.c @@ -140,7 +140,9 @@ static struct omap_irq_bank omap1510_irq_banks[] = { }; #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \ + || defined(CONFIG_ARCH_OMAP1710) + static struct omap_irq_bank omap1610_irq_banks[] = { { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfffff7ff }, @@ -171,8 +173,9 @@ void __init omap_init_irq(void) irq_bank_count = ARRAY_SIZE(omap1510_irq_banks); } #endif -#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) - if (cpu_is_omap1610() || cpu_is_omap5912()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \ + || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) { irq_banks = omap1610_irq_banks; irq_bank_count = ARRAY_SIZE(omap1610_irq_banks); } @@ -190,6 +193,11 @@ void __init omap_init_irq(void) irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET); irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET); + /* Enable interrupts in global mask */ + if (cpu_is_omap730()) { + irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET); + } + /* Install the interrupt handlers for each bank */ for (i = 0; i < irq_bank_count; i++) { for (j = i * 32; j < (i + 1) * 32; j++) { @@ -205,5 +213,9 @@ void __init omap_init_irq(void) } /* Unmask level 2 handler */ - omap_unmask_irq(INT_IH2_IRQ); + if (cpu_is_omap730()) { + omap_unmask_irq(INT_730_IH2_IRQ); + } else { + omap_unmask_irq(INT_IH2_IRQ); + } } diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c new file mode 100644 index 000000000..8ff27af0b --- /dev/null +++ b/arch/arm/mach-omap/leds-h2p2-debug.c @@ -0,0 +1,104 @@ +/* + * linux/arch/arm/mach-omap/leds-h2p2-debug.c + * + * Copyright 2003 by Texas Instruments Incorporated + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "leds.h" + +void h2p2_dbg_leds_event(led_event_t evt) +{ + unsigned long flags; + static unsigned long hw_led_state = 0; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state |= H2P2_DBG_FPGA_LED_STARTSTOP; + break; + + case led_stop: + hw_led_state &= ~H2P2_DBG_FPGA_LED_STARTSTOP; + break; + + case led_claim: + hw_led_state |= H2P2_DBG_FPGA_LED_CLAIMRELEASE; + break; + + case led_release: + hw_led_state &= ~H2P2_DBG_FPGA_LED_CLAIMRELEASE; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + /* + * Toggle Timer LED + */ + if (hw_led_state & H2P2_DBG_FPGA_LED_TIMER) + hw_led_state &= ~H2P2_DBG_FPGA_LED_TIMER; + else + hw_led_state |= H2P2_DBG_FPGA_LED_TIMER; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + hw_led_state |= H2P2_DBG_FPGA_LED_IDLE; + break; + + case led_idle_end: + hw_led_state &= ~H2P2_DBG_FPGA_LED_IDLE; + break; +#endif + + case led_halted: + if (hw_led_state & H2P2_DBG_FPGA_LED_HALTED) + hw_led_state &= ~H2P2_DBG_FPGA_LED_HALTED; + else + hw_led_state |= H2P2_DBG_FPGA_LED_HALTED; + break; + + case led_green_on: + break; + + case led_green_off: + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + break; + + case led_red_off: + break; + + default: + break; + } + + + /* + * Actually burn the LEDs + */ + __raw_writew(~hw_led_state & 0xffff, H2P2_DBG_FPGA_LEDS); + + local_irq_restore(flags); +} diff --git a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap/leds.c index e3f378b4a..b6d0c7203 100644 --- a/arch/arm/mach-omap/leds.c +++ b/arch/arm/mach-omap/leds.c @@ -3,6 +3,7 @@ * * OMAP LEDs dispatcher */ +#include #include #include @@ -11,17 +12,17 @@ #include "leds.h" static int __init -omap1510_leds_init(void) +omap_leds_init(void) { if (machine_is_omap_innovator()) leds_event = innovator_leds_event; - else if (machine_is_omap_perseus2()) { - leds_event = perseus2_leds_event; + else if (machine_is_omap_h2() || machine_is_omap_perseus2()) { + leds_event = h2p2_dbg_leds_event; } leds_event(led_start); return 0; } -__initcall(omap1510_leds_init); +__initcall(omap_leds_init); diff --git a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap/leds.h index ba2eb59d1..7571e2d63 100644 --- a/arch/arm/mach-omap/leds.h +++ b/arch/arm/mach-omap/leds.h @@ -1,2 +1,2 @@ extern void innovator_leds_event(led_event_t evt); -extern void perseus2_leds_event(led_event_t evt); +extern void h2p2_dbg_leds_event(led_event_t evt); diff --git a/arch/arm/mach-omap/mcbsp.c b/arch/arm/mach-omap/mcbsp.c new file mode 100644 index 000000000..d334395f1 --- /dev/null +++ b/arch/arm/mach-omap/mcbsp.c @@ -0,0 +1,669 @@ +/* + * linux/arch/arm/omap/mcbsp.c + * + * Copyright (C) 2004 Nokia Corporation + * Author: Samuel Ortiz + * + * + * 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. + * + * Multichannel mode not supported. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_MCBSP_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) do { } while (0) +#endif + +struct omap_mcbsp { + u32 io_base; + u8 id; + u8 free; + omap_mcbsp_word_length rx_word_length; + omap_mcbsp_word_length tx_word_length; + + /* IRQ based TX/RX */ + int rx_irq; + int tx_irq; + + /* DMA stuff */ + u8 dma_rx_sync; + short dma_rx_lch; + u8 dma_tx_sync; + short dma_tx_lch; + + /* Completion queues */ + struct completion tx_irq_completion; + struct completion rx_irq_completion; + struct completion tx_dma_completion; + struct completion rx_dma_completion; + + spinlock_t lock; +}; + +static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; + + +static void omap_mcbsp_dump_reg(u8 id) +{ + DBG("**** MCBSP%d regs ****\n", mcbsp[id].id); + DBG("DRR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2)); + DBG("DRR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1)); + DBG("DXR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2)); + DBG("DXR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1)); + DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2)); + DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1)); + DBG("RCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2)); + DBG("RCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1)); + DBG("XCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2)); + DBG("XCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1)); + DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2)); + DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1)); + DBG("PCR0: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0)); + DBG("***********************\n"); +} + + +static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); + + DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2)); + + complete(&mcbsp_tx->tx_irq_completion); + return IRQ_HANDLED; +} + +static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id); + + DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2)); + + complete(&mcbsp_rx->rx_irq_completion); + return IRQ_HANDLED; +} + + +static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data); + + DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2)); + + /* We can free the channels */ + omap_free_dma(mcbsp_dma_tx->dma_tx_lch); + mcbsp_dma_tx->dma_tx_lch = -1; + + complete(&mcbsp_dma_tx->tx_dma_completion); +} + +static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data); + + DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2)); + + /* We can free the channels */ + omap_free_dma(mcbsp_dma_rx->dma_rx_lch); + mcbsp_dma_rx->dma_rx_lch = -1; + + complete(&mcbsp_dma_rx->rx_dma_completion); +} + + +/* + * omap_mcbsp_config simply write a config to the + * appropriate McBSP. + * You either call this function or set the McBSP registers + * by yourself before calling omap_mcbsp_start(). + */ + +void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config) +{ + u32 io_base = mcbsp[id].io_base; + + DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base); + + /* We write the given config */ + OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2); + OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1); + OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2); + OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1); + OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2); + OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1); + OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2); + OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1); + OMAP_MCBSP_WRITE(io_base, SRGR2, config->mcr2); + OMAP_MCBSP_WRITE(io_base, SRGR1, config->mcr1); + OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0); +} + + + +static int omap_mcbsp_check(unsigned int id) +{ + if (cpu_is_omap730()) { + if (id > OMAP_MAX_MCBSP_COUNT - 1) { + printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); + return -1; + } + return 0; + } + + if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { + if (id > OMAP_MAX_MCBSP_COUNT) { + printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); + return -1; + } + return 0; + } + + return -1; +} + +#define DSP_RSTCT2 0xe1008014 + +static void omap_mcbsp_dsp_request(void) +{ + if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { + omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)), + ARM_RSTCT1); + omap_writew((omap_readw(ARM_CKCTL) | 1 << EN_DSPCK), + ARM_CKCTL); + omap_writew((omap_readw(ARM_IDLECT2) | (1 << EN_APICK)), + ARM_IDLECT2); + + /* enable 12MHz clock to mcbsp 1 & 3 */ + __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK), + DSP_IDLECT2); + __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1, + DSP_RSTCT2); + } +} + +static void omap_mcbsp_dsp_free(void) +{ + /* Useless for now */ +} + + +int omap_mcbsp_request(unsigned int id) +{ + int err; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + /* + * On 1510, 1610 and 1710, McBSP1 and McBSP3 + * are DSP public peripherals. + */ + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_request(); + + spin_lock(&mcbsp[id].lock); + if (!mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return -1; + } + + mcbsp[id].free = 0; + spin_unlock(&mcbsp[id].lock); + + /* We need to get IRQs here */ + err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", + mcbsp[id].tx_irq, mcbsp[id].id); + return err; + } + + init_completion(&(mcbsp[id].tx_irq_completion)); + + + err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", + mcbsp[id].rx_irq, mcbsp[id].id); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + return err; + } + + init_completion(&(mcbsp[id].rx_irq_completion)); + return 0; + +} + +void omap_mcbsp_free(unsigned int id) +{ + if (omap_mcbsp_check(id) < 0) + return; + + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_free(); + + spin_lock(&mcbsp[id].lock); + if (mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return; + } + + mcbsp[id].free = 1; + spin_unlock(&mcbsp[id].lock); + + /* Free IRQs */ + free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); +} + +/* + * Here we start the McBSP, by enabling the sample + * generator, both transmitter and receivers, + * and the frame sync. + */ +void omap_mcbsp_start(unsigned int id) +{ + u32 io_base; + u16 w; + + if (omap_mcbsp_check(id) < 0) + return; + + io_base = mcbsp[id].io_base; + + mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7); + mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7); + + /* Start the sample generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); + + /* Enable transmitter and receiver */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); + + w = OMAP_MCBSP_READ(io_base, SPCR1); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); + + udelay(100); + + /* Start frame sync */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); + + /* Dump McBSP Regs */ + omap_mcbsp_dump_reg(id); + +} + +void omap_mcbsp_stop(unsigned int id) +{ + u32 io_base; + u16 w; + + if (omap_mcbsp_check(id) < 0) + return; + + io_base = mcbsp[id].io_base; + + /* Reset transmitter */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); + + /* Reset receiver */ + w = OMAP_MCBSP_READ(io_base, SPCR1); + OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); + + /* Reset the sample rate generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); +} + + +/* + * IRQ based word transmission. + */ +void omap_mcbsp_xmit_word(unsigned int id, u32 word) +{ + u32 io_base; + omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length; + + if (omap_mcbsp_check(id) < 0) + return; + + io_base = mcbsp[id].io_base; + + wait_for_completion(&(mcbsp[id].tx_irq_completion)); + + if (word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); +} + +u32 omap_mcbsp_recv_word(unsigned int id) +{ + u32 io_base; + u16 word_lsb, word_msb = 0; + omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + io_base = mcbsp[id].io_base; + + wait_for_completion(&(mcbsp[id].rx_irq_completion)); + + if (word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + return (word_lsb | (word_msb << 16)); +} + + +/* + * Simple DMA based buffer rx/tx routines. + * Nothing fancy, just a single buffer tx/rx through DMA. + * The DMA resources are released once the transfer is done. + * For anything fancier, you should use your own customized DMA + * routines and callbacks. + */ +int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) +{ + int dma_tx_ch; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback, + &mcbsp[id], + &dma_tx_ch)) { + printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1); + return -EAGAIN; + } + mcbsp[id].dma_tx_lch = dma_tx_ch; + + DBG("TX DMA on channel %d\n", dma_tx_ch); + + init_completion(&(mcbsp[id].tx_dma_completion)); + + omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, + OMAP_DMA_DATA_TYPE_S16, + length >> 1, 1, + OMAP_DMA_SYNC_ELEMENT); + + omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1); + + omap_set_dma_src_params(mcbsp[id].dma_tx_lch, + OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + buffer); + + omap_start_dma(mcbsp[id].dma_tx_lch); + wait_for_completion(&(mcbsp[id].tx_dma_completion)); + return 0; +} + + +int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) +{ + int dma_rx_ch; + + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback, + &mcbsp[id], + &dma_rx_ch)) { + printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1); + return -EAGAIN; + } + mcbsp[id].dma_rx_lch = dma_rx_ch; + + DBG("RX DMA on channel %d\n", dma_rx_ch); + + init_completion(&(mcbsp[id].rx_dma_completion)); + + omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, + OMAP_DMA_DATA_TYPE_S16, + length >> 1, 1, + OMAP_DMA_SYNC_ELEMENT); + + omap_set_dma_src_params(mcbsp[id].dma_rx_lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1); + + omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, + OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + buffer); + + omap_start_dma(mcbsp[id].dma_rx_lch); + wait_for_completion(&(mcbsp[id].rx_dma_completion)); + return 0; +} + + +/* + * SPI wrapper. + * Since SPI setup is much simpler than the generic McBSP one, + * this wrapper just need an omap_mcbsp_spi_cfg structure as an input. + * Once this is done, you can call omap_mcbsp_start(). + */ +void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg) +{ + struct omap_mcbsp_reg_cfg mcbsp_cfg; + + if (omap_mcbsp_check(id) < 0) + return; + + memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg)); + + /* SPI has only one frame */ + mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0)); + mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0)); + + /* Clock stop mode */ + if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY) + mcbsp_cfg.spcr1 |= (1 << 12); + else + mcbsp_cfg.spcr1 |= (3 << 11); + + /* Set clock parities */ + if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING) + mcbsp_cfg.pcr0 |= CLKRP; + else + mcbsp_cfg.pcr0 &= ~CLKRP; + + if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING) + mcbsp_cfg.pcr0 &= ~CLKXP; + else + mcbsp_cfg.pcr0 |= CLKXP; + + /* Set SCLKME to 0 and CLKSM to 1 */ + mcbsp_cfg.pcr0 &= ~SCLKME; + mcbsp_cfg.srgr2 |= CLKSM; + + /* Set FSXP */ + if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH) + mcbsp_cfg.pcr0 &= ~FSXP; + else + mcbsp_cfg.pcr0 |= FSXP; + + if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) { + mcbsp_cfg.pcr0 |= CLKXM; + mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1); + mcbsp_cfg.pcr0 |= FSXM; + mcbsp_cfg.srgr2 &= ~FSGM; + mcbsp_cfg.xcr2 |= XDATDLY(1); + mcbsp_cfg.rcr2 |= RDATDLY(1); + } + else { + mcbsp_cfg.pcr0 &= ~CLKXM; + mcbsp_cfg.srgr1 |= CLKGDV(1); + mcbsp_cfg.pcr0 &= ~FSXM; + mcbsp_cfg.xcr2 &= ~XDATDLY(3); + mcbsp_cfg.rcr2 &= ~RDATDLY(3); + } + + mcbsp_cfg.xcr2 &= ~XPHASE; + mcbsp_cfg.rcr2 &= ~RPHASE; + + omap_mcbsp_config(id, &mcbsp_cfg); +} + + +/* + * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. + * 730 has only 2 McBSP, and both of them are MPU peripherals. + */ +struct omap_mcbsp_info { + u32 virt_base; + u8 dma_rx_sync, dma_tx_sync; + u16 rx_irq, tx_irq; +}; + +#ifdef CONFIG_ARCH_OMAP730 +static const struct omap_mcbsp_info mcbsp_730[] = { + [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP_DMA_MCBSP1_TX, + .rx_irq = INT_730_McBSP1RX, + .tx_irq = INT_730_McBSP1TX }, + [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP_DMA_MCBSP3_TX, + .rx_irq = INT_730_McBSP2RX, + .tx_irq = INT_730_McBSP2TX }, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1510 +static const struct omap_mcbsp_info mcbsp_1510[] = { + [0] = { .virt_base = OMAP1510_MCBSP1_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP_DMA_MCBSP1_TX, + .rx_irq = INT_McBSP1RX, + .tx_irq = INT_McBSP1TX }, + [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP_DMA_MCBSP2_TX, + .rx_irq = INT_1510_SPI_RX, + .tx_irq = INT_1510_SPI_TX }, + [2] = { .virt_base = OMAP1510_MCBSP3_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP_DMA_MCBSP3_TX, + .rx_irq = INT_McBSP3RX, + .tx_irq = INT_McBSP3TX }, +}; +#endif + +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) +static const struct omap_mcbsp_info mcbsp_1610[] = { + [0] = { .virt_base = OMAP1610_MCBSP1_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP_DMA_MCBSP1_TX, + .rx_irq = INT_McBSP1RX, + .tx_irq = INT_McBSP1TX }, + [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE), + .dma_rx_sync = OMAP_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP_DMA_MCBSP2_TX, + .rx_irq = INT_1610_McBSP2_RX, + .tx_irq = INT_1610_McBSP2_TX }, + [2] = { .virt_base = OMAP1610_MCBSP3_BASE, + .dma_rx_sync = OMAP_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP_DMA_MCBSP3_TX, + .rx_irq = INT_McBSP3RX, + .tx_irq = INT_McBSP3TX }, +}; +#endif + +static int __init omap_mcbsp_init(void) +{ + int mcbsp_count = 0, i; + static const struct omap_mcbsp_info *mcbsp_info; + + printk("Initializing OMAP McBSP system\n"); +#ifdef CONFIG_ARCH_OMAP730 + if (cpu_is_omap730()) { + mcbsp_info = mcbsp_730; + mcbsp_count = ARRAY_SIZE(mcbsp_730); + } +#endif +#ifdef CONFIG_ARCH_OMAP1510 + if (cpu_is_omap1510()) { + mcbsp_info = mcbsp_1510; + mcbsp_count = ARRAY_SIZE(mcbsp_1510); + } +#endif +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap1710()) { + mcbsp_info = mcbsp_1610; + mcbsp_count = ARRAY_SIZE(mcbsp_1610); + } +#endif + for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { + if (i >= mcbsp_count) { + mcbsp[i].io_base = 0; + mcbsp[i].free = 0; + continue; + } + mcbsp[i].id = i + 1; + mcbsp[i].free = 1; + mcbsp[i].dma_tx_lch = -1; + mcbsp[i].dma_rx_lch = -1; + + mcbsp[i].io_base = mcbsp_info[i].virt_base; + mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; + mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; + mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; + mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync; + spin_lock_init(&mcbsp[i].lock); + } + + return 0; +} + + +arch_initcall(omap_mcbsp_init); + +EXPORT_SYMBOL(omap_mcbsp_config); +EXPORT_SYMBOL(omap_mcbsp_request); +EXPORT_SYMBOL(omap_mcbsp_free); +EXPORT_SYMBOL(omap_mcbsp_start); +EXPORT_SYMBOL(omap_mcbsp_stop); +EXPORT_SYMBOL(omap_mcbsp_xmit_word); +EXPORT_SYMBOL(omap_mcbsp_recv_word); +EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); +EXPORT_SYMBOL(omap_mcbsp_recv_buffer); +EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c index 944c29418..93c7f4aca 100644 --- a/arch/arm/mach-omap/ocpi.c +++ b/arch/arm/mach-omap/ocpi.c @@ -59,8 +59,8 @@ int ocpi_enable(void) /* Make sure there's clock for OCPI */ -#ifdef CONFIG_ARCH_OMAP1610 - if (cpu_is_omap1610()) { +#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) + if (cpu_is_omap1610() || cpu_is_omap1710()) { val = omap_readl(OMAP1610_ARM_IDLECT3); val |= EN_OCPI_CK; val &= ~IDLOCPI_ARM; diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c new file mode 100644 index 000000000..f3451d269 --- /dev/null +++ b/arch/arm/mach-omap/usb.c @@ -0,0 +1,541 @@ +/* + * arch/arm/mach-omap/usb.c -- platform level USB initialization + * + * Copyright (C) 2004 Texas Instruments, 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. + * + * 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 + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* These routines should handle the standard chip-specific modes + * for usb0/1/2 ports, covering basic mux and transceiver setup. + * Call omap_usb_init() once, from INIT_MACHINE(). + * + * Some board-*.c files will need to set up additional mux options, + * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. + */ + +/* TESTED ON: + * - 1611B H2 (with usb1 mini-AB) + * - 1510 Innovator with built-in transceiver (custom cable feeding 5V VBUS) + * - 1710 custom development board using alternate pin group + */ + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP_OTG + +static struct otg_transceiver *xceiv; + +/** + * otg_get_transceiver - find the (single) OTG transceiver driver + * + * Returns the transceiver driver, after getting a refcount to it; or + * null if there is no such transceiver. The caller is responsible for + * releasing that count. + */ +struct otg_transceiver *otg_get_transceiver(void) +{ + if (xceiv) + get_device(xceiv->dev); + return xceiv; +} +EXPORT_SYMBOL(otg_get_transceiver); + +int otg_set_transceiver(struct otg_transceiver *x) +{ + if (xceiv && x) + return -EBUSY; + xceiv = x; + return 0; +} +EXPORT_SYMBOL(otg_set_transceiver); + +#endif + +/*-------------------------------------------------------------------------*/ + +static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) +{ + u32 syscon1 = 0; + + if (nwires == 0) { + USB_TRANSCEIVER_CTRL_REG &= ~(1 << 3); + return 0; + } + + /* + * VP and VM are needed for all active usb0 configurations. + * USB0_VP and USB0_VM are always set on 1510, there's no muxing + * available for them. + */ + if (nwires >= 2 && !cpu_is_omap1510()) { + omap_cfg_reg(AA9_USB0_VP); + omap_cfg_reg(R9_USB0_VM); + } + + /* internal transceiver */ + if (nwires == 2) { + if (cpu_is_omap1510()) { + /* This works for OHCI on 1510-Innovator, nothing to mux */ + return 0; + } + +#if 0 + /* NOTE: host OR device mode for now, no OTG */ + USB_TRANSCEIVER_CTRL_REG &= ~(3 << 4); + if (is_device) { + omap_cfg_reg(W4_USB_PUEN); + omap_cfg_reg(R18_1510_USB_GPIO0); + // omap_cfg_reg(USB0_VBUS); + // omap_cfg_reg(USB0_PUEN); + // USB_TRANSCEIVER_CTRL_REG.CONF_USB0_PORT_R = 7 + // when USB0_PUEN is needed + } else /* host mode needs D+ and D- pulldowns */ + USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1); + return 3 << 16; +#else + /* FIXME: 1610 needs to return the right value here */ + printk(KERN_ERR "usb0 internal transceiver, nyet\n"); + return 0; +#endif + } + + /* alternate pin config, external transceiver */ + omap_cfg_reg(V6_USB0_TXD); + omap_cfg_reg(W9_USB0_TXEN); + omap_cfg_reg(W5_USB0_SE0); + +#ifdef CONFIG_ARCH_OMAP_USB_SPEED + /* FIXME: there's good chance that pin V9 is used for MMC2 port cmddir */ + omap_cfg_reg(V9_USB0_SPEED); + // omap_cfg_reg(V9_USB0_SUSP); +#endif + + if (nwires != 3) + omap_cfg_reg(Y5_USB0_RCV); + + switch (nwires) { + case 3: + syscon1 = 2; + break; + case 4: + syscon1 = 1; + break; + case 6: + syscon1 = 3; + /* REVISIT: Is CONF_USB2_UNI_R only needed when nwires = 6? */ + USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; + break; + default: + printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", + 0, nwires); + } + return syscon1 << 16; +} + +static u32 __init omap_usb1_init(unsigned nwires) +{ + u32 syscon1 = 0; + + if (nwires != 6) + USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R; + if (nwires == 0) + return 0; + + /* external transceiver */ + omap_cfg_reg(USB1_TXD); + omap_cfg_reg(USB1_TXEN); + if (cpu_is_omap1510()) { + omap_cfg_reg(USB1_SEO); + omap_cfg_reg(USB1_SPEED); + // SUSP + } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) { + omap_cfg_reg(W13_1610_USB1_SE0); + omap_cfg_reg(R13_1610_USB1_SPEED); + // SUSP + } else { + pr_debug("usb unrecognized\n"); + } + if (nwires != 3) + omap_cfg_reg(USB1_RCV); + + switch (nwires) { + case 3: + syscon1 = 2; + break; + case 4: + syscon1 = 1; + break; + case 6: + syscon1 = 3; + omap_cfg_reg(USB1_VP); + omap_cfg_reg(USB1_VM); + USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R; + break; + default: + printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", + 1, nwires); + } + return syscon1 << 20; +} + +static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) +{ + u32 syscon1 = 0; + + if (alt_pingroup) + return 0; + if (nwires != 6) + USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; + if (nwires == 0) + return 0; + + /* external transceiver */ + if (cpu_is_omap1510()) { + omap_cfg_reg(USB2_TXD); + omap_cfg_reg(USB2_TXEN); + omap_cfg_reg(USB2_SEO); + if (nwires != 3) + omap_cfg_reg(USB2_RCV); + } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) { + omap_cfg_reg(V6_USB2_TXD); + omap_cfg_reg(W9_USB2_TXEN); + omap_cfg_reg(W5_USB2_SE0); + if (nwires != 3) + omap_cfg_reg(Y5_USB2_RCV); + } else { + pr_debug("usb unrecognized\n"); + } + // omap_cfg_reg(USB2_SUSP); + // FIXME omap_cfg_reg(USB2_SPEED); + + switch (nwires) { + case 3: + syscon1 = 2; + break; + case 4: + syscon1 = 1; + break; + case 6: + syscon1 = 3; + if (cpu_is_omap1510()) { + omap_cfg_reg(USB2_VP); + omap_cfg_reg(USB2_VM); + } else { + omap_cfg_reg(AA9_USB2_VP); + omap_cfg_reg(R9_USB2_VM); + } + USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; + break; + default: + printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", + 2, nwires); + } + return syscon1 << 24; +} + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_USB_GADGET_OMAP) || \ + defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \ + (defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)) +static void usb_release(struct device *dev) +{ + /* normally not freed */ +} +#endif + +#ifdef CONFIG_USB_GADGET_OMAP + +static struct resource udc_resources[] = { + /* order is significant! */ + { /* registers */ + .start = IO_ADDRESS(UDC_BASE), + .end = IO_ADDRESS(UDC_BASE + 0xff), + .flags = IORESOURCE_MEM, + }, { /* general IRQ */ + .start = IH2_BASE + 20, + .flags = IORESOURCE_IRQ, + }, { /* PIO IRQ */ + .start = IH2_BASE + 30, + .flags = IORESOURCE_IRQ, + }, { /* SOF IRQ */ + .start = IH2_BASE + 29, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 udc_dmamask = ~(u32)0; + +static struct platform_device udc_device = { + .name = "omap_udc", + .id = -1, + .dev = { + .release = usb_release, + .dma_mask = &udc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(udc_resources), + .resource = udc_resources, +}; + +#endif + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + +/* The dmamask must be set for OHCI to work */ +static u64 ohci_dmamask = ~(u32)0; + +static struct resource ohci_resources[] = { + { + .start = IO_ADDRESS(OMAP_OHCI_BASE), + .end = IO_ADDRESS(OMAP_OHCI_BASE + 4096), + .flags = IORESOURCE_MEM, + }, + { + .start = INT_USB_HHC_1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ohci_device = { + .name = "ohci", + .id = -1, + .dev = { + .release = usb_release, + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0x0fffffff, + }, + .num_resources = ARRAY_SIZE(ohci_resources), + .resource = ohci_resources, +}; + +#endif + +#if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG) + +static struct resource otg_resources[] = { + /* order is significant! */ + { + .start = IO_ADDRESS(OTG_BASE), + .end = IO_ADDRESS(OTG_BASE + 0xff), + .flags = IORESOURCE_MEM, + }, { + .start = IH2_BASE + 8, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device otg_device = { + .name = "omap_otg", + .id = -1, + .dev = { + .release = usb_release, + }, + .num_resources = ARRAY_SIZE(otg_resources), + .resource = otg_resources, +}; + +#endif + +/*-------------------------------------------------------------------------*/ + +// FIXME correct answer depends on hmc_mode, +// as does any nonzero value for config->otg port number +#define is_usb0_device(config) 0 + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP_OTG + +void __init +omap_otg_init(struct omap_usb_config *config) +{ + u32 syscon = OTG_SYSCON_1_REG & 0xffff; + int status; + int alt_pingroup = 0; + + /* NOTE: no bus or clock setup (yet?) */ + + syscon = OTG_SYSCON_1_REG & 0xffff; + if (!(syscon & OTG_RESET_DONE)) + pr_debug("USB resets not complete?\n"); + + // OTG_IRQ_EN_REG = 0; + + /* pin muxing and transceiver pinouts */ + if (config->pins[0] > 2) /* alt pingroup 2 */ + alt_pingroup = 1; + syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config)); + syscon |= omap_usb1_init(config->pins[1]); + syscon |= omap_usb2_init(config->pins[2], alt_pingroup); + pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); + OTG_SYSCON_1_REG = syscon; + + syscon = config->hmc_mode; + syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */; + if (config->otg || config->register_host) + syscon |= UHOST_EN; +#ifdef CONFIG_USB_OTG + if (config->otg) + syscon |= OTG_EN; +#endif + pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon); + OTG_SYSCON_2_REG = syscon; + + printk("USB: hmc %d", config->hmc_mode); + if (alt_pingroup) + printk(", usb2 alt %d wires", config->pins[2]); + else if (config->pins[0]) + printk(", usb0 %d wires%s", config->pins[2], + is_usb0_device(config) ? " (dev)" : ""); + if (config->pins[1]) + printk(", usb1 %d wires", config->pins[1]); + if (!alt_pingroup && config->pins[2]) + printk(", usb2 %d wires", config->pins[2]); + if (config->otg) + printk(", Mini-AB on usb%d", config->otg - 1); + printk("\n"); + + /* don't clock unused USB controllers */ + syscon = OTG_SYSCON_1_REG; + syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN; + +#ifdef CONFIG_USB_GADGET_OMAP + if (config->otg || config->register_dev) { + syscon &= ~DEV_IDLE_EN; + udc_device.dev.platform_data = config; + status = platform_device_register(&udc_device); + if (status) + pr_debug("can't register UDC device, %d\n", status); + } +#endif + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + if (config->otg || config->register_host) { + syscon &= ~HST_IDLE_EN; + ohci_device.dev.platform_data = config; + status = platform_device_register(&ohci_device); + if (status) + pr_debug("can't register OHCI device, %d\n", status); + } +#endif + +#ifdef CONFIG_USB_OTG + if (config->otg) { + syscon &= ~OTG_IDLE_EN; + if (cpu_is_omap730()) + otg_resources[1].start = INT_730_USB_OTG; + status = platform_device_register(&otg_device); + // ... + } +#endif + pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); + OTG_SYSCON_1_REG = syscon; + + status = 0; +} + +#else +static inline void omap_otg_init(struct omap_usb_config *config) {} +#endif + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP1510 + +static void __init omap_1510_usb_init(struct omap_usb_config *config) +{ + int status; + unsigned int val; + + omap_usb0_init(config->pins[0], is_usb0_device(config)); + omap_usb1_init(config->pins[1]); + omap_usb2_init(config->pins[2], 0); + + val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1); + val |= (config->hmc_mode << 1); + omap_writel(val, MOD_CONF_CTRL_0); + + // FIXME this has a UDC controller too + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + if (config->otg || config->register_host) { + ohci_device.dev.platform_data = config; + status = platform_device_register(&ohci_device); + if (status) + pr_debug("can't register OHCI device, %d\n", status); + } + // FIXME completely untested ... +#endif + +} + +#else +static inline void omap_1510_usb_init(struct omap_usb_config *config) {} +#endif + +/*-------------------------------------------------------------------------*/ + +static struct omap_usb_config platform_data; + +static int __init +omap_usb_init(void) +{ + const struct omap_usb_config *config; + + config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config); + if (config == NULL) { + printk(KERN_ERR "USB: No board-specific platform config found\n"); + return -ENODEV; + } + platform_data = *config; + + if (cpu_is_omap730() + || cpu_is_omap1610() + || cpu_is_omap1710() + || cpu_is_omap5912()) + omap_otg_init(&platform_data); + else if (cpu_is_omap1510()) + omap_1510_usb_init(&platform_data); + else { + printk(KERN_ERR "USB: No init for your chip yet\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(omap_usb_init); diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index d394f6957..bb28824d8 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -12,7 +12,7 @@ config ARCH_LUBBOCK config MACH_MAINSTONE bool "Intel HCDDBBVA0 Development Platform" select PXA27x - #select IWMMXT + select IWMMXT config ARCH_PXA_IDP bool "Accelent Xscale IDP" @@ -32,4 +32,9 @@ config PXA27x help Select code specific to PXA27x variants +config IWMMXT + bool + help + Enable support for iWMMXt + endif diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c index 3096fa7c5..458112b21 100644 --- a/arch/arm/mach-pxa/dma.c +++ b/arch/arm/mach-pxa/dma.c @@ -23,6 +23,7 @@ #include #include +#include static struct dma_channel { char *name; diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 80f3535e0..3f4755f70 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -30,8 +30,10 @@ #include #include +#include #include #include +#include #include "generic.h" @@ -128,6 +130,12 @@ static struct platform_device pxamci_device = { .resource = pxamci_resources, }; +void __init pxa_set_mci_info(struct pxamci_platform_data *info) +{ + pxamci_device.dev.platform_data = info; +} +EXPORT_SYMBOL(pxa_set_mci_info); + static struct pxa2xx_udc_mach_info pxa_udc_info; diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index db53cd571..6f8b4873e 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -27,6 +27,7 @@ #include #include +#include #include #include "generic.h" @@ -100,7 +101,7 @@ static void __init idp_map_io(void) pxa_map_io(); iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); - set_irq_type(IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE); + set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); // serial ports 2 & 3 pxa_gpio_mode(GPIO42_BTRXD_MD); diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index c771e4376..a676a8657 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -20,39 +20,64 @@ #include #include #include +#include #include "generic.h" /* - * This is for IRQs known as PXA_IRQ([8...31]). + * This is for peripheral IRQs internal to the PXA chip. */ -static void pxa_mask_irq(unsigned int irq) +static void pxa_mask_low_irq(unsigned int irq) { ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); } -static void pxa_unmask_irq(unsigned int irq) +static void pxa_unmask_low_irq(unsigned int irq) { ICMR |= (1 << (irq + PXA_IRQ_SKIP)); } -static struct irqchip pxa_internal_chip = { - .ack = pxa_mask_irq, - .mask = pxa_mask_irq, - .unmask = pxa_unmask_irq, +static struct irqchip pxa_internal_chip_low = { + .ack = pxa_mask_low_irq, + .mask = pxa_mask_low_irq, + .unmask = pxa_unmask_low_irq, }; +#if PXA_INTERNAL_IRQS > 32 + +/* + * This is for the second set of internal IRQs as found on the PXA27x. + */ + +static void pxa_mask_high_irq(unsigned int irq) +{ + ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); +} + +static void pxa_unmask_high_irq(unsigned int irq) +{ + ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); +} + +static struct irqchip pxa_internal_chip_high = { + .ack = pxa_mask_high_irq, + .mask = pxa_mask_high_irq, + .unmask = pxa_unmask_high_irq, +}; + +#endif + /* * PXA GPIO edge detection for IRQs: * IRQs are generated on Falling-Edge, Rising-Edge, or both. * Use this instead of directly setting GRER/GFER. */ -static long GPIO_IRQ_rising_edge[3]; -static long GPIO_IRQ_falling_edge[3]; -static long GPIO_IRQ_mask[3]; +static long GPIO_IRQ_rising_edge[4]; +static long GPIO_IRQ_falling_edge[4]; +static long GPIO_IRQ_mask[4]; static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) { @@ -106,13 +131,13 @@ static void pxa_ack_low_gpio(unsigned int irq) static struct irqchip pxa_low_gpio_chip = { .ack = pxa_ack_low_gpio, - .mask = pxa_mask_irq, - .unmask = pxa_unmask_irq, + .mask = pxa_mask_low_irq, + .unmask = pxa_unmask_low_irq, .type = pxa_gpio_irq_type, }; /* - * Demux handler for GPIO 2-80 edge detect interrupts + * Demux handler for GPIO>=2 edge detect interrupts */ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, @@ -169,6 +194,23 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, } while (mask); loop = 1; } + +#if PXA_LAST_GPIO >= 96 + mask = GEDR3; + if (mask) { + GEDR3 = mask; + irq = IRQ_GPIO(96); + desc = irq_desc + irq; + do { + if (mask & 1) + desc->handle(irq, desc, regs); + irq++; + desc++; + mask >>= 1; + } while (mask); + loop = 1; + } +#endif } while (loop); } @@ -214,12 +256,25 @@ void __init pxa_init_irq(void) ICLR = 0; /* clear all GPIO edge detects */ - GFER0 = GFER1 = GFER2 = 0; - GRER0 = GRER1 = GRER2 = 0; + GFER0 = 0; + GFER1 = 0; + GFER2 = 0; + GRER0 = 0; + GRER1 = 0; + GRER2 = 0; GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; +#ifdef CONFIG_PXA27x + /* And similarly for the extra regs on the PXA27x */ + ICMR2 = 0; + ICLR2 = 0; + GFER3 = 0; + GRER3 = 0; + GEDR3 = GEDR3; +#endif + /* only unmasked interrupts kick us out of idle */ ICCR = 1; @@ -227,10 +282,18 @@ void __init pxa_init_irq(void) GPIO_IRQ_mask[0] = 3; for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { - set_irq_chip(irq, &pxa_internal_chip); + set_irq_chip(irq, &pxa_internal_chip_low); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } + +#if PXA_INTERNAL_IRQS > 32 + for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { + set_irq_chip(irq, &pxa_internal_chip_high); set_irq_handler(irq, do_level_IRQ); set_irq_flags(irq, IRQF_VALID); } +#endif for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { set_irq_chip(irq, &pxa_low_gpio_chip); @@ -238,13 +301,13 @@ void __init pxa_init_irq(void) set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) { + for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { set_irq_chip(irq, &pxa_muxed_gpio_chip); set_irq_handler(irq, do_edge_IRQ); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - /* Install handler for GPIO 2-80 edge detect interrupts */ - set_irq_chip(IRQ_GPIO_2_80, &pxa_internal_chip); - set_irq_chained_handler(IRQ_GPIO_2_80, pxa_gpio_demux_handler); + /* Install handler for GPIO>=2 edge detect interrupts */ + set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); + set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); } diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c index 0e083b34e..05cf56059 100644 --- a/arch/arm/mach-pxa/leds-lubbock.c +++ b/arch/arm/mach-pxa/leds-lubbock.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "leds.h" diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c index 8403f6780..bbd3f87a9 100644 --- a/arch/arm/mach-pxa/leds-mainstone.c +++ b/arch/arm/mach-pxa/leds-mainstone.c @@ -17,6 +17,7 @@ #include #include +#include #include #include "leds.h" diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 28c9677a9..a09d4c11b 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 155b5950e..219fd4ecd 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -31,6 +31,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 245e25b08..5e84864a8 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include /* @@ -45,7 +47,7 @@ extern void pxa_cpu_resume(void); */ enum { SLEEP_SAVE_START = 0, - SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, + SLEEP_SAVE_OIER, SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, @@ -68,17 +70,18 @@ static int pxa_pm_enter(u32 state) { unsigned long sleep_save[SLEEP_SAVE_SIZE]; unsigned long checksum = 0; - unsigned long delta; + struct timespec delta, rtc; int i; if (state != PM_SUSPEND_MEM) return -EINVAL; /* preserve current time */ - delta = xtime.tv_sec - RCNR; + rtc.tv_sec = RCNR; + rtc.tv_nsec = 0; + save_time_delta(&delta, &rtc); /* save vital registers */ - SAVE(OSCR); SAVE(OSMR0); SAVE(OSMR1); SAVE(OSMR2); @@ -149,9 +152,11 @@ static int pxa_pm_enter(u32 state) RESTORE(OSMR1); RESTORE(OSMR2); RESTORE(OSMR3); - RESTORE(OSCR); RESTORE(OIER); + /* OSMR0 is the system timer: make sure OSCR is sufficiently behind */ + OSCR = OSMR0 - LATCH; + RESTORE(CKEN); ICLR = 0; @@ -159,7 +164,8 @@ static int pxa_pm_enter(u32 state) RESTORE(ICMR); /* restore current time */ - xtime.tv_sec = RCNR + delta; + rtc.tv_sec = RCNR; + restore_time_delta(&delta, &rtc); #ifdef DEBUG printk(KERN_DEBUG "*** made it back from resume\n"); diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 41150917f..e887b7175 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -22,6 +22,7 @@ #include #include +#include #include "generic.h" diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index b1573c837..e5e97fef8 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 189263939..be00614f5 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -16,6 +16,8 @@ #include #include +#include + .text /* @@ -64,6 +66,37 @@ ENTRY(pxa_cpu_suspend) @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 + @ Intel PXA255 Specification Update notes problems + @ about suspending with PXBus operating above 133MHz + @ (see Errata 31, GPIO output signals, ... unpredictable in sleep + @ + @ We keep the change-down close to the actual suspend on SDRAM + @ as possible to eliminate messing about with the refresh clock + @ as the system will restore with the original speed settings + @ + @ Ben Dooks, 13-Sep-2004 + + ldr r6, =CCCR + ldr r8, [r6] @ keep original value for resume + + @ ensure x1 for run and turbo mode with memory clock + bic r7, r8, #CCCR_M_MASK | CCCR_N_MASK + orr r7, r7, #(1<<5) | (2<<7) + + @ check that the memory frequency is within limits + and r14, r7, #CCCR_L_MASK + teq r14, #1 + bicne r7, r7, #CCCR_L_MASK + orrne r7, r7, #1 @@ 99.53MHz + + @ get ready for the change + @ note, since we are making turbo=run, do not remove the turbo + @ as this may cause non-turbo mode on resume + mrc p14, 0, r0, c6, c0, 0 + bic r0, r0, #2 @ clear change bit + mcr p14, 0, r0, c6, c0, 0 + orr r0, r0, #2 @ initiate change bit + @ align execution to a cache line b 1f @@ -74,6 +107,13 @@ ENTRY(pxa_cpu_suspend) @ All needed values are now in registers. @ These last instructions should be in cache + @ initiate the frequency change... + str r7, [r6] + mcr p14, 0, r0, c6, c0, 0 + + @ restore the original cpu speed value for resume + str r8, [r6] + @ put SDRAM into self-refresh str r5, [r4] @@ -83,8 +123,7 @@ ENTRY(pxa_cpu_suspend) @ enter sleep mode mcr p14, 0, r1, c7, c0, 0 -20: nop - b 20b @ loop waiting for sleep +20: b 20b @ loop waiting for sleep /* * cpu_pxa_resume() diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 7e8923563..a49fc0299 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -27,6 +27,7 @@ #include #include #include +#include static inline unsigned long pxa_get_rtc_time(void) diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 40e78bc44..ee42fe2c2 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -1,9 +1,10 @@ if ARCH_S3C2410 -menu "S3C2410 Implementations" +menu "S3C24XX Implementations" config ARCH_BAST bool "Simtec Electronics BAST (EB2410ITX)" + select CPU_S3C2410 help Say Y here if you are using the Simtec Electronics EB2410ITX development board (also known as BAST) @@ -12,18 +13,22 @@ config ARCH_BAST config ARCH_H1940 bool "IPAQ H1940" + select CPU_S3C2410 help Say Y here if you are using the HP IPAQ H1940 + . config ARCH_SMDK2410 bool "SMDK2410/A9M2410" + select CPU_S3C2410 help Say Y here if you are using the SMDK2410 or the derived module A9M2410 config MACH_VR1000 bool "Thorcom VR1000" + select CPU_S3C2410 help Say Y here if you are using the Thorcom VR1000 board. @@ -32,4 +37,39 @@ config MACH_VR1000 endmenu +config CPU_S3C2410 + bool + depends on ARCH_S3C2410 + help + Support for S3C2410 and S3C2410A family from the S3C24XX line + of Samsung Mobile CPUs. + +config CPU_S3C2440 + bool + depends on ARCH_S3C2410 + help + Support for S3C2440 Samsung Mobile CPU based systems. + +comment "S3C2410 Setup" + +config S3C2410_DMA + bool "S3C2410 DMA support" + depends on ARCH_S3C2410 + help + S3C2410 DMA support. This is needed for drivers like sound which + use the S3C2410's DMA system to move data to and from the + peripheral blocks. + +config S3C2410_DMA_DEBUG + bool "S3C2410 DMA support debug" + depends on ARCH_S3C2410 && S3C2410_DMA + help + Enable debugging output for the DMA code. This option sends info + to the kernel log, at priority KERN_DEBUG. + + Note, it is easy to create and fill the log buffer in a small + amount of time, as well as using an significant percantage of + the CPU time doing so. + + endif diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 476c6ca78..5d6d80e91 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -1,19 +1,28 @@ + # # Makefile for the linux kernel. # # Object file lists. -obj-y := s3c2410.o irq.o time.o gpio.o +obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o obj-m := obj-n := obj- := -obj-$(CONFIG_ARCH_BAST) += mach-bast.o -obj-$(CONFIG_MACH_H1940) += mach-h1940.o -obj-$(CONFIG_ARCH_H1940) += mach-h1940.o -obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o -obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o +# S3C2410 support files + +obj-$(CONFIG_CPU_S3C2410) += s3c2410.o +obj-$(CONFIG_S3C2410_DMA) += dma.o + +# S3C2440 support + +obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o + +# machine specific support + +obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o +obj-$(CONFIG_ARCH_H1940) += mach-h1940.o +obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o +obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o -#obj-$(CONFIG_PCI) +=$(pci-y) -#obj-$(CONFIG_LEDS) +=$(leds-y) diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c new file mode 100644 index 000000000..a12ade71b --- /dev/null +++ b/arch/arm/mach-s3c2410/clock.c @@ -0,0 +1,310 @@ +/* linux/arch/arm/mach-s3c2410/clock.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * S3C2410 Clock control support + * + * Based on, and code from linux/arch/arm/mach-versatile/clock.c + ** + ** Copyright (C) 2004 ARM Limited. + ** Written by Deep Blue Solutions Limited. + * + * + * 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 +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "clock.h" + + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); + + +/* old functions */ + +void s3c2410_clk_enable(unsigned int clocks, unsigned int enable) +{ + unsigned long clkcon; + unsigned long flags; + + local_irq_save(flags); + + clkcon = __raw_readl(S3C2410_CLKCON); + clkcon &= ~clocks; + + if (enable) + clkcon |= clocks; + + __raw_writel(clkcon, S3C2410_CLKCON); + + local_irq_restore(flags); +} + + +/* Clock API calls */ + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p; + struct clk *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, list) { + if (strcmp(id, p->name) == 0 && + try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} + +int clk_enable(struct clk *clk) +{ + if (clk->ctrlbit != 0) + s3c2410_clk_enable(clk->ctrlbit, 1); + + return 0; +} + +void clk_disable(struct clk *clk) +{ + s3c2410_clk_enable(clk->ctrlbit, 0); +} + + +int clk_use(struct clk *clk) +{ + atomic_inc(&clk->used); + return 0; +} + + +void clk_unuse(struct clk *clk) +{ + atomic_dec(&clk->used); +} + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk->parent != NULL) + return clk->parent->rate; + + return clk->rate; +} + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return -EINVAL; +} + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} + +EXPORT_SYMBOL(clk_get); +EXPORT_SYMBOL(clk_put); +EXPORT_SYMBOL(clk_enable); +EXPORT_SYMBOL(clk_disable); +EXPORT_SYMBOL(clk_use); +EXPORT_SYMBOL(clk_unuse); +EXPORT_SYMBOL(clk_get_rate); +EXPORT_SYMBOL(clk_round_rate); +EXPORT_SYMBOL(clk_set_rate); +EXPORT_SYMBOL(clk_get_parent); + +/* base clocks */ + +static struct clk clk_f = { + .name = "fclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0 +}; + +static struct clk clk_h = { + .name = "hclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0 +}; + +static struct clk clk_p = { + .name = "pclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0 +}; + +/* clock definitions */ + +static struct clk init_clocks[] = { + { .name = "nand", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_NAND + }, + { .name = "lcd", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_LCDC + }, + { .name = "usb-host", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_USBH + }, + { .name = "usb-device", + .parent = &clk_h, + .ctrlbit = S3C2410_CLKCON_USBD + }, + { .name = "timers", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_PWMT + }, + { .name = "sdi", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_SDI + }, + { .name = "uart0", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_UART0 + }, + { .name = "uart1", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_UART1 + }, + { .name = "uart2", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_UART2 + }, + { .name = "gpio", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_GPIO + }, + { .name = "rtc", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_RTC + }, + { .name = "adc", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_ADC + }, + { .name = "i2c", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_IIC + }, + { .name = "iis", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_IIS + }, + { .name = "spi", + .parent = &clk_p, + .ctrlbit = S3C2410_CLKCON_SPI + }, + { .name = "watchdog", + .parent = &clk_p, + .ctrlbit = 0 + } +}; + +/* initialise the clock system */ + +int s3c2410_register_clock(struct clk *clk) +{ + clk->owner = THIS_MODULE; + atomic_set(&clk->used, 0); + + /* add to the list of available clocks */ + + down(&clocks_sem); + list_add(&clk->list, &clocks); + up(&clocks_sem); + + return 0; +} + +/* initalise all the clocks */ + +static int __init s3c2410_init_clocks(void) +{ + struct clk *clkp = init_clocks; + int ptr; + int ret; + + printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n"); + + /* initialise the main system clocks */ + + clk_h.rate = s3c2410_hclk; + clk_p.rate = s3c2410_pclk; + clk_f.rate = s3c2410_fclk; + + /* set the enabled clocks to a minimal (known) state */ + __raw_writel(S3C2410_CLKCON_PWMT | S3C2410_CLKCON_UART0 | S3C2410_CLKCON_UART1 | S3C2410_CLKCON_UART2 | S3C2410_CLKCON_GPIO | S3C2410_CLKCON_RTC, S3C2410_CLKCON); + + /* register our clocks */ + + if (s3c2410_register_clock(&clk_f) < 0) + printk(KERN_ERR "failed to register cpu fclk\n"); + + if (s3c2410_register_clock(&clk_h) < 0) + printk(KERN_ERR "failed to register cpu hclk\n"); + + if (s3c2410_register_clock(&clk_p) < 0) + printk(KERN_ERR "failed to register cpu pclk\n"); + + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { + ret = s3c2410_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + return 0; +} + +arch_initcall(s3c2410_init_clocks); + diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h new file mode 100644 index 000000000..4c7b94e87 --- /dev/null +++ b/arch/arm/mach-s3c2410/clock.h @@ -0,0 +1,20 @@ +/* + * linux/arch/arm/mach-s3c2410/clock.h + * + * Copyright (c) 2004 Simtec Electronics + * Written by Ben Dooks, + * + * 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. +*/ + +struct clk { + struct list_head list; + struct module *owner; + struct clk *parent; + const char *name; + atomic_t used; + unsigned long rate; + unsigned long ctrlbit; +}; diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c new file mode 100644 index 000000000..42eec7912 --- /dev/null +++ b/arch/arm/mach-s3c2410/cpu.c @@ -0,0 +1,152 @@ +/* linux/arch/arm/mach-s3c2410/cpu.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * S3C24XX CPU Support + * + * 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 +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "cpu.h" +#include "s3c2410.h" +#include "s3c2440.h" + +struct cpu_table { + unsigned long idcode; + unsigned long idmask; + void (*map_io)(struct map_desc *mach_desc, int size); + int (*init)(void); + const char *name; +}; + +/* table of supported CPUs */ + +static const char name_s3c2410[] = "S3C2410"; +static const char name_s3c2440[] = "S3C2440"; +static const char name_s3c2410a[] = "S3C2410A"; +static const char name_s3c2440a[] = "S3C2440A"; + +static struct cpu_table cpu_ids[] __initdata = { + { + .idcode = 0x32410000, + .idmask = 0xffffffff, + .map_io = s3c2410_map_io, + .init = s3c2410_init, + .name = name_s3c2410 + }, + { + .idcode = 0x3241002, + .idmask = 0xffffffff, + .map_io = s3c2410_map_io, + .init = s3c2410_init, + .name = name_s3c2410a + }, + { + .idcode = 0x32440000, + .idmask = 0xffffffff, + .map_io = s3c2440_map_io, + .init = s3c2440_init, + .name = name_s3c2440 + }, + { + .idcode = 0x32440001, + .idmask = 0xffffffff, + .map_io = s3c2440_map_io, + .init = s3c2440_init, + .name = name_s3c2440a + } +}; + +/* minimal IO mapping */ + +static struct map_desc s3c_iodesc[] __initdata = { + IODESC_ENT(GPIO), + IODESC_ENT(IRQ), + IODESC_ENT(MEMCTRL), + IODESC_ENT(UART) +}; + + +static struct cpu_table * +s3c_lookup_cpu(unsigned long idcode) +{ + struct cpu_table *tab; + int count; + + tab = cpu_ids; + for (count = 0; count < ARRAY_SIZE(cpu_ids); count++) { + if ((idcode & tab->idmask) == tab->idcode) + return tab; + } + + return NULL; +} + +static struct cpu_table *cpu; + +void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) +{ + unsigned long idcode; + + /* initialise the io descriptors we need for initialisation */ + iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); + + idcode = __raw_readl(S3C2410_GSTATUS1); + cpu = s3c_lookup_cpu(idcode); + + if (cpu == NULL) { + printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); + panic("Unknown S3C24XX CPU"); + } + + if (cpu->map_io == NULL || cpu->init == NULL) { + printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); + panic("Unsupported S3C24XX CPU"); + } + + printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); + + (cpu->map_io)(mach_desc, size); +} + +static int __init s3c_arch_init(void) +{ + // do the correct init for cpu + + if (cpu == NULL) + panic("s3c_arch_init: NULL cpu\n"); + + return (cpu->init)(); +} + +arch_initcall(s3c_arch_init); diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h new file mode 100644 index 000000000..b0053d76d --- /dev/null +++ b/arch/arm/mach-s3c2410/cpu.h @@ -0,0 +1,41 @@ +/* arch/arm/mach-s3c2410/cpu.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for S3C24XX CPU support + * + * 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. + * + * Modifications: + * 24-Aug-2004 BJD Start of generic S3C24XX support +*/ + +#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE } + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000) + +#ifdef CONFIG_CPU_S3C2410 +extern int s3c2410_init(void); +extern void s3c2410_map_io(struct map_desc *mach_desc, int size); +#else +#define s3c2410_map_io NULL +#define s3c2410_init NULL +#endif + +#ifdef CONFIG_CPU_S3C2440 +extern int s3c2440_init(void); +extern void s3c2440_map_io(struct map_desc *mach_desc, int size); +#else +#define s3c2440_map_io NULL +#define s3c2440_init NULL +#endif + +extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); + diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c new file mode 100644 index 000000000..7cf560cae --- /dev/null +++ b/arch/arm/mach-s3c2410/devs.c @@ -0,0 +1,442 @@ +/* linux/arch/arm/mach-s3c2410/devs.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Base S3C2410 platform device definitions + * + * 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. + * + * Modifications: + * 29-Aug-2004 BJD Added timers 0 through 3 + * 29-Aug-2004 BJD Changed index of devices we only have one of to -1 + * 21-Aug-2004 BJD Added IRQ_TICK to RTC resources + * 18-Aug-2004 BJD Created initial version +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "devs.h" + +/* USB Host Controller */ + +static struct resource s3c_usb_resource[] = { + [0] = { + .start = S3C2410_PA_USBHOST, + .end = S3C2410_PA_USBHOST + S3C2410_SZ_USBHOST, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USBH, + .end = IRQ_USBH, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 s3c_device_usb_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_usb = { + .name = "s3c2410-ohci", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_resource), + .resource = s3c_usb_resource, + .dev = { + .dma_mask = &s3c_device_usb_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_usb); + +/* LCD Controller */ + +static struct resource s3c_lcd_resource[] = { + [0] = { + .start = S3C2410_PA_LCD, + .end = S3C2410_PA_LCD + S3C2410_SZ_LCD, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LCD, + .end = IRQ_LCD, + .flags = IORESOURCE_IRQ, + } + +}; + +static u64 s3c_device_lcd_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_lcd = { + .name = "s3c2410-lcd", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_lcd_resource), + .resource = s3c_lcd_resource, + .dev = { + .dma_mask = &s3c_device_lcd_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_lcd); + +/* NAND Controller */ + +static struct resource s3c_nand_resource[] = { + [0] = { + .start = S3C2410_PA_NAND, + .end = S3C2410_PA_NAND + S3C2410_SZ_NAND, + .flags = IORESOURCE_MEM, + } +}; + +struct platform_device s3c_device_nand = { + .name = "s3c2410-nand", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_nand_resource), + .resource = s3c_nand_resource, +}; + +EXPORT_SYMBOL(s3c_device_nand); + +/* USB Device (Gadget)*/ + +static struct resource s3c_usbgadget_resource[] = { + [0] = { + .start = S3C2410_PA_USBDEV, + .end = S3C2410_PA_USBDEV + S3C2410_SZ_USBDEV, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USBD, + .end = IRQ_USBD, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_usbgadget = { + .name = "s3c2410-usbgadget", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usbgadget_resource), + .resource = s3c_usbgadget_resource, +}; + +EXPORT_SYMBOL(s3c_device_usbgadget); + +/* Watchdog */ + +static struct resource s3c_wdt_resource[] = { + [0] = { + .start = S3C2410_PA_WATCHDOG, + .end = S3C2410_PA_WATCHDOG + S3C2410_SZ_WATCHDOG, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_WDT, + .end = IRQ_WDT, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_wdt = { + .name = "s3c2410-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_wdt_resource), + .resource = s3c_wdt_resource, +}; + +EXPORT_SYMBOL(s3c_device_wdt); + +/* I2C */ + +static struct resource s3c_i2c_resource[] = { + [0] = { + .start = S3C2410_PA_IIC, + .end = S3C2410_PA_IIC + S3C2410_SZ_IIC, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IIC, + .end = IRQ_IIC, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_i2c = { + .name = "s3c2410-i2c", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_i2c_resource), + .resource = s3c_i2c_resource, +}; + +EXPORT_SYMBOL(s3c_device_i2c); + +/* IIS */ + +static struct resource s3c_iis_resource[] = { + [0] = { + .start = S3C2410_PA_IIS, + .end = S3C2410_PA_IIS + S3C2410_SZ_IIS, + .flags = IORESOURCE_MEM, + } +}; + +static u64 s3c_device_iis_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_iis = { + .name = "s3c2410-iis", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_iis_resource), + .resource = s3c_iis_resource, + .dev = { + .dma_mask = &s3c_device_iis_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_iis); + +/* RTC */ + +static struct resource s3c_rtc_resource[] = { + [0] = { + .start = S3C2410_PA_RTC, + .end = S3C2410_PA_RTC + 0xff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .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 = { + .name = "s3c2410-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_rtc_resource), + .resource = s3c_rtc_resource, +}; + +EXPORT_SYMBOL(s3c_device_rtc); + +/* ADC */ + +static struct resource s3c_adc_resource[] = { + [0] = { + .start = S3C2410_PA_ADC, + .end = S3C2410_PA_ADC + S3C2410_SZ_ADC, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TC, + .end = IRQ_ADC, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_adc = { + .name = "s3c2410-adc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_adc_resource), + .resource = s3c_adc_resource, +}; + +/* SDI */ + +static struct resource s3c_sdi_resource[] = { + [0] = { + .start = S3C2410_PA_SDI, + .end = S3C2410_PA_SDI + S3C2410_SZ_SDI, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SDI, + .end = IRQ_SDI, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_sdi = { + .name = "s3c2410-sdi", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_sdi_resource), + .resource = s3c_sdi_resource, +}; + +EXPORT_SYMBOL(s3c_device_sdi); + +/* SPI (0) */ + +static struct resource s3c_spi0_resource[] = { + [0] = { + .start = S3C2410_PA_SPI, + .end = S3C2410_PA_SPI + 0x1f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SPI0, + .end = IRQ_SPI0, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_spi0 = { + .name = "s3c2410-spi", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_spi0_resource), + .resource = s3c_spi0_resource, +}; + +EXPORT_SYMBOL(s3c_device_spi0); + +/* SPI (1) */ + +static struct resource s3c_spi1_resource[] = { + [0] = { + .start = S3C2410_PA_SPI + 0x20, + .end = S3C2410_PA_SPI + 0x20 + 0x1f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SPI1, + .end = IRQ_SPI1, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_spi1 = { + .name = "s3c2410-spi", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_spi1_resource), + .resource = s3c_spi1_resource, +}; + +EXPORT_SYMBOL(s3c_device_spi1); + +/* pwm timer blocks */ + +static struct resource s3c_timer0_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x0C, + .end = S3C2410_PA_TIMER + 0x0C + 0xB, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER0, + .end = IRQ_TIMER0, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer0 = { + .name = "s3c2410-timer", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_timer0_resource), + .resource = s3c_timer0_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer0); + +/* timer 1 */ + +static struct resource s3c_timer1_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x18, + .end = S3C2410_PA_TIMER + 0x23, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER1, + .end = IRQ_TIMER1, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer1 = { + .name = "s3c2410-timer", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_timer1_resource), + .resource = s3c_timer1_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer1); + +/* timer 2 */ + +static struct resource s3c_timer2_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x24, + .end = S3C2410_PA_TIMER + 0x2F, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER2, + .end = IRQ_TIMER2, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer2 = { + .name = "s3c2410-timer", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_timer2_resource), + .resource = s3c_timer2_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer2); + +/* timer 3 */ + +static struct resource s3c_timer3_resource[] = { + [0] = { + .start = S3C2410_PA_TIMER + 0x30, + .end = S3C2410_PA_TIMER + 0x3B, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TIMER3, + .end = IRQ_TIMER3, + .flags = IORESOURCE_IRQ, + } + +}; + +struct platform_device s3c_device_timer3 = { + .name = "s3c2410-timer", + .id = 3, + .num_resources = ARRAY_SIZE(s3c_timer3_resource), + .resource = s3c_timer3_resource, +}; + +EXPORT_SYMBOL(s3c_device_timer3); diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h new file mode 100644 index 000000000..08a441659 --- /dev/null +++ b/arch/arm/mach-s3c2410/devs.h @@ -0,0 +1,36 @@ +/* arch/arm/mach-s3c2410/devs.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2410 standard platform devices + * + * 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. + * + * Modifications: + * 18-Aug-2004 BJD Created initial version + * 27-Aug-2004 BJD Added timers 0 through 3 +*/ + +extern struct platform_device s3c_device_usb; +extern struct platform_device s3c_device_lcd; +extern struct platform_device s3c_device_wdt; +extern struct platform_device s3c_device_i2c; +extern struct platform_device s3c_device_iis; +extern struct platform_device s3c_device_rtc; +extern struct platform_device s3c_device_adc; +extern struct platform_device s3c_device_sdi; + +extern struct platform_device s3c_device_spi0; +extern struct platform_device s3c_device_spi1; + +extern struct platform_device s3c_device_nand; + +extern struct platform_device s3c_device_timer0; +extern struct platform_device s3c_device_timer1; +extern struct platform_device s3c_device_timer2; +extern struct platform_device s3c_device_timer3; + +extern struct platform_device s3c_device_usbgadget; diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c new file mode 100644 index 000000000..819e5af16 --- /dev/null +++ b/arch/arm/mach-s3c2410/dma.c @@ -0,0 +1,1085 @@ +/* linux/arch/arm/mach-bast/dma.c + * + * (c) 2003,2004 Simtec Electronics + * Ben Dooks + * + * S3C2410 DMA core + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * 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. + * + * Changelog: + * 08-Aug-2004 BJD Apply rmk's suggestions + * 21-Jul-2004 BJD Ported to linux 2.6 + * 12-Jul-2004 BJD Finished re-write and change of API + * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems + * 23-May-2003 BJD Created file + * 19-Aug-2003 BJD Cleanup, header fix, added URL + * + * This file is based on the Sangwook Lee/Samsung patches, re-written due + * to various ommisions from the code (such as flexible dma configuration) + * for use with the BAST system board. + * + * The re-write is pretty much complete, and should be good enough for any + * possible DMA function + */ + +#include + +#ifdef CONFIG_S3C2410_DMA_DEBUG +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* io map for dma */ +static void *dma_base; + +/* dma channel state information */ +s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS]; + +/* debugging functions */ + +#define BUF_MAGIC (0xcafebabe) + +#define dmawarn(fmt...) printk(KERN_DEBUG fmt) + +#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) + +#if 1 +#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) +#else +static inline void +dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val) +{ + pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); + writel(val, dma_regaddr(chan, reg)); +} + +#endif + +#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) + +/* captured register state for debug */ + +struct s3c2410_dma_regstate { + unsigned long dcsrc; + unsigned long disrc; + unsigned long dstat; + unsigned long dcon; + unsigned long dmsktrig; +}; + +#ifdef CONFIG_S3C2410_DMA_DEBUG + +/* dmadbg_showregs + * + * simple debug routine to print the current state of the dma registers +*/ + +static void +dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs) +{ + regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); + regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); + regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); + regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); + regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); +} + +static void +dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan, + struct s3c2410_dma_regstate *regs) +{ + printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", + chan->number, fname, line, + regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, + regs->dcon); +} + +static void +dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan) +{ + struct s3c2410_dma_regstate state; + + dmadbg_capture(chan, &state); + + printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", + chan->number, fname, line, chan->load_state, + chan->curr, chan->next, chan->end); + + dmadbg_showregs(fname, line, chan, &state); +} + +#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan)) +#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan)) +#else +#define dbg_showregs(chan) do { } while(0) +#define dbg_showchan(chan) do { } while(0) +#endif /* CONFIG_S3C2410_DMA_DEBUG */ + +#define check_channel(chan) \ + do { if ((chan) >= S3C2410_DMA_CHANNELS) { \ + printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \ + return -EINVAL; \ + } } while(0) + + +/* s3c2410_dma_stats_timeout + * + * Update DMA stats from timeout info +*/ + +static void +s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val) +{ + if (stats == NULL) + return; + + if (val > stats->timeout_longest) + stats->timeout_longest = val; + if (val < stats->timeout_shortest) + stats->timeout_shortest = val; + + stats->timeout_avg += val; +} + +/* s3c2410_dma_waitforload + * + * wait for the DMA engine to load a buffer, and update the state accordingly +*/ + +static int +s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line) +{ + int timeout = chan->load_timeout; + int took; + + if (chan->load_state != S3C2410_DMALOAD_1LOADED) { + printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); + return 0; + } + + if (chan->stats != NULL) + chan->stats->loads++; + + while (--timeout > 0) { + if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { + took = chan->load_timeout - timeout; + + s3c2410_dma_stats_timeout(chan->stats, took); + + switch (chan->load_state) { + case S3C2410_DMALOAD_1LOADED: + chan->load_state = S3C2410_DMALOAD_1RUNNING; + break; + + default: + printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); + } + + return 1; + } + } + + if (chan->stats != NULL) { + chan->stats->timeout_failed++; + } + + return 0; +} + + + +/* s3c2410_dma_loadbuffer + * + * load a buffer, and update the channel state +*/ + +static inline int +s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan, + s3c2410_dma_buf_t *buf) +{ + unsigned long reload; + + pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", + buf, (unsigned long)buf->data, buf->size); + + if (buf == NULL) { + dmawarn("buffer is NULL\n"); + return -EINVAL; + } + + /* check the state of the channel before we do anything */ + + if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); + } + + if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { + dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); + } + + /* it would seem sensible if we are the last buffer to not bother + * with the auto-reload bit, so that the DMA engine will not try + * and load another transfer after this one has finished... + */ + if (chan->load_state == S3C2410_DMALOAD_NONE) { + pr_debug("load_state is none, checking for noreload (next=%p)\n", + buf->next); + reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; + } else { + pr_debug("load_state is %d => autoreload\n", chan->load_state); + reload = S3C2410_DCON_AUTORELOAD; + } + + writel(buf->data, chan->addr_reg); + + dma_wrreg(chan, S3C2410_DMA_DCON, + chan->dcon | reload | (buf->size/chan->xfer_unit)); + + chan->next = buf->next; + + /* update the state of the channel */ + + switch (chan->load_state) { + case S3C2410_DMALOAD_NONE: + chan->load_state = S3C2410_DMALOAD_1LOADED; + break; + + case S3C2410_DMALOAD_1RUNNING: + chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; + break; + + default: + dmawarn("dmaload: unknown state %d in loadbuffer\n", + chan->load_state); + break; + } + + return 0; +} + +/* s3c2410_dma_call_op + * + * small routine to call the op routine with the given op if it has been + * registered +*/ + +static void +s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op) +{ + if (chan->op_fn != NULL) { + (chan->op_fn)(chan, op); + } +} + +/* s3c2410_dma_buffdone + * + * small wrapper to check if callback routine needs to be called, and + * if so, call it +*/ + +static inline void +s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf, + s3c2410_dma_buffresult_t result) +{ + pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", + chan->callback_fn, buf, buf->id, buf->size, result); + + if (chan->callback_fn != NULL) { + (chan->callback_fn)(chan, buf->id, buf->size, result); + } +} + +/* s3c2410_dma_start + * + * start a dma channel going +*/ + +static int s3c2410_dma_start(s3c2410_dma_chan_t *chan) +{ + unsigned long tmp; + unsigned long flags; + + pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); + + local_irq_save(flags); + + if (chan->state == S3C2410_DMA_RUNNING) { + pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); + local_irq_restore(flags); + return 0; + } + + chan->state = S3C2410_DMA_RUNNING; + + /* check wether there is anything to load, and if not, see + * if we can find anything to load + */ + + if (chan->load_state == S3C2410_DMALOAD_NONE) { + if (chan->next == NULL) { + printk(KERN_ERR "dma%d: channel has nothing loaded\n", + chan->number); + chan->state = S3C2410_DMA_IDLE; + local_irq_restore(flags); + return -EINVAL; + } + + s3c2410_dma_loadbuffer(chan, chan->next); + } + + dbg_showchan(chan); + + /* enable the channel */ + + if (!chan->irq_enabled) { + enable_irq(chan->irq); + chan->irq_enabled = 1; + } + + /* start the channel going */ + + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp &= ~S3C2410_DMASKTRIG_STOP; + tmp |= S3C2410_DMASKTRIG_ON; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + + pr_debug("wrote %08lx to DMASKTRIG\n", tmp); + +#if 0 + /* the dma buffer loads should take care of clearing the AUTO + * reloading feature */ + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp &= ~S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + + s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); + + dbg_showchan(chan); + + local_irq_restore(flags); + return 0; +} + +/* s3c2410_dma_canload + * + * work out if we can queue another buffer into the DMA engine +*/ + +static int +s3c2410_dma_canload(s3c2410_dma_chan_t *chan) +{ + if (chan->load_state == S3C2410_DMALOAD_NONE || + chan->load_state == S3C2410_DMALOAD_1RUNNING) + return 1; + + return 0; +} + + +/* s3c2410_dma_enqueue + * + * queue an given buffer for dma transfer. + * + * id the device driver's id information for this buffer + * data the physical address of the buffer data + * size the size of the buffer in bytes + * + * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART + * is checked, and if set, the channel is started. If this flag isn't set, + * then an error will be returned. + * + * It is possible to queue more than one DMA buffer onto a channel at + * once, and the code will deal with the re-loading of the next buffer + * when necessary. +*/ + +int s3c2410_dma_enqueue(unsigned int channel, void *id, + dma_addr_t data, int size) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + s3c2410_dma_buf_t *buf; + unsigned long flags; + + check_channel(channel); + + pr_debug("%s: id=%p, data=%08x, size=%d\n", + __FUNCTION__, id, (unsigned int)data, size); + + buf = (s3c2410_dma_buf_t *)kmalloc(sizeof(*buf), GFP_ATOMIC); + if (buf == NULL) { + pr_debug("%s: out of memory (%d alloc)\n", + __FUNCTION__, sizeof(*buf)); + return -ENOMEM; + } + + pr_debug("%s: new buffer %p\n", __FUNCTION__, buf); + + //dbg_showchan(chan); + + buf->next = NULL; + buf->data = buf->ptr = data; + buf->size = size; + buf->id = id; + buf->magic = BUF_MAGIC; + + local_irq_save(flags); + + if (chan->curr == NULL) { + /* we've got nothing loaded... */ + pr_debug("%s: buffer %p queued onto empty channel\n", + __FUNCTION__, buf); + + chan->curr = buf; + chan->end = buf; + chan->next = NULL; + } else { + pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", + chan->number, __FUNCTION__, buf); + + if (chan->end == NULL) + pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", + chan->number, __FUNCTION__, chan); + + chan->end->next = buf; + chan->end = buf; + } + + /* if necessary, update the next buffer field */ + if (chan->next == NULL) + chan->next = buf; + + /* check to see if we can load a buffer */ + if (chan->state == S3C2410_DMA_RUNNING) { + if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + printk(KERN_ERR "dma%d: loadbuffer:" + "timeout loading buffer\n", + chan->number); + dbg_showchan(chan); + local_irq_restore(flags); + return -EINVAL; + } + } + + while (s3c2410_dma_canload(chan) && chan->next != NULL) { + s3c2410_dma_loadbuffer(chan, chan->next); + } + } else if (chan->state == S3C2410_DMA_IDLE) { + if (chan->flags & S3C2410_DMAF_AUTOSTART) { + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); + } else { + printk(KERN_DEBUG "dma%d: cannot load onto stopped channel'n", chan->number); + local_irq_restore(flags); + return -EINVAL; + } + } + + local_irq_restore(flags); + return 0; +} + +static inline void +s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf) +{ + int magicok = (buf->magic == BUF_MAGIC); + + buf->magic = -1; + + if (magicok) { + kfree(buf); + } else { + printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); + } +} + +/* s3c2410_dma_lastxfer + * + * called when the system is out of buffers, to ensure that the channel + * is prepared for shutdown. +*/ + +static inline void +s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan) +{ + pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", + chan->number, chan->load_state); + + switch (chan->load_state) { + case S3C2410_DMALOAD_NONE: + break; + + case S3C2410_DMALOAD_1LOADED: + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + /* flag error? */ + printk(KERN_ERR "dma%d: timeout waiting for load\n", + chan->number); + return; + } + break; + + default: + pr_debug("dma%d: lastxfer: unhandled load_state %d with no next", + chan->number, chan->load_state); + return; + + } + + /* hopefully this'll shut the damned thing up after the transfer... */ + dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); +} + + +#define dmadbg2(x...) + +static irqreturn_t +s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs) +{ + s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw; + s3c2410_dma_buf_t *buf; + + buf = chan->curr; + + dbg_showchan(chan); + + /* modify the channel state */ + + switch (chan->load_state) { + case S3C2410_DMALOAD_1RUNNING: + /* TODO - if we are running only one buffer, we probably + * want to reload here, and then worry about the buffer + * callback */ + + chan->load_state = S3C2410_DMALOAD_NONE; + break; + + case S3C2410_DMALOAD_1LOADED: + /* iirc, we should go back to NONE loaded here, we + * had a buffer, and it was never verified as being + * loaded. + */ + + chan->load_state = S3C2410_DMALOAD_NONE; + break; + + case S3C2410_DMALOAD_1LOADED_1RUNNING: + /* we'll worry about checking to see if another buffer is + * ready after we've called back the owner. This should + * ensure we do not wait around too long for the DMA + * engine to start the next transfer + */ + + chan->load_state = S3C2410_DMALOAD_1LOADED; + break; + + case S3C2410_DMALOAD_NONE: + printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", + chan->number); + break; + + default: + printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", + chan->number, chan->load_state); + break; + } + + if (buf != NULL) { + /* update the chain to make sure that if we load any more + * buffers when we call the callback function, things should + * work properly */ + + chan->curr = buf->next; + buf->next = NULL; + + if (buf->magic != BUF_MAGIC) { + printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", + chan->number, __FUNCTION__, buf); + return IRQ_HANDLED; + } + + s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); + + /* free resouces */ + s3c2410_dma_freebuf(buf); + } else { + } + + if (chan->next != NULL) { + unsigned long flags; + + switch (chan->load_state) { + case S3C2410_DMALOAD_1RUNNING: + /* don't need to do anything for this state */ + break; + + case S3C2410_DMALOAD_NONE: + /* can load buffer immediately */ + break; + + case S3C2410_DMALOAD_1LOADED: + if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { + /* flag error? */ + printk(KERN_ERR "dma%d: timeout waiting for load\n", + chan->number); + return IRQ_HANDLED; + } + + break; + + default: + printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", + chan->number, chan->load_state); + return IRQ_HANDLED; + } + + local_irq_save(flags); + s3c2410_dma_loadbuffer(chan, chan->next); + local_irq_restore(flags); + } else { + s3c2410_dma_lastxfer(chan); + + /* see if we can stop this channel.. */ + if (chan->load_state == S3C2410_DMALOAD_NONE) { + pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", + chan->number, jiffies); + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); + } + } + + return IRQ_HANDLED; +} + + + +/* s3c2410_request_dma + * + * get control of an dma channel +*/ + +int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client, + void *dev) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + unsigned long flags; + int err; + + pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", + channel, client->name, dev); + + check_channel(channel); + + local_irq_save(flags); + + dbg_showchan(chan); + + if (chan->in_use) { + if (client != chan->client) { + printk(KERN_ERR "dma%d: already in use\n", channel); + local_irq_restore(flags); + return -EBUSY; + } else { + printk(KERN_ERR "dma%d: client already has channel\n", channel); + } + } + + chan->client = client; + chan->in_use = 1; + + if (!chan->irq_claimed) { + pr_debug("dma%d: %s : requesting irq %d\n", + channel, __FUNCTION__, chan->irq); + + err = request_irq(chan->irq, s3c2410_dma_irq, SA_INTERRUPT, + client->name, (void *)chan); + + if (err) { + chan->in_use = 0; + local_irq_restore(flags); + + printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", + client->name, chan->irq, chan->number); + return err; + } + + chan->irq_claimed = 1; + chan->irq_enabled = 1; + } + + local_irq_restore(flags); + + /* need to setup */ + + pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan); + + return 0; +} + +/* s3c2410_dma_free + * + * release the given channel back to the system, will stop and flush + * any outstanding transfers, and ensure the channel is ready for the + * next claimant. + * + * Note, although a warning is currently printed if the freeing client + * info is not the same as the registrant's client info, the free is still + * allowed to go through. +*/ + +int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + unsigned long flags; + + check_channel(channel); + + local_irq_save(flags); + + + if (chan->client != client) { + printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", + channel, chan->client, client); + } + + /* sort out stopping and freeing the channel */ + + if (chan->state != S3C2410_DMA_IDLE) { + pr_debug("%s: need to stop dma channel %p\n", + __FUNCTION__, chan); + + /* possibly flush the channel */ + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); + } + + chan->client = NULL; + chan->in_use = 0; + + local_irq_restore(flags); + + return 0; +} + +static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan) +{ + unsigned long tmp; + unsigned long flags; + + pr_debug("%s:\n", __FUNCTION__); + + dbg_showchan(chan); + + local_irq_save(flags); + + s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); + + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp |= S3C2410_DMASKTRIG_STOP; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + +#if 0 + /* should also clear interrupts, according to WinCE BSP */ + tmp = dma_rdreg(chan, S3C2410_DMA_DCON); + tmp |= S3C2410_DCON_NORELOAD; + dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + + chan->state = S3C2410_DMA_IDLE; + chan->load_state = S3C2410_DMALOAD_NONE; + + local_irq_restore(flags); + + return 0; +} + +/* s3c2410_dma_flush + * + * stop the channel, and remove all current and pending transfers +*/ + +static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan) +{ + s3c2410_dma_buf_t *buf, *next; + unsigned long flags; + + pr_debug("%s:\n", __FUNCTION__); + + local_irq_save(flags); + + if (chan->state != S3C2410_DMA_IDLE) { + pr_debug("%s: stopping channel...\n", __FUNCTION__ ); + s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); + } + + buf = chan->curr; + if (buf == NULL) + buf = chan->next; + + chan->curr = chan->next = chan->end = NULL; + + if (buf != NULL) { + for ( ; buf != NULL; buf = next) { + next = buf->next; + + pr_debug("%s: free buffer %p, next %p\n", + __FUNCTION__, buf, buf->next); + + s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); + s3c2410_dma_freebuf(buf); + } + } + + local_irq_restore(flags); + + return 0; +} + + +int +s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + switch (op) { + case S3C2410_DMAOP_START: + return s3c2410_dma_start(chan); + + case S3C2410_DMAOP_STOP: + return s3c2410_dma_dostop(chan); + + case S3C2410_DMAOP_PAUSE: + return -ENOENT; + + case S3C2410_DMAOP_RESUME: + return -ENOENT; + + case S3C2410_DMAOP_FLUSH: + return s3c2410_dma_flush(chan); + + case S3C2410_DMAOP_TIMEOUT: + return 0; + + } + + return -ENOENT; /* unknown, don't bother */ +} + + +/* DMA configuration for each channel + * + * DISRCC -> source of the DMA (AHB,APB) + * DISRC -> source address of the DMA + * DIDSTC -> destination of the DMA (AHB,APD) + * DIDST -> destination address of the DMA +*/ + +/* s3c2410_dma_config + * + * xfersize: size of unit in bytes (1,2,4) + * dcon: base value of the DCONx register +*/ + +int s3c2410_dma_config(dmach_t channel, + int xferunit, + int dcon) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", + __FUNCTION__, channel, xferunit, dcon); + + check_channel(channel); + + switch (xferunit) { + case 1: + dcon |= S3C2410_DCON_BYTE; + break; + + case 2: + dcon |= S3C2410_DCON_HALFWORD; + break; + + case 4: + dcon |= S3C2410_DCON_WORD; + break; + + default: + pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit); + return -EINVAL; + } + + dcon |= S3C2410_DCON_HWTRIG; + dcon |= S3C2410_DCON_INTREQ; + + pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon); + + chan->dcon = dcon; + chan->xfer_unit = xferunit; + + return 0; +} + + +int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); + + chan->flags = flags; + + return 0; +} + +/* do we need to protect the settings of the fields from + * irq? +*/ + +int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); + + chan->op_fn = rtn; + + return 0; +} + +int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); + + chan->callback_fn = rtn; + + return 0; +} + +/* s3c2410_dma_devconfig + * + * configure the dma source/destination hardware type and address + * + * source: S3C2410_DMASRC_HW: source is hardware + * S3C2410_DMASRC_MEM: source is memory + * + * hwcfg: the value for xxxSTCn register, + * bit 0: 0=increment pointer, 1=leave pointer + * bit 1: 0=soucre is AHB, 1=soucre is APB + * + * devaddr: physical address of the source +*/ + +int s3c2410_dma_devconfig(int channel, + s3c2410_dmasrc_t source, + int hwcfg, + unsigned long devaddr) +{ + s3c2410_dma_chan_t *chan = &s3c2410_chans[channel]; + + check_channel(channel); + + pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", + __FUNCTION__, (int)source, hwcfg, devaddr); + + chan->source = source; + chan->dev_addr = devaddr; + + switch (source) { + case S3C2410_DMASRC_HW: + /* source is hardware */ + pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", + __FUNCTION__, devaddr, hwcfg); + dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); + dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); + dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); + + chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); + return 0; + + case S3C2410_DMASRC_MEM: + /* source is memory */ + pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n", + __FUNCTION__, devaddr, hwcfg); + dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); + dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); + dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); + + chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); + return 0; + } + + printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); + return -EINVAL; +} + +/* initialisation code */ + +static int __init s3c2410_init_dma(void) +{ + int channel; + s3c2410_dma_chan_t *cp; + + printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n"); + + dma_base = ioremap(S3C2410_PA_DMA, 0x200); + if (dma_base == NULL) { + printk(KERN_ERR "dma failed to remap register block\n"); + return -ENOMEM; + } + + for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) { + cp = &s3c2410_chans[channel]; + + memset(cp, 0, sizeof(s3c2410_dma_chan_t)); + + /* dma channel irqs are in order.. */ + cp->number = channel; + cp->irq = channel + IRQ_DMA0; + cp->regs = (unsigned long)dma_base + (channel*0x40); + + /* point current stats somewhere */ + cp->stats = &cp->stats_store; + cp->stats_store.timeout_shortest = LONG_MAX; + + /* basic channel configuration */ + + cp->load_timeout = 1<<18; + + printk("DMA channel %d at %08lx, irq %d\n", + cp->number, cp->regs, cp->irq); + } + + return 0; +} + +__initcall(s3c2410_init_dma); diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c index 450b132af..8996725e9 100644 --- a/arch/arm/mach-s3c2410/gpio.c +++ b/arch/arm/mach-s3c2410/gpio.c @@ -19,6 +19,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * Changelog + * 13-Sep-2004 BJD Implemented change of MISCCR + * 14-Sep-2004 BJD Added getpin call + * 14-Sep-2004 BJD Fixed bug in setpin() call + * 30-Sep-2004 BJD Fixed cfgpin() mask bug + * 01-Oct-2004 BJD Added getcfg() to get pin configuration + * 01-Oct-2004 BJD Fixed mask bug in pullup() call + * 01-Oct-2004 BJD Added getirq() to turn pin into irqno + * 04-Oct-2004 BJD Added irq filter controls for GPIO */ @@ -36,23 +45,20 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) { unsigned long base = S3C2410_GPIO_BASE(pin); - unsigned long shift = 1; - unsigned long mask = 3; + unsigned long mask; unsigned long con; unsigned long flags; if (pin < S3C2410_GPIO_BANKB) { - shift = 0; - mask = 1; + mask = 1 << S3C2410_GPIO_OFFSET(pin); + } else { + mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; } - mask <<= S3C2410_GPIO_OFFSET(pin); - local_irq_save(flags); - con = __raw_readl(base + 0x00); - - con &= mask << shift; + con = __raw_readl(base + 0x00); + con &= ~mask; con |= function; __raw_writel(con, base + 0x00); @@ -60,6 +66,20 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) local_irq_restore(flags); } +unsigned int s3c2410_gpio_getcfg(unsigned int pin) +{ + unsigned long base = S3C2410_GPIO_BASE(pin); + unsigned long mask; + + if (pin < S3C2410_GPIO_BANKB) { + mask = 1 << S3C2410_GPIO_OFFSET(pin); + } else { + mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; + } + + return __raw_readl(base) & mask; +} + void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) { unsigned long base = S3C2410_GPIO_BASE(pin); @@ -73,7 +93,7 @@ void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) local_irq_save(flags); up = __raw_readl(base + 0x08); - up &= 1 << offs; + up &= ~(1L << offs); up |= to << offs; __raw_writel(up, base + 0x08); @@ -90,9 +110,85 @@ void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) local_irq_save(flags); dat = __raw_readl(base + 0x04); - dat &= 1 << offs; + dat &= ~(1 << offs); dat |= to << offs; __raw_writel(dat, base + 0x04); local_irq_restore(flags); } + +unsigned int s3c2410_gpio_getpin(unsigned int pin) +{ + unsigned long base = S3C2410_GPIO_BASE(pin); + unsigned long offs = S3C2410_GPIO_OFFSET(pin); + + return __raw_readl(base + 0x04) & (1<< offs); +} + +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C2410_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C2410_MISCCR); + local_irq_restore(flags); + + return misccr; +} + +int s3c2410_gpio_getirq(unsigned int pin) +{ + if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23) + return -1; /* not valid interrupts */ + + if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) + return -1; /* not valid pin */ + + if (pin < S3C2410_GPF4) + return (pin - S3C2410_GPF0) + IRQ_EINT0; + + if (pin < S3C2410_GPG0) + return (pin - S3C2410_GPF4) + IRQ_EINT4; + + return (pin - S3C2410_GPG0) + IRQ_EINT8; +} + +int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, + unsigned int config) +{ + unsigned long reg = S3C2410_EINFLT0; + unsigned long flags; + unsigned long val; + + if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15) + return -1; + + config &= 0xff; + + pin -= S3C2410_GPG8_EINT16; + reg += pin & ~3; + + local_irq_save(flags); + + /* update filter width and clock source */ + + val = __raw_readl(reg); + val &= ~(0xff << ((pin & 3) * 8)); + val |= config << ((pin & 3) * 8); + __raw_writel(val, reg); + + /* update filter enable */ + + val = __raw_readl(S3C2410_EXTINT2); + val &= ~(1 << ((pin * 4) + 3)); + val |= on << ((pin * 4) + 3); + __raw_writel(val, S3C2410_EXTINT2); + + local_irq_restore(flags); + + return 0; +} diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 878b9740d..1951a0323 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -1,7 +1,7 @@ /* linux/arch/arm/mach-s3c2410/irq.c * - * Copyright (c) 2003 Simtec Electronics - * Ben Dooks + * Copyright (c) 2003,2004 Simtec Electronics + * Ben Dooks * * 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 @@ -17,7 +17,23 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - */ + * Changelog: + * + * 22-Jul-2004 Ben Dooks + * Fixed compile warnings + * + * 22-Jul-2004 Roc Wu + * Fixed s3c_extirq_type + * + * 21-Jul-2004 Arnaud Patard (Rtp) + * Addition of ADC/TC demux + * + * 04-Oct-2004 Klaus Fetscher + * Fix for set_irq_type() on low EINT numbers + * + * 05-Oct-2004 Ben Dooks + * Tidy up KF's patch and sort out new release +*/ #include @@ -34,11 +50,8 @@ #include #include -#include +#include -#if 0 -#include -#endif #define irqdbf(x...) #define irqdbf2(x...) @@ -177,12 +190,84 @@ s3c_irqext_unmask(unsigned int irqno) s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); } -/* todo - put type handler in here */ - static int s3c_irqext_type(unsigned int irq, unsigned int type) { - irqdbf("s3c_irqext_type: called for irq %d, type %d\n", irq, type); + unsigned long extint_reg; + unsigned long gpcon_reg; + unsigned long gpcon_offset, extint_offset; + unsigned long newvalue = 0, value; + + if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) + { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C2410_EXTINT0; + gpcon_offset = (irq - IRQ_EINT0) * 2; + extint_offset = (irq - IRQ_EINT0) * 4; + } + else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) + { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C2410_EXTINT0; + gpcon_offset = (irq - (EXTINT_OFF)) * 2; + extint_offset = (irq - (EXTINT_OFF)) * 4; + } + else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) + { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C2410_EXTINT1; + gpcon_offset = (irq - IRQ_EINT8) * 2; + extint_offset = (irq - IRQ_EINT8) * 4; + } + else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) + { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C2410_EXTINT2; + gpcon_offset = (irq - IRQ_EINT8) * 2; + extint_offset = (irq - IRQ_EINT16) * 4; + } else + return -1; + + /* Set the GPIO to external interrupt mode */ + value = __raw_readl(gpcon_reg); + value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); + __raw_writel(value, gpcon_reg); + + /* Set the external interrupt to pointed trigger type */ + switch (type) + { + case IRQT_NOEDGE: + printk(KERN_WARNING "No edge setting!\n"); + break; + + case IRQT_RISING: + newvalue = S3C2410_EXTINT_RISEEDGE; + break; + + case IRQT_FALLING: + newvalue = S3C2410_EXTINT_FALLEDGE; + break; + + case IRQT_BOTHEDGE: + newvalue = S3C2410_EXTINT_BOTHEDGE; + break; + + case IRQT_LOW: + newvalue = S3C2410_EXTINT_LOWLEV; + break; + + case IRQT_HIGH: + newvalue = S3C2410_EXTINT_HILEV; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -1; + } + + value = __raw_readl(extint_reg); + value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); + __raw_writel(value, extint_reg); return 0; } @@ -194,6 +279,13 @@ static struct irqchip s3c_irqext_chip = { .type = s3c_irqext_type }; +static struct irqchip s3c_irq_eint0t4 = { + .ack = s3c_irq_ack, + .mask = s3c_irq_mask, + .unmask = s3c_irq_unmask, + .type = s3c_irqext_type +}; + /* mask values for the parent registers for each of the interrupt types */ #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) @@ -368,37 +460,37 @@ static struct irqchip s3c_irq_adc = { .ack = s3c_irq_adc_ack, }; -#if 0 -/* LCD (todo) */ - -static void -s3c_irq_lcd_mask(unsigned int irqno) +/* irq demux for adc */ +static void s3c_irq_demux_adc(unsigned int irq, + struct irqdesc *desc, + struct pt_regs *regs) { + unsigned int subsrc, submsk; + unsigned int offset = 9; + struct irqdesc *mydesc; -} - -static void -s3c_irq_lcd_unmask(unsigned int irqno) -{ + /* read the current pending interrupts, and the mask + * for what it is available */ -} + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); -static void -s3c_irq_lcd_ack(unsigned int irqno) -{ + subsrc &= ~submsk; + subsrc >>= offset; + subsrc &= 3; + if (subsrc != 0) { + if (subsrc & 1) { + mydesc = irq_desc + IRQ_TC; + mydesc->handle( IRQ_TC, mydesc, regs); + } + if (subsrc & 2) { + mydesc = irq_desc + IRQ_ADC; + mydesc->handle(IRQ_ADC, mydesc, regs); + } + } } -static struct irqchip s3c_irq_lcd = { - .mask = s3c_irq_lcd_mask, - .unmask = s3c_irq_lcd_unmask, - .ack = s3c_irq_lcd_ack, -}; -#endif - -/* irq demux */ - - static void s3c_irq_demux_uart(unsigned int start, struct pt_regs *regs) { @@ -466,11 +558,15 @@ s3c_irq_demux_uart2(unsigned int irq, s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); } - +/* s3c2410_init_irq + * + * Initialise S3C2410 IRQ system +*/ void __init s3c2410_init_irq(void) { unsigned long pend; + unsigned long last; int irqno; int i; @@ -478,48 +574,51 @@ void __init s3c2410_init_irq(void) /* first, clear all interrupts pending... */ + last = 0; for (i = 0; i < 4; i++) { pend = __raw_readl(S3C2410_EINTPEND); - if (pend == 0) + + if (pend == 0 || pend == last) break; + __raw_writel(pend, S3C2410_EINTPEND); printk("irq: clearing pending ext status %08x\n", (int)pend); + last = pend; } + last = 0; for (i = 0; i < 4; i++) { pend = __raw_readl(S3C2410_INTPND); - if (pend == 0) + + if (pend == 0 || pend == last) break; + __raw_writel(pend, S3C2410_SRCPND); __raw_writel(pend, S3C2410_INTPND); printk("irq: clearing pending status %08x\n", (int)pend); + last = pend; } + last = 0; for (i = 0; i < 4; i++) { pend = __raw_readl(S3C2410_SUBSRCPND); - if (pend == 0) + if (pend == 0 || pend == last) break; printk("irq: clearing subpending status %08x\n", (int)pend); __raw_writel(pend, S3C2410_SUBSRCPND); + last = pend; } /* register the main interrupts */ irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); - for (irqno = IRQ_EINT0; irqno < IRQ_ADCPARENT; irqno++) { + for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { /* set all the s3c2410 internal irqs */ switch (irqno) { - - case IRQ_EINT4t7: - case IRQ_EINT8t23: - /* these are already dealt with, so should never - * appear */ - break; - /* deal with the special IRQs (cascaded) */ case IRQ_UART0: @@ -549,12 +648,18 @@ void __init s3c2410_init_irq(void) set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); - //set_irq_chained_handler(IRQ_LCD, s3c_irq_demux_); - //set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_); + set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); /* external interrupts */ + for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { + irqdbf("registering irq %d (ext int)\n", irqno); + set_irq_chip(irqno, &s3c_irq_eint0t4); + set_irq_handler(irqno, do_edge_IRQ); + set_irq_flags(irqno, IRQF_VALID); + } + for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { irqdbf("registering irq %d (extended s3c irq)\n", irqno); set_irq_chip(irqno, &s3c_irqext_chip); diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 2268ab3c7..f75266907 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 * * http://www.simtec.co.uk/products/EB2410ITX/ @@ -10,6 +10,9 @@ * published by the Free Software Foundation. * * Modifications: + * 14-Sep-2004 BJD USB power control + * 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 +26,7 @@ #include #include #include +#include #include #include @@ -39,6 +43,9 @@ #include #include "s3c2410.h" +#include "devs.h" +#include "cpu.h" +#include "usb-simtec.h" /* macros for virtual address mods for the io space entries */ #define VA_C5(item) ((item) + BAST_VAM_CS5) @@ -154,6 +161,7 @@ static struct s3c2410_uartcfg bast_uartcfgs[] = { [1] = { .hwport = 1, .flags = 0, + .clock = &bast_serial_clock, .ucon = UCON, .ulcon = ULCON, @@ -170,19 +178,51 @@ static struct s3c2410_uartcfg bast_uartcfgs[] = { } }; +/* NOR Flash on BAST board */ + +static struct resource bast_nor_resource[] = { + [0] = { + .start = S3C2410_CS1 + 0x4000000, + .end = S3C2410_CS1 + 0x4000000 + (32*1024*1024) - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device bast_device_nor = { + .name = "bast-nor", + .id = -1, + .num_resources = ARRAY_SIZE(bast_nor_resource), + .resource = bast_nor_resource, +}; + +/* Standard BAST devices */ + +static struct platform_device *bast_devices[] __initdata = { + &s3c_device_usb, + &s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, + &s3c_device_rtc, + &bast_device_nor +}; + +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; + s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); + s3c2410_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); + s3c2410_set_board(&bast_board); + usb_simtec_init(); } 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 0a9ba135b..397c546b7 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 * * http://www.handhelds.org/projects/h1940.html @@ -16,6 +16,8 @@ * 06-Jan-2003 BJD Updates for * 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 + * 04-Sep-2004 BJD Changed uart init, renamed ipaq_ -> h1940_ */ #include @@ -39,8 +41,10 @@ #include #include "s3c2410.h" +#include "devs.h" +#include "cpu.h" -static struct map_desc ipaq_iodesc[] __initdata = { +static struct map_desc h1940_iodesc[] __initdata = { /* nothing here yet */ }; @@ -48,7 +52,7 @@ static struct map_desc ipaq_iodesc[] __initdata = { #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB #define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE -static struct s3c2410_uartcfg ipaq_uartcfgs[] = { +static struct s3c2410_uartcfg h1940_uartcfgs[] = { [0] = { .hwport = 0, .flags = 0, @@ -77,21 +81,35 @@ static struct s3c2410_uartcfg ipaq_uartcfgs[] = { }; -void __init ipaq_map_io(void) + + +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 h1940_map_io(void) { - s3c2410_map_io(ipaq_iodesc, ARRAY_SIZE(ipaq_iodesc)); - s3c2410_uartcfgs = ipaq_uartcfgs; + s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); + s3c2410_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs)); + s3c2410_set_board(&h1940_board); } -void __init ipaq_init_irq(void) +void __init h1940_init_irq(void) { - //llprintk("ipaq_init_irq:\n"); - s3c2410_init_irq(); } -void __init ipaq_init_time(void) +void __init h1940_init_time(void) { s3c2410_init_time(); } @@ -100,7 +118,7 @@ MACHINE_START(H1940, "IPAQ-H1940") MAINTAINER("Ben Dooks ") BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) - MAPIO(ipaq_map_io) - INITIRQ(ipaq_init_irq) - INITTIME(ipaq_init_time) + MAPIO(h1940_map_io) + INITIRQ(h1940_init_irq) + INITTIME(h1940_init_time) MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index bfadbd425..9f4286569 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -47,7 +47,8 @@ #include #include "s3c2410.h" - +#include "devs.h" +#include "cpu.h" static struct map_desc smdk2410_iodesc[] __initdata = { /* nothing here yet */ @@ -87,11 +88,24 @@ 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; + s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); + s3c2410_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); + s3c2410_set_board(&smdk2410_board); } void __init smdk2410_init_irq(void) @@ -113,3 +127,5 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc INITIRQ(smdk2410_init_irq) INITTIME(smdk2410_init_time) MACHINE_END + + diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index aae341c69..4a07a40cc 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -11,13 +11,10 @@ * published by the Free Software Foundation. * * Modifications: + * 14-Sep-2004 BJD USB Power control + * 04-Sep-2004 BJD Added new uart init, and io init + * 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 - * 18-Jan-2003 BJD Added serial port configuration * 05-Apr-2004 BJD Copied to make mach-vr1000.c */ @@ -44,6 +41,9 @@ #include #include "s3c2410.h" +#include "devs.h" +#include "cpu.h" +#include "usb-simtec.h" /* macros for virtual address mods for the io space entries */ #define VA_C5(item) ((item) + BAST_VAM_CS5) @@ -143,19 +143,31 @@ 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; + s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); + s3c2410_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs)); + s3c2410_set_board(&vr1000_board); + usb_simtec_init(); } void __init vr1000_init_irq(void) { - //llprintk("vr1000init_irq:\n"); - s3c2410_init_irq(); - } void __init vr1000_init_time(void) diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index bfd843cef..7709e8dde 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 * * 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 @@ -35,6 +36,9 @@ #include #include +#include "s3c2410.h" +#include "cpu.h" + int s3c2410_clock_tick_rate = 12*1000*1000; /* current timers at 12MHz */ /* serial port setup */ @@ -47,33 +51,14 @@ unsigned long s3c2410_fclk; unsigned long s3c2410_hclk; unsigned long s3c2410_pclk; -#ifndef MHZ -#define MHZ (1000*1000) -#endif - -#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000) - -#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(USBHOST), + IODESC_ENT(CLKPWR), + IODESC_ENT(LCD), + IODESC_ENT(UART), + IODESC_ENT(TIMER), + IODESC_ENT(ADC), + IODESC_ENT(WATCHDOG) }; static struct resource s3c_uart0_resource[] = { @@ -146,14 +131,16 @@ static struct platform_device *uart_devices[] __initdata = { &s3c_uart2 }; -void __init s3c2410_map_io(struct map_desc *mach_desc, int size) +void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size) { unsigned long tmp; /* register our io-tables */ iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc)); - iotable_init(mach_desc, size); + iotable_init(mach_desc, mach_size); + + printk("machine_initted %p,%d\n", mach_desc, mach_size); /* now we've got our machine bits initialised, work out what * clocks we've got */ @@ -175,16 +162,41 @@ 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; +} + +void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + s3c2410_uartcfgs = cfg; +} -static int __init s3c2410_init(void) +int __init s3c2410_init(void) { int ret; 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; } - -arch_initcall(s3c2410_init); diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h index 862a7c86d..09742c9bc 100644 --- a/arch/arm/mach-s3c2410/s3c2410.h +++ b/arch/arm/mach-s3c2410/s3c2410.h @@ -1,4 +1,19 @@ - +/* arch/arm/mach-s3c2410/s3c2410.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2410 machine directory + * + * 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. + * + * Modifications: + * 18-Aug-2004 BJD Created initial version + * 20-Aug-2004 BJD Added s3c2410_board struct + * 04-Sep-2004 BJD Added s3c2410_init_uarts() call +*/ extern void s3c2410_map_io(struct map_desc *, int count); @@ -6,3 +21,18 @@ 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); + +extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c new file mode 100644 index 000000000..fb3078379 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2440-dsc.c @@ -0,0 +1,57 @@ +/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Samsung S3C2440 Drive Strength Control support + * + * 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. + * + * Modifications: + * 29-Aug-2004 BJD Start of drive-strength control +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "s3c2440.h" +#include "cpu.h" + +int s3c2440_set_dsc(unsigned int pin, unsigned int value) +{ + unsigned long base; + unsigned long val; + unsigned long flags; + unsigned long mask; + + base = (pin & S3C2440_SELECT_DSC1) ? S3C2440_DSC1 : S3C2440_DSC0; + mask = 3 << S3C2440_DSC_GETSHIFT(pin); + + local_irq_save(flags); + + val = __raw_readl(base); + val &= ~mask; + val |= value & mask; + __raw_writel(val, base); + + local_irq_restore(flags); + return 0; +} diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c new file mode 100644 index 000000000..f4bb10c58 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2440.c @@ -0,0 +1,192 @@ +/* linux/arch/arm/mach-s3c2410/s3c2440.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Samsung S3C2440 Mobile CPU support + * + * 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. + * + * Modifications: + * 24-Aug-2004 BJD Start of s3c2440 support +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "s3c2440.h" +#include "cpu.h" + +int s3c2440_clock_tick_rate = 12*1000*1000; /* current timers at 12MHz */ + +/* clock info */ + +unsigned long s3c2440_baseclk = 12*1000*1000; /* assume base is 12MHz */ +unsigned long s3c2440_hdiv; + +unsigned long s3c2440_fclk; +unsigned long s3c2440_hclk; +unsigned long s3c2440_pclk; + +static struct map_desc s3c2440_iodesc[] __initdata = { + IODESC_ENT(USBHOST), + IODESC_ENT(CLKPWR), + IODESC_ENT(LCD), + IODESC_ENT(TIMER), + IODESC_ENT(ADC), +}; + +static struct resource s3c_uart0_resource[] = { + [0] = { + .start = S3C2410_PA_UART0, + .end = S3C2410_PA_UART0 + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_S3CUART_RX0, + .end = IRQ_S3CUART_ERR0, + .flags = IORESOURCE_IRQ, + } + +}; + +static struct resource s3c_uart1_resource[] = { + [0] = { + .start = S3C2410_PA_UART1, + .end = S3C2410_PA_UART1 + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_S3CUART_RX1, + .end = IRQ_S3CUART_ERR1, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource s3c_uart2_resource[] = { + [0] = { + .start = S3C2410_PA_UART2, + .end = S3C2410_PA_UART2 + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_S3CUART_RX2, + .end = IRQ_S3CUART_ERR2, + .flags = IORESOURCE_IRQ, + } +}; + +/* our uart devices */ + +static struct platform_device s3c_uart0 = { + .name = "s3c2440-uart", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_uart0_resource), + .resource = s3c_uart0_resource, +}; + + +static struct platform_device s3c_uart1 = { + .name = "s3c2440-uart", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_uart1_resource), + .resource = s3c_uart1_resource, +}; + +static struct platform_device s3c_uart2 = { + .name = "s3c2440-uart", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_uart2_resource), + .resource = s3c_uart2_resource, +}; + +static struct platform_device *uart_devices[] __initdata = { + &s3c_uart0, + &s3c_uart1, + &s3c_uart2 +}; + +void __init s3c2440_map_io(struct map_desc *mach_desc, int size) +{ + unsigned long tmp; + unsigned long camdiv; + + /* register our io-tables */ + + iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc)); + iotable_init(mach_desc, size); + + /* now we've got our machine bits initialised, work out what + * clocks we've got */ + + s3c2440_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), + s3c2440_baseclk); + + tmp = __raw_readl(S3C2410_CLKDIVN); + camdiv = __raw_readl(S3C2440_CAMDIVN); + + /* work out clock scalings */ + + switch (tmp & S3C2440_CLKDIVN_HDIVN_MASK) { + case S3C2440_CLKDIVN_HDIVN_1: + s3c2440_hdiv = 1; + break; + + case S3C2440_CLKDIVN_HDIVN_2: + s3c2440_hdiv = 1; + break; + + case S3C2440_CLKDIVN_HDIVN_4_8: + s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; + break; + + case S3C2440_CLKDIVN_HDIVN_3_6: + s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 6 : 3; + break; + } + + s3c2440_hclk = s3c2440_fclk / s3c2440_hdiv; + s3c2440_pclk = s3c2440_hclk / ((tmp & S3C2440_CLKDIVN_PDIVN) ? 2 : 1); + + /* print brieft summary of clocks, etc */ + + printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", + print_mhz(s3c2440_fclk), print_mhz(s3c2440_hclk), + print_mhz(s3c2440_pclk)); +} + + + +int __init s3c2440_init(void) +{ + int ret; + + printk("S3C2440: Initialising architecture\n"); + + ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices)); + if (ret) + return ret; + + // todo: board specific inits? + + return ret; +} + diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/arch/arm/mach-s3c2410/s3c2440.h new file mode 100644 index 000000000..bf49a66d5 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2440.h @@ -0,0 +1,18 @@ +/* arch/arm/mach-s3c2410/s3c2440.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2440 cpu support + * + * 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. + * + * Modifications: + * 24-Aug-2004 BJD Start of S3C2440 CPU support +*/ + +extern void s3c2440_init_irq(void); + +extern void s3c2440_init_time(void); diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c index 62d89d98c..04ba5dfe0 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/mach-s3c2410/time.c @@ -31,14 +31,12 @@ #include #include #include +#include #include static unsigned long timer_startval; static unsigned long timer_ticks_usec; -#ifdef CONFIG_S3C2410_RTC -extern void s3c2410_rtc_check(); -#endif /* with an 12MHz clock, we get 12 ticks per-usec */ @@ -49,15 +47,30 @@ extern void s3c2410_rtc_check(); * will have been disabled by do_gettimeoffset() * IRQs are disabled before entering here from do_gettimeofday() */ + +#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0)) + static unsigned long s3c2410_gettimeoffset (void) { unsigned long tdone; unsigned long usec; + unsigned long irqpend; /* work out how many ticks have gone since last timer interrupt */ tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); + /* check to see if there is an interrupt pending */ + + irqpend = __raw_readl(S3C2410_SRCPND); + if (irqpend & SRCPND_TIMER4) { + /* re-read the timer, and try and fix up for the missed + * interrupt */ + + tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); + tdone += 1<<16; + } + /* currently, tcnt is in 12MHz units, but this may change * for non-bast machines... */ diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c new file mode 100644 index 000000000..b8f8ded4b --- /dev/null +++ b/arch/arm/mach-s3c2410/usb-simtec.c @@ -0,0 +1,123 @@ +/* linux/arch/arm/mach-s3c2410/usb-simtec.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * Simtec BAST and Thorcom VR1000 USB port support functions + * + * 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. + * + * Modifications: + * 14-Sep-2004 BJD Created +*/ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "devs.h" +#include "usb-simtec.h" + +/* control power and monitor over-current events on various Simtec + * designed boards. +*/ + +static void +usb_simtec_powercontrol(int port, int to) +{ + pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to); + + if (port == 1) { + s3c2410_gpio_setpin(S3C2410_GPB4, to ? 0:1); + pr_debug("GPBDAT now %08x\n", __raw_readl(S3C2410_GPBDAT)); + } +} + +static irqreturn_t +usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs) +{ + struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw; + + if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) { + pr_debug("usb_simtec: over-current irq (oc detected)\n"); + s3c2410_report_oc(info, 3); + } else { + pr_debug("usb_simtec: over-current irq (oc cleared)\n"); + } + + return IRQ_HANDLED; +} + +static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on) +{ + int ret; + + if (on) { + pr_debug("claiming usb overccurent\n"); + ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, SA_INTERRUPT, + "usb-oc", info); + if (ret != 0) { + printk(KERN_ERR "failed to request usb oc irq\n"); + } + + set_irq_type(IRQ_USBOC, IRQT_BOTHEDGE); + } else { + free_irq(IRQ_USBOC, NULL); + } +} + +static struct s3c2410_hcd_info usb_simtec_info = { + .port[0] = { + .flags = S3C_HCDFLG_USED + }, + .port[1] = { + .flags = S3C_HCDFLG_USED + }, + + .power_control = usb_simtec_powercontrol, + .enable_oc = usb_simtec_enableoc, +}; + + +int usb_simtec_init(void) +{ + printk("USB Power Control, (c) 2004 Simtec Electronics\n"); + s3c_device_usb.dev.platform_data = &usb_simtec_info; + + s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP); + s3c2410_gpio_setpin(S3C2410_GPB4, 1); + + pr_debug("GPB: CON=%08x, DAT=%08x\n", + __raw_readl(S3C2410_GPBCON), __raw_readl(S3C2410_GPBDAT)); + + if (0) { + s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, + S3C2410_MISCCR_USBDEV); + } + + return 0; +} diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h new file mode 100644 index 000000000..92c0cc83a --- /dev/null +++ b/arch/arm/mach-s3c2410/usb-simtec.h @@ -0,0 +1,19 @@ +/* linux/arch/arm/mach-s3c2410/usb-simtec.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * Simtec BAST and Thorcom VR1000 USB port support functions + * + * 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. + * + * Modifications: + * 20-Aug-2004 BJD Created +*/ + +extern int usb_simtec_init(void); + diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c index be5dd86f4..6435b2e48 100644 --- a/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/arch/arm/mach-sa1100/cpu-sa1100.c @@ -230,9 +230,7 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver sa1100_driver = { - .flags = CPUFREQ_STICKY | - CPUFREQ_PANIC_OUTOFSYNC | - CPUFREQ_PANIC_RESUME_OUTOFSYNC, + .flags = CPUFREQ_STICKY, .verify = sa11x0_verify_speed, .target = sa1100_target, .get = sa11x0_getspeed, diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c index 62a4dbcce..8d2a89a2e 100644 --- a/arch/arm/mach-sa1100/cpu-sa1110.c +++ b/arch/arm/mach-sa1100/cpu-sa1110.c @@ -329,9 +329,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver sa1110_driver = { - .flags = CPUFREQ_STICKY | - CPUFREQ_PANIC_OUTOFSYNC | - CPUFREQ_PANIC_RESUME_OUTOFSYNC, + .flags = CPUFREQ_STICKY, .verify = sa11x0_verify_speed, .target = sa1110_target, .get = sa11x0_getspeed, diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 2532b7f80..7120ec5aa 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -30,6 +30,7 @@ #include #include #include +#include extern void sa1100_cpu_suspend(void); extern void sa1100_cpu_resume(void); @@ -44,7 +45,7 @@ extern void sa1100_cpu_resume(void); */ enum { SLEEP_SAVE_SP = 0, - SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, + SLEEP_SAVE_OIER, SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR, @@ -58,18 +59,19 @@ enum { SLEEP_SAVE_SP = 0, static int sa11x0_pm_enter(u32 state) { - unsigned long sleep_save[SLEEP_SAVE_SIZE]; - unsigned long delta, gpio; + unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE]; + struct timespec delta, rtc; if (state != PM_SUSPEND_MEM) return -EINVAL; /* preserve current time */ - delta = xtime.tv_sec - RCNR; + rtc.tv_sec = RCNR; + rtc.tv_nsec = 0; + save_time_delta(&delta, &rtc); gpio = GPLR; /* save vital registers */ - SAVE(OSCR); SAVE(OSMR0); SAVE(OSMR1); SAVE(OSMR2); @@ -131,11 +133,14 @@ static int sa11x0_pm_enter(u32 state) RESTORE(OSMR1); RESTORE(OSMR2); RESTORE(OSMR3); - RESTORE(OSCR); RESTORE(OIER); + /* OSMR0 is the system timer: make sure OSCR is sufficiently behind */ + OSCR = OSMR0 - LATCH; + /* restore current time */ - xtime.tv_sec = RCNR + delta; + rtc.tv_sec = RCNR; + restore_time_delta(&delta, &rtc); return 0; } diff --git a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c index a13253692..24f12bdfb 100644 --- a/arch/arm/mach-versatile/clock.c +++ b/arch/arm/mach-versatile/clock.c @@ -87,8 +87,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate) if (clk->setvco) { struct icst525_vco vco; - vco = icst525_khz_to_vco(clk->params, rate); - clk->rate = icst525_khz(clk->params, vco); + vco = icst525_khz_to_vco(clk->params, rate / 1000); + clk->rate = icst525_khz(clk->params, vco) * 1000; printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", clk->name, vco.s, vco.r, vco.v); diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 285ca9abb..239d9897d 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include @@ -325,6 +327,213 @@ static struct mmc_platform_data mmc1_plat_data = { }; #endif +/* + * CLCD support. + */ +#define SYS_CLCD_MODE_MASK (3 << 0) +#define SYS_CLCD_MODE_5551 (0 << 0) +#define SYS_CLCD_MODE_565 (1 << 0) +#define SYS_CLCD_MODE_888 (2 << 0) +#define SYS_CLCD_MODE_LT (3 << 0) +#define SYS_CLCD_NLCDIOON (1 << 2) +#define SYS_CLCD_VDDPOSSWITCH (1 << 3) +#define SYS_CLCD_PWR3V5SWITCH (1 << 4) +#define SYS_CLCD_ID_MASK (0x1f << 8) +#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) +#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) +#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) +#define SYS_CLCD_ID_VGA (0x1f << 8) + +static struct clcd_panel vga = { + .mode = { + .name = "VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +static struct clcd_panel sanyo_3_8_in = { + .mode = { + .name = "Sanyo QVGA", + .refresh = 116, + .xres = 320, + .yres = 240, + .pixclock = 100000, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 5, + .lower_margin = 5, + .hsync_len = 6, + .vsync_len = 6, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +static struct clcd_panel epson_2_2_in = { + .mode = { + .name = "Epson QCIF", + .refresh = 390, + .xres = 176, + .yres = 220, + .pixclock = 62500, + .left_margin = 3, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 0, + .hsync_len = 3, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +/* + * Detect which LCD panel is connected, and return the appropriate + * clcd_panel structure. Note: we do not have any information on + * the required timings for the 8.4in panel, so we presently assume + * VGA timings. + */ +static struct clcd_panel *versatile_clcd_panel(void) +{ + unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; + struct clcd_panel *panel = &vga; + u32 val; + + val = readl(sys_clcd) & SYS_CLCD_ID_MASK; + if (val == SYS_CLCD_ID_SANYO_3_8) + panel = &sanyo_3_8_in; + else if (val == SYS_CLCD_ID_EPSON_2_2) + panel = &epson_2_2_in; + else if (val == SYS_CLCD_ID_VGA) + panel = &vga; + else { + printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", + val); + } + + return &vga; +} + +/* + * Disable all display connectors on the interface module. + */ +static void versatile_clcd_disable(struct clcd_fb *fb) +{ + unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; + u32 val; + + val = readl(sys_clcd); + val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; + writel(val, sys_clcd); +} + +/* + * Enable the relevant connector on the interface module. + */ +static void versatile_clcd_enable(struct clcd_fb *fb) +{ + unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; + u32 val; + + val = readl(sys_clcd); + val &= ~SYS_CLCD_MODE_MASK; + + switch (fb->fb.var.green.length) { + case 5: +#if 0 + /* + * For some undocumented reason, we need to select 565 mode + * even when using 555 with VGA. Maybe this is only true + * for the VGA output and needs to be done for LCD panels? + * I can't get an explaination from the people who should + * know. + */ + val |= SYS_CLCD_MODE_5551; + break; +#endif + case 6: + val |= SYS_CLCD_MODE_565; + break; + case 8: + val |= SYS_CLCD_MODE_888; + break; + } + + /* + * Set the MUX + */ + writel(val, sys_clcd); + + /* + * And now enable the PSUs + */ + val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; + writel(val, sys_clcd); +} + +static unsigned long framesize = SZ_1M; + +static int versatile_clcd_setup(struct clcd_fb *fb) +{ + dma_addr_t dma; + + fb->panel = versatile_clcd_panel(); + + fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, + &dma, GFP_KERNEL); + if (!fb->fb.screen_base) { + printk(KERN_ERR "CLCD: unable to map framebuffer\n"); + return -ENOMEM; + } + + fb->fb.fix.smem_start = dma; + fb->fb.fix.smem_len = framesize; + + return 0; +} + +static void versatile_clcd_remove(struct clcd_fb *fb) +{ + dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, + fb->fb.screen_base, fb->fb.fix.smem_start); +} + +static struct clcd_board clcd_plat_data = { + .name = "Versatile PB", + .check = clcdfb_check, + .decode = clcdfb_decode, + .disable = versatile_clcd_disable, + .enable = versatile_clcd_enable, + .setup = versatile_clcd_setup, + .remove = versatile_clcd_remove, +}; + #define AMBA_DEVICE(name,busid,base,plat) \ static struct amba_device name##_device = { \ .dev = { \ @@ -417,7 +626,7 @@ AMBA_DEVICE(mmc1, "fpga:0b", MMCI1, &mmc1_plat_data); /* DevChip Primecells */ AMBA_DEVICE(smc, "dev:00", SMC, NULL); AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); -AMBA_DEVICE(clcd, "dev:20", CLCD, NULL); +AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 545a548b1..f0a878204 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -43,7 +43,7 @@ config CPU_ARM710 # ARM720T config CPU_ARM720T bool "Support ARM720T processor" if !ARCH_CLPS711X && !ARCH_L7200 && !ARCH_CDB89712 && ARCH_INTEGRATOR - default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 + default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 || ARCH_H720X select CPU_32v4 select CPU_ABRT_LV4T select CPU_CACHE_V4 @@ -59,7 +59,7 @@ config CPU_ARM720T # ARM920T config CPU_ARM920T bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_INTEGRATOR || ARCH_S3C2410 + depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX default y if ARCH_S3C2410 select CPU_32v4 select CPU_ABRT_EV4T @@ -220,7 +220,7 @@ config CPU_SA1100 # XScale config CPU_XSCALE bool - depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX + depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000 default y select CPU_32v5 select CPU_ABRT_EV5T diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index fc764e17e..ccf316c11 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -3,7 +3,8 @@ # obj-y := consistent.o extable.o fault-armv.o \ - fault.o init.o ioremap.o mmap.o mm-armv.o + fault.o flush.o init.o ioremap.o mmap.o \ + mm-armv.o obj-$(CONFIG_MODULES) += proc-syms.o diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index 922e05a4d..fd0584a92 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S @@ -23,7 +23,6 @@ ENTRY(v5tj_early_abort) mrc p15, 0, r0, c6, c0, 0 @ get FAR bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #PSR_J_BIT @ Java? - orrne r1, r1, #1 << 11 @ always assume write movne pc, lr tst r3, #PSR_T_BIT @ Thumb? ldrneh r3, [r2] @ read aborted thumb instruction diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index 6659439f6..e1994788c 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S @@ -57,6 +57,19 @@ ENTRY(v3_flush_user_cache_range) * - end - virtual end address */ ENTRY(v3_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v3_coherent_user_range) mov pc, lr /* @@ -116,6 +129,7 @@ ENTRY(v3_cache_fns) .long v3_flush_user_cache_all .long v3_flush_user_cache_range .long v3_coherent_kern_range + .long v3_coherent_user_range .long v3_flush_kern_dcache_page .long v3_dma_inv_range .long v3_dma_clean_range diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index bbc822f16..b8ad5d58e 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S @@ -59,6 +59,19 @@ ENTRY(v4_flush_user_cache_range) * - end - virtual end address */ ENTRY(v4_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v4_coherent_user_range) mov pc, lr /* @@ -118,6 +131,7 @@ ENTRY(v4_cache_fns) .long v4_flush_user_cache_all .long v4_flush_user_cache_range .long v4_coherent_kern_range + .long v4_coherent_user_range .long v4_flush_kern_dcache_page .long v4_dma_inv_range .long v4_dma_clean_range diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index 4f7c918e6..5c4055b62 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S @@ -121,6 +121,19 @@ ENTRY(v4wb_flush_kern_dcache_page) * - end - virtual end address */ ENTRY(v4wb_coherent_kern_range) + /* fall through */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v4wb_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry @@ -195,6 +208,7 @@ ENTRY(v4wb_cache_fns) .long v4wb_flush_user_cache_all .long v4wb_flush_user_cache_range .long v4wb_coherent_kern_range + .long v4wb_coherent_user_range .long v4wb_flush_kern_dcache_page .long v4wb_dma_inv_range .long v4wb_dma_clean_range diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S index 61c9fc60f..9bcabd86c 100644 --- a/arch/arm/mm/cache-v4wt.S +++ b/arch/arm/mm/cache-v4wt.S @@ -97,6 +97,19 @@ ENTRY(v4wt_flush_user_cache_range) * - end - virtual end address */ ENTRY(v4wt_coherent_kern_range) + /* FALLTRHOUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v4wt_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry add r0, r0, #CACHE_DLINESIZE @@ -167,6 +180,7 @@ ENTRY(v4wt_cache_fns) .long v4wt_flush_user_cache_all .long v4wt_flush_user_cache_range .long v4wt_coherent_kern_range + .long v4wt_coherent_user_range .long v4wt_flush_kern_dcache_page .long v4wt_dma_inv_range .long v4wt_dma_clean_range diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 336aa0e40..85c10a71e 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -75,6 +75,22 @@ ENTRY(v6_flush_user_cache_range) * - the Icache does not read data from the write buffer */ ENTRY(v6_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * v6_coherent_user_range(start,end) + * + * Ensure that the I and D caches are coherent within specified + * region. This is typically used when code has been written to + * a memory region, and will be executed. + * + * - start - virtual start address of region + * - end - virtual end address of region + * + * It is assumed that: + * - the Icache does not read data from the write buffer + */ +ENTRY(v6_coherent_user_range) bic r0, r0, #CACHE_LINE_SIZE - 1 1: #ifdef HARVARD_CACHE @@ -203,6 +219,7 @@ ENTRY(v6_cache_fns) .long v6_flush_user_cache_all .long v6_flush_user_cache_range .long v6_coherent_kern_range + .long v6_coherent_user_range .long v6_flush_kern_dcache_page .long v6_dma_inv_range .long v6_dma_clean_range diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index f9b8fe2c7..57b0be2ab 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -138,7 +138,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, struct page *page; struct vm_region *c; unsigned long order; - u64 mask = 0x00ffffff, limit; /* ISA default */ + u64 mask = ISA_DMA_THRESHOLD, limit; if (!consistent_pte) { printk(KERN_ERR "%s: not initialised\n", __func__); @@ -148,19 +148,34 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, if (dev) { mask = dev->coherent_dma_mask; + + /* + * Sanity check the DMA mask - it must be non-zero, and + * must be able to be satisfied by a DMA allocation. + */ if (mask == 0) { dev_warn(dev, "coherent DMA mask is unset\n"); - return NULL; + goto no_page; + } + + if ((~mask) & ISA_DMA_THRESHOLD) { + dev_warn(dev, "coherent DMA mask %#llx is smaller " + "than system GFP_DMA mask %#llx\n", + mask, (unsigned long long)ISA_DMA_THRESHOLD); + goto no_page; } } + /* + * Sanity check the allocation size. + */ size = PAGE_ALIGN(size); limit = (mask + 1) & ~mask; - if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) { - printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", - size, mask); - *handle = ~0; - return NULL; + if ((limit && size >= limit) || + size >= (CONSISTENT_END - CONSISTENT_BASE)) { + printk(KERN_WARNING "coherent allocation too big " + "(requested %#x mask %#llx)\n", size, mask); + goto no_page; } order = get_order(size); @@ -221,6 +236,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, if (page) __free_pages(page, order); no_page: + *handle = ~0; return NULL; } diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index e6a139ee2..402dad21a 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -31,14 +31,46 @@ static spinlock_t v6_lock = SPIN_LOCK_UNLOCKED; #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) +/* + * Copy the user page. No aliasing to deal with so we can just + * attack the kernel's existing mapping of these pages. + */ +void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr) +{ + copy_page(kto, kfrom); +} + +/* + * Clear the user page. No aliasing to deal with so we can just + * attack the kernel's existing mapping of this page. + */ +void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr) +{ + clear_page(kaddr); +} + /* * Copy the page, taking account of the cache colour. */ -void v6_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) +void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr) { unsigned int offset = DCACHE_COLOUR(vaddr); unsigned long from, to; + /* + * Discard data in the kernel mapping for the new page. + * FIXME: needs this MCRR to be supported. + */ + __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" + : + : "r" (kto), + "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES) + : "cc"); + + /* + * Now copy the page using the same cache colour as the + * pages ultimate destination. + */ spin_lock(&v6_lock); set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); @@ -55,11 +87,30 @@ void v6_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) spin_unlock(&v6_lock); } -void v6_clear_user_page(void *kaddr, unsigned long vaddr) +/* + * Clear the user page. We need to deal with the aliasing issues, + * so remap the kernel page into the same cache colour as the user + * page. + */ +void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) { unsigned int offset = DCACHE_COLOUR(vaddr); unsigned long to = to_address + (offset << PAGE_SHIFT); + /* + * Discard data in the kernel mapping for the new page + * FIXME: needs this MCRR to be supported. + */ + __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" + : + : "r" (kaddr), + "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES) + : "cc"); + + /* + * Now clear the page using the same cache colour as + * the pages ultimate destination. + */ spin_lock(&v6_lock); set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); @@ -70,26 +121,31 @@ void v6_clear_user_page(void *kaddr, unsigned long vaddr) } struct cpu_user_fns v6_user_fns __initdata = { - .cpu_clear_user_page = v6_clear_user_page, - .cpu_copy_user_page = v6_copy_user_page, + .cpu_clear_user_page = v6_clear_user_page_nonaliasing, + .cpu_copy_user_page = v6_copy_user_page_nonaliasing, }; static int __init v6_userpage_init(void) { - pgd_t *pgd; - pmd_t *pmd; - - pgd = pgd_offset_k(from_address); - pmd = pmd_alloc(&init_mm, pgd, from_address); - if (!pmd) - BUG(); - from_pte = pte_alloc_kernel(&init_mm, pmd, from_address); - if (!from_pte) - BUG(); - - to_pte = pte_alloc_kernel(&init_mm, pmd, to_address); - if (!to_pte) - BUG(); + if (cache_is_vipt_aliasing()) { + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset_k(from_address); + pmd = pmd_alloc(&init_mm, pgd, from_address); + if (!pmd) + BUG(); + from_pte = pte_alloc_kernel(&init_mm, pmd, from_address); + if (!from_pte) + BUG(); + + to_pte = pte_alloc_kernel(&init_mm, pmd, to_address); + if (!to_pte) + BUG(); + + cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; + cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; + } return 0; } diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index d03940c1b..5f0a79094 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -76,59 +76,12 @@ no_pmd: return 0; } -static void __flush_dcache_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *mpnt = NULL; - struct prio_tree_iter iter; - unsigned long offset; - pgoff_t pgoff; - - __cpuc_flush_dcache_page(page_address(page)); - - if (!mapping) - return; - - /* - * With a VIVT cache, we need to also write back - * and invalidate any user data. - */ - pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); - - flush_dcache_mmap_lock(mapping); - while ((mpnt = vma_prio_tree_next(mpnt, &mapping->i_mmap, - &iter, pgoff, pgoff)) != NULL) { - /* - * If this VMA is not in our MM, we can ignore it. - */ - if (mpnt->vm_mm != mm) - continue; - if (!(mpnt->vm_flags & VM_MAYSHARE)) - continue; - offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; - flush_cache_page(mpnt, mpnt->vm_start + offset); - } - flush_dcache_mmap_unlock(mapping); -} - -void flush_dcache_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - - if (mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); - else - __flush_dcache_page(page); -} -EXPORT_SYMBOL(flush_dcache_page); - static void make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) { struct address_space *mapping = page_mapping(page); struct mm_struct *mm = vma->vm_mm; - struct vm_area_struct *mpnt = NULL; + struct vm_area_struct *mpnt; struct prio_tree_iter iter; unsigned long offset; pgoff_t pgoff; @@ -145,8 +98,7 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, * cache coherency. */ flush_dcache_mmap_lock(mapping); - while ((mpnt = vma_prio_tree_next(mpnt, &mapping->i_mmap, - &iter, pgoff, pgoff)) != NULL) { + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { /* * If this VMA is not in our MM, we can ignore it. * Note that we intentionally mask out the VMA @@ -190,10 +142,21 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) if (page_mapping(page)) { int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) + if (dirty) { + /* + * This is our first userspace mapping of this page. + * Ensure that the physical page is coherent with + * the kernel mapping. + * + * FIXME: only need to do this on VIVT and aliasing + * VIPT cache architectures. We can do that + * by choosing whether to set this bit... + */ __cpuc_flush_dcache_page(page_address(page)); + } - make_coherent(vma, addr, page, dirty); + if (cache_is_vivt()) + make_coherent(vma, addr, page, dirty); } } diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c new file mode 100644 index 000000000..ff5f62ce4 --- /dev/null +++ b/arch/arm/mm/flush.c @@ -0,0 +1,94 @@ +/* + * linux/arch/arm/mm/flush.c + * + * Copyright (C) 1995-2002 Russell King + * + * 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 +#include +#include + +#include +#include + +static void __flush_dcache_page(struct address_space *mapping, struct page *page) +{ + struct mm_struct *mm = current->active_mm; + struct vm_area_struct *mpnt; + struct prio_tree_iter iter; + pgoff_t pgoff; + + /* + * Writeback any data associated with the kernel mapping of this + * page. This ensures that data in the physical page is mutually + * coherent with the kernels mapping. + */ + __cpuc_flush_dcache_page(page_address(page)); + + /* + * If there's no mapping pointer here, then this page isn't + * visible to userspace yet, so there are no cache lines + * associated with any other aliases. + */ + if (!mapping) + return; + + /* + * There are possible user space mappings of this page: + * - VIVT cache: we need to also write back and invalidate all user + * data in the current VM view associated with this page. + * - aliasing VIPT: we only need to find one mapping of this page. + */ + pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); + + flush_dcache_mmap_lock(mapping); + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { + unsigned long offset; + + /* + * If this VMA is not in our MM, we can ignore it. + */ + if (mpnt->vm_mm != mm) + continue; + if (!(mpnt->vm_flags & VM_MAYSHARE)) + continue; + offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; + flush_cache_page(mpnt, mpnt->vm_start + offset); + if (cache_is_vipt()) + break; + } + flush_dcache_mmap_unlock(mapping); +} + +/* + * Ensure cache coherency between kernel mapping and userspace mapping + * of this page. + * + * We have three cases to consider: + * - VIPT non-aliasing cache: fully coherent so nothing required. + * - VIVT: fully aliasing, so we need to handle every alias in our + * current VM view. + * - VIPT aliasing: need to handle one alias in our current VM view. + * + * If we need to handle aliasing: + * If the page only exists in the page cache and there are no user + * space mappings, we can be lazy and remember that we may have dirty + * kernel cache lines for later. Otherwise, we assume we have + * aliasing mappings. + */ +void flush_dcache_page(struct page *page) +{ + struct address_space *mapping = page_mapping(page); + + if (cache_is_vipt_nonaliasing()) + return; + + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else + __flush_dcache_page(mapping, page); +} +EXPORT_SYMBOL(flush_dcache_page); diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 060fea2e1..d7b4441ac 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -344,7 +345,7 @@ static inline void free_bootmem_node_bank(int node, struct meminfo *mi) * Initialise the bootmem allocator for all nodes. This is called * early during the architecture specific initialisation. */ -void __init bootmem_init(struct meminfo *mi) +static void __init bootmem_init(struct meminfo *mi) { struct node_info node_info[MAX_NUMNODES], *np = node_info; unsigned int bootmap_pages, bootmap_pfn, map_pg; @@ -412,9 +413,7 @@ void __init bootmem_init(struct meminfo *mi) } #endif - if (map_pg != bootmap_pfn + bootmap_pages) - BUG(); - + BUG_ON(map_pg != bootmap_pfn + bootmap_pages); } /* @@ -426,6 +425,8 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) void *zero_page; int node; + bootmem_init(mi); + memcpy(&meminfo, mi, sizeof(meminfo)); /* @@ -495,7 +496,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); } @@ -590,7 +591,7 @@ void __init mem_init(void) * anywhere without overcommit, so turn * it on by default. */ - sysctl_overcommit_memory = 1; + sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; } } diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 7fe21a95d..1267ab586 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -196,6 +196,19 @@ ENTRY(arm1020_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm1020_coherent_kern_range) + /* FALLTRHOUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1020_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 mcr p15, 0, ip, c7, c10, 4 @@ -317,6 +330,7 @@ ENTRY(arm1020_cache_fns) .long arm1020_flush_user_cache_all .long arm1020_flush_user_cache_range .long arm1020_coherent_kern_range + .long arm1020_coherent_user_range .long arm1020_flush_kern_dcache_page .long arm1020_dma_inv_range .long arm1020_dma_clean_range diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index 0332c3e69..947790dd3 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -193,6 +193,18 @@ ENTRY(arm1020e_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm1020e_coherent_kern_range) + /* FALLTHROUGH */ +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1020e_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 1: @@ -304,6 +316,7 @@ ENTRY(arm1020e_cache_fns) .long arm1020e_flush_user_cache_all .long arm1020e_flush_user_cache_range .long arm1020e_coherent_kern_range + .long arm1020e_coherent_user_range .long arm1020e_flush_kern_dcache_page .long arm1020e_dma_inv_range .long arm1020e_dma_clean_range @@ -495,7 +508,7 @@ __arm1020e_proc_info: b __arm1020e_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB + .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP .long cpu_arm1020e_name .long arm1020e_processor_functions .long v4wbi_tlb_fns diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 35a5c2f00..7c8426384 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -180,6 +180,19 @@ ENTRY(arm1022_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm1022_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1022_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 1: @@ -291,6 +304,7 @@ ENTRY(arm1022_cache_fns) .long arm1022_flush_user_cache_all .long arm1022_flush_user_cache_range .long arm1022_coherent_kern_range + .long arm1022_coherent_user_range .long arm1022_flush_kern_dcache_page .long arm1022_dma_inv_range .long arm1022_dma_clean_range @@ -475,7 +489,7 @@ __arm1022_proc_info: b __arm1022_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB + .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP .long cpu_arm1022_name .long arm1022_processor_functions .long v4wbi_tlb_fns diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index 0009f2d27..38a06cb1e 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -175,6 +175,18 @@ ENTRY(arm1026_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm1026_coherent_kern_range) + /* FALLTHROUGH */ +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm1026_coherent_user_range) mov ip, #0 bic r0, r0, #CACHE_DLINESIZE - 1 1: @@ -286,6 +298,7 @@ ENTRY(arm1026_cache_fns) .long arm1026_flush_user_cache_all .long arm1026_flush_user_cache_range .long arm1026_coherent_kern_range + .long arm1026_coherent_user_range .long arm1026_flush_kern_dcache_page .long arm1026_dma_inv_range .long arm1026_dma_clean_range @@ -471,7 +484,7 @@ __arm1026_proc_info: b __arm1026_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA .long cpu_arm1026_name .long arm1026_processor_functions .long v4wbi_tlb_fns diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 3922a8213..8c9204a7c 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -182,6 +182,19 @@ ENTRY(arm920_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm920_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm920_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -277,6 +290,7 @@ ENTRY(arm920_cache_fns) .long arm920_flush_user_cache_all .long arm920_flush_user_cache_range .long arm920_coherent_kern_range + .long arm920_coherent_user_range .long arm920_flush_kern_dcache_page .long arm920_dma_inv_range .long arm920_dma_clean_range diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 86065117c..13e65cb8a 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -184,6 +184,19 @@ ENTRY(arm922_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm922_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm922_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -279,6 +292,7 @@ ENTRY(arm922_cache_fns) .long arm922_flush_user_cache_all .long arm922_flush_user_cache_range .long arm922_coherent_kern_range + .long arm922_coherent_user_range .long arm922_flush_kern_dcache_page .long arm922_dma_inv_range .long arm922_dma_clean_range diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index 917eb5e16..e8b3ff1fb 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -225,6 +225,19 @@ ENTRY(arm925_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm925_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm925_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -329,6 +342,7 @@ ENTRY(arm925_cache_fns) .long arm925_flush_user_cache_all .long arm925_flush_user_cache_range .long arm925_coherent_kern_range + .long arm925_coherent_user_range .long arm925_flush_kern_dcache_page .long arm925_dma_inv_range .long arm925_dma_clean_range diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 9b098e05c..5631c8bbd 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -185,6 +185,19 @@ ENTRY(arm926_flush_user_cache_range) * - end - virtual end address */ ENTRY(arm926_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(arm926_coherent_user_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -289,6 +302,7 @@ ENTRY(arm926_cache_fns) .long arm926_flush_user_cache_all .long arm926_flush_user_cache_range .long arm926_coherent_kern_range + .long arm926_coherent_user_range .long arm926_flush_kern_dcache_page .long arm926_dma_inv_range .long arm926_dma_clean_range @@ -473,7 +487,7 @@ __arm926_proc_info: b __arm926_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | HWCAP_JAVA + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA .long cpu_arm926_name .long arm926_processor_functions .long v4wbi_tlb_fns diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index 8df666f8d..6c5f0fe57 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c @@ -22,10 +22,10 @@ EXPORT_SYMBOL(processor); #endif #ifndef MULTI_CACHE -EXPORT_SYMBOL_NOVERS(__cpuc_flush_kern_all); -EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_all); -EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_range); -EXPORT_SYMBOL_NOVERS(__cpuc_coherent_kern_range); +EXPORT_SYMBOL(__cpuc_flush_kern_all); +EXPORT_SYMBOL(__cpuc_flush_user_all); +EXPORT_SYMBOL(__cpuc_flush_user_range); +EXPORT_SYMBOL(__cpuc_coherent_kern_range); #else EXPORT_SYMBOL(cpu_cache); #endif diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index c22cc3601..0a4ff2624 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -189,12 +189,10 @@ cpu_v6_name: * - cache type register is implemented */ __v6_setup: - mrc p15, 0, r10, c0, c0, 1 @ read cache type register - tst r10, #1 << 24 @ Harvard cache? mov r10, #0 - mcrne p15, 0, r10, c7, c14, 0 @ clean+invalidate D cache - mcrne p15, 0, r10, c7, c5, 0 @ invalidate I cache - mcreq p15, 0, r10, c7, c15, 0 @ clean+invalidate cache + mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D cache + mcr p15, 0, r10, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r10, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, r10, c7, c10, 4 @ drain write buffer mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r10, c2, c0, 2 @ TTB control register @@ -258,7 +256,7 @@ __v6_proc_info: b __v6_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_FAST_MULT | HWCAP_VFP + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA .long cpu_v6_name .long v6_processor_functions .long v6wbi_tlb_fns diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 2652d141f..2be02f7f5 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -241,6 +241,22 @@ ENTRY(xscale_flush_user_cache_range) * it also trashes the mini I-cache used by JTAG debuggers. */ ENTRY(xscale_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + * + * Note: single I-cache line invalidation isn't used here since + * it also trashes the mini I-cache used by JTAG debuggers. + */ +ENTRY(xscale_coherent_user_range) bic r0, r0, #CACHELINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHELINESIZE @@ -341,6 +357,7 @@ ENTRY(xscale_cache_fns) .long xscale_flush_user_cache_all .long xscale_flush_user_cache_range .long xscale_coherent_kern_range + .long xscale_coherent_user_range .long xscale_flush_kern_dcache_page .long xscale_dma_inv_range .long xscale_dma_clean_range @@ -585,7 +602,12 @@ __xscale_setup: mcr p15, 0, r4, c2, c0, 0 @ load page table pointer mov r0, #0x1f @ Domains 0, 1 = client mcr p15, 0, r0, c3, c0, 0 @ load domain access register - mov r0, #1 @ Allow access to CP0 and CP13 +#ifdef CONFIG_IWMMXT + mov r0, #0 @ initially disallow access to CP0/CP1 +#else + mov r0, #1 @ Allow access to CP0 +#endif + orr r0, r0, #1 << 6 @ cp6 for IOP3xx and Bulverde orr r0, r0, #1 << 13 @ Its undefined whether this mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes mrc p15, 0, r0, c1, c0, 0 @ get control register @@ -632,10 +654,15 @@ cpu_80200_name: .asciz "XScale-80200" .size cpu_80200_name, . - cpu_80200_name - .type cpu_80321_name, #object -cpu_80321_name: - .asciz "XScale-IOP80321" - .size cpu_80321_name, . - cpu_80321_name + .type cpu_8032x_name, #object +cpu_8032x_name: + .asciz "XScale-IOP8032x Family" + .size cpu_8032x_name, . - cpu_8032x_name + + .type cpu_8033x_name, #object +cpu_8033x_name: + .asciz "XScale-IOP8033x Family" + .size cpu_8033x_name, . - cpu_8033x_name .type cpu_pxa250_name, #object cpu_pxa250_name: @@ -652,6 +679,16 @@ cpu_ixp42x_name: .asciz "XScale-IXP42x Family" .size cpu_ixp42x_name, . - cpu_ixp42x_name + .type cpu_ixp2400_name, #object +cpu_ixp2400_name: + .asciz "XScale-IXP2400" + .size cpu_ixp2400_name, . - cpu_ixp2400_name + + .type cpu_ixp2800_name, #object +cpu_ixp2800_name: + .asciz "XScale-IXP2800" + .size cpu_ixp2800_name, . - cpu_ixp2800_name + .type cpu_pxa255_name, #object cpu_pxa255_name: .asciz "XScale-PXA255" @@ -682,21 +719,37 @@ __80200_proc_info: .long xscale_cache_fns .size __80200_proc_info, . - __80200_proc_info - .type __80321_proc_info,#object -__80321_proc_info: + .type __8032x_proc_info,#object +__8032x_proc_info: .long 0x69052420 - .long 0xfffff7e0 + .long 0xfffff5e0 @ mask should accomodate IOP80219 also + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_8032x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __8032x_proc_info, . - __8032x_proc_info + + .type __8033x_proc_info,#object +__8033x_proc_info: + .long 0x69054090 + .long 0xffffffb0 .long 0x00000c0e b __xscale_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP - .long cpu_80321_name + .long cpu_8033x_name .long xscale_processor_functions .long v4wbi_tlb_fns .long xscale_mc_user_fns .long xscale_cache_fns - .size __80321_proc_info, . - __80321_proc_info + .size __8033x_proc_info, . - __8033x_proc_info .type __pxa250_proc_info,#object __pxa250_proc_info: @@ -730,6 +783,38 @@ __pxa210_proc_info: .long xscale_cache_fns .size __pxa210_proc_info, . - __pxa210_proc_info + .type __ixp2400_proc_info, #object +__ixp2400_proc_info: + .long 0x69054190 + .long 0xfffffff0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2400_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp2400_proc_info, . - __ixp2400_proc_info + + .type __ixp2800_proc_info, #object +__ixp2800_proc_info: + .long 0x690541a0 + .long 0xfffffff0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2800_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp2800_proc_info, . - __ixp2800_proc_info + .type __ixp42x_proc_info, #object __ixp42x_proc_info: .long 0x690541c0 diff --git a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c index 2ad457558..95fb63fa9 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 284874be3..447653df1 100644 --- a/arch/arm/oprofile/op_model_xscale.c +++ b/arch/arm/oprofile/op_model_xscale.c @@ -7,7 +7,7 @@ * @remark Copyright 2004 Dave Jiang * @remark Copyright 2004 Intel Corporation * @remark Copyright 2004 Zwane Mwaikambo - * @remark Copyright 2004 Oprofile Authors + * @remark Copyright 2004 OProfile Authors * * @remark Read the file COPYING * @@ -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; } @@ -249,7 +256,7 @@ static int xscale_setup_ctrs(void) int i; for (i = CCNT; i < MAX_COUNTERS; i++) { - if (counter_config[i].event) + if (counter_config[i].enabled) continue; counter_config[i].event = EVT_UNUSED; @@ -336,7 +343,7 @@ static void inline __xsc2_check_ctrs(void) static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) { - unsigned long eip = instruction_pointer(regs); + unsigned long pc = profile_pc(regs); int i, is_kernel = !user_mode(regs); u32 pmnc; @@ -350,7 +357,7 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs continue; write_counter(i, -(u32)results[i].reset_counter); - oprofile_add_sample(eip, is_kernel, i, smp_processor_id()); + oprofile_add_sample(pc, is_kernel, i, smp_processor_id()); results[i].ovf--; } @@ -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/arm/tools/mach-types b/arch/arm/tools/mach-types index d2ce22372..4df5b0f30 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Jul 2 11:58:36 2004 +# Last update: Thu Sep 30 15:23:21 2004 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -519,7 +519,7 @@ scb9328 MACH_SCB9328 SCB9328 508 omap_h3 MACH_OMAP_H3 OMAP_H3 509 omap_h4 MACH_OMAP_H4 OMAP_H4 510 n10 MACH_N10 N10 511 -montajade MACH_MONTAJADE MONTAJADE 512 +montejade MACH_MONTAJADE MONTAJADE 512 sg560 MACH_SG560 SG560 513 dp1000 MACH_DP1000 DP1000 514 omap_osk MACH_OMAP_OSK OMAP_OSK 515 @@ -559,3 +559,59 @@ lpc2294 MACH_LPC2294 LPC2294 548 switchgrass MACH_SWITCHGRASS SWITCHGRASS 549 ens_cmu MACH_ENS_CMU ENS_CMU 550 mm6_sdb MACH_MM6_SDB MM6_SDB 551 +saturn MACH_SATURN SATURN 552 +argonplusevb MACH_ARGONPLUSEVB ARGONPLUSEVB 553 +scma11evb MACH_SCMA11EVB SCMA11EVB 554 +smdk2800 MACH_SMDK2800 SMDK2800 555 +mtwilson MACH_MTWILSON MTWILSON 556 +ziti MACH_ZITI ZITI 557 +grandfather MACH_GRANDFATHER GRANDFATHER 558 +tengine MACH_TENGINE TENGINE 559 +s3c2460 MACH_S3C2460 S3C2460 560 +pdm MACH_PDM PDM 561 +h4700 MACH_H4700 H4700 562 +h6300 MACH_H6300 H6300 563 +rz1700 MACH_RZ1700 RZ1700 564 +a716 MACH_A716 A716 565 +estk2440a MACH_ESTK2440A ESTK2440A 566 +atwixp425 MACH_ATWIXP425 ATWIXP425 567 +csb336 MACH_CSB336 CSB336 568 +rirm2 MACH_RIRM2 RIRM2 569 +cx23518 MACH_CX23518 CX23518 570 +cx2351x MACH_CX2351X CX2351X 571 +computime MACH_COMPUTIME COMPUTIME 572 +izarus MACH_IZARUS IZARUS 573 +pxa_rts MACH_RTS RTS 574 +se5100 MACH_SE5100 SE5100 575 +s3c2510 MACH_S3C2510 S3C2510 576 +csb437tl MACH_CSB437TL CSB437TL 577 +slauson MACH_SLAUSON SLAUSON 578 +pearlriver MACH_PEARLRIVER PEARLRIVER 579 +tdc_p210 MACH_TDC_P210 TDC_P210 580 +sg580 MACH_SG580 SG580 581 +wrsbcarm7 MACH_WRSBCARM7 WRSBCARM7 582 +ipd MACH_IPD IPD 583 +pxa_dnp2110 MACH_PXA_DNP2110 PXA_DNP2110 584 +xaeniax MACH_XAENIAX XAENIAX 585 +somn4250 MACH_SOMN4250 SOMN4250 586 +pleb2 MACH_PLEB2 PLEB2 587 +cwl MACH_CWL CWL 588 +gd MACH_GD GD 589 +chaffee MACH_CHAFFEE CHAFFEE 590 +rms101 MACH_RMS101 RMS101 591 +rx3715 MACH_RX3715 RX3715 592 +swift MACH_SWIFT SWIFT 593 +roverp7 MACH_ROVERP7 ROVERP7 594 +pr818s MACH_PR818S PR818S 595 +trxpro MACH_TRXPRO TRXPRO 596 +nslu2 MACH_NSLU2 NSLU2 597 +e400 MACH_E400 E400 598 +trab MACH_TRAB TRAB 599 +cmc_pu2 MACH_CMC_PU2 CMC_PU2 600 +fulcrum MACH_FULCRUM FULCRUM 601 +netgate42x MACH_NETGATE42X NETGATE42X 602 +str710 MACH_STR710 STR710 603 +ixdpg425 MACH_IXDPG425 IXDPG425 604 +tomtomgo MACH_TOMTOMGO TOMTOMGO 605 +versatile_ab MACH_VERSATILE_AB VERSATILE_AB 606 +edb9307 MACH_EDB9307 EDB9307 607 diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index ce96fd34b..d51376a09 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -62,7 +62,7 @@ config ARCH_ARC bool "Archimedes" help Say Y to support the Acorn Archimedes. - + The Acorn Archimedes was an personal computer based on an 8MHz ARM2 processor, released in 1987. It supported up to 16MB of RAM in later models and floppy, harddisc, ethernet etc. @@ -71,7 +71,7 @@ config ARCH_A5K bool "A5000" help Say Y here to to support the Acorn A5000. - + Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. Note that on some A5000s the floppy is @@ -214,118 +214,7 @@ source "drivers/misc/Kconfig" source "drivers/usb/Kconfig" -menu "Kernel hacking" - -# RMK wants arm kernels compiled with frame pointers so hardwire this to y. -# If you know what you are doing and are willing to live without stack -# traces, you can get a slightly smaller kernel by setting this option to -# n, but then RMK will have to kill you ;). -config FRAME_POINTER - bool - default y - help - If you say N here, the resulting kernel will be slightly smaller and - faster. However, when a problem occurs with the kernel, the - information that is reported is severely limited. Most people - should say Y here. - -config DEBUG_USER - bool "Verbose user fault messages" - help - When a user program crashes due to an exception, the kernel can - print a brief message explaining what the problem was. This is - sometimes helpful for debugging but serves no purpose on a - production system. Most people should say N here. - -config DEBUG_INFO - bool "Include GDB debugging information in kernel binary" - help - Say Y here to include source-level debugging information in the - `vmlinux' binary image. This is handy if you want to use gdb or - addr2line to debug the kernel. It has no impact on the in-memory - footprint of the running kernel but it can increase the amount of - time and disk space needed for compilation of the kernel. If in - doubt say N. - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_WAITQ - bool "Wait queue debugging" - depends on DEBUG_KERNEL - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" - depends on DEBUG_KERNEL - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -config DEBUG_ERRORS - bool "Verbose kernel error messages" - depends on DEBUG_KERNEL - help - This option controls verbose debugging information which can be - printed when the kernel detects an internal error. This debugging - information is useful to kernel hackers when tracking down problems, - but mostly meaningless to other people. It's safe to say Y unless - you are concerned with the code size or don't want to see these - messages. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -# These options are only for real kernel hackers who want to get their hands dirty. -config DEBUG_LL - bool "Kernel low-level debugging functions" - depends on DEBUG_KERNEL - help - Say Y here to include definitions of printascii, printchar, printhex - in the kernel. This is helpful if you are debugging code that - executes before the console is initialized. - -endmenu +source "arch/arm26/Kconfig.debug" source "security/Kconfig" diff --git a/arch/arm26/Kconfig.debug b/arch/arm26/Kconfig.debug new file mode 100644 index 000000000..e2c920dc1 --- /dev/null +++ b/arch/arm26/Kconfig.debug @@ -0,0 +1,60 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +# RMK wants arm kernels compiled with frame pointers so hardwire this to y. +# If you know what you are doing and are willing to live without stack +# traces, you can get a slightly smaller kernel by setting this option to +# n, but then RMK will have to kill you ;). +config FRAME_POINTER + bool + default y + help + If you say N here, the resulting kernel will be slightly smaller and + faster. However, when a problem occurs with the kernel, the + information that is reported is severely limited. Most people + should say Y here. + +config DEBUG_USER + bool "Verbose user fault messages" + help + When a user program crashes due to an exception, the kernel can + print a brief message explaining what the problem was. This is + sometimes helpful for debugging but serves no purpose on a + production system. Most people should say N here. + +config DEBUG_WAITQ + bool "Wait queue debugging" + depends on DEBUG_KERNEL + +config DEBUG_ERRORS + bool "Verbose kernel error messages" + depends on DEBUG_KERNEL + help + This option controls verbose debugging information which can be + printed when the kernel detects an internal error. This debugging + information is useful to kernel hackers when tracking down problems, + but mostly meaningless to other people. It's safe to say Y unless + you are concerned with the code size or don't want to see these + messages. + +config DEBUG_INFO + bool "Include GDB debugging information in kernel binary" + help + Say Y here to include source-level debugging information in the + `vmlinux' binary image. This is handy if you want to use gdb or + addr2line to debug the kernel. It has no impact on the in-memory + footprint of the running kernel but it can increase the amount of + time and disk space needed for compilation of the kernel. If in + doubt say N. + +# These options are only for real kernel hackers who want to get their hands dirty. +config DEBUG_LL + bool "Kernel low-level debugging functions" + depends on DEBUG_KERNEL + help + Say Y here to include definitions of printascii, printchar, printhex + in the kernel. This is helpful if you are debugging code that + executes before the console is initialized. + +endmenu diff --git a/arch/arm26/Makefile b/arch/arm26/Makefile index 3b0294a8d..631c20aef 100644 --- a/arch/arm26/Makefile +++ b/arch/arm26/Makefile @@ -8,8 +8,7 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=-p -X -LDFLAGS_BLOB :=--format binary -AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) +CPPFLAGS_vmlinux.lds = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) OBJCOPYFLAGS :=-O binary -R .note -R .comment -S GZFLAGS :=-9 @@ -28,7 +27,6 @@ CFLAGS +=-mapcs-26 -mcpu=arm3 -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uar AFLAGS +=-mapcs-26 -mcpu=arm3 -mno-fpu -msoft-float -Wa,-mno-fpu head-y := arch/arm26/machine/head.o arch/arm26/kernel/init_task.o -LDFLAGS_BLOB += --oformat elf32-littlearm ifeq ($(CONFIG_XIP_KERNEL),y) TEXTADDR := 0x03880000 diff --git a/arch/arm26/boot/Makefile b/arch/arm26/boot/Makefile index 3d992e597..004dd81f9 100644 --- a/arch/arm26/boot/Makefile +++ b/arch/arm26/boot/Makefile @@ -67,12 +67,12 @@ initrd: install: $(obj)/Image $(CONFIG_SHELL) $(obj)/install.sh \ - $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) \ + $(KERNELRELEASE) \ $(obj)/Image System.map "$(INSTALL_PATH)" zinstall: $(obj)/zImage $(CONFIG_SHELL) $(obj)/install.sh \ - $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) \ + $(KERNELRELEASE) \ $(obj)/zImage System.map "$(INSTALL_PATH)" subdir- := compressed diff --git a/arch/arm26/kernel/Makefile b/arch/arm26/kernel/Makefile index 7e10b557c..e2e5503f7 100644 --- a/arch/arm26/kernel/Makefile +++ b/arch/arm26/kernel/Makefile @@ -14,5 +14,5 @@ obj-y := compat.o dma.o entry.o irq.o \ obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_MODULES) += armksyms.o -extra-y := init_task.o vmlinux.lds.s +extra-y := init_task.o vmlinux.lds diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c index c540f22f9..bd6c30669 100644 --- a/arch/arm26/kernel/armksyms.c +++ b/arch/arm26/kernel/armksyms.c @@ -95,7 +95,7 @@ EXPORT_SYMBOL(ret_from_exception); EXPORT_SYMBOL(kd_mksound); #endif -EXPORT_SYMBOL_NOVERS(__do_softirq); +EXPORT_SYMBOL(__do_softirq); /* platform dependent support */ EXPORT_SYMBOL(dump_thread); @@ -125,71 +125,71 @@ EXPORT_SYMBOL(__csum_ipv6_magic); /* io */ #ifndef __raw_readsb -EXPORT_SYMBOL_NOVERS(__raw_readsb); +EXPORT_SYMBOL(__raw_readsb); #endif #ifndef __raw_readsw -EXPORT_SYMBOL_NOVERS(__raw_readsw); +EXPORT_SYMBOL(__raw_readsw); #endif #ifndef __raw_readsl -EXPORT_SYMBOL_NOVERS(__raw_readsl); +EXPORT_SYMBOL(__raw_readsl); #endif #ifndef __raw_writesb -EXPORT_SYMBOL_NOVERS(__raw_writesb); +EXPORT_SYMBOL(__raw_writesb); #endif #ifndef __raw_writesw -EXPORT_SYMBOL_NOVERS(__raw_writesw); +EXPORT_SYMBOL(__raw_writesw); #endif #ifndef __raw_writesl -EXPORT_SYMBOL_NOVERS(__raw_writesl); +EXPORT_SYMBOL(__raw_writesl); #endif /* string / mem functions */ -EXPORT_SYMBOL_NOVERS(strcpy); -EXPORT_SYMBOL_NOVERS(strncpy); -EXPORT_SYMBOL_NOVERS(strcat); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(strcmp); -EXPORT_SYMBOL_NOVERS(strncmp); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(__memzero); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(__memzero); /* user mem (segment) */ EXPORT_SYMBOL(uaccess_kernel); EXPORT_SYMBOL(uaccess_user); -EXPORT_SYMBOL_NOVERS(__get_user_1); -EXPORT_SYMBOL_NOVERS(__get_user_2); -EXPORT_SYMBOL_NOVERS(__get_user_4); -EXPORT_SYMBOL_NOVERS(__get_user_8); +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); +EXPORT_SYMBOL(__get_user_8); -EXPORT_SYMBOL_NOVERS(__put_user_1); -EXPORT_SYMBOL_NOVERS(__put_user_2); -EXPORT_SYMBOL_NOVERS(__put_user_4); -EXPORT_SYMBOL_NOVERS(__put_user_8); +EXPORT_SYMBOL(__put_user_1); +EXPORT_SYMBOL(__put_user_2); +EXPORT_SYMBOL(__put_user_4); +EXPORT_SYMBOL(__put_user_8); /* gcc lib functions */ -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__divsi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(__modsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__ucmpdi2); -EXPORT_SYMBOL_NOVERS(__udivdi3); -EXPORT_SYMBOL_NOVERS(__umoddi3); -EXPORT_SYMBOL_NOVERS(__udivmoddi4); -EXPORT_SYMBOL_NOVERS(__udivsi3); -EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__umoddi3); +EXPORT_SYMBOL(__udivmoddi4); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); /* bitops */ EXPORT_SYMBOL(_set_bit_le); @@ -214,10 +214,10 @@ EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_wait4); /* semaphores */ -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); -EXPORT_SYMBOL_NOVERS(__down_trylock_failed); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_interruptible_failed); +EXPORT_SYMBOL(__down_trylock_failed); +EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(get_wchan); diff --git a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c index 7869d1b22..be2ebeaa8 100644 --- a/arch/arm26/kernel/irq.c +++ b/arch/arm26/kernel/irq.c @@ -187,6 +187,7 @@ static void __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) { unsigned int status; + int ret; spin_unlock(&irq_controller_lock); if (!(action->flags & SA_INTERRUPT)) @@ -194,8 +195,9 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) status = 0; do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c index 57b9fb1e2..e2ffb2007 100644 --- a/arch/arm26/kernel/ptrace.c +++ b/arch/arm26/kernel/ptrace.c @@ -729,11 +729,8 @@ asmlinkage void syscall_trace(int why, struct pt_regs *regs) /* 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 * for normal use. strace only continues with a signal if the diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c index 16cf7db5c..bf05f1537 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 0d1cdd503..431f9f85e 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/time.c b/arch/arm26/kernel/time.c index af2905a1f..dbbc21404 100644 --- a/arch/arm26/kernel/time.c +++ b/arch/arm26/kernel/time.c @@ -67,28 +67,6 @@ static unsigned long dummy_gettimeoffset(void) */ unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; -/* - * Handle kernel profile stuff... - */ -static inline void do_profile(struct pt_regs *regs) -{ - if (!user_mode(regs) && - prof_buffer && - current->pid) { - unsigned long pc = instruction_pointer(regs); - extern int _stext; - - pc -= (unsigned long)&_stext; - - pc >>= prof_shift; - - if (pc >= prof_len) - pc = prof_len - 1; - - prof_buffer[pc] += 1; - } -} - static unsigned long next_rtc_update; /* @@ -189,7 +167,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_timer(regs); do_set_rtc(); //FIME - EVERY timer IRQ? - do_profile(regs); + profile_tick(CPU_PROFILING, regs); return IRQ_HANDLED; //FIXME - is this right? } diff --git a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in index 61eedf0bc..cbbda2766 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 2393f3805..128eb9195 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 ad41cebe2..17f7dc3e9 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; @@ -376,7 +376,7 @@ void __init mem_init(void) * Turn on overcommit on tiny machines */ if (PAGE_SIZE >= 16384 && num_physpages <= 128) { - sysctl_overcommit_memory = 1; + sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; printk("Turning on overcommit\n"); } } diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 481edcadc..81a4a9c18 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -20,8 +20,11 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool -source "init/Kconfig" +config CRIS + bool + default y +source "init/Kconfig" menu "General setup" @@ -51,7 +54,7 @@ config ETRAX_FAST_TIMER bool "Enable ETRAX fast timer API" help This options enables the API to a fast timer implementation using - timer1 to get sub jiffie resolution timers (primarily one-shot + timer1 to get sub jiffie resolution timers (primarily one-shot timers). This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. @@ -69,7 +72,6 @@ config PREEMPT endmenu - menu "Hardware setup" choice @@ -96,7 +98,7 @@ endchoice config ETRAX_ARCH_V10 bool default y if ETRAX100LX || ETRAX100LX_V2 - default n if !(ETRAX100LX || ETRAX100LX_V2) + default n if !(ETRAX100LX || ETRAX100LX_V2) config ETRAX_DRAM_SIZE int "DRAM size (dec, in MB)" @@ -165,54 +167,10 @@ source "sound/Kconfig" source "drivers/usb/Kconfig" - -menu "Kernel hacking" - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -config PROFILE - bool "Kernel profiling support" - -config PROFILE_SHIFT - int "Profile shift count" - depends on PROFILE - default "2" - -config ETRAX_KGDB - bool "Use kernel GDB debugger" - ---help--- - The CRIS version of gdb can be used to remotely debug a running - Linux kernel via the serial debug port. Provided you have gdb-cris - installed, run gdb-cris vmlinux, then type - - (gdb) set remotebaud 115200 <- kgdb uses 115200 as default - (gdb) target remote /dev/ttyS0 <- maybe you use another port - - This should connect you to your booted kernel (or boot it now if you - didn't before). The kernel halts when it boots, waiting for gdb if - this option is turned on! - - -config DEBUG_INFO - bool "Compile the kernel with debug info" - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - -endmenu +source "arch/cris/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/cris/Kconfig.debug b/arch/cris/Kconfig.debug new file mode 100644 index 000000000..9864aade2 --- /dev/null +++ b/arch/cris/Kconfig.debug @@ -0,0 +1,28 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +config PROFILE + bool "Kernel profiling support" + +config PROFILE_SHIFT + int "Profile shift count" + depends on PROFILE + default "2" + +config ETRAX_KGDB + bool "Use kernel GDB debugger" + ---help--- + The CRIS version of gdb can be used to remotely debug a running + Linux kernel via the serial debug port. Provided you have gdb-cris + installed, run gdb-cris vmlinux, then type + + (gdb) set remotebaud 115200 <- kgdb uses 115200 as default + (gdb) target remote /dev/ttyS0 <- maybe you use another port + + This should connect you to your booted kernel (or boot it now if you + didn't before). The kernel halts when it boots, waiting for gdb if + this option is turned on! + +endmenu diff --git a/arch/cris/Makefile b/arch/cris/Makefile index 30585a70c..0c6944c7c 100644 --- a/arch/cris/Makefile +++ b/arch/cris/Makefile @@ -24,12 +24,10 @@ SARCH := endif LD = $(CROSS_COMPILE)ld -mcrislinux -LDFLAGS_BLOB := --format binary --oformat elf32-cris \ - -T arch/cris/$(SARCH)/output_arch.ld OBJCOPYFLAGS := -O binary -R .note -R .comment -S -AFLAGS_vmlinux.lds.o = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) +CPPFLAGS_vmlinux.lds = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) AFLAGS += -mlinux CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe @@ -39,7 +37,7 @@ CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS += -fno-omit-frame-pointer endif -HEAD := arch/$(ARCH)/$(SARCH)/kernel/head.o +head-y := arch/$(ARCH)/$(SARCH)/kernel/head.o LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index d80269f6f..d8f20d79f 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -259,7 +259,7 @@ static struct console sercons = { void __init init_etrax_debug(void) { -#if CONFIG_ETRAX_DEBUG_PORT_NULL +#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL return; #endif diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 8aba42472..d0993bf72 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/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index 39dcc3c72..3c7e0a51a 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -85,17 +85,8 @@ sys_ptrace(long request, long pid, long addr, long data) goto out_tsk; } - ret = -ESRCH; - - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - - if (child->parent != current) + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; switch (request) { diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 8db985e29..19f93fe42 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 df03dea5b..720b9c156 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 6b73a2c0d..9e134c688 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/cris/kernel/Makefile b/arch/cris/kernel/Makefile index 7c071a765..1546a0e74 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds obj-y := process.o traps.o irq.o ptrace.o setup.o \ time.o sys_cris.o semaphore.o diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index 6ded633f8..7141bbecd 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -91,8 +90,8 @@ EXPORT_SYMBOL(prepare_rx_descriptor); #undef memset extern void * memset(void *, int, __kernel_size_t); extern void * memcpy(void *, const void *, __kernel_size_t); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); #ifdef CONFIG_ETRAX_FAST_TIMER /* Fast timer functions */ diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index 94d702790..bb8d2e4e7 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -125,7 +125,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction *action; int do_random, cpu; - int retval = 0; + int ret, retval = 0; cpu = smp_processor_id(); irq_enter(); @@ -137,8 +137,10 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) local_irq_enable(); do_random = 0; do { - do_random |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + do_random |= action->flags; + retval |= ret; action = action->next; } while (action); diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 8497cfb80..62bb7ba4c 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -176,86 +176,15 @@ source "drivers/serial/Kconfig" source "drivers/i2c/Kconfig" source "drivers/usb/Kconfig" - + endmenu source "fs/Kconfig" -menu "Kernel hacking" - -config FULLDEBUG - bool "Full Symbolic/Source Debugging support" - help - Enable debugging symbols on kernel build. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - help - Enables console device to interprent special characters as - commands to dump state information. - -config HIGHPROFILE - bool "Use fast second timer for profiling" - help - Use a fast secondary clock to produce profiling information. - -config NO_KERNEL_MSG - bool "Suppress Kernel BUG Messages" - help - Do not output any debug BUG messages within the kernel. - -config GDB_MAGICPRINT - bool "Message Output for GDB MagicPrint service" - depends on (H8300H_SIM || H8S_SIM) - help - kernel messages output useing MagicPrint service from GDB - -config SYSCALL_PRINT - bool "SystemCall trace print" - help - outout history of systemcall - -config GDB_DEBUG - bool "Use gdb stub" - depends on (!H8300H_SIM && !H8S_SIM) - help - gdb stub exception support - -config CONFIG_SH_STANDARD_BIOS - bool "Use gdb protocol serial console" - depends on (!H8300H_SIM && !H8S_SIM) - help - serial console output using GDB protocol. - Require eCos/RedBoot - -config DEFAULT_CMDLINE - bool "Use buildin commandline" - default n - help - buildin kernel commandline enabled. - -config KERNEL_COMMAND - string "Buildin commmand string" - depends on DEFAULT_CMDLINE - help - buildin kernel commandline strings. - -config BLKDEV_RESERVE - bool "BLKDEV Reserved Memory" - default n - help - Reserved BLKDEV area. - -config CONFIG_BLKDEV_RESERVE_ADDRESS - hex 'start address' - depends on BLKDEV_RESERVE - help - BLKDEV start address. -endmenu +source "arch/h8300/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/h8300/Kconfig.debug b/arch/h8300/Kconfig.debug new file mode 100644 index 000000000..55034d08a --- /dev/null +++ b/arch/h8300/Kconfig.debug @@ -0,0 +1,68 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debugging symbols on kernel build. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + help + Use a fast secondary clock to produce profiling information. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config GDB_MAGICPRINT + bool "Message Output for GDB MagicPrint service" + depends on (H8300H_SIM || H8S_SIM) + help + kernel messages output useing MagicPrint service from GDB + +config SYSCALL_PRINT + bool "SystemCall trace print" + help + outout history of systemcall + +config GDB_DEBUG + bool "Use gdb stub" + depends on (!H8300H_SIM && !H8S_SIM) + help + gdb stub exception support + +config CONFIG_SH_STANDARD_BIOS + bool "Use gdb protocol serial console" + depends on (!H8300H_SIM && !H8S_SIM) + help + serial console output using GDB protocol. + Require eCos/RedBoot + +config DEFAULT_CMDLINE + bool "Use buildin commandline" + default n + help + buildin kernel commandline enabled. + +config KERNEL_COMMAND + string "Buildin commmand string" + depends on DEFAULT_CMDLINE + help + buildin kernel commandline strings. + +config BLKDEV_RESERVE + bool "BLKDEV Reserved Memory" + default n + help + Reserved BLKDEV area. + +config CONFIG_BLKDEV_RESERVE_ADDRESS + hex 'start address' + depends on BLKDEV_RESERVE + help + BLKDEV start address. + +endmenu diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile index 1f4ef89b5..71b6131e9 100644 --- a/arch/h8300/kernel/Makefile +++ b/arch/h8300/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds obj-y := process.o traps.o ptrace.o ints.o \ sys_h8300.o time.o semaphore.o signal.o \ diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c index 5e50c0893..b78b82ad2 100644 --- a/arch/h8300/kernel/asm-offsets.c +++ b/arch/h8300/kernel/asm-offsets.c @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #include #define DEFINE(sym, val) \ diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c index ca8578fed..5a6302331 100644 --- a/arch/h8300/kernel/h8300_ksyms.c +++ b/arch/h8300/kernel/h8300_ksyms.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -50,13 +49,13 @@ EXPORT_SYMBOL(csum_partial_copy); explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -//EXPORT_SYMBOL_NOVERS(__ashrdi3); -//EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memmove); +//EXPORT_SYMBOL(__ashrdi3); +//EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(get_wchan); @@ -85,29 +84,29 @@ extern void __umoddi3(void); extern void __umodsi3(void); /* gcc lib functions */ -EXPORT_SYMBOL_NOVERS(__gcc_bcmp); -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__cmpdi2); -EXPORT_SYMBOL_NOVERS(__divdi3); -EXPORT_SYMBOL_NOVERS(__divsi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(__moddi3); -EXPORT_SYMBOL_NOVERS(__modsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__mulsi3); -EXPORT_SYMBOL_NOVERS(__negdi2); -EXPORT_SYMBOL_NOVERS(__ucmpdi2); -EXPORT_SYMBOL_NOVERS(__udivdi3); -EXPORT_SYMBOL_NOVERS(__udivmoddi4); -EXPORT_SYMBOL_NOVERS(__udivsi3); -EXPORT_SYMBOL_NOVERS(__umoddi3); -EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL(__gcc_bcmp); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__cmpdi2); +EXPORT_SYMBOL(__divdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__moddi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__negdi2); +EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__udivmoddi4); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umoddi3); +EXPORT_SYMBOL(__umodsi3); #ifdef MAGIC_ROM_PTR -EXPORT_SYMBOL_NOVERS(is_in_rom); +EXPORT_SYMBOL(is_in_rom); #endif -EXPORT_SYMBOL_NOVERS(h8300_reserved_gpio); -EXPORT_SYMBOL_NOVERS(h8300_free_gpio); -EXPORT_SYMBOL_NOVERS(h8300_set_gpio_dir); +EXPORT_SYMBOL(h8300_reserved_gpio); +EXPORT_SYMBOL(h8300_free_gpio); +EXPORT_SYMBOL(h8300_set_gpio_dir); diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c index 7246e29ea..edb3c4170 100644 --- a/arch/h8300/kernel/ints.c +++ b/arch/h8300/kernel/ints.c @@ -22,13 +22,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include /* diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index d7c058d64..134aec1c6 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/ptrace.c b/arch/h8300/kernel/ptrace.c index 5905ceeaa..b60d234d1 100644 --- a/arch/h8300/kernel/ptrace.c +++ b/arch/h8300/kernel/ptrace.c @@ -89,13 +89,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; @@ -114,7 +107,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { - unsigned long tmp; + unsigned long tmp = 0; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) { ret = -EIO; @@ -270,10 +263,8 @@ asmlinkage void syscall_trace(void) return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; - 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 * for normal use. strace only continues with a signal if the diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 17c83890c..5fd383a6a 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/time.c b/arch/h8300/kernel/time.c index 87e284901..0b293d652 100644 --- a/arch/h8300/kernel/time.c +++ b/arch/h8300/kernel/time.c @@ -36,24 +36,6 @@ u64 jiffies_64; EXPORT_SYMBOL(jiffies_64); -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -64,10 +46,7 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) platform_timer_eoi(); do_timer(regs); - - if (!user_mode(regs)) - do_profile(regs->pc); - + profile_tick(CPU_PROFILING, regs); } void time_init(void) diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S index 7a6009cf2..427f1891c 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/h8300/lib/checksum.c b/arch/h8300/lib/checksum.c index 6691d0b93..5aa688d92 100644 --- a/arch/h8300/lib/checksum.c +++ b/arch/h8300/lib/checksum.c @@ -32,6 +32,7 @@ of the assembly has to go. */ #include +#include static inline unsigned short from32to16(unsigned long x) { diff --git a/arch/h8300/platform/h8300h/generic/timer.c b/arch/h8300/platform/h8300h/generic/timer.c index ffc0349b7..6590f89e5 100644 --- a/arch/h8300/platform/h8300h/generic/timer.c +++ b/arch/h8300/platform/h8300h/generic/timer.c @@ -32,7 +32,7 @@ #define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */ -int platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) +void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) { /* setup 8bit timer ch2 */ ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2); /* set interval */ @@ -69,7 +69,7 @@ void platform_timer_eoi(void) #define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8 /* Timer input freq. */ -int platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) +void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *)) { *(unsigned short *)GRA= H8300_TIMER_FREQ / HZ; /* set interval */ *(unsigned short *)TCNT=0; /* clear counter */ diff --git a/arch/h8300/platform/h8s/ints.c b/arch/h8300/platform/h8s/ints.c index bbefac403..5441cdd12 100644 --- a/arch/h8300/platform/h8s/ints.c +++ b/arch/h8300/platform/h8s/ints.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index af9750136..597a99691 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -29,8 +29,11 @@ config GENERIC_ISA_DMA bool default y -source "init/Kconfig" +config GENERIC_IOMAP + bool + default y +source "init/Kconfig" menu "Processor type and features" @@ -55,20 +58,20 @@ config X86_ELAN config X86_VOYAGER bool "Voyager (NCR)" help - Voyager is a MCA based 32 way capable SMP architecture proprietary - to NCR Corp. Machine classes 345x/35xx/4100/51xx are voyager based. - + Voyager is an MCA-based 32-way capable SMP architecture proprietary + to NCR Corp. Machine classes 345x/35xx/4100/51xx are Voyager-based. + *** WARNING *** - + If you do not specifically know you have a Voyager based machine, - say N here otherwise the kernel you build will not be bootable. + say N here, otherwise the kernel you build will not be bootable. config X86_NUMAQ bool "NUMAQ (IBM/Sequent)" select DISCONTIGMEM select NUMA help - This option is used for getting Linux to run on a (IBM/Sequent) NUMA + This option is used for getting Linux to run on a (IBM/Sequent) NUMA multiquad box. This changes the way that processors are bootstrapped, and uses Clustered Logical APIC addressing mode instead of Flat Logical. You will need a new lynxer.elf file to flash your firmware with - send @@ -115,8 +118,8 @@ config X86_ES7000 depends on SMP help Support for Unisys ES7000 systems. Say 'Y' here if this kernel is - supposed to run on an IA32-based Unisys ES7000 system. - Only choose this option if you have such a system, otherwise you + supposed to run on an IA32-based Unisys ES7000 system. + Only choose this option if you have such a system, otherwise you should say N here. endchoice @@ -322,7 +325,7 @@ config MVIAC3_2 endchoice config X86_GENERIC - bool "Generic x86 support" + bool "Generic x86 support" help Instead of just including optimizations for the selected x86 variant (e.g. PII, Crusoe or Athlon), include some more @@ -1027,7 +1030,6 @@ source "arch/i386/kernel/cpu/cpufreq/Kconfig" endmenu - menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" config X86_VISWS_APIC @@ -1105,7 +1107,7 @@ config PCI_DIRECT config PCI_MMCONFIG bool - depends on PCI && (PCI_GOMMCONFIG || PCI_GOANY) + depends on PCI && (PCI_GOMMCONFIG || (PCI_GOANY && ACPI)) select ACPI_BOOT default y @@ -1158,7 +1160,7 @@ config SCx200 tristate "NatSemi SCx200 support" depends on !X86_VOYAGER help - This provides basic support for the National Semiconductor SCx200 + This provides basic support for the National Semiconductor SCx200 processor. Right now this is just a driver for the GPIO pins. If you don't know what to do here, say N. @@ -1172,7 +1174,6 @@ source "drivers/pci/hotplug/Kconfig" endmenu - menu "Executable file formats" source "fs/Kconfig.binfmt" @@ -1185,130 +1186,7 @@ source "fs/Kconfig" source "arch/i386/oprofile/Kconfig" - -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config EARLY_PRINTK - bool "Early printk" if EMBEDDED - default y - help - Write kernel log output directly into the VGA buffer or to a serial - port. - - This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks ugly and doesn't cooperate - with klogd/syslogd or the X server. You should normally N here, - unless you want to debug such a crash. - -config DEBUG_STACKOVERFLOW - bool "Check for stack overflows" - depends on DEBUG_KERNEL - -config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_PAGEALLOC - bool "Page alloc debugging" - depends on DEBUG_KERNEL - help - Unmap pages from the kernel linear mapping after free_pages(). - This results in a large slowdown, but helps to find certain types - of memory corruptions. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This options enables addition error checking for high memory systems. - Disable for production systems. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - -config 4KSTACKS - bool "Use 4Kb for kernel stacks instead of 8Kb" - help - If you say Y here the kernel will use a 4Kb stacksize for the - kernel stack attached to each process/thread. This facilitates - running more threads on a system and also reduces the pressure - on the VM subsystem for higher order allocations. This option - will also use IRQ stacks to compensate for the reduced stackspace. - -config X86_FIND_SMP_CONFIG - bool - depends on X86_LOCAL_APIC || X86_VOYAGER - default y - -config X86_MPPARSE - bool - depends on X86_LOCAL_APIC && !X86_VISWS - default y - -endmenu +source "arch/i386/Kconfig.debug" source "security/Kconfig" diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug new file mode 100644 index 000000000..cf069b721 --- /dev/null +++ b/arch/i386/Kconfig.debug @@ -0,0 +1,80 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config EARLY_PRINTK + bool "Early printk" if EMBEDDED + default y + help + Write kernel log output directly into the VGA buffer or to a serial + port. + + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. For normal operation + it is not recommended because it looks ugly and doesn't cooperate + with klogd/syslogd or the X server. You should normally N here, + unless you want to debug such a crash. + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config DEBUG_PAGEALLOC + bool "Page alloc debugging" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a large slowdown, but helps to find certain types + of memory corruptions. + +config 4KSTACKS + bool "Use 4Kb for kernel stacks instead of 8Kb" + help + If you say Y here the kernel will use a 4Kb stacksize for the + kernel stack attached to each process/thread. This facilitates + running more threads on a system and also reduces the pressure + 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 + default y + +config X86_MPPARSE + bool + depends on X86_LOCAL_APIC && !X86_VISWS + default y + +endmenu diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 1e446b234..8fc05ee7c 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -18,48 +18,47 @@ LDFLAGS := -m elf_i386 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -CHECK := $(CHECK) -D__i386__=1 +CHECKFLAGS += -D__i386__ CFLAGS += -pipe -msoft-float # prevent gcc from keeping the stack 16 byte aligned -CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,) - -align := $(subst -functions=0,,$(call check_gcc,-falign-functions=0,-malign-functions=0)) +CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2) +align := $(subst -functions=0,,$(call cc-option,-falign-functions=0,-malign-functions=0)) cflags-$(CONFIG_M386) += -march=i386 cflags-$(CONFIG_M486) += -march=i486 cflags-$(CONFIG_M586) += -march=i586 cflags-$(CONFIG_M586TSC) += -march=i586 -cflags-$(CONFIG_M586MMX) += $(call check_gcc,-march=pentium-mmx,-march=i586) +cflags-$(CONFIG_M586MMX) += $(call cc-option,-march=pentium-mmx,-march=i586) cflags-$(CONFIG_M686) += -march=i686 -cflags-$(CONFIG_MPENTIUMII) += $(call check_gcc,-march=pentium2,-march=i686) -cflags-$(CONFIG_MPENTIUMIII) += $(call check_gcc,-march=pentium3,-march=i686) -cflags-$(CONFIG_MPENTIUMM) += $(call check_gcc,-march=pentium3,-march=i686) -cflags-$(CONFIG_MPENTIUM4) += $(call check_gcc,-march=pentium4,-march=i686) +cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,-march=pentium2,-march=i686) +cflags-$(CONFIG_MPENTIUMIII) += $(call cc-option,-march=pentium3,-march=i686) +cflags-$(CONFIG_MPENTIUMM) += $(call cc-option,-march=pentium3,-march=i686) +cflags-$(CONFIG_MPENTIUM4) += $(call cc-option,-march=pentium4,-march=i686) cflags-$(CONFIG_MK6) += -march=k6 # Please note, that patches that add -march=athlon-xp and friends are pointless. # They make zero difference whatsosever to performance at this time. -cflags-$(CONFIG_MK7) += $(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4) -cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,$(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4)) +cflags-$(CONFIG_MK7) += $(call cc-option,-march=athlon,-march=i686 $(align)-functions=4) +cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,$(call cc-option,-march=athlon,-march=i686 $(align)-functions=4)) cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 -cflags-$(CONFIG_MWINCHIPC6) += $(call check_gcc,-march=winchip-c6,-march=i586) -cflags-$(CONFIG_MWINCHIP2) += $(call check_gcc,-march=winchip2,-march=i586) -cflags-$(CONFIG_MWINCHIP3D) += $(call check_gcc,-march=winchip2,-march=i586) -cflags-$(CONFIG_MCYRIXIII) += $(call check_gcc,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 -cflags-$(CONFIG_MVIAC3_2) += $(call check_gcc,-march=c3-2,-march=i686) +cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) +cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586) +cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586) +cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 +cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) # AMD Elan support cflags-$(CONFIG_X86_ELAN) += -march=i486 # -mregparm=3 works ok on gcc-3.0 and later # -GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) +GCC_VERSION := $(call cc-version) cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) # Disable unit-at-a-time mode, it makes gcc use a lot more stack # due to the lack of sharing of stacklots. -CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) +CFLAGS += $(call cc-option,-fno-unit-at-a-time) CFLAGS += $(cflags-y) diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile index d70853d99..aa7064a75 100644 --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -29,9 +29,9 @@ targets := vmlinux.bin bootsect bootsect.o setup setup.o \ zImage bzImage subdir- := compressed -host-progs := tools/build +hostprogs-y := tools/build -HOSTCFLAGS_build.o := -Iinclude +HOSTCFLAGS_build.o := $(LINUXINCLUDE) # --------------------------------------------------------------------------- diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index d606d0687..5623e821f 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -156,7 +156,7 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later) # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long (MAXMEM-1) & 0x7fffffff +ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 7e2c665e6..a6e043c46 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -232,6 +232,41 @@ mopar_gr: xorl %eax, %eax movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) + +# switching the DAC to 8-bit is for <= 8 bpp only + movw %fs:(PARAM_LFB_DEPTH), %ax + cmpw $8, %ax + jg dac_done + +# get DAC switching capability + xorl %eax, %eax + movb 10(%di), %al + testb $1, %al + jz dac_set + +# attempt to switch DAC to 8-bit + movw $0x4f08, %ax + movw $0x0800, %bx + int $0x10 + cmpw $0x004f, %ax + jne dac_set + movb %bh, dac_size # store actual DAC size + +dac_set: +# set color size to DAC size + movb dac_size, %al + movb %al, %fs:(PARAM_LFB_COLORS+0) + movb %al, %fs:(PARAM_LFB_COLORS+2) + movb %al, %fs:(PARAM_LFB_COLORS+4) + movb %al, %fs:(PARAM_LFB_COLORS+6) + +# set color offsets to 0 + movb $0, %fs:(PARAM_LFB_COLORS+1) + movb $0, %fs:(PARAM_LFB_COLORS+3) + movb $0, %fs:(PARAM_LFB_COLORS+5) + movb $0, %fs:(PARAM_LFB_COLORS+7) + +dac_done: # get protected mode interface informations movw $0x4f0a, %ax xorw %bx, %bx @@ -1929,6 +1964,7 @@ scanning: .byte 0 # Performing mode scan do_restore: .byte 0 # Screen contents altered during mode change svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes graphic_mode: .byte 0 # Graphic mode with a linear frame buffer +dac_size: .byte 6 # DAC bit depth # Status messages keymsg: .ascii "Press to see video modes available, " diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 00cc32e33..3d828bbac 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ @@ -25,6 +25,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o +obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o @@ -41,12 +42,15 @@ obj-$(CONFIG_SCx200) += scx200.o # Note: kbuild does not track this dependency due to usage of .incbin $(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) +targets += vsyscall.lds # The DSO images are built using a special linker script. quiet_cmd_syscall = SYSCALL $@ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ -Wl,-T,$(filter-out FORCE,$^) -o $@ +export CPPFLAGS_vsyscall.lds += -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) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index e54aefaa8..8a0536250 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -71,6 +71,7 @@ int acpi_ht __initdata = 1; /* enable HT */ int acpi_lapic; int acpi_ioapic; int acpi_strict; +EXPORT_SYMBOL(acpi_strict); acpi_interrupt_flags acpi_sci_flags __initdata; int acpi_sci_override_gsi __initdata; @@ -84,6 +85,11 @@ static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; #warning ACPI uses CMPXCHG, i486 and later hardware #endif +#define MAX_MADT_ENTRIES 256 +u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = + { [0 ... MAX_MADT_ENTRIES-1] = 0xff }; +EXPORT_SYMBOL(x86_acpiid_to_apicid); + /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ @@ -225,6 +231,8 @@ acpi_parse_lapic ( if (processor->flags.enabled == 0) return 0; + x86_acpiid_to_apicid[processor->acpi_id] = processor->id; + mp_register_lapic ( processor->id, /* APIC ID */ processor->flags.enabled); /* Enabled? */ @@ -822,9 +830,15 @@ acpi_boot_init (void) */ error = acpi_blacklisted(); if (error) { - printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); - disable_acpi(); - return error; + extern int acpi_force; + + if (acpi_force) { + printk(KERN_WARNING PREFIX "acpi=force override\n"); + } else { + printk(KERN_WARNING PREFIX "Disabling ACPI support\n"); + disable_acpi(); + return error; + } } /* diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c index 92fd1760a..2a12d12e3 100644 --- a/arch/i386/kernel/acpi/sleep.c +++ b/arch/i386/kernel/acpi/sleep.c @@ -77,10 +77,7 @@ void __init acpi_reserve_bootmem(void) printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n"); return; } -#ifdef CONFIG_X86_PAE - printk(KERN_ERR "ACPI: S3 and PAE do not like each other for now, S3 disabled.\n"); - return; -#endif + acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); if (!acpi_wakeup_address) printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index ecf2b632f..64c175ff4 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -39,6 +39,12 @@ #include "io_ports.h" +/* + * Debug level + */ +int apic_verbosity; + + static void apic_pm_activate(void); void __init apic_intr_init(void) @@ -85,7 +91,7 @@ int get_physical_broadcast(void) unsigned int lvr, version; lvr = apic_read(APIC_LVR); version = GET_APIC_VERSION(lvr); - if (version >= 0x14) + if (!APIC_INTEGRATED(version) || version >= 0x14) return 0xff; else return 0xf; @@ -173,7 +179,8 @@ void __init connect_bsp_APIC(void) * PIC mode, enable APIC mode in the IMCR, i.e. * connect BSP's local APIC to INT and NMI lines. */ - printk("leaving PIC mode, enabling APIC mode.\n"); + apic_printk(APIC_VERBOSE, "leaving PIC mode, " + "enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -189,7 +196,8 @@ void disconnect_bsp_APIC(void) * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk("disabling APIC mode, entering PIC mode.\n"); + apic_printk(APIC_VERBOSE, "disabling APIC mode, " + "entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -230,10 +238,10 @@ int __init verify_local_APIC(void) * The version register is read-only in a real APIC. */ reg0 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0); apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); reg1 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1); /* * The two version reads above should print the same @@ -257,7 +265,7 @@ int __init verify_local_APIC(void) * The ID register is read/write in a real APIC. */ reg0 = apic_read(APIC_ID); - Dprintk("Getting ID: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); /* * The next two are just to see if we have sane values. @@ -265,9 +273,9 @@ int __init verify_local_APIC(void) * compatibility mode, but most boxes are anymore. */ reg0 = apic_read(APIC_LVT0); - Dprintk("Getting LVT0: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting LVT0: %x\n", reg0); reg1 = apic_read(APIC_LVT1); - Dprintk("Getting LVT1: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting LVT1: %x\n", reg1); return 1; } @@ -279,7 +287,7 @@ void __init sync_Arb_IDs(void) */ apic_wait_icr_idle(); - Dprintk("Synchronizing Arb IDs.\n"); + apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n"); apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT); } @@ -335,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) { @@ -427,10 +435,12 @@ void __init setup_local_APIC (void) value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; if (!smp_processor_id() && (pic_mode || !value)) { value = APIC_DM_EXTINT; - printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", + smp_processor_id()); } else { value = APIC_DM_EXTINT | APIC_LVT_MASKED; - printk("masked ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", + smp_processor_id()); } apic_write_around(APIC_LVT0, value); @@ -449,8 +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); - printk("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); @@ -460,7 +469,10 @@ void __init setup_local_APIC (void) if (maxlvt > 3) apic_write(APIC_ESR, 0); value = apic_read(APIC_ESR); - printk("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) /* @@ -635,6 +647,21 @@ static int __init lapic_enable(char *str) } __setup("lapic", lapic_enable); +static int __init apic_set_verbosity(char *str) +{ + if (strcmp("debug", str) == 0) + apic_verbosity = APIC_DEBUG; + else if (strcmp("verbose", str) == 0) + apic_verbosity = APIC_VERBOSE; + else + printk(KERN_WARNING "APIC Verbosity level %s not recognised" + " use apic=verbose or apic=debug", str); + + return 0; +} + +__setup("apic=", apic_set_verbosity); + static int __init detect_init_APIC (void) { u32 h, l, features; @@ -664,6 +691,12 @@ static int __init detect_init_APIC (void) } if (!cpu_has_apic) { + /* + * Over-ride BIOS and try to enable LAPIC + * only if "lapic" specified + */ + if (enable_local_apic != 1) + goto no_apic; /* * Some BIOSes disable the local APIC in the * APIC_BASE MSR. This can only be done in @@ -671,7 +704,8 @@ static int __init detect_init_APIC (void) */ rdmsr(MSR_IA32_APICBASE, l, h); if (!(l & MSR_IA32_APICBASE_ENABLE)) { - printk("Local APIC disabled by BIOS -- reenabling.\n"); + apic_printk(APIC_VERBOSE, "Local APIC disabled " + "by BIOS -- reenabling.\n"); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); @@ -698,7 +732,7 @@ static int __init detect_init_APIC (void) if (nmi_watchdog != NMI_NONE) nmi_watchdog = NMI_LOCAL_APIC; - printk("Found and enabled local APIC!\n"); + apic_printk(APIC_VERBOSE, "Found and enabled local APIC!\n"); apic_pm_activate(); @@ -725,7 +759,8 @@ void __init init_apic_mappings(void) apic_phys = mp_lapic_addr; set_fixmap_nocache(FIX_APIC_BASE, apic_phys); - Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); + apic_printk(APIC_DEBUG, "mapped APIC to %08lx (%08lx)\n", APIC_BASE, + apic_phys); /* * Fetch the APIC ID of the BSP in case we have a @@ -755,7 +790,8 @@ fake_ioapic_page: ioapic_phys = __pa(ioapic_phys); } set_fixmap_nocache(idx, ioapic_phys); - Dprintk("mapped IOAPIC to %08lx (%08lx)\n", + apic_printk(APIC_DEBUG, "mapped IOAPIC to " + "%08lx (%08lx)\n", __fix_to_virt(idx), ioapic_phys); idx++; } @@ -894,7 +930,7 @@ int __init calibrate_APIC_clock(void) int i; const int LOOPS = HZ/10; - printk("calibrating APIC timer ...\n"); + apic_printk(APIC_VERBOSE, "calibrating APIC timer ...\n"); /* * Put whatever arbitrary (but long enough) timeout @@ -939,11 +975,13 @@ int __init calibrate_APIC_clock(void) result = (tt1-tt2)*APIC_DIVISOR/LOOPS; if (cpu_has_tsc) - printk("..... CPU clock speed is %ld.%04ld MHz.\n", + apic_printk(APIC_VERBOSE, "..... CPU clock speed is " + "%ld.%04ld MHz.\n", ((long)(t2-t1)/LOOPS)/(1000000/HZ), ((long)(t2-t1)/LOOPS)%(1000000/HZ)); - printk("..... host bus clock speed is %ld.%04ld MHz.\n", + apic_printk(APIC_VERBOSE, "..... host bus clock speed is " + "%ld.%04ld MHz.\n", result/(1000000/HZ), result%(1000000/HZ)); @@ -954,7 +992,7 @@ static unsigned int calibration_result; void __init setup_boot_APIC_clock(void) { - printk("Using local APIC timer interrupts.\n"); + apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"); using_apic_timer = 1; local_irq_disable(); @@ -1039,8 +1077,7 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs) { int cpu = smp_processor_id(); - x86_do_profile(regs); - + profile_tick(CPU_PROFILING, regs); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got @@ -1159,7 +1196,7 @@ asmlinkage void smp_error_interrupt(void) 6: Received illegal vector 7: Illegal register address */ - printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n", + printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", smp_processor_id(), v , v1); irq_exit(); } diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 3b1ef4bcb..d9a80ba23 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -601,8 +601,8 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, cpus = apm_save_cpus(); cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; local_save_flags(flags); APM_DO_CLI; @@ -610,7 +610,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; local_irq_restore(flags); - cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); @@ -644,8 +644,8 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) cpus = apm_save_cpus(); cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; local_save_flags(flags); APM_DO_CLI; @@ -653,7 +653,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; local_irq_restore(flags); - cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40; + __get_cpu_var(cpu_gdt_table)[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); return error; @@ -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; @@ -2292,35 +2294,35 @@ static int __init apm_init(void) apm_bios_entry.segment = APM_CS; for (i = 0; i < NR_CPUS; i++) { - set_base(cpu_gdt_table[i][APM_CS >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); - set_base(cpu_gdt_table[i][APM_CS_16 >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], __va((unsigned long)apm_info.bios.cseg_16 << 4)); - set_base(cpu_gdt_table[i][APM_DS >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ - _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ - _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], 64 * 1024 - 1); #ifndef APM_RELAX_SEGMENTS } else { - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], (apm_info.bios.cseg_len - 1) & 0xffff); - _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], (apm_info.bios.cseg_16_len - 1) & 0xffff); - _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], (apm_info.bios.dseg_len - 1) & 0xffff); /* workaround for broken BIOSes */ if (apm_info.bios.cseg_len <= apm_info.bios.offset) - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 -1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 -1); if (apm_info.bios.dseg_len <= 0x40) { /* 0x40 * 4kB == 64kB */ /* for the BIOS that assumes granularity = 1 */ - cpu_gdt_table[i][APM_DS >> 3].b |= 0x800000; + per_cpu(cpu_gdt_table, i)[APM_DS >> 3].b |= 0x800000; printk(KERN_NOTICE "apm: we set the granularity of dseg.\n"); } } @@ -2360,8 +2362,15 @@ static void __exit apm_exit(void) { int error; - if (set_pm_idle) + if (set_pm_idle) { pm_idle = original_pm_idle; + /* + * We are about to unload the current idle thread pm callback + * (pm_idle), Wait for all processors to update cached/local + * copies of pm_idle before proceeding. + */ + synchronize_kernel(); + } if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0) && (apm_info.connection_version > 0x0100)) { error = apm_engage_power_management(APM_DEVICE_ALL, 0); diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c index 6248bf257..38d82e380 100644 --- a/arch/i386/kernel/asm-offsets.c +++ b/arch/i386/kernel/asm-offsets.c @@ -62,4 +62,5 @@ void foo(void) sizeof(struct tss_struct)); DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL)); } diff --git a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c index e85f4827e..394814e57 100644 --- a/arch/i386/kernel/cpu/centaur.c +++ b/arch/i386/kernel/cpu/centaur.c @@ -286,23 +286,20 @@ static void __init init_c3(struct cpuinfo_x86 *c) c->x86_capability[5] = cpuid_edx(0xC0000001); } - switch (c->x86_model) { - case 6 ... 8: /* Cyrix III family */ - rdmsr (MSR_VIA_FCR, lo, hi); - lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ - wrmsr (MSR_VIA_FCR, lo, hi); - - set_bit(X86_FEATURE_CX8, c->x86_capability); - set_bit(X86_FEATURE_3DNOW, c->x86_capability); + /* Cyrix III family needs CX8 & PGE explicity enabled. */ + if (c->x86_model >=6 && c->x86_model <= 9) { + rdmsr (MSR_VIA_FCR, lo, hi); + lo |= (1<<1 | 1<<7); + wrmsr (MSR_VIA_FCR, lo, hi); + set_bit(X86_FEATURE_CX8, c->x86_capability); + } - /* fall through */ + /* Before Nehemiah, the C3's had 3dNOW! */ + if (c->x86_model >=6 && c->x86_model <9) + set_bit(X86_FEATURE_3DNOW, c->x86_capability); - case 9: /* Nehemiah */ - default: - get_model_name(c); - display_cacheinfo(c); - break; - } + get_model_name(c); + display_cacheinfo(c); } static void __init init_centaur(struct cpuinfo_x86 *c) diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 30e25e357..89dc79a65 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include @@ -11,6 +13,9 @@ #include "cpu.h" +DEFINE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]); +EXPORT_PER_CPU_SYMBOL(cpu_gdt_table); + static int cachesize_override __initdata = -1; static int disable_x86_fxsr __initdata = 0; static int disable_x86_serial_nr __initdata = 1; @@ -501,7 +506,7 @@ void __init early_cpu_init(void) void __init cpu_init (void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct * t = &per_cpu(init_tss, cpu); struct thread_struct *thread = ¤t->thread; if (test_and_set_bit(cpu, &cpu_initialized)) { @@ -523,15 +528,17 @@ void __init cpu_init (void) * Initialize the per-CPU GDT with the boot GDT, * and set up the GDT descriptor: */ - if (cpu) { - memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE); - cpu_gdt_descr[cpu].size = GDT_SIZE - 1; - cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu]; - } + memcpy(&per_cpu(cpu_gdt_table, cpu), cpu_gdt_table, + GDT_SIZE); + cpu_gdt_descr[cpu].size = GDT_SIZE - 1; + cpu_gdt_descr[cpu].address = + (unsigned long)&per_cpu(cpu_gdt_table, cpu); + /* * Set up the per-thread TLS descriptor cache: */ - memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8); + memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu), + GDT_ENTRY_TLS_ENTRIES * 8); __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu])); __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); @@ -552,13 +559,11 @@ void __init cpu_init (void) load_esp0(t, thread); set_tss_desc(cpu,t); - 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); - 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/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig index d285dc1ba..5cd444214 100644 --- a/arch/i386/kernel/cpu/cpufreq/Kconfig +++ b/arch/i386/kernel/cpu/cpufreq/Kconfig @@ -88,6 +88,11 @@ config X86_POWERNOW_K7 If in doubt, say N. +config X86_POWERNOW_K7_ACPI + bool + depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y")) + default y + config X86_POWERNOW_K8 tristate "AMD Opteron/Athlon64 PowerNow!" depends on CPU_FREQ && EXPERIMENTAL @@ -98,6 +103,11 @@ config X86_POWERNOW_K8 If in doubt, say N. +config X86_POWERNOW_K8_ACPI + bool + depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y")) + default y + config X86_GX_SUSPMOD tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" depends on CPU_FREQ diff --git a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c index 8c056882d..4ba912733 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c @@ -108,13 +108,27 @@ acpi_processor_set_performance ( u32 value = 0; int i = 0; struct cpufreq_freqs cpufreq_freqs; + cpumask_t saved_mask; + int retval; ACPI_FUNCTION_TRACE("acpi_processor_set_performance"); + /* + * TBD: Use something other than set_cpus_allowed. + * As set_cpus_allowed is a bit racy, + * with any other set_cpus_allowed for this process. + */ + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (smp_processor_id() != cpu) { + return_VALUE(-EAGAIN); + } + if (state == data->acpi_data.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at target state (P%d)\n", state)); - return_VALUE(0); + retval = 0; + goto migrate_end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n", @@ -144,7 +158,8 @@ acpi_processor_set_performance ( if (ret) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid port width 0x%04x\n", bit_width)); - return_VALUE(ret); + retval = ret; + goto migrate_end; } /* @@ -166,7 +181,8 @@ acpi_processor_set_performance ( if (ret) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid port width 0x%04x\n", bit_width)); - return_VALUE(ret); + retval = ret; + goto migrate_end; } if (value == (u32) data->acpi_data.states[state].status) break; @@ -183,7 +199,8 @@ acpi_processor_set_performance ( cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n")); - return_VALUE(-ENODEV); + retval = -ENODEV; + goto migrate_end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -192,7 +209,10 @@ acpi_processor_set_performance ( data->acpi_data.state = state; - return_VALUE(0); + retval = 0; +migrate_end: + set_cpus_allowed(current, saved_mask); + return_VALUE(retval); } @@ -266,6 +286,69 @@ acpi_cpufreq_guess_freq ( } + +/* + * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities + * of this driver + * @perf: processor-specific acpi_io_data struct + * @cpu: CPU being initialized + * + * To avoid issues with legacy OSes, some BIOSes require to be informed of + * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC + * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in + * driver/acpi/processor.c + */ +static void +acpi_processor_cpu_init_pdc_est( + struct acpi_processor_performance *perf, + unsigned int cpu, + struct acpi_object_list *obj_list + ) +{ + union acpi_object *obj; + u32 *buf; + struct cpuinfo_x86 *c = cpu_data + cpu; + ACPI_FUNCTION_TRACE("acpi_processor_cpu_init_pdc_est"); + + if (!cpu_has(c, X86_FEATURE_EST)) + return_VOID; + + /* Initialize pdc. It will be used later. */ + if (!obj_list) + return_VOID; + + if (!(obj_list->count && obj_list->pointer)) + return_VOID; + + obj = obj_list->pointer; + if ((obj->buffer.length == 12) && obj->buffer.pointer) { + buf = (u32 *)obj->buffer.pointer; + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; + perf->pdc = obj_list; + } + return_VOID; +} + + +/* CPU specific PDC initialization */ +static void +acpi_processor_cpu_init_pdc( + struct acpi_processor_performance *perf, + unsigned int cpu, + struct acpi_object_list *obj_list + ) +{ + struct cpuinfo_x86 *c = cpu_data + cpu; + ACPI_FUNCTION_TRACE("acpi_processor_cpu_init_pdc"); + perf->pdc = NULL; + if (cpu_has(c, X86_FEATURE_EST)) + acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list); + return_VOID; +} + + static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -275,7 +358,14 @@ acpi_cpufreq_cpu_init ( struct cpufreq_acpi_io *data; unsigned int result = 0; + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; + u32 arg0_buf[3]; + struct acpi_object_list arg_list = {1, &arg0}; + ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init"); + /* setup arg_list for _PDC settings */ + arg0.buffer.length = 12; + arg0.buffer.pointer = (u8 *) arg0_buf; data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -284,7 +374,10 @@ acpi_cpufreq_cpu_init ( acpi_io_data[cpu] = data; + acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list); result = acpi_processor_register_performance(&data->acpi_data, cpu); + data->acpi_data.pdc = NULL; + if (result) goto err_free; diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index fefaf45a0..1f855c54c 100644 --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -297,6 +297,7 @@ static void gx_set_cpuspeed(unsigned int khz) case PCI_DEVICE_ID_CYRIX_5520: case PCI_DEVICE_ID_CYRIX_5510: suscfg = gx_params->pci_suscfg | SUSMOD; + break; default: local_irq_restore(flags); dprintk("fatal: try to set unknown chipset.\n"); diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 57c0377b4..e243f0fdd 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -5,14 +5,19 @@ * Licensed under the terms of the GNU GPL License version 2. * Based upon datasheets & sample CPUs kindly provided by VIA. * - * VIA have currently 2 different versions of Longhaul. + * VIA have currently 3 different versions of Longhaul. * Version 1 (Longhaul) uses the BCR2 MSR at 0x1147. - * It is present only in Samuel 1, Samuel 2 and Ezra. - * Version 2 (Powersaver) uses the POWERSAVER MSR at 0x110a. - * It is present in Ezra-T, Nehemiah and above. - * In addition to scaling multiplier, it can also scale voltage. - * There is provision for scaling FSB too, but this doesn't work - * too well in practice. + * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0. + * Version 2 of longhaul is the same as v1, but adds voltage scaling. + * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C) + * voltage scaling support has currently been disabled in this driver + * until we have code that gets it right. + * Version 3 of longhaul got renamed to Powersaver and redesigned + * to use the POWERSAVER MSR at 0x110a. + * It is present in Ezra-T (C5M), Nehemiah (C5X) and above. + * It's pretty much the same feature wise to longhaul v2, though + * there is provision for scaling FSB too, but this doesn't work + * too well in practice so we don't even try to use this. * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* */ @@ -33,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; @@ -68,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; @@ -87,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; } @@ -95,11 +125,45 @@ static int longhaul_get_cpu_mult(void) } +static void do_powersaver(union msr_longhaul *longhaul, + 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; + longhaul->bits.EnableSoftBusRatio = 1; + longhaul->bits.RevisionKey = 0; + local_irq_disable(); + wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); + local_irq_enable(); + __hlt(); + + rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); + longhaul->bits.EnableSoftBusRatio = 0; + longhaul->bits.RevisionKey = version; + local_irq_disable(); + wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); + local_irq_enable(); +} + /** * 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) @@ -108,79 +172,71 @@ 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) { - case 1: + + /* + * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B]) + * Software controlled multipliers only. + * + * *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 TYPE_LONGHAUL_V1: + case TYPE_LONGHAUL_V2: rdmsrl (MSR_VIA_BCR2, bcr2.val); /* Enable software clock multiplier */ bcr2.bits.ESOFTBF = 1; bcr2.bits.CLOCKMUL = clock_ratio_index; + local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); + local_irq_enable(); __hlt(); /* Disable software clock multiplier */ rdmsrl (MSR_VIA_BCR2, bcr2.val); bcr2.bits.ESOFTBF = 0; + local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); + local_irq_enable(); break; /* - * Powersaver. (Ezra-T [C5M], Nehemiah [C5N]) + * 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. - * We also need to do the voltage/freq setting in order depending - * on the direction of scaling (like we do in powernow-k7.c) - * Ezra-T was alleged to do FSB scaling too, but it never worked in practice. + * 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) + * Nehemiah can do FSB scaling too, but this has never been proven + * to work in practice. */ - case 2: - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; - longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; - longhaul.bits.EnableSoftBusRatio = 1; - /* We must program the revision key only with values we - * know about, not blindly copy it from 0:3 */ - longhaul.bits.RevisionKey = 3; /* SoftVID & SoftBSEL */ - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - __hlt(); - - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.EnableSoftBusRatio = 0; - longhaul.bits.RevisionKey = 3; - wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); - break; - case 3: - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; - longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; - longhaul.bits.EnableSoftBusRatio = 1; - - longhaul.bits.RevisionKey = 0x0; - - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - __hlt(); - - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - longhaul.bits.EnableSoftBusRatio = 0; - longhaul.bits.RevisionKey = 0xf; - wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); + case TYPE_POWERSAVER: + do_powersaver(&longhaul, clock_ratio_index); break; } @@ -230,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, @@ -242,58 +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 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; + } - 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(); - - fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; - 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) { @@ -301,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"); @@ -327,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++; } @@ -403,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; @@ -419,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; @@ -434,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; @@ -461,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: @@ -495,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) @@ -540,6 +621,7 @@ static struct cpufreq_driver longhaul_driver = { .attr = longhaul_attr, }; + static int __init longhaul_init(void) { struct cpuinfo_x86 *c = cpu_data; @@ -557,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/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c index c04c99bba..ab3cfc3cd 100644 --- a/arch/i386/kernel/cpu/cpufreq/longrun.c +++ b/arch/i386/kernel/cpu/cpufreq/longrun.c @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include #include @@ -19,7 +19,7 @@ static struct cpufreq_driver longrun_driver; /** - * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz + * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz * values into per cent values. In TMTA microcode, the following is valid: * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) */ @@ -42,18 +42,18 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy) policy->policy = CPUFREQ_POLICY_PERFORMANCE; else policy->policy = CPUFREQ_POLICY_POWERSAVE; - + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); msr_lo &= 0x0000007F; msr_hi &= 0x0000007F; - + if ( longrun_high_freq <= longrun_low_freq ) { /* Assume degenerate Longrun table */ policy->min = policy->max = longrun_high_freq; } else { - policy->min = longrun_low_freq + msr_lo * + policy->min = longrun_low_freq + msr_lo * ((longrun_high_freq - longrun_low_freq) / 100); - policy->max = longrun_low_freq + msr_hi * + policy->max = longrun_low_freq + msr_hi * ((longrun_high_freq - longrun_low_freq) / 100); } policy->cpu = 0; @@ -79,9 +79,9 @@ static int longrun_set_policy(struct cpufreq_policy *policy) /* Assume degenerate Longrun table */ pctg_lo = pctg_hi = 100; } else { - pctg_lo = (policy->min - longrun_low_freq) / + pctg_lo = (policy->min - longrun_low_freq) / ((longrun_high_freq - longrun_low_freq) / 100); - pctg_hi = (policy->max - longrun_low_freq) / + pctg_hi = (policy->max - longrun_low_freq) / ((longrun_high_freq - longrun_low_freq) / 100); } @@ -118,7 +118,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy) * longrun_verify_poliy - verifies a new CPUFreq policy * @policy: the policy to verify * - * Validates a new CPUFreq policy. This function has to be called with + * Validates a new CPUFreq policy. This function has to be called with * cpufreq_driver locked. */ static int longrun_verify_policy(struct cpufreq_policy *policy) @@ -127,8 +127,8 @@ static int longrun_verify_policy(struct cpufreq_policy *policy) return -EINVAL; policy->cpu = 0; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && @@ -160,7 +160,7 @@ static unsigned int longrun_get(unsigned int cpu) * TMTA rules: * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq) */ -static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, +static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, unsigned int *high_freq) { u32 msr_lo, msr_hi; @@ -174,9 +174,9 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, if (cpu_has(c, X86_FEATURE_LRTI)) { /* if the LongRun Table Interface is present, the - * detection is a bit easier: + * detection is a bit easier: * For minimum frequency, read out the maximum - * level (msr_hi), write that into "currently + * level (msr_hi), write that into "currently * selected level", and read out the frequency. * For maximum frequency, read out level zero. */ @@ -223,7 +223,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, cpuid(0x80860007, &eax, &ebx, &ecx, &edx); /* restore values */ - wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); + wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); } /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) @@ -237,7 +237,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, if ((ecx > 95) || (ecx == 0) || (eax < ebx)) return -EIO; - edx = (eax - ebx) / (100 - ecx); + edx = (eax - ebx) / (100 - ecx); *low_freq = edx * 1000; /* back to kHz */ if (*low_freq > *high_freq) @@ -249,7 +249,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, static int __init longrun_cpu_init(struct cpufreq_policy *policy) { - int result = 0; + int result = 0; /* capability check */ if (policy->cpu != 0) @@ -265,15 +265,15 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = longrun_high_freq; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; longrun_get_policy(policy); - + return 0; } static struct cpufreq_driver longrun_driver = { .flags = CPUFREQ_CONST_LOOPS, - .verify = longrun_verify_policy, - .setpolicy = longrun_set_policy, + .verify = longrun_verify_policy, + .setpolicy = longrun_set_policy, .get = longrun_get, .init = longrun_cpu_init, .name = "longrun", @@ -290,7 +290,7 @@ static int __init longrun_init(void) { struct cpuinfo_x86 *c = cpu_data; - if (c->x86_vendor != X86_VENDOR_TRANSMETA || + if (c->x86_vendor != X86_VENDOR_TRANSMETA || !cpu_has(c, X86_FEATURE_LONGRUN)) return -ENODEV; diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index fa01a95bb..ef1394964 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -184,7 +184,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) "The speedstep_centrino module offers voltage scaling" " in addition of frequency scaling. You should use " "that instead of p4-clockmod, if possible.\n"); - /* on P-4s, the TSC runs with constant frequency independent wether + /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); @@ -195,7 +195,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) return 0; } - /* on P-4s, the TSC runs with constant frequency independent wether + /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 18d30ab9a..c7e3aa60d 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -6,8 +6,6 @@ * Licensed under the terms of the GNU GPL License version 2. * Based upon datasheets & sample CPUs kindly provided by AMD. * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - * * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt. * - We cli/sti on stepping A0 CPUs around the FID/VID transition. * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect. @@ -29,21 +27,13 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI #include #include #endif #include "powernow-k7.h" -#define DEBUG - -#ifdef DEBUG -#define dprintk(msg...) printk(msg) -#else -#define dprintk(msg...) do { } while(0) -#endif - #define PFX "powernow: " @@ -64,7 +54,7 @@ struct pst_s { u8 numpstates; }; -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI union powernow_acpi_control_t { struct { unsigned long fid:5, @@ -97,6 +87,7 @@ static int fid_codes[32] = { */ static int acpi_force; +static int debug; static struct cpufreq_frequency_table *powernow_table; @@ -109,6 +100,21 @@ static unsigned int fsb; static unsigned int latency; static char have_a0; +static void dprintk(const char *fmt, ...) +{ + char s[256]; + va_list args; + + if (debug==0) + return; + + va_start(args,fmt); + vsprintf(s, fmt, args); + printk(s); + va_end(args); +} + + static int check_fsb(unsigned int fsbspeed) { int delta; @@ -190,13 +196,13 @@ static int get_ranges (unsigned char *pst) speed = powernow_table[j].frequency; if ((fid_codes[fid] % 10)==5) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI if (have_a0 == 1) powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; #endif } - dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); if (speed < minimum_speed) @@ -285,7 +291,7 @@ static void change_speed (unsigned int index) change_VID(vid); change_FID(fid); } - + if (have_a0 == 1) local_irq_enable(); @@ -294,7 +300,7 @@ static void change_speed (unsigned int index) } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI struct acpi_processor_performance *acpi_processor_perf; @@ -377,7 +383,7 @@ static int powernow_acpi_init(void) powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; } - dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); @@ -467,9 +473,9 @@ static int powernow_decode_bios (int maxfid, int startvid) (maxfid==pst->maxfid) && (startvid==pst->startvid)) { dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst); - dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid); - dprintk ("fsb: %d\t", pst->fsbspeed); - dprintk ("maxFID: 0x%x\t", pst->maxfid); + dprintk (KERN_INFO PFX " cpuid: 0x%x ", pst->cpuid); + dprintk ("fsb: %d ", pst->fsbspeed); + dprintk ("maxFID: 0x%x ", pst->maxfid); dprintk ("startvid: 0x%x\n", pst->startvid); ret = get_ranges ((char *) pst + sizeof (struct pst_s)); @@ -591,14 +597,14 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); /* A K7 with powernow technology is set to max frequency by BIOS */ - fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID]; if (!fsb) { printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; } dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); - if (dmi_check_system(powernow_dmi_table) || acpi_force) { + if (dmi_check_system(powernow_dmi_table) || acpi_force) { printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); result = powernow_acpi_init(); } else { @@ -628,7 +634,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = 20 * latency / fsb; + policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); policy->cur = powernow_get(0); @@ -648,14 +654,14 @@ static struct freq_attr* powernow_table_attr[] = { }; static struct cpufreq_driver powernow_driver = { - .verify = powernow_verify, - .target = powernow_target, - .get = powernow_get, - .init = powernow_cpu_init, - .exit = powernow_cpu_exit, - .name = "powernow-k7", - .owner = THIS_MODULE, - .attr = powernow_table_attr, + .verify = powernow_verify, + .target = powernow_target, + .get = powernow_get, + .init = powernow_cpu_init, + .exit = powernow_cpu_exit, + .name = "powernow-k7", + .owner = THIS_MODULE, + .attr = powernow_table_attr, }; static int __init powernow_init (void) @@ -668,7 +674,7 @@ static int __init powernow_init (void) static void __exit powernow_exit (void) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI if (acpi_processor_perf) { acpi_processor_unregister_performance(acpi_processor_perf, 0); kfree(acpi_processor_perf); @@ -679,8 +685,10 @@ static void __exit powernow_exit (void) kfree(powernow_table); } +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "enable debug output."); module_param(acpi_force, int, 0444); -MODULE_PARM_DESC(acpi_force, "Force ACPI to be used"); +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); MODULE_AUTHOR ("Dave Jones "); MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 05ed9025e..e52390d12 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -32,7 +32,7 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI #include #include #endif @@ -664,7 +664,7 @@ static int find_psb_table(struct powernow_k8_data *data) return -ENODEV; } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { if (!data->acpi_data.state_count) @@ -948,13 +948,13 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) * an UP version, and is deprecated by AMD. */ - if (pol->cpu != 0) { - printk(KERN_ERR PFX "init not cpu 0\n"); + if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { + printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); kfree(data); return -ENODEV; } - if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { - printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); + if (pol->cpu != 0) { + printk(KERN_ERR PFX "init not cpu 0\n"); kfree(data); return -ENODEV; } @@ -1024,7 +1024,7 @@ err_out: return -ENODEV; } -static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol) +static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol) { struct powernow_k8_data *data = powernow_data[pol->cpu]; @@ -1076,7 +1076,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = { .verify = powernowk8_verify, .target = powernowk8_target, .init = powernowk8_cpu_init, - .exit = powernowk8_cpu_exit, + .exit = __devexit_p(powernowk8_cpu_exit), .get = powernowk8_get, .name = "powernow-k8", .owner = THIS_MODULE, diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h index 500f28d27..a95db64a9 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h @@ -29,7 +29,7 @@ struct powernow_k8_data { * frequency is in kHz */ struct cpufreq_frequency_table *powernow_table; -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI /* the acpi table needs to be kept. it's only available if ACPI was * used to determine valid frequency/vid/fid states */ struct acpi_processor_performance acpi_data; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index ea9173812..56aafbde6 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -10,7 +10,7 @@ * Copyright (C) 2003 Jeremy Fitzhardinge * * WARNING WARNING WARNING - * + * * This driver manipulates the PERF_CTL MSR, which is only somewhat * documented. While it seems to work on my laptop, it has not been * tested anywhere else, and it may not work for you, do strange @@ -23,6 +23,11 @@ #include #include +#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI +#include +#include +#endif + #include #include #include @@ -41,24 +46,24 @@ struct cpu_id { __u8 x86; /* CPU family */ - __u8 x86_vendor; /* CPU vendor */ __u8 x86_model; /* model */ __u8 x86_mask; /* stepping */ }; -static const struct cpu_id cpu_id_banias = { - .x86_vendor = X86_VENDOR_INTEL, - .x86 = 6, - .x86_model = 9, - .x86_mask = 5, +enum { + CPU_BANIAS, + CPU_DOTHAN_A1, + CPU_DOTHAN_A2, + CPU_DOTHAN_B0, }; -static const struct cpu_id cpu_id_dothan_a1 = { - .x86_vendor = X86_VENDOR_INTEL, - .x86 = 6, - .x86_model = 13, - .x86_mask = 1, +static const struct cpu_id cpu_ids[] = { + [CPU_BANIAS] = { 6, 9, 5 }, + [CPU_DOTHAN_A1] = { 6, 13, 1 }, + [CPU_DOTHAN_A2] = { 6, 13, 2 }, + [CPU_DOTHAN_B0] = { 6, 13, 6 }, }; +#define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0])) struct cpu_model { @@ -68,10 +73,11 @@ struct cpu_model struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ }; -static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x); +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x); /* Operating points for current CPU */ static struct cpu_model *centrino_model; +static int centrino_cpu; #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE @@ -84,7 +90,7 @@ static struct cpu_model *centrino_model; .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ } -/* +/* * These voltage tables were derived from the Intel Pentium M * datasheet, document 25261202.pdf, Table 5. I have verified they * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium @@ -103,9 +109,9 @@ static struct cpufreq_frequency_table banias_900[] = /* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ static struct cpufreq_frequency_table banias_1000[] = { - OP(600, 844), - OP(800, 972), - OP(900, 988), + OP(600, 844), + OP(800, 972), + OP(900, 988), OP(1000, 1004), { .frequency = CPUFREQ_TABLE_END } }; @@ -135,7 +141,7 @@ static struct cpufreq_frequency_table banias_1200[] = }; /* Intel Pentium M processor 1.30GHz (Banias) */ -static struct cpufreq_frequency_table banias_1300[] = +static struct cpufreq_frequency_table banias_1300[] = { OP( 600, 956), OP( 800, 1260), @@ -146,7 +152,7 @@ static struct cpufreq_frequency_table banias_1300[] = }; /* Intel Pentium M processor 1.40GHz (Banias) */ -static struct cpufreq_frequency_table banias_1400[] = +static struct cpufreq_frequency_table banias_1400[] = { OP( 600, 956), OP( 800, 1180), @@ -157,7 +163,7 @@ static struct cpufreq_frequency_table banias_1400[] = }; /* Intel Pentium M processor 1.50GHz (Banias) */ -static struct cpufreq_frequency_table banias_1500[] = +static struct cpufreq_frequency_table banias_1500[] = { OP( 600, 956), OP( 800, 1116), @@ -169,7 +175,7 @@ static struct cpufreq_frequency_table banias_1500[] = }; /* Intel Pentium M processor 1.60GHz (Banias) */ -static struct cpufreq_frequency_table banias_1600[] = +static struct cpufreq_frequency_table banias_1600[] = { OP( 600, 956), OP( 800, 1036), @@ -199,13 +205,13 @@ static struct cpufreq_frequency_table banias_1700[] = .max_freq = (max)*1000, \ .op_points = banias_##max, \ } -#define BANIAS(max) _BANIAS(&cpu_id_banias, max, #max) +#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) /* CPU models, their operating frequency range, and freq/voltage operating points */ -static struct cpu_model models[] = +static struct cpu_model models[] = { - _BANIAS(&cpu_id_banias, 900, " 900"), + _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), BANIAS(1000), BANIAS(1100), BANIAS(1200), @@ -214,6 +220,12 @@ static struct cpu_model models[] = BANIAS(1500), BANIAS(1600), BANIAS(1700), + + /* NULL model_name is a wildcard */ + { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, + { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, + { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, + { NULL, } }; #undef _BANIAS @@ -224,19 +236,30 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; struct cpu_model *model; - for(model = models; model->model_name != NULL; model++) - if ((strcmp(cpu->x86_model_id, model->model_name) == 0) && - (!centrino_verify_cpu_id(cpu, model->cpu_id))) + for(model = models; model->cpu_id != NULL; model++) + if (centrino_verify_cpu_id(cpu, model->cpu_id) && + (model->model_name == NULL || + strcmp(cpu->x86_model_id, model->model_name) == 0)) break; - if (model->model_name == NULL) { + + if (model->cpu_id == NULL) { + /* No match at all */ printk(KERN_INFO PFX "no support for CPU model \"%s\": " "send /proc/cpuinfo to " MAINTAINER "\n", cpu->x86_model_id); return -ENOENT; } + if (model->op_points == NULL) { + /* Matched a non-match */ + printk(KERN_INFO PFX "no table support for CPU model \"%s\": \n", + cpu->x86_model_id); + printk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n"); + return -ENOENT; + } + centrino_model = model; - + printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); @@ -247,31 +270,54 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; } #endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ -static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x) +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x) { if ((c->x86 == x->x86) && - (c->x86_vendor == x->x86_vendor) && (c->x86_model == x->x86_model) && (c->x86_mask == x->x86_mask)) - return 0; - return -ENODEV; + return 1; + return 0; } -/* Extract clock in kHz from PERF_CTL value */ +/* To be called only after centrino_model is initialized */ static unsigned extract_clock(unsigned msr) { - msr = (msr >> 8) & 0xff; - return msr * 100000; + int i; + + /* + * Extract clock in kHz from PERF_CTL value + * for centrino, as some DSDTs are buggy. + * Ideally, this can be done using the acpi_data structure. + */ + if (centrino_cpu) { + msr = (msr >> 8) & 0xff; + return msr * 100000; + } + + if ((!centrino_model) || (!centrino_model->op_points)) + return 0; + + msr &= 0xffff; + for (i=0;centrino_model->op_points[i].frequency != CPUFREQ_TABLE_END; i++) { + if (msr == centrino_model->op_points[i].index) + return centrino_model->op_points[i].frequency; + } + return 0; } /* Return the current CPU frequency in kHz */ static unsigned int get_cur_freq(unsigned int cpu) { unsigned l, h; - if (cpu) + cpumask_t saved_mask; + + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (smp_processor_id() != cpu) return 0; rdmsr(MSR_IA32_PERF_STATUS, l, h); + set_cpus_allowed(current, saved_mask); return extract_clock(l); } @@ -280,13 +326,8 @@ static unsigned int get_cur_freq(unsigned int cpu) static struct acpi_processor_performance p; -#include -#include - -#define ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP 0x1 - /* - * centrino_cpu_init_acpi - register with ACPI P-States library + * centrino_cpu_init_acpi - register with ACPI P-States library * * Register with the ACPI P-States library (part of drivers/acpi/processor.c) * in order to determine correct frequency and voltage pairings by reading @@ -296,7 +337,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { union acpi_object arg0 = {ACPI_TYPE_BUFFER}; u32 arg0_buf[3]; - struct acpi_object_list arg_list = {1, &arg0}; + struct acpi_object_list arg_list = {1, &arg0}; unsigned long cur_freq; int result = 0, i; @@ -305,12 +346,12 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) arg0.buffer.pointer = (u8 *) arg0_buf; arg0_buf[0] = ACPI_PDC_REVISION_ID; arg0_buf[1] = 1; - arg0_buf[2] = ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP; + arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP | ACPI_PDC_EST_CAPABILITY_MSR; p.pdc = &arg_list; /* register with ACPI core */ - if (acpi_processor_register_performance(&p, 0)) + if (acpi_processor_register_performance(&p, policy->cpu)) return -EIO; /* verify the acpi_data */ @@ -318,7 +359,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) printk(KERN_DEBUG "No P-States\n"); result = -ENODEV; goto err_unreg; - } + } if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { @@ -340,11 +381,10 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) goto err_unreg; } - if (extract_clock(p.states[i].control) != - (p.states[i].core_frequency * 1000)) { - printk(KERN_DEBUG "Invalid encoded frequency\n"); - result = -EINVAL; - goto err_unreg; + if (p.states[i].core_frequency > p.states[0].core_frequency) { + printk(KERN_DEBUG "P%u has larger frequency than P0, skipping\n", i); + p.states[i].core_frequency = 0; + continue; } } @@ -357,29 +397,43 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) centrino_model->model_name=NULL; centrino_model->max_freq = p.states[0].core_frequency * 1000; - centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * + centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * (p.state_count + 1), GFP_KERNEL); if (!centrino_model->op_points) { result = -ENOMEM; goto err_kfree; } - cur_freq = get_cur_freq(0); - for (i=0; iop_points[i].index = p.states[i].control; centrino_model->op_points[i].frequency = p.states[i].core_frequency * 1000; + } + centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; + + cur_freq = get_cur_freq(policy->cpu); + + for (i=0; iop_points[i].index) != + (centrino_model->op_points[i].frequency)) { + printk(KERN_DEBUG "Invalid encoded frequency\n"); + result = -EINVAL; + goto err_kfree_all; + } + if (cur_freq == centrino_model->op_points[i].frequency) p.state = i; + if (!p.states[i].core_frequency) + centrino_model->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; } - centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; return 0; + err_kfree_all: + kfree(centrino_model->op_points); err_kfree: kfree(centrino_model); err_unreg: - acpi_processor_unregister_performance(&p, 0); + acpi_processor_unregister_performance(&p, policy->cpu); return (result); } #else @@ -392,21 +446,30 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) unsigned freq; unsigned l, h; int ret; + int i; - if (policy->cpu != 0) + /* Only Intel makes Enhanced Speedstep-capable CPUs */ + if (cpu->x86_vendor != X86_VENDOR_INTEL || !cpu_has(cpu, X86_FEATURE_EST)) return -ENODEV; - if (!cpu_has(cpu, X86_FEATURE_EST)) - return -ENODEV; + for (i = 0; i < N_IDS; i++) + if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) + break; - if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) && - (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) { - printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " - "send /proc/cpuinfo to " MAINTAINER "\n"); - return -ENODEV; - } + if (i != N_IDS) + centrino_cpu = 1; if (centrino_cpu_init_acpi(policy)) { + if (policy->cpu != 0) + return -ENODEV; + + if (!centrino_cpu) { + printk(KERN_INFO PFX "found unsupported CPU with " + "Enhanced SpeedStep: send /proc/cpuinfo to " + MAINTAINER "\n"); + return -ENODEV; + } + if (centrino_cpu_init_table(policy)) { return -ENODEV; } @@ -415,11 +478,11 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) /* Check to see if Enhanced SpeedStep is enabled, and try to enable it if not. */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); - + if (!(l & (1<<16))) { l |= (1<<16); wrmsr(MSR_IA32_MISC_ENABLE, l, h); - + /* check to see if it stuck */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); if (!(l & (1<<16))) { @@ -428,7 +491,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) } } - freq = get_cur_freq(0); + freq = get_cur_freq(policy->cpu); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ @@ -436,7 +499,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n", policy->policy, policy->cur); - + ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); if (ret) return (ret); @@ -455,7 +518,7 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy) #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI if (!centrino_model->model_name) { - acpi_processor_unregister_performance(&p, 0); + acpi_processor_unregister_performance(&p, policy->cpu); kfree(centrino_model->op_points); kfree(centrino_model); } @@ -493,19 +556,35 @@ static int centrino_target (struct cpufreq_policy *policy, unsigned int newstate = 0; unsigned int msr, oldmsr, h; struct cpufreq_freqs freqs; + cpumask_t saved_mask; + int retval; if (centrino_model == NULL) return -ENODEV; + /* + * Support for SMP systems. + * Make sure we are running on the CPU that wants to change frequency + */ + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(policy->cpu)); + if (smp_processor_id() != policy->cpu) { + return(-EAGAIN); + } + if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq, - relation, &newstate)) - return -EINVAL; + relation, &newstate)) { + retval = -EINVAL; + goto migrate_end; + } msr = centrino_model->op_points[newstate].index; rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); - if (msr == (oldmsr & 0xffff)) - return 0; + if (msr == (oldmsr & 0xffff)) { + retval = 0; + goto migrate_end; + } /* Hm, old frequency can either be the last value we put in PERF_CTL, or whatever it is now. The trouble is that TM2 @@ -514,31 +593,34 @@ static int centrino_target (struct cpufreq_policy *policy, tell us something happened, but it may leave the things on the notifier chain confused; we therefore stick to using the last programmed speed rather than the current speed for - "old". + "old". TODO: work out how the TCC interrupts work, and try to catch the CPU changing things under us. */ - freqs.cpu = 0; + freqs.cpu = policy->cpu; freqs.old = extract_clock(oldmsr); freqs.new = extract_clock(msr); - + dprintk(KERN_INFO PFX "target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* all but 16 LSB are "reserved", so treat them with care */ oldmsr &= ~0xffff; msr &= 0xffff; oldmsr |= msr; - + wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - return 0; + retval = 0; +migrate_end: + set_cpus_allowed(current, saved_mask); + return (retval); } static struct freq_attr* centrino_attr[] = { @@ -547,12 +629,12 @@ static struct freq_attr* centrino_attr[] = { }; static struct cpufreq_driver centrino_driver = { - .name = "centrino", /* should be speedstep-centrino, + .name = "centrino", /* should be speedstep-centrino, but there's a 16 char limit */ .init = centrino_cpu_init, .exit = centrino_cpu_exit, - .verify = centrino_verify, - .target = centrino_target, + .verify = centrino_verify, + .target = centrino_target, .get = get_cur_freq, .attr = centrino_attr, .owner = THIS_MODULE, diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c index 93b70f0dc..5f94c4fa2 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c @@ -7,7 +7,7 @@ * for chipsets ICH2-M and ICH3-M. * * Many thanks to Ducrot Bruno for finding and fixing the last - * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler + * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler * for extensive testing. * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* @@ -19,7 +19,7 @@ *********************************************************************/ #include -#include +#include #include #include #include @@ -29,24 +29,24 @@ /* speedstep_chipset: - * It is necessary to know which chipset is used. As accesses to - * this device occur at various places in this module, we need a + * It is necessary to know which chipset is used. As accesses to + * this device occur at various places in this module, we need a * static struct pci_dev * pointing to that device. */ -static struct pci_dev *speedstep_chipset_dev; +static struct pci_dev *speedstep_chipset_dev; /* speedstep_processor */ -static unsigned int speedstep_processor = 0; +static unsigned int speedstep_processor = 0; -/* +/* * There are only two frequency states for each processor. Values * are in kHz for the time being. */ static struct cpufreq_frequency_table speedstep_freqs[] = { - {SPEEDSTEP_HIGH, 0}, + {SPEEDSTEP_HIGH, 0}, {SPEEDSTEP_LOW, 0}, {0, CPUFREQ_TABLE_END}, }; @@ -68,22 +68,21 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * - * Tries to change the SpeedStep state. + * Tries to change the SpeedStep state. */ static void speedstep_set_state (unsigned int state) { - u32 pmbase; - u8 pm2_blk; - u8 value; - unsigned long flags; + u32 pmbase; + u8 pm2_blk; + u8 value; + unsigned long flags; if (!speedstep_chipset_dev || (state > 0x1)) return; /* get PMBASE */ pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); - if (!(pmbase & 0x01)) - { + if (!(pmbase & 0x01)) { printk(KERN_ERR "cpufreq: could not find speedstep register\n"); return; } @@ -146,18 +145,16 @@ static void speedstep_set_state (unsigned int state) */ static int speedstep_activate (void) { - u16 value = 0; + u16 value = 0; if (!speedstep_chipset_dev) return -EINVAL; - pci_read_config_word(speedstep_chipset_dev, - 0x00A0, &value); + pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); if (!(value & 0x08)) { value |= 0x08; dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n"); - pci_write_config_word(speedstep_chipset_dev, - 0x00A0, value); + pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); } return 0; @@ -167,15 +164,15 @@ static int speedstep_activate (void) /** * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic * - * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to - * the LPC bridge / PM module which contains all power-management + * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to + * the LPC bridge / PM module which contains all power-management * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected * chipset, or zero on failure. */ static unsigned int speedstep_detect_chipset (void) { speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801DB_12, + PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, NULL); @@ -183,7 +180,7 @@ static unsigned int speedstep_detect_chipset (void) return 4; /* 4-M */ speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801CA_12, + PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, NULL); @@ -198,11 +195,11 @@ static unsigned int speedstep_detect_chipset (void) NULL); if (speedstep_chipset_dev) { /* speedstep.c causes lockups on Dell Inspirons 8000 and - * 8100 which use a pretty old revision of the 82815 + * 8100 which use a pretty old revision of the 82815 * host brige. Abort on these systems. */ - static struct pci_dev *hostbridge; - u8 rev = 0; + static struct pci_dev *hostbridge; + u8 rev = 0; hostbridge = pci_find_subsys(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_MC, @@ -212,7 +209,7 @@ static unsigned int speedstep_detect_chipset (void) if (!hostbridge) return 2; /* 2-M */ - + pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev); if (rev < 5) { dprintk(KERN_INFO "cpufreq: hostbridge does not support speedstep\n"); @@ -226,6 +223,23 @@ static unsigned int speedstep_detect_chipset (void) return 0; } +static unsigned int speedstep_get(unsigned int cpu) +{ + unsigned int speed; + cpumask_t cpus_allowed,affected_cpu_map; + + /* only run on CPU to be set, or on its sibling */ + cpus_allowed = current->cpus_allowed; +#ifdef CONFIG_SMP + affected_cpu_map = cpu_sibling_map[cpu]; +#else + affected_cpu_map = cpumask_of_cpu(cpu); +#endif + set_cpus_allowed(current, affected_cpu_map); + speed=speedstep_get_processor_frequency(speedstep_processor); + set_cpus_allowed(current, cpus_allowed); + return speed; +} /** * speedstep_target - set a new CPUFreq policy @@ -239,7 +253,7 @@ static int speedstep_target (struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int newstate = 0; + unsigned int newstate = 0; struct cpufreq_freqs freqs; cpumask_t cpus_allowed, affected_cpu_map; int i; @@ -247,14 +261,14 @@ static int speedstep_target (struct cpufreq_policy *policy, if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) return -EINVAL; + freqs.old = speedstep_get(policy->cpu); + freqs.new = speedstep_freqs[newstate].frequency; + freqs.cpu = policy->cpu; + /* no transition necessary */ if (freqs.old == freqs.new) return 0; - freqs.old = speedstep_get_processor_frequency(speedstep_processor); - freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = policy->cpu; - cpus_allowed = current->cpus_allowed; /* only run on CPU to be set, or on its sibling */ @@ -301,9 +315,9 @@ static int speedstep_verify (struct cpufreq_policy *policy) static int speedstep_cpu_init(struct cpufreq_policy *policy) { - int result = 0; - unsigned int speed; - cpumask_t cpus_allowed,affected_cpu_map; + int result = 0; + unsigned int speed; + cpumask_t cpus_allowed,affected_cpu_map; /* capability check */ @@ -324,18 +338,16 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) &speedstep_freqs[SPEEDSTEP_LOW].frequency, &speedstep_freqs[SPEEDSTEP_HIGH].frequency, &speedstep_set_state); - if (result) { - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed(current, cpus_allowed); + if (result) return result; - } /* get current speed setting */ - speed = speedstep_get_processor_frequency(speedstep_processor); - set_cpus_allowed(current, cpus_allowed); + speed = speedstep_get(policy->cpu); if (!speed) return -EIO; - dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", + dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed / 1000)); @@ -360,11 +372,6 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy) return 0; } -static unsigned int speedstep_get(unsigned int cpu) -{ - return speedstep_get_processor_frequency(speedstep_processor); -} - static struct freq_attr* speedstep_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, @@ -372,14 +379,14 @@ static struct freq_attr* speedstep_attr[] = { static struct cpufreq_driver speedstep_driver = { - .name = "speedstep-ich", - .verify = speedstep_verify, - .target = speedstep_target, - .init = speedstep_cpu_init, - .exit = speedstep_cpu_exit, - .get = speedstep_get, - .owner = THIS_MODULE, - .attr = speedstep_attr, + .name = "speedstep-ich", + .verify = speedstep_verify, + .target = speedstep_target, + .init = speedstep_cpu_init, + .exit = speedstep_cpu_exit, + .get = speedstep_get, + .owner = THIS_MODULE, + .attr = speedstep_attr, }; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index 6aa31cd5a..5d176b19a 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -115,6 +115,11 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high) : "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi) : "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0) ); + + /* abort if results are obviously incorrect... */ + if ((high_mhz + low_mhz) < 600) + return -EINVAL; + *high = high_mhz * 1000; *low = low_mhz * 1000; @@ -180,7 +185,7 @@ static void speedstep_set_state (unsigned int state) local_irq_restore(flags); if (new_state == state) { - dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (freqs.new / 1000), retry, result); + dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result); } else { printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result); } diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index 09acdd76b..d13f9bb47 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -72,41 +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 }, - { 0x79, LVL_2, 128 }, - { 0x7a, LVL_2, 256 }, - { 0x7b, LVL_2, 512 }, - { 0x7c, LVL_2, 1024 }, - { 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/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h index fee8b5ccc..0d10c115d 100644 --- a/arch/i386/kernel/cpu/mtrr/mtrr.h +++ b/arch/i386/kernel/cpu/mtrr/mtrr.h @@ -52,7 +52,6 @@ struct mtrr_ops { }; extern int generic_get_free_region(unsigned long base, unsigned long size); -extern void generic_init_secondary(void); extern int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type); diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 423429491..bdd13285f 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/dmi_scan.c b/arch/i386/kernel/dmi_scan.c index d2d2610f2..d4f4a5aff 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/arch/i386/kernel/dmi_scan.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -162,27 +162,6 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) #define NO_MATCH { DMI_NONE, NULL} #define MATCH DMI_MATCH -/* - * Some machines, usually laptops, can't handle an enabled local APIC. - * The symptoms include hangs or reboots when suspending or resuming, - * attaching or detaching the power cord, or entering BIOS setup screens - * through magic key sequences. - */ -static int __init local_apic_kills_bios(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int enable_local_apic; - if (enable_local_apic == 0) { - enable_local_apic = -1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - - /* * Toshiba keyboard likes to repeat keys when they are not repeated. */ @@ -284,32 +263,6 @@ static __init int disable_acpi_pci(struct dmi_blacklist *d) static __initdata struct dmi_blacklist dmi_blacklist[]={ - /* Machines which have problems handling enabled local APICs */ - - { local_apic_kills_bios, "Dell Inspiron", { - MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_PRODUCT_NAME, "Inspiron"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "Dell Latitude", { - MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_PRODUCT_NAME, "Latitude"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "IBM Thinkpad T20", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "264741U"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "ASUS L3C", { - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - MATCH(DMI_BOARD_NAME, "P4_L3C"), - NO_MATCH, NO_MATCH - } }, - { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */ MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), NO_MATCH, NO_MATCH, NO_MATCH @@ -490,41 +443,6 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={ { NULL, } }; - - -/* - * Walk the blacklist table running matching functions until someone - * returns 1 or we hit the end. - */ - - -static __init void dmi_check_blacklist(void) -{ -#ifdef CONFIG_ACPI_BOOT -#define ACPI_BLACKLIST_CUTOFF_YEAR 2001 - - if (dmi_ident[DMI_BIOS_DATE]) { - char *s = strrchr(dmi_ident[DMI_BIOS_DATE], '/'); - if (s) { - int year, disable = 0; - s++; - year = simple_strtoul(s,NULL,0); - if (year >= 1000) - disable = year < ACPI_BLACKLIST_CUTOFF_YEAR; - else if (year < 1 || (year > 90 && year <= 99)) - disable = 1; - if (disable && !acpi_force) { - printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s); - printk(KERN_NOTICE "You can enable it with acpi=force\n"); - disable_acpi(); - } - } - } -#endif - dmi_check_system(dmi_blacklist); -} - - /* * Process a DMI table entry. Right now all we care about are the BIOS @@ -582,7 +500,7 @@ void __init dmi_scan_machine(void) { int err = dmi_iterate(dmi_decode); if(err == 0) - dmi_check_blacklist(); + dmi_check_system(dmi_blacklist); else printk(KERN_INFO "DMI not present.\n"); } diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c index 6b4a8f3cc..789af3e9f 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/entry.S b/arch/i386/kernel/entry.S index 7b6856363..3a8c31eda 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -255,11 +255,11 @@ sysenter_past_esp: pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) - cmpl $(nr_syscalls), %eax - jae syscall_badsys testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry + cmpl $(nr_syscalls), %eax + jae syscall_badsys call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) cli @@ -278,11 +278,11 @@ ENTRY(system_call) pushl %eax # save orig_eax SAVE_ALL GET_THREAD_INFO(%ebp) - cmpl $(nr_syscalls), %eax - jae syscall_badsys # system call tracing in operation testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry + cmpl $(nr_syscalls), %eax + jae syscall_badsys syscall_call: call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) # store the return value @@ -348,7 +348,7 @@ syscall_trace_entry: # perform syscall exit tracing ALIGN syscall_exit_work: - testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %cl + testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl jz work_pending sti # could let do_syscall_trace() call # schedule() instead @@ -489,9 +489,16 @@ ENTRY(debug) jne debug_stack_correct FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) debug_stack_correct: - pushl $0 - pushl $do_debug - jmp error_code + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx + pushl $0 + pushl %edx + call do_debug + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception /* * NMI is doubly nasty. It can happen _while_ we're handling @@ -540,9 +547,16 @@ nmi_debug_stack_fixup: jmp nmi_stack_correct ENTRY(int3) + pushl $-1 # mark this as an int + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $do_int3 - jmp error_code + pushl %edx + call do_int3 + addl $8,%esp + testl %eax,%eax + jnz restore_all + jmp ret_from_exception ENTRY(overflow) pushl $0 @@ -886,5 +900,6 @@ ENTRY(sys_call_table) .long sys_mq_notify .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid syscall_table_size=(.-sys_call_table) diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 69bad9bd0..95fe2fdf4 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -521,6 +521,3 @@ ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ -#ifdef CONFIG_SMP - .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ -#endif diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 064d6fb8a..b93f0332d 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -87,10 +87,10 @@ EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(apm_info); -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ @@ -99,9 +99,9 @@ EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL_NOVERS(__get_user_1); -EXPORT_SYMBOL_NOVERS(__get_user_2); -EXPORT_SYMBOL_NOVERS(__get_user_4); +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); @@ -142,8 +142,8 @@ EXPORT_SYMBOL(cpu_sibling_map); EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_callout_map); -EXPORT_SYMBOL_NOVERS(__write_lock_failed); -EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(__write_lock_failed); +EXPORT_SYMBOL(__read_lock_failed); /* Global SMP stuff */ EXPORT_SYMBOL(synchronize_irq); @@ -175,8 +175,9 @@ EXPORT_SYMBOL_GPL(unset_nmi_callback); #undef memcmp extern int memcmp(const void *,const void *,__kernel_size_t); -EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(register_die_notifier); #ifdef CONFIG_HAVE_DEC_LOCK EXPORT_SYMBOL(atomic_dec_and_lock); #endif diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index 97653d20f..dec7ebf49 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -12,10 +11,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -225,7 +226,7 @@ spurious_8259A_irq: * lets ACK and report it. [once per IRQ] */ if (!(spurious_irq_mask & irqmask)) { - printk("spurious 8259A interrupt: IRQ%d.\n", irq); + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } atomic_inc(&irq_err_count); @@ -238,14 +239,39 @@ spurious_8259A_irq: } } +static char irq_trigger[2]; +/** + * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ + */ +static void restore_ELCR(char *trigger) +{ + outb(trigger[0], 0x4d0); + outb(trigger[1], 0x4d1); +} + +static void save_ELCR(char *trigger) +{ + /* IRQ 0,1,2,8,13 are marked as reserved */ + trigger[0] = inb(0x4d0) & 0xF8; + trigger[1] = inb(0x4d1) & 0xDE; +} + static int i8259A_resume(struct sys_device *dev) { init_8259A(0); + restore_ELCR(irq_trigger); + return 0; +} + +static int i8259A_suspend(struct sys_device *dev, u32 state) +{ + save_ELCR(irq_trigger); return 0; } static struct sysdev_class i8259_sysdev_class = { set_kset_name("i8259"), + .suspend = i8259A_suspend, .resume = i8259A_resume, }; @@ -362,46 +388,6 @@ void __init init_ISA_irqs (void) } } -static void setup_timer(void) -{ - extern spinlock_t i8253_lock; - unsigned long flags; - - spin_lock_irqsave(&i8253_lock, flags); - outb_p(0x34,PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ - udelay(10); - outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ - udelay(10); - outb(LATCH >> 8 , PIT_CH0); /* MSB */ - spin_unlock_irqrestore(&i8253_lock, flags); -} - -static int timer_resume(struct sys_device *dev) -{ - setup_timer(); - return 0; -} - -static struct sysdev_class timer_sysclass = { - set_kset_name("timer"), - .resume = timer_resume, -}; - -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int __init init_timer_sysfs(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; -} - -device_initcall(init_timer_sysfs); - void __init init_IRQ(void) { int i; @@ -431,7 +417,7 @@ void __init init_IRQ(void) * Set the clock to HZ Hz, we already have a valid * vector now: */ - setup_timer(); + setup_pit_timer(); /* * External FPU? Set up irq13 if so, for diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c index 5e1897649..9caa8e8db 100644 --- a/arch/i386/kernel/init_task.c +++ b/arch/i386/kernel/init_task.c @@ -40,10 +40,7 @@ EXPORT_SYMBOL(init_task); /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, - * no more per-task TSS's. The TSS size is kept cacheline-aligned - * so they are allowed to end up in the .data.cacheline_aligned - * section. Since TSS's are completely CPU-local, we want them - * on exact cacheline boundaries, to eliminate cacheline ping-pong. + * no more per-task TSS's. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index a40687e7c..4bbd49692 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -85,7 +86,7 @@ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void __init add_pin_to_irq(unsigned int irq, int apic, int pin) +static void add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -705,13 +706,15 @@ static int __init ioapic_pirq_setup(char *str) pirq_entries[i] = -1; pirqs_enabled = 1; - printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); + apic_printk(APIC_VERBOSE, KERN_INFO + "PIRQ redirection, working around broken MP-BIOS.\n"); max = MAX_PIRQS; if (ints[0] < MAX_PIRQS) max = ints[0]; for (i = 0; i < max; i++) { - printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); + apic_printk(APIC_VERBOSE, KERN_DEBUG + "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ @@ -742,7 +745,7 @@ static int __init find_irq_entry(int apic, int pin, int type) /* * Find the pin to which IRQ[irq] (ISA) is connected */ -static int __init find_isa_irq_pin(int irq, int type) +static int find_isa_irq_pin(int irq, int type) { int i; @@ -772,8 +775,8 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) { int apic, i, best_guess = -1; - Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", - bus, slot, pin); + apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " + "slot:%d, pin:%d.\n", bus, slot, pin); if (mp_bus_id_to_pci_bus[bus] == -1) { printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; @@ -841,7 +844,8 @@ static int __init EISA_ELCR(unsigned int irq) unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); + apic_printk(APIC_VERBOSE, KERN_INFO + "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -1083,10 +1087,12 @@ static int pin_2_irq(int idx, int apic, int pin) if ((pin >= 16) && (pin <= 23)) { if (pirq_entries[pin-16] != -1) { if (!pirq_entries[pin-16]) { - printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); + apic_printk(APIC_VERBOSE, KERN_DEBUG + "disabling PIRQ%d\n", pin-16); } else { irq = pirq_entries[pin-16]; - printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", + apic_printk(APIC_VERBOSE, KERN_DEBUG + "using PIRQ%d -> IRQ %d\n", pin-16, irq); } } @@ -1114,11 +1120,7 @@ static inline int IO_APIC_irq_trigger(int irq) /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; -#ifdef CONFIG_PCI_MSI int assign_irq_vector(int irq) -#else -int __init assign_irq_vector(int irq) -#endif { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; @@ -1176,7 +1178,7 @@ void __init setup_IO_APIC_irqs(void) int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; - printk(KERN_DEBUG "init IO_APIC IRQs\n"); + apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -1195,10 +1197,14 @@ void __init setup_IO_APIC_irqs(void) idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, KERN_DEBUG + " IO-APIC (apicid-pin) %d-%d", + mp_ioapics[apic].mpc_apicid, + pin); first_notcon = 0; } else - printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, ", %d-%d", + mp_ioapics[apic].mpc_apicid, pin); continue; } @@ -1239,7 +1245,7 @@ void __init setup_IO_APIC_irqs(void) } if (!first_notcon) - printk(" not connected.\n"); + apic_printk(APIC_VERBOSE, " not connected.\n"); } /* @@ -1299,6 +1305,9 @@ void __init print_IO_APIC(void) union IO_APIC_reg_03 reg_03; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", @@ -1441,6 +1450,9 @@ static void print_APIC_bitfield (int base) unsigned int v; int i, j; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); for (i = 0; i < 8; i++) { v = apic_read(base + i*0x10); @@ -1458,6 +1470,9 @@ void /*__init*/ print_local_APIC(void * dummy) { unsigned int v, ver, maxlvt; + if (apic_verbosity == APIC_QUIET) + return; + printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", smp_processor_id(), hard_smp_processor_id()); v = apic_read(APIC_ID); @@ -1545,6 +1560,9 @@ void /*__init*/ print_PIC(void) unsigned int v; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "\nprinting PIC contents\n"); spin_lock_irqsave(&i8259A_lock, flags); @@ -1680,7 +1698,9 @@ static void __init setup_ioapic_ids_from_mpc(void) } else { physid_mask_t tmp; tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid); - printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, "Setting %d in the " + "phys_id_present_map\n", + mp_ioapics[apic].mpc_apicid); physids_or(phys_id_present_map, phys_id_present_map, tmp); } @@ -1699,8 +1719,9 @@ static void __init setup_ioapic_ids_from_mpc(void) * Read the right value from the MPC table and * write it into the ID register. */ - printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", - mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, KERN_INFO + "...changing IO-APIC physical APIC ID to %d ...", + mp_ioapics[apic].mpc_apicid); reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; spin_lock_irqsave(&ioapic_lock, flags); @@ -1714,9 +1735,9 @@ 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 - printk(" ok.\n"); + apic_printk(APIC_VERBOSE, " ok.\n"); } } #else @@ -2031,11 +2052,11 @@ static void setup_nmi (void) * is from Maciej W. Rozycki - so we do not have to EOI from * the NMI handler or the timer interrupt. */ - printk(KERN_INFO "activating NMI Watchdog ..."); + apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); - printk(" done.\n"); + apic_printk(APIC_VERBOSE, " done.\n"); } /* @@ -2212,7 +2233,8 @@ static inline void check_timer(void) return; } printk(" failed :(.\n"); - panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); + panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " + "report. Then try booting with the 'noapic' option"); } /* @@ -2262,6 +2284,98 @@ static int __init io_apic_bug_finalize(void) late_initcall(io_apic_bug_finalize); +struct sysfs_ioapic_data { + struct sys_device dev; + struct IO_APIC_route_entry entry[0]; +}; +static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; + +static int ioapic_suspend(struct sys_device *dev, u32 state) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + spin_lock_irqsave(&ioapic_lock, flags); + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); + *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static int ioapic_resume(struct sys_device *dev) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + union IO_APIC_reg_00 reg_00; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + + spin_lock_irqsave(&ioapic_lock, flags); + reg_00.raw = io_apic_read(dev->id, 0); + if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { + reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; + io_apic_write(dev->id, 0, reg_00.raw); + } + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); + io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static struct sysdev_class ioapic_sysdev_class = { + set_kset_name("ioapic"), + .suspend = ioapic_suspend, + .resume = ioapic_resume, +}; + +static int __init ioapic_init_sysfs(void) +{ + struct sys_device * dev; + int i, size, error = 0; + + error = sysdev_class_register(&ioapic_sysdev_class); + if (error) + return error; + + for (i = 0; i < nr_ioapics; i++ ) { + size = sizeof(struct sys_device) + nr_ioapic_registers[i] + * sizeof(struct IO_APIC_route_entry); + mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); + if (!mp_ioapic_data[i]) { + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + memset(mp_ioapic_data[i], 0, size); + dev = &mp_ioapic_data[i]->dev; + dev->id = i; + dev->cls = &ioapic_sysdev_class; + error = sysdev_register(dev); + if (error) { + kfree(mp_ioapic_data[i]); + mp_ioapic_data[i] = NULL; + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + } + + return 0; +} + +device_initcall(ioapic_init_sysfs); + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ @@ -2334,7 +2448,8 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + apic_printk(APIC_VERBOSE, KERN_INFO + "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } @@ -2400,19 +2515,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a entry.vector = assign_irq_vector(irq); - Dprintk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " - "IRQ %d Mode:%i Active:%i)\n", ioapic, - mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - - if (use_pci_vector() && !platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); - if (edge_level) { - irq_desc[irq].handler = &ioapic_level_type; - } else { - irq_desc[irq].handler = &ioapic_edge_type; - } + apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " + "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, + edge_level, active_high_low); - set_intr_gate(entry.vector, interrupt[irq]); + ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index 3346657c3..8b2516039 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -56,6 +56,7 @@ static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int ex */ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) { + unsigned long i, max_long, bytes, bytes_updated; struct thread_struct * t = ¤t->thread; struct tss_struct * tss; unsigned long *bitmap; @@ -81,16 +82,37 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) /* * do it in the per-thread copy and in the TSS ... + * + * Disable preemption via get_cpu() - we must not switch away + * because the ->io_bitmap_max value must match the bitmap + * contents: */ + tss = &per_cpu(init_tss, get_cpu()); + set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); - tss = init_tss + get_cpu(); - if (tss->io_bitmap_base == IO_BITMAP_OFFSET) { /* already active? */ - set_bitmap(tss->io_bitmap, from, num, !turn_on); - } else { - memcpy(tss->io_bitmap, t->io_bitmap_ptr, IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; /* Activate it in the TSS */ - } + + /* + * Search for a (possibly new) maximum. This is simple and stupid, + * to keep it obviously correct: + */ + max_long = 0; + for (i = 0; i < IO_BITMAP_LONGS; i++) + if (t->io_bitmap_ptr[i] != ~0UL) + max_long = i; + + bytes = (max_long + 1) * sizeof(long); + bytes_updated = max(bytes, t->io_bitmap_max); + + t->io_bitmap_max = bytes; + + /* + * Sets the lazy trigger so that the next I/O operation will + * reload the correct bitmap. + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; + put_cpu(); + return 0; } diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 355dc0eca..693b41afd 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -220,14 +220,16 @@ asmlinkage int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -1025,32 +1027,6 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, } #endif - -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -1086,27 +1062,13 @@ static void register_irq_proc (unsigned int irq) #endif } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); - - /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; - + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. */ diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c new file mode 100644 index 000000000..4d066cc30 --- /dev/null +++ b/arch/i386/kernel/kprobes.c @@ -0,0 +1,349 @@ +/* + * Kernel Probes (KProbes) + * arch/i386/kernel/kprobes.c + * + * 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. + * + * Copyright (C) IBM Corporation, 2002, 2004 + * + * 2002-Oct Created by Vamsi Krishna S Kernel + * Probes initial implementation ( includes contributions from + * Rusty Russell). + * 2004-July Suparna Bhattacharya added jumper probes + * interface to access function arguments. + */ + +#include +#include +#include +#include +#include +#include + +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 + +static struct kprobe *current_kprobe; +static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; +static struct pt_regs jprobe_saved_regs; +static long *jprobe_saved_esp; +/* copy of the kernel stack at the probe fire time */ +static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; + +/* + * returns non-zero if opcode modifies the interrupt flag. + */ +static inline int is_IF_modifier(kprobe_opcode_t opcode) +{ + switch (opcode) { + case 0xfa: /* cli */ + case 0xfb: /* sti */ + case 0xcf: /* iret/iretd */ + case 0x9d: /* popf/popfd */ + return 1; + } + return 0; +} + +void arch_prepare_kprobe(struct kprobe *p) +{ + memcpy(p->insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); +} + +static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + *p->addr = p->opcode; + regs->eip = (unsigned long)p->addr; +} + +static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->eflags |= TF_MASK; + regs->eflags &= ~IF_MASK; + regs->eip = (unsigned long)&p->insn; +} + +/* + * Interrupts are disabled on entry as trap3 is an interrupt gate and they + * remain disabled thorough out this function. + */ +static inline int kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + int ret = 0; + u8 *addr = (u8 *) (regs->eip - 1); + + /* We're in an interrupt, but this is clear and BUG()-safe. */ + preempt_disable(); + + /* Check we're not actually recursing */ + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + Disarm the probe we just hit, and ignore it. */ + p = get_kprobe(addr); + if (p) { + disarm_kprobe(p, regs); + ret = 1; + } else { + p = current_kprobe; + if (p->break_handler && p->break_handler(p, regs)) { + goto ss_probe; + } + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) { + unlock_kprobes(); + if (*addr != BREAKPOINT_INSTRUCTION) { + /* + * The breakpoint instruction was removed right + * after we hit it. Another cpu has removed + * either a probepoint or a debugger breakpoint + * at this address. In either case, no further + * handling of this interrupt is appropriate. + */ + ret = 1; + } + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + kprobe_saved_eflags = kprobe_old_eflags + = (regs->eflags & (TF_MASK | IF_MASK)); + if (is_IF_modifier(p->opcode)) + kprobe_saved_eflags &= ~IF_MASK; + + if (p->pre_handler(p, regs)) { + /* handler has already set things up, so skip ss setup */ + return 1; + } + + ss_probe: + prepare_singlestep(p, regs); + kprobe_status = KPROBE_HIT_SS; + return 1; + + no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the "int 3" + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->insn. + * + * This function prepares to return from the post-single-step + * interrupt. We have to fix up the stack as follows: + * + * 0) Except in the case of absolute or indirect jump or call instructions, + * the new eip is relative to the copied instruction. We need to make + * it relative to the original instruction. + * + * 1) If the single-stepped instruction was pushfl, then the TF and IF + * flags are set in the just-pushed eflags, and may need to be cleared. + * + * 2) If the single-stepped instruction was a call, the return address + * that is atop the stack is the address following the copied instruction. + * We need to make it the address following the original instruction. + */ +static void resume_execution(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long *tos = (unsigned long *)®s->esp; + unsigned long next_eip = 0; + unsigned long copy_eip = (unsigned long)&p->insn; + unsigned long orig_eip = (unsigned long)p->addr; + + switch (p->insn[0]) { + case 0x9c: /* pushfl */ + *tos &= ~(TF_MASK | IF_MASK); + *tos |= kprobe_old_eflags; + break; + case 0xe8: /* call relative - Fix return addr */ + *tos = orig_eip + (*tos - copy_eip); + break; + case 0xff: + if ((p->insn[1] & 0x30) == 0x10) { + /* call absolute, indirect */ + /* Fix return addr; eip is correct. */ + next_eip = regs->eip; + *tos = orig_eip + (*tos - copy_eip); + } else if (((p->insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */ + ((p->insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */ + /* eip is correct. */ + next_eip = regs->eip; + } + break; + case 0xea: /* jmp absolute -- eip is correct */ + next_eip = regs->eip; + break; + default: + break; + } + + regs->eflags &= ~TF_MASK; + if (next_eip) { + regs->eip = next_eip; + } else { + regs->eip = orig_eip + (regs->eip - copy_eip); + } +} + +/* + * Interrupts are disabled on entry as trap1 is an interrupt gate and they + * remain disabled thoroughout this function. And we hold kprobe lock. + */ +static inline int post_kprobe_handler(struct pt_regs *regs) +{ + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) + current_kprobe->post_handler(current_kprobe, regs, 0); + + resume_execution(current_kprobe, regs); + regs->eflags |= kprobe_saved_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + + /* + * if somebody else is singlestepping across a probe point, eflags + * will have TF set, in which case, continue the remaining processing + * of do_debug, as if this is not a probe hit. + */ + if (regs->eflags & TF_MASK) + return 0; + + return 1; +} + +/* Interrupts disabled, kprobe_lock held. */ +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + resume_execution(current_kprobe, regs); + regs->eflags |= kprobe_old_eflags; + + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} + +/* + * Wrapper routine to for handling exceptions. + */ +int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, + void *data) +{ + struct die_args *args = (struct die_args *)data; + switch (val) { + case DIE_INT3: + if (kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_DEBUG: + if (post_kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_GPF: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + case DIE_PAGE_FAULT: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + default: + break; + } + return NOTIFY_DONE; +} + +int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + unsigned long addr; + + jprobe_saved_regs = *regs; + jprobe_saved_esp = ®s->esp; + addr = (unsigned long)jprobe_saved_esp; + + /* + * TBD: As Linus pointed out, gcc assumes that the callee + * owns the argument space and could overwrite it, e.g. + * tailcall optimization. So, to be absolutely safe + * we also save and restore enough stack bytes to cover + * the argument area. + */ + memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr)); + regs->eflags &= ~IF_MASK; + regs->eip = (unsigned long)(jp->entry); + return 1; +} + +void jprobe_return(void) +{ + preempt_enable_no_resched(); + asm volatile (" xchgl %%ebx,%%esp \n" + " int3 \n"::"b" + (jprobe_saved_esp):"memory"); +} +void jprobe_return_end(void) +{ +}; + +int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + u8 *addr = (u8 *) (regs->eip - 1); + unsigned long stack_addr = (unsigned long)jprobe_saved_esp; + struct jprobe *jp = container_of(p, struct jprobe, kp); + + if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { + if (®s->esp != jprobe_saved_esp) { + struct pt_regs *saved_regs = + container_of(jprobe_saved_esp, struct pt_regs, esp); + printk("current esp %p does not match saved esp %p\n", + ®s->esp, jprobe_saved_esp); + printk("Saved registers for jprobe %p\n", jp); + show_registers(saved_regs); + printk("Current registers\n"); + show_registers(regs); + BUG(); + } + *regs = jprobe_saved_regs; + memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack, + MIN_STACK_SIZE(stack_addr)); + return 1; + } + return 0; +} diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index 038d30034..bb50afbee 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -142,12 +142,17 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) err = -EFAULT; up(&mm->context.sem); if (err < 0) - return err; + goto error_return; if (size != bytecount) { /* zero-fill the rest */ - clear_user(ptr+size, bytecount-size); + if (clear_user(ptr+size, bytecount-size) != 0) { + err = -EFAULT; + goto error_return; + } } return bytecount; +error_return: + return err; } static int read_default_ldt(void __user * ptr, unsigned long bytecount) diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 12ccd65bd..aca20edc5 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -485,6 +485,7 @@ static struct file_operations microcode_fops = { static struct miscdevice microcode_dev = { .minor = MICROCODE_MINOR, .name = "microcode", + .devfs_name = "cpu/microcode", .fops = µcode_fops, }; diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 16d91e3e1..c9dcd1f42 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -25,13 +25,17 @@ #include #include #include +#include #include #include #include #include +#include "mach_traps.h" + unsigned int nmi_watchdog = NMI_NONE; +extern int unknown_nmi_panic; static unsigned int nmi_hz = HZ; static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ static unsigned int nmi_p4_cccr_val; @@ -376,7 +380,13 @@ static int setup_p4_watchdog(void) clear_msr_range(0x3F1, 2); /* MSR 0x3F0 seems to have a default value of 0xFC00, but current docs doesn't fully define it, so leave it alone for now. */ - clear_msr_range(0x3A0, 31); + if (boot_cpu_data.x86_model >= 0x3) { + /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */ + clear_msr_range(0x3A0, 26); + clear_msr_range(0x3BC, 3); + } else { + clear_msr_range(0x3A0, 31); + } clear_msr_range(0x3C0, 6); clear_msr_range(0x3C8, 6); clear_msr_range(0x3E0, 2); @@ -426,8 +436,6 @@ void setup_apic_nmi_watchdog (void) nmi_active = 1; } -static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; - /* * the best way to detect whether a CPU has a 'hard lockup' problem * is to check it's local APIC timer IRQ counts. If they are not @@ -459,6 +467,8 @@ void touch_nmi_watchdog (void) alert_counter[i] = 0; } +extern void die_nmi(struct pt_regs *, const char *msg); + void nmi_watchdog_tick (struct pt_regs * regs) { @@ -477,21 +487,8 @@ void nmi_watchdog_tick (struct pt_regs * regs) * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; - if (alert_counter[cpu] == 5*nmi_hz) { - spin_lock(&nmi_print_lock); - /* - * We are in trouble anyway, lets at least try - * to get a message out. - */ - bust_spinlocks(1); - printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip); - show_registers(regs); - printk("console shuts up ...\n"); - console_silent(); - spin_unlock(&nmi_print_lock); - bust_spinlocks(0); - do_exit(SIGSEGV); - } + if (alert_counter[cpu] == 5*nmi_hz) + die_nmi(regs, "NMI Watchdog detected LOCKUP"); } else { last_irq_sums[cpu] = sum; alert_counter[cpu] = 0; @@ -518,6 +515,49 @@ void nmi_watchdog_tick (struct pt_regs * regs) } } +#ifdef CONFIG_SYSCTL + +static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) +{ + unsigned char reason = get_nmi_reason(); + char buf[64]; + + if (!(reason & 0xc0)) { + sprintf(buf, "NMI received for unknown reason %02x\n", reason); + die_nmi(regs, buf); + } + return 0; +} + +/* + * proc handler for /proc/sys/kernel/unknown_nmi_panic + */ +int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int old_state; + + old_state = unknown_nmi_panic; + proc_dointvec(table, write, file, buffer, length, ppos); + if (!!old_state == !!unknown_nmi_panic) + return 0; + + if (unknown_nmi_panic) { + if (reserve_lapic_nmi() < 0) { + unknown_nmi_panic = 0; + return -EBUSY; + } else { + set_nmi_callback(unknown_nmi_panic_callback); + } + } else { + release_lapic_nmi(); + unset_nmi_callback(); + } + return 0; +} + +#endif + EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_watchdog); EXPORT_SYMBOL(reserve_lapic_nmi); diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c index 10dc6b79d..982fe8c2b 100644 --- a/arch/i386/kernel/pci-dma.c +++ b/arch/i386/kernel/pci-dma.c @@ -13,17 +13,40 @@ #include #include +struct dma_coherent_mem { + void *virt_base; + u32 device_base; + int size; + int flags; + unsigned long *bitmap; +}; + void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int gfp) { void *ret; + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; + int order = get_order(size); /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + if (mem) { + int page = bitmap_find_free_region(mem->bitmap, mem->size, + order); + if (page >= 0) { + *dma_handle = mem->device_base + (page << PAGE_SHIFT); + ret = mem->virt_base + (page << PAGE_SHIFT); + memset(ret, 0, size); + return ret; + } + if (mem->flags & DMA_MEMORY_EXCLUSIVE) + return NULL; + } + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); + ret = (void *)__get_free_pages(gfp, order); if (ret != NULL) { memset(ret, 0, size); @@ -35,5 +58,89 @@ void *dma_alloc_coherent(struct device *dev, size_t size, void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, get_order(size)); + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; + int order = get_order(size); + + if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { + int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + + bitmap_release_region(mem->bitmap, page, order); + } else + free_pages((unsigned long)vaddr, order); +} + +int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + void __iomem *mem_base; + int pages = size >> PAGE_SHIFT; + int bitmap_size = (pages + 31)/32; + + if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) + goto out; + if (!size) + goto out; + if (dev->dma_mem) + goto out; + + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + mem_base = ioremap(bus_addr, size); + if (!mem_base) + goto out; + + dev->dma_mem = kmalloc(GFP_KERNEL, sizeof(struct dma_coherent_mem)); + if (!dev->dma_mem) + goto out; + memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem)); + dev->dma_mem->bitmap = kmalloc(GFP_KERNEL, bitmap_size); + if (!dev->dma_mem->bitmap) + goto free1_out; + memset(dev->dma_mem->bitmap, 0, bitmap_size); + + dev->dma_mem->virt_base = mem_base; + dev->dma_mem->device_base = device_addr; + dev->dma_mem->size = pages; + dev->dma_mem->flags = flags; + + if (flags & DMA_MEMORY_MAP) + return DMA_MEMORY_MAP; + + return DMA_MEMORY_IO; + + free1_out: + kfree(dev->dma_mem->bitmap); + out: + return 0; +} +EXPORT_SYMBOL(dma_declare_coherent_memory); + +void dma_release_declared_memory(struct device *dev) +{ + struct dma_coherent_mem *mem = dev->dma_mem; + + if(!mem) + return; + dev->dma_mem = NULL; + kfree(mem->bitmap); + kfree(mem); +} +EXPORT_SYMBOL(dma_release_declared_memory); + +void *dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) +{ + struct dma_coherent_mem *mem = dev->dma_mem; + int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; + int pos, err; + + if (!mem) + return ERR_PTR(-EINVAL); + + pos = (device_addr - mem->device_base) >> PAGE_SHIFT; + err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); + if (err != 0) + return ERR_PTR(err); + return mem->virt_base + (pos << PAGE_SHIFT); } +EXPORT_SYMBOL(dma_mark_declared_memory_occupied); diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 75b200985..0095fa1dd 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -142,13 +142,21 @@ void cpu_idle (void) /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { - void (*idle)(void) = pm_idle; + void (*idle)(void); + /* + * Mark this as an RCU critical section so that + * synchronize_kernel() in the unload path waits + * for our completion. + */ + rcu_read_lock(); + idle = pm_idle; if (!idle) idle = default_idle; irq_stat[smp_processor_id()].idle_timestamp = jiffies; idle(); + rcu_read_unlock(); } schedule(); } @@ -183,18 +191,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) @@ -294,13 +297,22 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) void exit_thread(void) { struct task_struct *tsk = current; + struct thread_struct *t = &tsk->thread; /* The process may have allocated an io port bitmap... nuke it. */ - if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { + if (unlikely(NULL != t->io_bitmap_ptr)) { int cpu = get_cpu(); - struct tss_struct *tss = init_tss + cpu; - kfree(tsk->thread.io_bitmap_ptr); - tsk->thread.io_bitmap_ptr = NULL; + struct tss_struct *tss = &per_cpu(init_tss, cpu); + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; + /* + * Careful, clear this in the TSS too: + */ + memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); + t->io_bitmap_max = 0; + tss->io_bitmap_owner = NULL; + tss->io_bitmap_max = 0; tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; put_cpu(); } @@ -369,8 +381,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, tsk = current; if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); - if (!p->thread.io_bitmap_ptr) + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; return -ENOMEM; + } memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr, IO_BITMAP_BYTES); } @@ -401,8 +415,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, err = 0; out: - if (err && p->thread.io_bitmap_ptr) + if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); + p->thread.io_bitmap_max = 0; + } return err; } @@ -467,6 +483,37 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) return 1; } +static inline void +handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) +{ + if (!next->io_bitmap_ptr) { + /* + * Disable the bitmap via an invalid offset. We still cache + * the previous bitmap owner and the IO bitmap contents: + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + return; + } + if (likely(next == tss->io_bitmap_owner)) { + /* + * Previous owner of the bitmap (hence the bitmap content) + * matches the next task, we dont have to do anything but + * to set a valid offset in the TSS: + */ + tss->io_bitmap_base = IO_BITMAP_OFFSET; + return; + } + /* + * Lazy TSS's I/O bitmap copy. We set an invalid offset here + * and we let the task to get a GPF in case an I/O instruction + * is performed. The handler of the GPF will verify that the + * faulting task has a valid I/O bitmap and, it true, does the + * real copy and restart the instruction. This will save us + * redundant copies when the currently switched task does not + * perform any I/O during its timeslice. + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; +} /* * This special macro can be used to load a debugging register */ @@ -507,7 +554,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; int cpu = smp_processor_id(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -551,28 +598,9 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas loaddebug(next, 7); } - if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - if (next->io_bitmap_ptr) { - /* - * 4 cachelines copy ... not good, but not that - * bad either. Anyone got something better? - * This only affects processes which use ioperm(). - * [Putting the TSSs into 4k-tlb mapped regions - * and playing VM tricks to switch the IO bitmap - * is not really acceptable.] - */ - memcpy(tss->io_bitmap, next->io_bitmap_ptr, - IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; - } else - /* - * a bitmap offset pointing outside of the TSS limit - * causes a nicely controllable SIGSEGV if a process - * tries to use a port IO instruction. The first - * sys_ioperm() call sets up the bitmap properly. - */ - tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; - } + if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) + handle_io_bitmap(next, tss); + return prev_p; } @@ -593,7 +621,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, ®s, 0, parent_tidptr, child_tidptr); + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } /* diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 0cf2f1187..e0c9a0373 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -147,6 +147,7 @@ void ptrace_disable(struct task_struct *child) { long tmp; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); } @@ -370,6 +371,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) else { clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -391,6 +393,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); @@ -411,6 +414,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + set_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -535,14 +539,15 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) audit_syscall_exit(current, regs->eax); } - if (!test_thread_flag(TIF_SYSCALL_TRACE)) + if (!test_thread_flag(TIF_SYSCALL_TRACE) && + !test_thread_flag(TIF_SINGLESTEP)) return; if (!(current->ptrace & PT_PTRACED)) return; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && + !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 375fd0761..19827c0c5 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -49,6 +49,7 @@ #include #include #include "setup_arch_pre.h" +#include /* This value is set up by the early boot code to point to the value immediately after the boot time page tables. It contains a *physical* @@ -218,9 +219,14 @@ static struct resource standard_io_resources[] = { { .end = 0x0021, .flags = IORESOURCE_BUSY | IORESOURCE_IO }, { - .name = "timer", + .name = "timer0", .start = 0x0040, - .end = 0x005f, + .end = 0x0043, + .flags = IORESOURCE_BUSY | IORESOURCE_IO +}, { + .name = "timer1", + .start = 0x0050, + .end = 0x0053, .flags = IORESOURCE_BUSY | IORESOURCE_IO }, { .name = "keyboard", @@ -809,6 +815,14 @@ static void __init parse_cmdline_early (char ** cmdline_p) if (c == ' ' && !memcmp(from, "highmem=", 8)) highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; + /* + * vmalloc=size forces the vmalloc area to be exactly 'size' + * bytes. This can be used to increase (or decrease) the + * vmalloc area - the default is 128m. + */ + if (c == ' ' && !memcmp(from, "vmalloc=", 8)) + __VMALLOC_RESERVE = memparse(from+8, &from); + c = *(from++); if (!c) break; @@ -991,6 +1005,17 @@ static void __init register_bootmem_low_pages(unsigned long max_low_pfn) } } +/* + * workaround for Dell systems that neglect to reserve EBDA + */ +static void __init reserve_ebda_region(void) +{ + unsigned int addr; + addr = get_bios_ebda(); + if (addr) + reserve_bootmem(addr, PAGE_SIZE); +} + static unsigned long __init setup_memory(void) { unsigned long bootmap_size, start_pfn, max_low_pfn; @@ -1037,6 +1062,9 @@ static unsigned long __init setup_memory(void) */ reserve_bootmem(0, PAGE_SIZE); + /* reserve EBDA region, it's a 4K region */ + reserve_ebda_region(); + /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent PCI prefetch into it (errata #56). Usually the page is reserved anyways, unless you have no PS/2 mouse plugged in. */ @@ -1335,7 +1363,12 @@ void __init setup_arch(char **cmdline_p) /* * NOTE: before this point _nobody_ is allowed to allocate - * any memory using the bootmem allocator. + * any memory using the bootmem allocator. Although the + * alloctor is now initialised only the first 8Mb of the kernel + * virtual address space has been mapped. All allocations before + * paging_init() has completed must use the alloc_bootmem_low_pages() + * variant (which allocates DMA'able memory) and care must be taken + * not to exceed the 8Mb limit. */ #ifdef CONFIG_SMP @@ -1343,6 +1376,10 @@ void __init setup_arch(char **cmdline_p) #endif paging_init(); + /* + * NOTE: at this point the bootmem allocator is fully available. + */ + #ifdef CONFIG_EARLY_PRINTK { char *s = strstr(*cmdline_p, "earlyprintk="); diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 57e88b625..a9b33b1e9 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -269,6 +270,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { int tmp, err = 0; + unsigned long eflags; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); @@ -290,7 +292,11 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(regs->eip, &sc->eip); err |= __put_user(regs->xcs, (unsigned int __user *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); + eflags = regs->eflags; + if (current->ptrace & PT_PTRACED) { + eflags &= ~TF_MASK; + } + err |= __put_user(eflags, &sc->eflags); err |= __put_user(regs->esp, &sc->esp_at_signal); err |= __put_user(regs->xss, (unsigned int __user *)&sc->ss); @@ -345,18 +351,20 @@ static void setup_frame(int sig, struct k_sigaction *ka, void __user *restorer; struct sigframe __user *frame; int err = 0; + int usig; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __put_user((current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); + usig = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(usig, &frame->sig); if (err) goto give_sigsegv; @@ -395,13 +403,22 @@ static void setup_frame(int sig, struct k_sigaction *ka, /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; + regs->eax = (unsigned long) sig; + regs->edx = (unsigned long) 0; + regs->ecx = (unsigned long) 0; set_fs(USER_DS); regs->xds = __USER_DS; regs->xes = __USER_DS; regs->xss = __USER_DS; regs->xcs = __USER_CS; - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -411,9 +428,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, @@ -422,18 +437,20 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, void __user *restorer; struct rt_sigframe __user *frame; int err = 0; + int usig; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __put_user((current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); + usig = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(usig, &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); @@ -476,13 +493,22 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; + regs->eax = (unsigned long) usig; + regs->edx = (unsigned long) &frame->info; + regs->ecx = (unsigned long) &frame->uc; set_fs(USER_DS); regs->xds = __USER_DS; regs->xes = __USER_DS; regs->xss = __USER_DS; regs->xcs = __USER_CS; - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -492,9 +518,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 +526,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 = ¤t->sighand->action[sig-1]; - /* Are we from a system call? */ if (regs->orig_eax >= 0) { /* If so, check system call restarting.. */ @@ -534,9 +556,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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -555,6 +574,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 +593,7 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) if (!oldset) oldset = ¤t->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 +603,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/smp.c b/arch/i386/kernel/smp.c index bb5960134..cf6ddbcf9 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -22,7 +22,6 @@ #include #include -#include #include /* @@ -104,7 +103,7 @@ * about nothing of note with C stepping upwards. */ -struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }}; +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, }; /* * the following functions deal with sending IPIs between CPUs. @@ -122,7 +121,7 @@ static inline int __prepare_ICR2 (unsigned int mask) return SET_APIC_DEST_FIELD(mask); } -inline void __send_IPI_shortcut(unsigned int shortcut, int vector) +void __send_IPI_shortcut(unsigned int shortcut, int vector) { /* * Subtle. In the case of the 'never do double writes' workaround @@ -157,7 +156,7 @@ void fastcall send_IPI_self(int vector) /* * This is only used on smaller machines. */ -inline void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) +void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) { unsigned long mask = cpus_addr(cpumask)[0]; unsigned long cfg; @@ -230,6 +229,8 @@ inline void send_IPI_mask_sequence(cpumask_t mask, int vector) local_irq_restore(flags); } +#include /* must come after the send_IPI functions above for inlining */ + /* * Smarter SMP flushing macros. * c/o Linus Torvalds. @@ -255,9 +256,9 @@ static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED; */ static inline void leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) BUG(); - cpu_clear(cpu, cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); load_cr3(swapper_pg_dir); } @@ -324,8 +325,8 @@ asmlinkage void smp_invalidate_interrupt (void) * BUG(); */ - if (flush_mm == cpu_tlbstate[cpu].active_mm) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) local_flush_tlb(); else @@ -457,7 +458,7 @@ static void do_flush_tlb_all(void* info) unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) leave_mm(cpu); } diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 1a9b08190..016a07067 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -17,7 +17,7 @@ * Fixes * Felix Koop : NR_CPUS used properly * Jose Renau : Handle single CPU case. - * Alan Cox : By repeated request 8) - Total BogoMIP report. + * Alan Cox : By repeated request 8) - Total BogoMIPS report. * Greg Wright : Fix for kernel stacks panic. * Erich Boleyn : MP v1.4 and additional changes. * Matthias Sattler : Changes for 2.1 kernel map. @@ -72,6 +72,10 @@ static cpumask_t smp_commenced_mask; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; +u8 x86_cpu_to_apicid[NR_CPUS] = + { [0 ... NR_CPUS-1] = 0xff }; +EXPORT_SYMBOL(x86_cpu_to_apicid); + /* Set when the idlers are all forked */ int smp_threads_ready; @@ -187,34 +191,6 @@ static unsigned long long tsc_values[NR_CPUS]; #define NR_LOOPS 5 -/* - * accurate 64-bit/32-bit division, expanded to 32-bit divisions and 64-bit - * multiplication. Not terribly optimized but we need it at boot time only - * anyway. - * - * result == a / b - * == (a1 + a2*(2^32)) / b - * == a1/b + a2*(2^32/b) - * == a1/b + a2*((2^32-1)/b) + a2/b + (a2*((2^32-1) % b))/b - * ^---- (this multiplication can overflow) - */ - -static unsigned long long __init div64 (unsigned long long a, unsigned long b0) -{ - unsigned int a1, a2; - unsigned long long res; - - a1 = ((unsigned int*)&a)[0]; - a2 = ((unsigned int*)&a)[1]; - - res = a1/b0 + - (unsigned long long)a2 * (unsigned long long)(0xffffffff/b0) + - a2 / b0 + - (a2 * (0xffffffff % b0)) / b0; - - return res; -} - static void __init synchronize_tsc_bp (void) { int i; @@ -224,7 +200,7 @@ static void __init synchronize_tsc_bp (void) unsigned long one_usec; int buggy = 0; - printk("checking TSC synchronization across %u CPUs: ", num_booting_cpus()); + printk(KERN_INFO "checking TSC synchronization across %u CPUs: ", num_booting_cpus()); /* convert from kcyc/sec to cyc/usec */ one_usec = cpu_khz / 1000; @@ -279,7 +255,8 @@ static void __init synchronize_tsc_bp (void) sum += t0; } } - avg = div64(sum, num_booting_cpus()); + avg = sum; + do_div(avg, num_booting_cpus()); sum = 0; for (i = 0; i < NR_CPUS; i++) { @@ -297,18 +274,18 @@ static void __init synchronize_tsc_bp (void) buggy = 1; printk("\n"); } - realdelta = div64(delta, one_usec); + realdelta = delta; + do_div(realdelta, one_usec); if (tsc_values[i] < avg) realdelta = -realdelta; - printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", i, realdelta); + printk(KERN_INFO "CPU#%d had %ld usecs TSC skew, fixed it up.\n", i, realdelta); } sum += delta; } if (!buggy) printk("passed.\n"); - ; } static void __init synchronize_tsc_ap (void) @@ -492,16 +469,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, ®s, 0, NULL, NULL); -} - #ifdef CONFIG_NUMA /* which logical CPUs are on which nodes */ @@ -797,21 +764,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(); @@ -875,6 +831,7 @@ static int __init do_boot_cpu(int apicid) inquire_remote_apic(apicid); } } + x86_cpu_to_apicid[cpu] = apicid; if (boot_error) { /* Try to put things back the way they were before ... */ unmap_cpu_to_logical_apicid(cpu); @@ -957,6 +914,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); boot_cpu_logical_apicid = logical_smp_processor_id(); + x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; current_thread_info()->cpu = 0; smp_tune_scheduling(); @@ -1132,213 +1090,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/sysenter.c b/arch/i386/kernel/sysenter.c index 0daa404f5..960d8bd13 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c @@ -24,7 +24,7 @@ extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void *info) { int cpu = get_cpu(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; @@ -43,18 +43,18 @@ extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; static int __init sysenter_setup(void) { - unsigned long page = get_zeroed_page(GFP_ATOMIC); + void *page = (void *)get_zeroed_page(GFP_ATOMIC); __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC); if (!boot_cpu_has(X86_FEATURE_SEP)) { - memcpy((void *) page, + memcpy(page, &vsyscall_int80_start, &vsyscall_int80_end - &vsyscall_int80_start); return 0; } - memcpy((void *) page, + memcpy(page, &vsyscall_sysenter_start, &vsyscall_sysenter_end - &vsyscall_sysenter_start); diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index f8dcf5d68..a9711fc35 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -200,6 +200,18 @@ unsigned long long monotonic_clock(void) } EXPORT_SYMBOL(monotonic_clock); +#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return *(unsigned long *)(regs->ebp + 4); + + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif /* * timer_interrupt() needs to keep up the real-time clock, @@ -321,11 +333,12 @@ static int time_suspend(struct sys_device *dev, u32 state) static int time_resume(struct sys_device *dev) { + unsigned long flags; unsigned long sec = get_cmos_time() + clock_cmos_diff; - write_seqlock_irq(&xtime_lock); + write_seqlock_irqsave(&xtime_lock, flags); xtime.tv_sec = sec; xtime.tv_nsec = 0; - write_sequnlock_irq(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock, flags); return 0; } diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 0ec677d9e..52fc52661 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -29,7 +29,7 @@ unsigned long hpet_address; /* hpet memory map physical address */ static int use_hpet; /* can be used for runtime check of hpet */ static int boot_hpet_disable; /* boottime override for HPET timer */ -static unsigned long hpet_virt_address; /* hpet kernel virtual address */ +static void __iomem * hpet_virt_address; /* hpet kernel virtual address */ #define FSEC_TO_USEC (1000000000UL) @@ -76,8 +76,7 @@ int __init hpet_enable(void) if (!hpet_address) { return -1; } - hpet_virt_address = (unsigned long) ioremap_nocache(hpet_address, - HPET_MMAP_SIZE); + hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); /* * Read the period, compute tick and quotient. */ @@ -162,11 +161,11 @@ int __init hpet_enable(void) hd.hd_irq[0] = HPET_LEGACY_8254; hd.hd_irq[1] = HPET_LEGACY_RTC; if (ntimer > 2) { - struct hpet *hpet; - struct hpet_timer *timer; + struct hpet __iomem *hpet; + struct hpet_timer __iomem *timer; int i; - hpet = (struct hpet *) hpet_virt_address; + hpet = hpet_virt_address; for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer; timer++, i++) diff --git a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c index 7ddbf1c76..a433cb046 100644 --- a/arch/i386/kernel/timers/timer_pit.c +++ b/arch/i386/kernel/timers/timer_pit.c @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -156,3 +159,44 @@ struct timer_opts timer_pit = { .monotonic_clock = monotonic_clock_pit, .delay = delay_pit, }; + +void setup_pit_timer(void) +{ + extern spinlock_t i8253_lock; + unsigned long flags; + + spin_lock_irqsave(&i8253_lock, flags); + outb_p(0x34,PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ + udelay(10); + outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ + udelay(10); + outb(LATCH >> 8 , PIT_CH0); /* MSB */ + spin_unlock_irqrestore(&i8253_lock, flags); +} + +static int timer_resume(struct sys_device *dev) +{ + setup_pit_timer(); + return 0; +} + +static struct sysdev_class timer_sysclass = { + set_kset_name("timer"), + .resume = timer_resume, +}; + +static struct sys_device device_timer = { + .id = 0, + .cls = &timer_sysclass, +}; + +static int __init init_timer_sysfs(void) +{ + int error = sysdev_class_register(&timer_sysclass); + if (!error) + error = sysdev_register(&device_timer); + return error; +} + +device_initcall(init_timer_sysfs); + diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index a1e3f6f96..34e9b8eba 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -265,7 +265,8 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, { struct cpufreq_freqs *freq = data; - write_seqlock_irq(&xtime_lock); + if (val != CPUFREQ_RESUMECHANGE) + write_seqlock_irq(&xtime_lock); if (!ref_freq) { ref_freq = freq->old; loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; @@ -291,7 +292,9 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, } #endif } - write_sequnlock_irq(&xtime_lock); + + if (val != CPUFREQ_RESUMECHANGE) + write_sequnlock_irq(&xtime_lock); return 0; } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index a3daea013..e8889024f 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -48,6 +49,7 @@ #include #include +#include #include #include @@ -92,6 +94,18 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; +struct notifier_block *i386die_chain; +static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED; + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&i386die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + return err; +} static int valid_stack_ptr(struct task_struct *task, void *p) { @@ -216,7 +230,7 @@ void show_registers(struct pt_regs *regs) ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx" + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx" " (%s) \n", smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags, UTS_RELEASE); @@ -234,23 +248,25 @@ void show_registers(struct pt_regs *regs) * time of the fault.. */ if (in_kernel) { + u8 *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - if(regs->eip < PAGE_OFFSET) - goto bad; - for(i=0;i<20;i++) - { + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + + if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) { printk(" Bad EIP value."); break; } - printk("%02x ", c); + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); } } printk("\n"); @@ -292,35 +308,53 @@ bug: printk("Kernel BUG\n"); } -spinlock_t die_lock = SPIN_LOCK_UNLOCKED; - void die(const char * str, struct pt_regs * regs, long err) { + static struct { + spinlock_t lock; + u32 lock_owner; + int lock_owner_depth; + } die = { + .lock = SPIN_LOCK_UNLOCKED, + .lock_owner = -1, + .lock_owner_depth = 0 + }; static int die_counter; - int nl = 0; - console_verbose(); - spin_lock_irq(&die_lock); - bust_spinlocks(1); - handle_BUG(regs); - printk(KERN_ALERT "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); + if (die.lock_owner != smp_processor_id()) { + console_verbose(); + spin_lock_irq(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); + } + + if (++die.lock_owner_depth < 3) { + int nl = 0; + handle_BUG(regs); + printk(KERN_ALERT "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); #ifdef CONFIG_PREEMPT - printk("PREEMPT "); - nl = 1; + printk("PREEMPT "); + nl = 1; #endif #ifdef CONFIG_SMP - printk("SMP "); - nl = 1; + printk("SMP "); + nl = 1; #endif #ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC"); - nl = 1; + printk("DEBUG_PAGEALLOC"); + nl = 1; #endif - if (nl) - printk("\n"); - show_registers(regs); + if (nl) + printk("\n"); + notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); + show_registers(regs); + } else + printk(KERN_ERR "Recursive die() failure, output suppressed\n"); + bust_spinlocks(0); - spin_unlock_irq(&die_lock); + die.lock_owner = -1; + spin_unlock_irq(&die.lock); if (in_interrupt()) panic("Fatal exception in interrupt"); @@ -387,6 +421,9 @@ static inline void do_trap(int trapnr, int signr, char *str, int vm86, #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -398,12 +435,18 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ } #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ } @@ -415,11 +458,16 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +#ifndef CONFIG_KPROBES DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +#endif DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) @@ -427,13 +475,40 @@ DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) -DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { - if (regs->eflags & X86_EFLAGS_IF) - local_irq_enable(); - + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct thread_struct *thread = ¤t->thread; + + /* + * Perform the lazy TSS's I/O bitmap copy. If the TSS has an + * invalid offset set (the LAZY one) and the faulting thread has + * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS + * and we set the offset field correctly. Then we let the CPU to + * restart the faulting instruction. + */ + if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && + thread->io_bitmap_ptr) { + memcpy(tss->io_bitmap, thread->io_bitmap_ptr, + thread->io_bitmap_max); + /* + * If the previously set map was extending to higher ports + * than the current one, pad extra space with 0xff (no access). + */ + if (thread->io_bitmap_max < tss->io_bitmap_max) + memset((char *) tss->io_bitmap + + thread->io_bitmap_max, 0xff, + tss->io_bitmap_max - thread->io_bitmap_max); + tss->io_bitmap_max = thread->io_bitmap_max; + tss->io_bitmap_base = IO_BITMAP_OFFSET; + put_cpu(); + return; + } + put_cpu(); + if (regs->eflags & VM_MASK) goto gp_in_vm86; @@ -451,8 +526,12 @@ gp_in_vm86: return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)) { + if (notify_die(DIE_GPF, "general protection fault", regs, + error_code, 13, SIGSEGV) == NOTIFY_STOP); + return; die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -496,11 +575,35 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) printk("Do you have a strange power saving mode enabled?\n"); } +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; + +void die_nmi (struct pt_regs *regs, const char *msg) +{ + spin_lock(&nmi_print_lock); + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + bust_spinlocks(1); + printk(msg); + printk(" on CPU%d, eip %08lx, registers:\n", + smp_processor_id(), regs->eip); + show_registers(regs); + printk("console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); + do_exit(SIGSEGV); +} + static void default_do_nmi(struct pt_regs * regs) { unsigned char reason = get_nmi_reason(); if (!(reason & 0xc0)) { + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) + == NOTIFY_STOP) + return; #ifdef CONFIG_X86_LOCAL_APIC /* * Ok, so this is none of the documented NMI sources, @@ -514,6 +617,8 @@ static void default_do_nmi(struct pt_regs * regs) unknown_nmi_error(reason, regs); return; } + if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) + return; if (reason & 0x80) mem_parity_error(reason, regs); if (reason & 0x40) @@ -557,6 +662,20 @@ void unset_nmi_callback(void) nmi_callback = dummy_nmi_callback; } +#ifdef CONFIG_KPROBES +asmlinkage int do_int3(struct pt_regs *regs, long error_code) +{ + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return 1; + /* This is an interrupt gate, because kprobes wants interrupts + disabled. Normal trap handlers don't. */ + restore_interrupts(regs); + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); + return 0; +} +#endif + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -587,6 +706,9 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, + SIGTRAP) == NOTIFY_STOP) + return; /* It's safe to allow irq's after DR6 has been saved */ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); @@ -875,6 +997,14 @@ void set_intr_gate(unsigned int n, void *addr) _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } +/* + * This routine sets up an interrupt gate at directory privilege level 3. + */ +static inline void set_system_intr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS); +} + static void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); @@ -911,7 +1041,7 @@ void __init trap_init(void) set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); - set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_intr_gate(3, &int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 4484e47a7..483e9b2e4 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -121,7 +121,7 @@ struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs) do_exit(SIGSEGV); } - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; load_esp0(tss, ¤t->thread); @@ -303,7 +303,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs)); asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs)); - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 829f1c91d..e0512cc8b 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -4,6 +4,7 @@ #include #include +#include OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -11,12 +12,13 @@ ENTRY(startup_32) jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x9090 @@ -66,9 +68,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.S b/arch/i386/kernel/vsyscall.lds.S new file mode 100644 index 000000000..3a8329d65 --- /dev/null +++ b/arch/i386/kernel/vsyscall.lds.S @@ -0,0 +1,65 @@ +/* + * Linker script for vsyscall DSO. The vsyscall page is an ELF shared + * object prelinked to its virtual address, and with only one read-only + * segment (that fits in one page). This script controls its layout. + */ +#include + +SECTIONS +{ + . = VSYSCALL_BASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + /* This linker script is used both with -r and with -shared. + For the layouts to match, we need to skip more than enough + space for the dynamic symbol table et al. If this amount + is insufficient, ld -shared will barf. Just increase it here. */ + . = VSYSCALL_BASE + 0x400; + + .text : { *(.text) } :text =0x90909090 + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .dynamic : { *(.dynamic) } :text :dynamic + .useless : { + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + } :text +} + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + LINUX_2.5 { + global: + __kernel_vsyscall; + __kernel_sigreturn; + __kernel_rt_sigreturn; + + local: *; + }; +} + +/* The ELF entry point can be used to set the AT_SYSINFO value. */ +ENTRY(__kernel_vsyscall); diff --git a/arch/i386/lib/memcpy.c b/arch/i386/lib/memcpy.c index ad16efa52..891b2359d 100644 --- a/arch/i386/lib/memcpy.c +++ b/arch/i386/lib/memcpy.c @@ -13,13 +13,13 @@ void *memcpy(void *to, const void *from, size_t n) return __memcpy(to, from, n); #endif } -EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL(memcpy); void *memset(void *s, int c, size_t count) { return __memset(s, c, count); } -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memset); void *memmove(void *dest, const void *src, size_t n) { @@ -41,4 +41,4 @@ void *memmove(void *dest, const void *src, size_t n) } return dest; } -EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL(memmove); diff --git a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c index d6fc84f37..01f8b1a2c 100644 --- a/arch/i386/lib/mmx.c +++ b/arch/i386/lib/mmx.c @@ -2,9 +2,9 @@ #include #include #include +#include #include -#include /* diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index e1bcec2b5..3347c47b0 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -31,6 +31,7 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon #define __do_strncpy_from_user(dst,src,count,res) \ do { \ int __d0, __d1, __d2; \ + might_sleep(); \ __asm__ __volatile__( \ " testl %1,%1\n" \ " jz 2f\n" \ @@ -119,6 +120,7 @@ strncpy_from_user(char *dst, const char __user *src, long count) #define __do_clear_user(addr,size) \ do { \ int __d0; \ + might_sleep(); \ __asm__ __volatile__( \ "0: rep; stosl\n" \ " movl %2,%0\n" \ diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h index 1cb878fc5..1ff0caeb8 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) @@ -104,6 +104,13 @@ struct mip_reg { #define MIP_SW_APIC 0x1020b #define MIP_FUNC(VALUE) (VALUE & 0xff) +#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT)) +#define IOAPIC_GSI_BOUND(ioapic) ((ioapic+1) * (nr_ioapic_registers[ioapic]-1)) +#define MAX_GSI_MAPSIZE 32 +#endif + +extern unsigned long io_apic_irqs; + extern int parse_unisys_oem (char *oemptr, int oem_entries); extern int find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length); extern int es7000_start_cpu(int cpu, unsigned long eip); diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c index 784576c53..1d1954a7f 100644 --- a/arch/i386/mach-es7000/es7000plat.c +++ b/arch/i386/mach-es7000/es7000plat.c @@ -51,27 +51,74 @@ struct mip_reg *host_reg; int mip_port; unsigned long mip_addr, host_addr; +#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT)) +static unsigned long cycle_irqs = 0; +static unsigned long free_irqs = 0; +static int gsi_map[MAX_GSI_MAPSIZE] = { [0 ... MAX_GSI_MAPSIZE-1] = -1 }; + +/* + * GSI override for ES7000 platforms. + */ + +static int __init +es7000_gsi_override(int ioapic, int gsi) +{ + static int newgsi = 0; + + if (gsi_map[gsi] != -1) + gsi = gsi_map[gsi]; + else if (cycle_irqs ^ free_irqs) { + newgsi = find_next_bit(&cycle_irqs, IOAPIC_GSI_BOUND(0), newgsi); + __set_bit(newgsi, &free_irqs); + gsi_map[gsi] = newgsi; + gsi = newgsi; + newgsi++; + Dprintk("es7000_gsi_override: free_irqs = 0x%lx\n", free_irqs); + } + + return gsi; +} + static int __init es7000_rename_gsi(int ioapic, int gsi) { + static int initialized = 0; + int i; + + /* + * These should NEVER be true at this point but we'd rather be + * safe than sorry. + */ + if (acpi_disabled || acpi_pci_disabled || acpi_noirq) + return gsi; + if (ioapic) - return gsi; - else { - if (gsi == 0) - return 13; - if (gsi == 1) - return 16; - if (gsi == 4) - return 17; - if (gsi == 6) - return 18; - if (gsi == 7) - return 19; - if (gsi == 8) - return 20; - return gsi; - } + return gsi; + + if (!initialized) { + unsigned long tmp_irqs = 0; + + for (i = 0; i < nr_ioapic_registers[0]; i++) + __set_bit(mp_irqs[i].mpc_srcbusirq, &tmp_irqs); + + cycle_irqs = (~tmp_irqs & io_apic_irqs & ((1 << IOAPIC_GSI_BOUND(0)) - 1)); + + initialized = 1; + Dprintk("es7000_rename_gsi: cycle_irqs = 0x%lx\n", cycle_irqs); + } + + for (i = 0; i < nr_ioapic_registers[0]; i++) { + if (mp_irqs[i].mpc_srcbusirq == gsi) { + if (mp_irqs[i].mpc_dstirq == gsi) + return gsi; + else + return es7000_gsi_override(0, gsi); + } + } + + return gsi; } +#endif // (CONFIG_X86_IO_APIC) && (CONFIG_ACPI_INTERPRETER || CONFIG_ACPI_BOOT) /* * Parse the OEM Table @@ -193,7 +240,7 @@ find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length) } } } - printk("ES7000: did not find Unisys ACPI OEM table!\n"); + Dprintk("ES7000: did not find Unisys ACPI OEM table!\n"); return -1; } @@ -237,7 +284,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 f599d8564..25883b44f 100644 --- a/arch/i386/mach-generic/bigsmp.c +++ b/arch/i386/mach-generic/bigsmp.c @@ -13,15 +13,41 @@ #include #include #include +#include #include #include #include #include -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 90c918f11..7cb7e8046 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -35,7 +35,7 @@ int reboot_smp = 0; /* TLB state -- visible externally, indexed physically */ -struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0 }}; +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; /* CPU IRQ affinity -- set to all ones initially */ static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = ~0UL }; @@ -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, ®s, 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; @@ -860,9 +845,9 @@ static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED; static inline void leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) BUG(); - cpu_clear(cpu, cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); load_cr3(swapper_pg_dir); } @@ -883,8 +868,8 @@ smp_invalidate_interrupt(void) smp_processor_id())); */ - if (flush_mm == cpu_tlbstate[cpu].active_mm) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) local_flush_tlb(); else @@ -1218,7 +1203,7 @@ do_flush_tlb_all(void* info) unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) leave_mm(cpu); } @@ -1302,8 +1287,7 @@ smp_local_timer_interrupt(struct pt_regs * regs) int cpu = smp_processor_id(); long weight; - x86_do_profile(regs); - + profile_tick(CPU_PROFILING, regs); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got diff --git a/arch/i386/math-emu/fpu_proto.h b/arch/i386/math-emu/fpu_proto.h index a8618dfd6..a9fe07c9b 100644 --- a/arch/i386/math-emu/fpu_proto.h +++ b/arch/i386/math-emu/fpu_proto.h @@ -69,7 +69,6 @@ extern int isNaN(FPU_REG const *ptr); extern void FPU_pop(void); extern int FPU_empty_i(int stnr); extern int FPU_stackoverflow(FPU_REG **st_new_ptr); -extern void FPU_sync_tags(void); extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 87dd63c98..fc3272506 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 569e08e5b..efdcb0da9 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c @@ -31,6 +31,7 @@ #include #include #include +#include struct pglist_data *node_data[MAX_NUMNODES]; bootmem_data_t node0_bdata; @@ -219,6 +220,17 @@ static unsigned long calculate_numa_remap_pages(void) return reserve_pages; } +/* + * workaround for Dell systems that neglect to reserve EBDA + */ +static void __init reserve_ebda_region_node(void) +{ + unsigned int addr; + addr = get_bios_ebda(); + if (addr) + reserve_bootmem_node(NODE_DATA(0), addr, PAGE_SIZE); +} + unsigned long __init setup_memory(void) { int nid; @@ -318,6 +330,9 @@ unsigned long __init setup_memory(void) */ reserve_bootmem_node(NODE_DATA(0), PAGE_SIZE, PAGE_SIZE); + /* reserve EBDA region, it's a 4K region */ + reserve_ebda_region_node(); + #ifdef CONFIG_ACPI_SLEEP /* * Reserve low memory region for sleep support. @@ -402,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/fault.c b/arch/i386/mm/fault.c index debed4754..e92938476 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -24,8 +24,8 @@ #include #include -#include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -107,7 +107,7 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, desc = (void *)desc + (seg & ~7); } else { /* Must disable preemption while reading the GDT. */ - desc = (u32 *)&cpu_gdt_table[get_cpu()]; + desc = (u32 *)&per_cpu(cpu_gdt_table, get_cpu()); desc = (void *)desc + (seg & ~7); } @@ -226,6 +226,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, + SIGSEGV) == NOTIFY_STOP) + return; /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & (X86_EFLAGS_IF|VM_MASK)) local_irq_enable(); @@ -513,12 +516,13 @@ vmalloc_fault: * an interrupt in the middle of a task switch.. */ int index = pgd_index(address); + unsigned long pgd_paddr; pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; pte_t *pte_k; - asm("movl %%cr3,%0":"=r" (pgd)); - pgd = index + (pgd_t *)__va(pgd); + asm("movl %%cr3,%0":"=r" (pgd_paddr)); + pgd = index + (pgd_t *)__va(pgd_paddr); pgd_k = init_mm.pgd + index; if (!pgd_present(*pgd_k)) diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index a8bd0544a..567ec7c49 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -40,10 +40,12 @@ #include #include +unsigned int __VMALLOC_RESERVE = 128 << 20; + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; -static int do_test_wp_bit(void); +static int noinline do_test_wp_bit(void); /* * Creates a middle page table and puts a pointer to it in the @@ -671,7 +673,7 @@ void __init pgtable_cache_init(void) * This function cannot be __init, since exceptions don't work in that * section. Put this after the callers, so that it cannot be inlined. */ -static int do_test_wp_bit(void) +static int noinline do_test_wp_bit(void) { char tmp_reg; int flag; diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 7b11be028..aee0bb1f4 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -110,9 +110,9 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { - void * addr; + void __iomem * addr; struct vm_struct * area; unsigned long offset, last_addr; @@ -125,7 +125,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag * Don't remap the low PCI/ISA area, it's always mapped.. */ if (phys_addr >= 0xA0000 && last_addr < 0x100000) - return phys_to_virt(phys_addr); + return (void __iomem *) phys_to_virt(phys_addr); /* * Don't allow anybody to remap normal RAM that we're using.. @@ -156,12 +156,12 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag if (!area) return NULL; area->phys_addr = phys_addr; - addr = area->addr; + addr = (void __iomem *) area->addr; if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { - vunmap(addr); + vunmap((void __force *) addr); return NULL; } - return (void *) (offset + (char *)addr); + return (void __iomem *) (offset + (char __iomem *)addr); } @@ -187,10 +187,10 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag * Must be freed with iounmap. */ -void *ioremap_nocache (unsigned long phys_addr, unsigned long size) +void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) { unsigned long last_addr; - void *p = __ioremap(phys_addr, size, _PAGE_PCD); + void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD); if (!p) return p; @@ -221,12 +221,12 @@ void *ioremap_nocache (unsigned long phys_addr, unsigned long size) return p; } -void iounmap(void *addr) +void iounmap(volatile void __iomem *addr) { struct vm_struct *p; - if (addr <= high_memory) + if ((void __force *) addr <= high_memory) return; - p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr)); + p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); if (!p) { printk("__iounmap: bad address %p\n", addr); return; diff --git a/arch/i386/mm/mmap.c b/arch/i386/mm/mmap.c index f88a6c88d..a6270ee14 100644 --- a/arch/i386/mm/mmap.c +++ b/arch/i386/mm/mmap.c @@ -57,7 +57,8 @@ 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) || + 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; @@ -65,7 +66,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm) } else { mm->mmap_base = mmap_base(mm); mm->get_unmapped_area = arch_get_unmapped_area_topdown; - mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; mm->unmap_area = arch_unmap_area_topdown; } } diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c index 8eb95be7d..4cfc30349 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c @@ -114,7 +114,7 @@ __change_page_attr(struct page *page, pgprot_t prot) kpte = lookup_address(address); if (!kpte) return -EINVAL; - kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK); + kpte_page = virt_to_page(kpte); if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { if ((pte_val(*kpte) & _PAGE_PSE) == 0) { pte_t old = *kpte; diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c index 5f6cc84ab..0d4e00f42 100644 --- a/arch/i386/oprofile/op_model_athlon.c +++ b/arch/i386/oprofile/op_model_athlon.c @@ -70,7 +70,7 @@ static void athlon_setup_ctrs(struct op_msrs const * const msrs) /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (counter_config[i].event) { + if (counter_config[i].enabled) { reset_value[i] = counter_config[i].count; CTR_WRITE(counter_config[i].count, msrs, i); @@ -96,7 +96,7 @@ static int athlon_check_ctrs(unsigned int const cpu, { unsigned int low, high; int i; - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); for (i = 0 ; i < NUM_COUNTERS; ++i) { diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c index e92eaed25..1b3626df5 100644 --- a/arch/i386/oprofile/op_model_p4.c +++ b/arch/i386/oprofile/op_model_p4.c @@ -419,9 +419,28 @@ static void p4_fill_in_addresses(struct op_msrs * const msrs) msrs->controls[i].addr = addr; } - /* 43 ESCR registers in three discontiguous group */ + /* 43 ESCR registers in three or four discontiguous group */ for (addr = MSR_P4_BSU_ESCR0 + stag; - addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { + addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) { + msrs->controls[i].addr = addr; + } + + /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1 + * to avoid special case in nmi_{save|restore}_registers() */ + if (boot_cpu_data.x86_model >= 0x3) { + for (addr = MSR_P4_BSU_ESCR0 + stag; + addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) { + msrs->controls[i].addr = addr; + } + } else { + for (addr = MSR_P4_IQ_ESCR0 + stag; + addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) { + msrs->controls[i].addr = addr; + } + } + + for (addr = MSR_P4_RAT_ESCR0 + stag; + addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { msrs->controls[i].addr = addr; } @@ -553,7 +572,18 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs) /* clear all escrs (including those outside our concern) */ for (addr = MSR_P4_BSU_ESCR0 + stag; - addr <= MSR_P4_SSU_ESCR0; addr += addr_increment()) { + addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) { + wrmsr(addr, 0, 0); + } + + /* On older models clear also MSR_P4_IQ_ESCR0/1 */ + if (boot_cpu_data.x86_model < 0x3) { + wrmsr(MSR_P4_IQ_ESCR0, 0, 0); + wrmsr(MSR_P4_IQ_ESCR1, 0, 0); + } + + for (addr = MSR_P4_RAT_ESCR0 + stag; + addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { wrmsr(addr, 0, 0); } @@ -578,7 +608,7 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs) /* setup all counters */ for (i = 0 ; i < num_counters ; ++i) { - if (counter_config[i].event) { + if (counter_config[i].enabled) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i)); @@ -595,7 +625,7 @@ static int p4_check_ctrs(unsigned int const cpu, { unsigned long ctr, low, high, stag, real; int i; - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); stag = get_stagger(); diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c index 21578b26d..0cc80654d 100644 --- a/arch/i386/oprofile/op_model_ppro.c +++ b/arch/i386/oprofile/op_model_ppro.c @@ -67,7 +67,7 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (counter_config[i].event) { + if (counter_config[i].enabled) { reset_value[i] = counter_config[i].count; CTR_WRITE(counter_config[i].count, msrs, i); @@ -91,7 +91,7 @@ static int ppro_check_ctrs(unsigned int const cpu, { unsigned int low, high; int i; - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); for (i = 0 ; i < NUM_COUNTERS; ++i) { diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 383827d92..88c832a0e 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -70,7 +70,7 @@ static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) int i; DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); - for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { + list_for_each(ln, &b->devices) { d = pci_dev_b(ln); if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) seen_host_bridge++; diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index a8b1954ae..bfcecdc55 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -29,6 +29,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) } pcibios_last_bus = -1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); static void __devinit pci_fixup_i450gx(struct pci_dev *d) { @@ -42,6 +43,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d) pci_scan_bus(busno, &pci_root_ops, NULL); pcibios_last_bus = -1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx); static void __devinit pci_fixup_umc_ide(struct pci_dev *d) { @@ -55,6 +57,7 @@ static void __devinit pci_fixup_umc_ide(struct pci_dev *d) for(i=0; i<4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) { @@ -67,6 +70,7 @@ static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) d->class = PCI_CLASS_STORAGE_SCSI << 8; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); static void __devinit pci_fixup_ide_bases(struct pci_dev *d) { @@ -86,6 +90,7 @@ static void __devinit pci_fixup_ide_bases(struct pci_dev *d) } } } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); static void __devinit pci_fixup_ide_trash(struct pci_dev *d) { @@ -108,6 +113,10 @@ static void __devinit pci_fixup_ide_trash(struct pci_dev *d) for(i=0; i<4; i++) d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_fixup_ide_trash); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_fixup_ide_trash); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_fixup_ide_trash); static void __devinit pci_fixup_latency(struct pci_dev *d) { @@ -118,6 +127,8 @@ static void __devinit pci_fixup_latency(struct pci_dev *d) DBG("PCI: Setting max latency to 32\n"); pcibios_max_latency = 32; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) { @@ -126,6 +137,7 @@ static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) */ d->irq = 9; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi); /* * Addresses issues with problems in the memory write queue timer in @@ -179,6 +191,10 @@ static void __devinit pci_fixup_via_northbridge_bug(struct pci_dev *d) pci_write_config_byte(d, where, v); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); /* * For some reasons Intel decided that certain parts of their @@ -195,6 +211,7 @@ static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev) (dev->device & 0xff00) == 0x2400) dev->transparent = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge); /* * Fixup for C1 Halt Disconnect problem on nForce2 systems. @@ -236,115 +253,5 @@ static void __init pci_fixup_nforce2(struct pci_dev *dev) pci_write_config_dword(dev, 0x6c, fixed_val); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); -struct pci_fixup pcibios_fixups[] = { - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82451NX, - .hook = pci_fixup_i450nx - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82454GX, - .hook = pci_fixup_i450gx - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_UMC, - .device = PCI_DEVICE_ID_UMC_UM8886BF, - .hook = pci_fixup_umc_ide - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5513, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .hook = pci_fixup_ide_bases - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5597, - .hook = pci_fixup_latency - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5598, - .hook = pci_fixup_latency - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82371AB_3, - .hook = pci_fixup_piix4_acpi - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801CA_10, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801CA_11, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801DB_9, - .hook = pci_fixup_ide_trash - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8363_0, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8622, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8361, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8367_0, - .hook = pci_fixup_via_northbridge_bug - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_NCR, - .device = PCI_DEVICE_ID_NCR_53C810, - .hook = pci_fixup_ncr53c810 - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_ANY_ID, - .hook = pci_fixup_transparent_bridge - }, - { - .pass = PCI_FIXUP_HEADER, - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE2, - .hook = pci_fixup_nforce2 - }, - { .pass = 0 } -}; diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c index 2ebc7c672..ec859ad0e 100644 --- a/arch/i386/pci/i386.c +++ b/arch/i386/pci/i386.c @@ -164,7 +164,7 @@ static void __init pcibios_allocate_resources(int pass) } } -static void __init pcibios_assign_resources(void) +static int __init pcibios_assign_resources(void) { struct pci_dev *dev = NULL; int idx; @@ -204,6 +204,7 @@ static void __init pcibios_assign_resources(void) pci_assign_resource(dev, PCI_ROM_RESOURCE); } } + return 0; } void __init pcibios_resource_survey(void) @@ -212,9 +213,14 @@ void __init pcibios_resource_survey(void) pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); - pcibios_assign_resources(); } +/** + * called in fs_initcall (one below subsys_initcall), + * give a chance for motherboard reserve resources + */ +fs_initcall(pcibios_assign_resources); + int pcibios_enable_resources(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 0b95fc46d..f42c45305 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2004 Matthew Wilcox + * Copyright (C) 2004 Intel Corp. + * + * This code is released under the GNU General Public License version 2. + */ + /* * mmconfig.c - Low-level direct PCI config space access via MMCONFIG */ @@ -9,7 +16,7 @@ /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ u32 pci_mmcfg_base_addr; -#define mmcfg_virt_addr (fix_to_virt(FIX_PCIE_MCFG)) +#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ static u32 mmcfg_last_accessed_device; diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index d77450067..c8046737b 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -100,10 +100,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) } pcibios_last_bus = -1; } - -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); static int __init pci_numa_init(void) { diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c index 700188d0f..50fc1f31e 100644 --- a/arch/i386/pci/pcbios.c +++ b/arch/i386/pci/pcbios.c @@ -365,7 +365,7 @@ void __devinit pcibios_sort(void) idx = found = 0; while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { idx++; - for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) { + list_for_each(ln, &pci_devices) { d = pci_dev_g(ln); if (d->bus->number == bus && d->devfn == devfn) { list_del(&d->global_list); diff --git a/arch/i386/power/Makefile b/arch/i386/power/Makefile index 2e1c9ab34..8cfa4e8a7 100644 --- a/arch/i386/power/Makefile +++ b/arch/i386/power/Makefile @@ -1,3 +1,2 @@ obj-$(CONFIG_PM) += cpu.o -obj-$(CONFIG_PM_DISK) += pmdisk.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index d58d30777..53542e3a9 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -83,10 +83,10 @@ do_fpu_end(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct * t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ - cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); /* This does ltr */ load_LDT(¤t->active_mm->context); /* This does lldt */ diff --git a/arch/i386/power/swsusp.S b/arch/i386/power/swsusp.S index 8e4a7baca..6e6335f89 100644 --- a/arch/i386/power/swsusp.S +++ b/arch/i386/power/swsusp.S @@ -15,83 +15,47 @@ .text -ENTRY(do_magic) - pushl %ebx - cmpl $0,8(%esp) - jne resume - call do_magic_suspend_1 - call save_processor_state +ENTRY(swsusp_arch_suspend) movl %esp, saved_context_esp - movl %eax, saved_context_eax movl %ebx, saved_context_ebx - movl %ecx, saved_context_ecx - movl %edx, saved_context_edx movl %ebp, saved_context_ebp movl %esi, saved_context_esi movl %edi, saved_context_edi pushfl ; popl saved_context_eflags - call do_magic_suspend_2 - popl %ebx + call swsusp_save ret -resume: +ENTRY(swsusp_arch_resume) movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx movl %ecx,%cr3 - call do_magic_resume_1 - movl $0,loop - cmpl $0,nr_copy_pages - je copy_done -copy_loop: - movl $0,loop2 + movl pagedir_nosave, %ebx + xorl %eax, %eax + xorl %edx, %edx .p2align 4,,7 -copy_one_page: - movl pagedir_nosave,%ecx - movl loop,%eax - movl loop2,%edx - sall $4,%eax - movl 4(%ecx,%eax),%ebx - movl (%ecx,%eax),%eax - movb (%edx,%eax),%al - movb %al,(%edx,%ebx) - movl loop2,%eax - leal 1(%eax),%edx - movl %edx,loop2 - movl %edx,%eax - cmpl $4095,%eax - jbe copy_one_page - movl loop,%eax - leal 1(%eax),%edx - movl %edx,loop - movl %edx,%eax - cmpl nr_copy_pages,%eax - jb copy_loop +copy_loop: + movl 4(%ebx,%edx),%edi + movl (%ebx,%edx),%esi + + movl $1024, %ecx + rep + movsl -copy_done: - movl $__USER_DS,%eax + incl %eax + addl $16, %edx + cmpl nr_copy_pages,%eax + jb copy_loop + .p2align 4,,7 - movw %ax, %ds - movw %ax, %es movl saved_context_esp, %esp movl saved_context_ebp, %ebp - movl saved_context_eax, %eax movl saved_context_ebx, %ebx - movl saved_context_ecx, %ecx - movl saved_context_edx, %edx movl saved_context_esi, %esi movl saved_context_edi, %edi - call restore_processor_state + pushl saved_context_eflags ; popfl - call do_magic_resume_2 - popl %ebx + call swsusp_restore ret - - .section .data.nosave -loop: - .quad 0 -loop2: - .quad 0 - .previous diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 72b48fb29..98da6394e 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -38,6 +38,10 @@ config EFI bool default y +config GENERIC_IOMAP + bool + default y + choice prompt "System type" default IA64_GENERIC @@ -72,6 +76,12 @@ config IA64_HP_ZX1 config IA64_SGI_SN2 bool "SGI-SN2" + help + Selecting this option will optimize the kernel for use on sn2 based + systems, but the resulting kernel binary will not run on other + types of ia64 systems. If you have an SGI Altix system, it's safe + to select this option. If in doubt, select ia64 generic support + instead. config IA64_HP_SIM bool "Ski-simulator" @@ -270,6 +280,9 @@ config COMPAT depends on IA32_SUPPORT default y +config IA64_MCA_RECOVERY + tristate "MCA recovery from errors other than TLB." + config PERFMON bool "Performance monitor support" help @@ -372,119 +385,7 @@ source "arch/ia64/hp/sim/Kconfig" source "arch/ia64/oprofile/Kconfig" -menu "Kernel hacking" - -choice - prompt "Physical memory granularity" - default IA64_GRANULE_64MB - -config IA64_GRANULE_16MB - bool "16MB" - help - IA-64 identity-mapped regions use a large page size called "granules". - - Select "16MB" for a small granule size. - Select "64MB" for a large granule size. This is the current default. - -config IA64_GRANULE_64MB - bool "64MB" - depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_SGI_SN2) - -endchoice - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config IA64_PRINT_HAZARDS - bool "Print possible IA-64 dependency violations to console" - depends on DEBUG_KERNEL - help - Selecting this option prints more information for Illegal Dependency - Faults, that is, for Read-after-Write (RAW), Write-after-Write (WAW), - or Write-after-Read (WAR) violations. This option is ignored if you - are compiling for an Itanium A step processor - (CONFIG_ITANIUM_ASTEP_SPECIFIC). If you're unsure, select Y. - -config DISABLE_VHPT - bool "Disable VHPT" - depends on DEBUG_KERNEL - help - The Virtual Hash Page Table (VHPT) enhances virtual address - translation performance. Normally you want the VHPT active but you - can select this option to disable the VHPT for debugging. If you're - unsure, answer N. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -config IA64_DEBUG_CMPXCHG - bool "Turn on compare-and-exchange bug checking (slow!)" - depends on DEBUG_KERNEL - help - Selecting this option turns on bug checking for the IA-64 - compare-and-exchange instructions. This is slow! Itaniums - from step B3 or later don't have this problem. If you're unsure, - select N. - -config IA64_DEBUG_IRQ - bool "Turn on irq debug checks (slow!)" - depends on DEBUG_KERNEL - help - Selecting this option turns on bug checking for the IA-64 irq_save - and restore instructions. It's useful for tracking down spinlock - problems, but slow! If you're unsure, select N. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config SYSVIPC_COMPAT - bool - depends on COMPAT && SYSVIPC - default y -endmenu +source "arch/ia64/Kconfig.debug" source "security/Kconfig" diff --git a/arch/ia64/Kconfig.debug b/arch/ia64/Kconfig.debug new file mode 100644 index 000000000..19edc8b2c --- /dev/null +++ b/arch/ia64/Kconfig.debug @@ -0,0 +1,64 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +choice + prompt "Physical memory granularity" + default IA64_GRANULE_64MB + +config IA64_GRANULE_16MB + bool "16MB" + help + IA-64 identity-mapped regions use a large page size called "granules". + + Select "16MB" for a small granule size. + Select "64MB" for a large granule size. This is the current default. + +config IA64_GRANULE_64MB + bool "64MB" + depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_SGI_SN2) + +endchoice + +config IA64_PRINT_HAZARDS + bool "Print possible IA-64 dependency violations to console" + depends on DEBUG_KERNEL + help + Selecting this option prints more information for Illegal Dependency + Faults, that is, for Read-after-Write (RAW), Write-after-Write (WAW), + or Write-after-Read (WAR) violations. This option is ignored if you + are compiling for an Itanium A step processor + (CONFIG_ITANIUM_ASTEP_SPECIFIC). If you're unsure, select Y. + +config DISABLE_VHPT + bool "Disable VHPT" + depends on DEBUG_KERNEL + help + The Virtual Hash Page Table (VHPT) enhances virtual address + translation performance. Normally you want the VHPT active but you + can select this option to disable the VHPT for debugging. If you're + unsure, answer N. + +config IA64_DEBUG_CMPXCHG + bool "Turn on compare-and-exchange bug checking (slow!)" + depends on DEBUG_KERNEL + help + Selecting this option turns on bug checking for the IA-64 + compare-and-exchange instructions. This is slow! Itaniums + from step B3 or later don't have this problem. If you're unsure, + select N. + +config IA64_DEBUG_IRQ + bool "Turn on irq debug checks (slow!)" + depends on DEBUG_KERNEL + help + Selecting this option turns on bug checking for the IA-64 irq_save + and restore instructions. It's useful for tracking down spinlock + problems, but slow! If you're unsure, select N. + +config SYSVIPC_COMPAT + bool + depends on COMPAT && SYSVIPC + default y + +endmenu diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index f2ca1e231..a32ebd61a 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -13,6 +13,8 @@ READELF := $(CROSS_COMPILE)readelf export AWK +CHECKFLAGS += -m64 -D__ia64=1 -D__ia64__=1 -D_LP64 -D__LP64__ + OBJCOPYFLAGS := --strip-all LDFLAGS_vmlinux := -static LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds @@ -20,14 +22,12 @@ AFLAGS_KERNEL := -mconstant-gp EXTRA := cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \ - -falign-functions=32 -frename-registers + -falign-functions=32 -frename-registers -fno-optimize-sibling-calls CFLAGS_KERNEL := -mconstant-gp -GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') -GCC_MINOR_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f2 -d'.') - -GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas $(CC) $(OBJDUMP)) -CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags $(CC) $(OBJDUMP) $(READELF)) +GCC_VERSION := $(call cc-version) +GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas "$(CC)" "$(OBJDUMP)") +CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags "$(CC)" "$(OBJDUMP)" "$(READELF)") ifeq ($(GAS_STATUS),buggy) $(error Sorry, you need a newer version of the assember, one that is built from \ @@ -37,16 +37,14 @@ $(error Sorry, you need a newer version of the assember, one that is built from ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifeq ($(GCC_VERSION),2) +ifneq ($(shell if [ $(GCC_VERSION) -lt 0300 ] ; then echo "bad"; fi ;),) $(error Sorry, your compiler is too old. GCC v2.96 is known to generate bad code.) endif -ifeq ($(GCC_VERSION),3) - ifeq ($(GCC_MINOR_VERSION),4) +ifeq ($(GCC_VERSION),0304) # Workaround Itanium 1 bugs in gcc 3.4. # cflags-$(CONFIG_ITANIUM) += -mtune=merced cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley - endif endif cflags-$(CONFIG_ITANIUM_BSTEP_SPECIFIC) += -mb-step diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig new file mode 100644 index 000000000..f16fd2e14 --- /dev/null +++ b/arch/ia64/configs/bigsur_defconfig @@ -0,0 +1,1132 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Tue Sep 28 13:26:53 2004 +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_HOTPLUG=y +# 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_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_VIRTUAL_MEM_MAP is not set +# CONFIG_IA64_CYCLONE is not set +CONFIG_IOSAPIC=y +CONFIG_FORCE_MAX_ZONEORDER=18 +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +# CONFIG_HOTPLUG_CPU is not set +CONFIG_PREEMPT=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# +CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# Power management and ACPI +# +CONFIG_PM=y +CONFIG_ACPI=y + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_THERMAL=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y + +# +# Bus options (PCI, PCMCIA) +# +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=m +# 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=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=m +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=m +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE 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_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +# 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_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC 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_IPS is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 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=y +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_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +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 +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# 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_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI 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) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN 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 is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +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=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input 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 + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=m +CONFIG_AGP_I460=m +CONFIG_DRM=y +# CONFIG_DRM_TDFX is not set +CONFIG_DRM_R128=m +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_SEQUENCER_OSS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_OPL3_LIB=m +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +CONFIG_SND_CS4281=m +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VX222 is not set + +# +# ALSA USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_USX2Y is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +CONFIG_USB_BLUETOOTH_TTY=m +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT 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 + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +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 is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +CONFIG_CIFS=m +CONFIG_CIFS_STATS=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +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_INFO is not set +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_SYSVIPC_COMPAT=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT 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 +# CONFIG_CRYPTO_TEST is not set diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig index e64003e02..a2684739b 100644 --- a/arch/ia64/configs/generic_defconfig +++ b/arch/ia64/configs/generic_defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc1 +# Tue Aug 24 15:08:24 2004 # # @@ -126,6 +128,7 @@ CONFIG_PCI_NAMES=y CONFIG_HOTPLUG_PCI=m # CONFIG_HOTPLUG_PCI_FAKE is not set CONFIG_HOTPLUG_PCI_ACPI=m +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set # CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set @@ -172,6 +175,7 @@ CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_SIZE=4096 @@ -313,6 +317,7 @@ CONFIG_BLK_DEV_MD=m CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=m CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m @@ -365,6 +370,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -575,6 +581,7 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set # CONFIG_STALDRV is not set +CONFIG_SGI_SNSC=y # # Serial drivers @@ -766,6 +773,7 @@ CONFIG_USB=m CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set # # USB Host Controller Drivers @@ -918,6 +926,8 @@ CONFIG_UDF_NLS=y CONFIG_FAT_FS=y # CONFIG_MSDOS_FS is not set CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_NTFS_FS=m # CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set @@ -945,7 +955,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 @@ -970,6 +979,7 @@ CONFIG_EXPORTFS=m CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m CONFIG_SMB_NLS_DEFAULT=y CONFIG_SMB_NLS_REMOTE="cp437" @@ -1006,7 +1016,7 @@ CONFIG_EFI_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m CONFIG_NLS_CODEPAGE_775=m CONFIG_NLS_CODEPAGE_850=m @@ -1030,7 +1040,7 @@ CONFIG_NLS_ISO8859_8=m CONFIG_NLS_CODEPAGE_1250=m CONFIG_NLS_CODEPAGE_1251=m # CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m CONFIG_NLS_ISO8859_4=m @@ -1067,18 +1077,18 @@ CONFIG_CRC32=y # # Kernel hacking # -CONFIG_IA64_GRANULE_16MB=y -# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_DISABLE_VHPT 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_INFO is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_DEBUG_INFO is not set CONFIG_SYSVIPC_COMPAT=y # @@ -1101,11 +1111,12 @@ CONFIG_CRYPTO_DES=m # 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/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig index 2797cb4eb..80b53c925 100644 --- a/arch/ia64/configs/sn2_defconfig +++ b/arch/ia64/configs/sn2_defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Fri Sep 24 08:59:00 2004 # # @@ -7,11 +9,11 @@ # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -32,6 +34,8 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -53,6 +57,7 @@ CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set # CONFIG_IA64_HP_ZX1 is not set @@ -75,7 +80,7 @@ CONFIG_FORCE_MAX_ZONEORDER=18 CONFIG_SMP=y CONFIG_NR_CPUS=512 # CONFIG_HOTPLUG_CPU is not set -# CONFIG_PREEMPT is not set +CONFIG_PREEMPT=y CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y @@ -115,7 +120,7 @@ CONFIG_ACPI_SYSTEM=y # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y -# CONFIG_PCI_USE_VECTOR is not set +# CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y @@ -142,6 +147,7 @@ CONFIG_HOTPLUG_PCI_SGI=y # # Generic Driver Options # +CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set @@ -171,6 +177,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -185,7 +192,8 @@ 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_IDEDISK is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -206,7 +214,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set @@ -273,7 +280,8 @@ CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_SVW is not set # CONFIG_SCSI_ATA_PIIX is not set @@ -316,6 +324,7 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=y # CONFIG_MD_RAID6 is not set CONFIG_MD_MULTIPATH=y @@ -329,8 +338,7 @@ CONFIG_DM_ZERO=m # Fusion MPT device support # CONFIG_FUSION=y -CONFIG_FUSION_MAX_SGE=40 -CONFIG_FUSION_ISENSE=m +CONFIG_FUSION_MAX_SGE=128 CONFIG_FUSION_CTL=m # @@ -368,11 +376,13 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set CONFIG_IPV6=m # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set @@ -527,6 +537,7 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set # CONFIG_STALDRV is not set +CONFIG_SGI_SNSC=y # # Serial drivers @@ -537,11 +548,11 @@ CONFIG_SERIAL_NONSTANDARD=y # Non-8250 serial port support # CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_SGI_L1_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -566,6 +577,7 @@ CONFIG_EFI_RTC=y CONFIG_RAW_DRIVER=m # CONFIG_HPET is not set CONFIG_MAX_RAW_DEVS=256 +CONFIG_MMTIMER=y # # I2C support @@ -600,7 +612,6 @@ CONFIG_MAX_RAW_DEVS=256 # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # @@ -620,6 +631,7 @@ CONFIG_USB=m # CONFIG_USB_DEVICEFS is not set # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -716,7 +728,7 @@ CONFIG_USB_HIDINPUT=y # # File systems # -CONFIG_EXT2_FS=m +CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT2_FS_SECURITY=y @@ -791,7 +803,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 @@ -816,10 +827,12 @@ CONFIG_EXPORTFS=m CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set # CONFIG_CIFS_POSIX is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -906,18 +919,18 @@ CONFIG_ZLIB_DEFLATE=m # # Kernel hacking # -CONFIG_IA64_GRANULE_16MB=y -# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_DISABLE_VHPT 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_INFO=y +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_DEBUG_INFO=y CONFIG_SYSVIPC_COMPAT=y # @@ -936,6 +949,7 @@ CONFIG_CRYPTO_MD5=m CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set CONFIG_CRYPTO_DES=m # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set @@ -945,6 +959,7 @@ CONFIG_CRYPTO_DES=m # 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=m # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig new file mode 100644 index 000000000..ce9412586 --- /dev/null +++ b/arch/ia64/configs/tiger_defconfig @@ -0,0 +1,1028 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Tue Sep 28 09:03:25 2004 +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=20 +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 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 +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +# CONFIG_NUMA is not set +CONFIG_VIRTUAL_MEM_MAP=y +CONFIG_IA64_CYCLONE=y +CONFIG_IOSAPIC=y +CONFIG_FORCE_MAX_ZONEORDER=18 +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_PREEMPT is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# +CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# Power management and ACPI +# +CONFIG_PM=y +CONFIG_ACPI=y + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_THERMAL=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y + +# +# Bus options (PCI, PCMCIA) +# +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=m +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_ACPI=m +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +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_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=m +# 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=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE 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_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN 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=y + +# +# 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_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC 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_IPS is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +CONFIG_SCSI_QLOGIC_1280=y +CONFIG_SCSI_QLA2XXX=y +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +# 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_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_CTL is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# 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=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +# CONFIG_E100_NAPI is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI 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) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +# CONFIG_E1000_NAPI is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +CONFIG_TIGON3=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN 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=y + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +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=m +CONFIG_SOUND_GAMEPORT=m +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_VORTEX is not set +# CONFIG_GAMEPORT_FM801 is not set +# CONFIG_GAMEPORT_CS461x is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input 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=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_STALDRV is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_ACPI=y +CONFIG_SERIAL_8250_NR_UARTS=6 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=m +CONFIG_AGP_I460=m +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_RAW_DRIVER=m +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_MAX_RAW_DEVS=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=y + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT 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 + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW 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_XATTR is not set +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_POSIX is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +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_INFO is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_SYSVIPC_COMPAT=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT 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 +# CONFIG_CRYPTO_TEST is not set diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig index e9eda7323..7ef08d376 100644 --- a/arch/ia64/configs/zx1_defconfig +++ b/arch/ia64/configs/zx1_defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2-aegl +# Mon Sep 27 19:03:13 2004 # # @@ -7,33 +9,45 @@ # CONFIG_EXPERIMENTAL=y # CONFIG_CLEAN_COMPILE is not set -CONFIG_STANDALONE=y CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y # # General setup # +CONFIG_LOCALVERSION="" 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=17 CONFIG_HOTPLUG=y # 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_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set # # Processor type and features @@ -44,54 +58,53 @@ CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y +CONFIG_GENERIC_IOMAP=y # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set CONFIG_IA64_HP_ZX1=y # CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_HP_SIM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_ACPI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y CONFIG_IA64_L1_CACHE_SHIFT=7 -# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set # CONFIG_NUMA is not set CONFIG_VIRTUAL_MEM_MAP=y -CONFIG_IA64_MCA=y # CONFIG_IA64_CYCLONE is not set -CONFIG_PM=y CONFIG_IOSAPIC=y CONFIG_FORCE_MAX_ZONEORDER=18 -# CONFIG_HUGETLB_PAGE_SIZE_4GB is not set -# CONFIG_HUGETLB_PAGE_SIZE_1GB is not set -# CONFIG_HUGETLB_PAGE_SIZE_256MB is not set -CONFIG_HUGETLB_PAGE_SIZE_64MB=y -# CONFIG_HUGETLB_PAGE_SIZE_16MB is not set -# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set -# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set -# CONFIG_HUGETLB_PAGE_SIZE_256KB is not set -CONFIG_IA64_PAL_IDLE=y CONFIG_SMP=y CONFIG_NR_CPUS=16 +# CONFIG_HOTPLUG_CPU is not set # CONFIG_PREEMPT is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y +# +# Power management and ACPI +# +CONFIG_PM=y +CONFIG_ACPI=y + # # ACPI (Advanced Configuration and Power Interface) Support # CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y CONFIG_ACPI_BUTTON=y CONFIG_ACPI_FAN=y CONFIG_ACPI_PROCESSOR=y @@ -101,8 +114,13 @@ CONFIG_ACPI_BUS=y CONFIG_ACPI_POWER=y CONFIG_ACPI_PCI=y CONFIG_ACPI_SYSTEM=y + +# +# Bus options (PCI, PCMCIA) +# CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y @@ -112,6 +130,7 @@ CONFIG_PCI_NAMES=y CONFIG_HOTPLUG_PCI=y # CONFIG_HOTPLUG_PCI_FAKE is not set CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set # CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set @@ -122,20 +141,27 @@ CONFIG_HOTPLUG_PCI_ACPI=y # CONFIG_PCMCIA is not set # -# Parallel port support +# Device Drivers # -# CONFIG_PARPORT is not set # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set # # Memory Technology Devices (MTD) # # CONFIG_MTD is not set +# +# Parallel port support +# +# CONFIG_PARPORT is not set + # # Plug and Play support # @@ -143,7 +169,6 @@ CONFIG_HOTPLUG_PCI_ACPI=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -151,10 +176,11 @@ CONFIG_HOTPLUG_PCI_ACPI=y CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -# CONFIG_DCSSBLK is not set # # ATA/ATAPI/MFM/RLL support @@ -165,9 +191,9 @@ 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_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# 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 @@ -187,7 +213,6 @@ CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set # CONFIG_IDEDMA_PCI_AUTO is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set @@ -208,32 +233,12 @@ CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_BLK_DEV_HD is not set -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -CONFIG_FUSION=y -CONFIG_FUSION_BOOT=y -CONFIG_FUSION_MAX_SGE=40 - # # SCSI device support # @@ -254,21 +259,28 @@ CONFIG_CHR_DEV_SG=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y +# +# 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_ADVANSYS is not set -CONFIG_SCSI_MEGARAID=y +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set # CONFIG_SCSI_SATA is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -285,6 +297,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_QLOGIC_ISP is not set @@ -301,6 +314,28 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_DC390T 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=y +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_CTL is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + # # Networking support # @@ -322,19 +357,17 @@ CONFIG_IP_MULTICAST=y # 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 +# CONFIG_INET_TUNNEL is not set # # IP: Virtual Server Configuration # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -353,10 +386,11 @@ CONFIG_IP_NF_ARPTABLES=y # # 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_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -371,21 +405,27 @@ 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=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set # # Ethernet (10 or 100Mbit) @@ -429,6 +469,7 @@ CONFIG_E100=y # 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) @@ -441,7 +482,6 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set CONFIG_TIGON3=y @@ -449,47 +489,39 @@ CONFIG_TIGON3=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 - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set +# CONFIG_S2IO is not set # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set # -# Amateur Radio support +# Wireless LAN (non-hamradio) # -# CONFIG_HAMRADIO is not set +# CONFIG_NET_RADIO is not set # -# IrDA (infrared) support +# Wan interfaces # -# CONFIG_IRDA is not set +# CONFIG_WAN 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 # -# Bluetooth support +# ISDN subsystem # -# CONFIG_BT is not set +# CONFIG_ISDN is not set # -# ISDN subsystem +# Telephony Support # -# CONFIG_ISDN is not set +# CONFIG_PHONE is not set # # Input device support @@ -518,6 +550,7 @@ CONFIG_SERIO=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -541,7 +574,6 @@ CONFIG_HW_CONSOLE=y # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_HCDP=y CONFIG_SERIAL_8250_ACPI=y CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_EXTENDED=y @@ -559,12 +591,6 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set - # # IPMI # @@ -575,8 +601,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set -# CONFIG_GEN_RTC is not set CONFIG_EFI_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -585,7 +609,6 @@ CONFIG_EFI_RTC=y # # Ftape, the floppy tape device driver # -# CONFIG_FTAPE is not set CONFIG_AGP=y CONFIG_AGP_HP_ZX1=y CONFIG_DRM=y @@ -596,6 +619,7 @@ CONFIG_DRM_RADEON=y # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set # CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set # # I2C support @@ -608,11 +632,13 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_ALGOBIT=y CONFIG_I2C_ALGOPCF=y +# CONFIG_I2C_ALGOPCA is not set # # I2C Hardware Bus support # # CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set # CONFIG_I2C_ALI15X3 is not set # CONFIG_I2C_AMD756 is not set # CONFIG_I2C_AMD8111 is not set @@ -630,29 +656,55 @@ CONFIG_I2C_ALGOPCF=y # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set # -# I2C Hardware Sensors Chip support +# Hardware Sensors Chip support # # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + # # Multimedia devices # @@ -663,6 +715,167 @@ CONFIG_I2C_ALGOPCF=y # # CONFIG_DVB is not set +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_DEBUG=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_BANDWIDTH=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT 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 + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + # # File systems # @@ -693,6 +906,7 @@ CONFIG_ISO9660_FS=y CONFIG_JOLIET=y # CONFIG_ZISOFS is not set CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -700,6 +914,8 @@ CONFIG_UDF_FS=y 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 # @@ -707,6 +923,7 @@ CONFIG_VFAT_FS=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -747,11 +964,12 @@ CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 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 # @@ -769,7 +987,6 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_LDM_PARTITION is not set -# CONFIG_NEC98_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set @@ -803,6 +1020,7 @@ CONFIG_NLS_CODEPAGE_874=y CONFIG_NLS_ISO8859_8=y # CONFIG_NLS_CODEPAGE_1250 is not set CONFIG_NLS_CODEPAGE_1251=y +# CONFIG_NLS_ASCII is not set CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_2=y CONFIG_NLS_ISO8859_3=y @@ -818,227 +1036,12 @@ CONFIG_NLS_KOI8_R=y CONFIG_NLS_KOI8_U=y CONFIG_NLS_UTF8=y -# -# Graphics support -# -CONFIG_FB=y -# CONFIG_FB_CIRRUS is not set -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -# CONFIG_FB_IMSTT is not set -# CONFIG_FB_RIVA is not set -# CONFIG_FB_MATROX is not set -# CONFIG_FB_RADEON_OLD is not set -CONFIG_FB_RADEON=y -CONFIG_FB_RADEON_I2C=y -CONFIG_FB_RADEON_DEBUG=y -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_PM3 is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -CONFIG_VGA_CONSOLE=y -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y - -# -# Logo configuration -# -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_LOGO_LINUX_CLUT224=y - -# -# Sound -# -CONFIG_SOUND=y - -# -# Advanced Linux Sound Architecture -# -CONFIG_SND=y -CONFIG_SND_SEQUENCER=y -# CONFIG_SND_SEQ_DUMMY is not set -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -CONFIG_SND_SEQUENCER_OSS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set - -# -# Generic devices -# -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_VIRMIDI is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set - -# -# PCI devices -# -# CONFIG_SND_ALI5451 is not set -# CONFIG_SND_AZT3328 is not set -# CONFIG_SND_BT87X is not set -# CONFIG_SND_CS46XX is not set -# CONFIG_SND_CS4281 is not set -# CONFIG_SND_EMU10K1 is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set -# CONFIG_SND_CMIPCI is not set -# CONFIG_SND_ENS1370 is not set -# CONFIG_SND_ENS1371 is not set -# CONFIG_SND_ES1938 is not set -# CONFIG_SND_ES1968 is not set -# CONFIG_SND_MAESTRO3 is not set -CONFIG_SND_FM801=y -# CONFIG_SND_ICE1712 is not set -# CONFIG_SND_ICE1724 is not set -# CONFIG_SND_INTEL8X0 is not set -# CONFIG_SND_SONICVIBES is not set -# CONFIG_SND_VIA82XX is not set -# CONFIG_SND_VX222 is not set - -# -# ALSA USB devices -# -# CONFIG_SND_USB_AUDIO is not set - -# -# Open Sound System -# -# CONFIG_SOUND_PRIME is not set - -# -# USB support -# -CONFIG_USB=y -# CONFIG_USB_DEBUG is not set - -# -# Miscellaneous USB options -# -# CONFIG_USB_DEVICEFS is not set -CONFIG_USB_BANDWIDTH=y -# CONFIG_USB_DYNAMIC_MINORS is not set - -# -# USB Host Controller Drivers -# -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_UHCI_HCD=y - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -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 - -# -# USB Human Interface Devices (HID) -# -CONFIG_USB_HID=y -CONFIG_USB_HIDINPUT=y -# CONFIG_HID_FF is not set -CONFIG_USB_HIDDEV=y -# CONFIG_USB_AIPTEK is not set -# CONFIG_USB_WACOM is not set -# CONFIG_USB_KBTAB is not set -# CONFIG_USB_POWERMATE is not set -# CONFIG_USB_XPAD is not set - -# -# USB Imaging devices -# -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# -# CONFIG_USB_DABUSB is not set - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_CATC is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_RTL8150 is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_EMI62 is not set -# CONFIG_USB_EMI26 is not set -# CONFIG_USB_TIGL is not set -# CONFIG_USB_AUERSWALD is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_LCD is not set -# CONFIG_USB_LED is not set - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - # # Library routines # +# CONFIG_CRC_CCITT is not set CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set # # Profiling support @@ -1048,18 +1051,19 @@ CONFIG_CRC32=y # # Kernel hacking # -CONFIG_IA64_GRANULE_16MB=y -# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT 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_INFO is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_SYSVIPC_COMPAT=y # # Security options @@ -1069,4 +1073,26 @@ CONFIG_MAGIC_SYSRQ=y # # Cryptographic options # -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WHIRLPOOL is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT 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 +# CONFIG_CRYPTO_TEST is not set diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 5333e6190..e50c446e0 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -191,7 +191,7 @@ static unsigned long iovp_shift; static unsigned long iovp_mask; struct ioc { - void *ioc_hpa; /* I/O MMU base address */ + void __iomem *ioc_hpa; /* I/O MMU base address */ char *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ unsigned long ibase; /* pdir IOV Space base */ @@ -203,6 +203,9 @@ struct ioc { /* clearing pdir to prevent races with allocations. */ unsigned int res_bitshift; /* from the RIGHT! */ unsigned int res_size; /* size of resource map in bytes */ +#ifdef CONFIG_NUMA + unsigned int node; /* node where this IOC lives */ +#endif #if DELAYED_RESOURCE_CNT > 0 spinlock_t saved_lock; /* may want to try to get this on a separate cacheline */ /* than res_lock for bigger systems. */ @@ -1057,7 +1060,24 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int struct ioc *ioc; void *addr; + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef CONFIG_NUMA + { + struct page *page; + page = alloc_pages_node(ioc->node == MAX_NUMNODES ? + numa_node_id() : ioc->node, flags, + get_order(size)); + + if (unlikely(!page)) + return NULL; + + addr = page_address(page); + } +#else addr = (void *) __get_free_pages(flags, get_order(size)); +#endif if (unlikely(!addr)) return NULL; @@ -1081,8 +1101,6 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int * If device can't bypass or bypass is disabled, pass the 32bit fake * device to map single to get an iova mapping. */ - ioc = GET_IOC(dev); - ASSERT(ioc); *dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0); return addr; @@ -1135,7 +1153,7 @@ sba_fill_pdir( { struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ int n_mappings = 0; - u64 *pdirp = 0; + u64 *pdirp = NULL; unsigned long dma_offset = 0; dma_sg--; @@ -1799,6 +1817,10 @@ ioc_show(struct seq_file *s, void *v) seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n", ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF)); +#ifdef CONFIG_NUMA + if (ioc->node != MAX_NUMNODES) + seq_printf(s, "NUMA node : %d\n", ioc->node); +#endif seq_printf(s, "IOVA size : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024)); seq_printf(s, "IOVA page size : %ld kb\n", iovp_size/1024); @@ -1853,7 +1875,7 @@ ioc_proc_init(void) { struct proc_dir_entry *dir, *entry; - dir = proc_mkdir("bus/mckinley", 0); + dir = proc_mkdir("bus/mckinley", NULL); if (!dir) return; @@ -1899,6 +1921,58 @@ sba_connect_bus(struct pci_bus *bus) printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", pci_domain_nr(bus), bus->number); } +#ifdef CONFIG_NUMA +static void __init +sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + acpi_handle phandle; + unsigned int node; + + ioc->node = MAX_NUMNODES; + + /* + * Check for a _PXM on this node first. We don't typically see + * one here, so we'll end up getting it from the parent. + */ + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer))) { + if (ACPI_FAILURE(acpi_get_parent(handle, &phandle))) + return; + + /* Reset the acpi buffer */ + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + + if (ACPI_FAILURE(acpi_evaluate_object(phandle, "_PXM", NULL, + &buffer))) + return; + } + + if (!buffer.length || !buffer.pointer) + return; + + obj = buffer.pointer; + + if (obj->type != ACPI_TYPE_INTEGER || + obj->integer.value >= MAX_PXM_DOMAINS) { + acpi_os_free(buffer.pointer); + return; + } + + node = pxm_to_nid_map[obj->integer.value]; + acpi_os_free(buffer.pointer); + + if (node >= MAX_NUMNODES || !node_online(node)) + return; + + ioc->node = node; + return; +} +#else +#define sba_map_ioc_to_node(ioc, handle) +#endif + static int __init acpi_sba_ioc_add(struct acpi_device *device) { @@ -1941,6 +2015,8 @@ acpi_sba_ioc_add(struct acpi_device *device) if (!ioc) return 1; + /* setup NUMA node association */ + sba_map_ioc_to_node(ioc, device->handle); return 0; } diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 381277884..af4b7143d 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -50,10 +50,6 @@ #define _INLINE_ inline #endif -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) #define SSC_GETCHAR 21 @@ -275,7 +271,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) * Then from the beginning of the buffer until necessary */ - count = MIN(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), + count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), SERIAL_XMIT_SIZE - info->xmit.tail); console->write(console, info->xmit.buf+info->xmit.tail, count); @@ -1055,7 +1051,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/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index 9618f6282..a4da6a93d 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -48,6 +48,7 @@ static void elf32_set_personality (void); extern struct page *ia32_shared_page[]; extern unsigned long *ia32_gdt; +extern struct page *ia32_gate_page; struct page * ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int *type) @@ -59,10 +60,25 @@ ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int return pg; } +struct page * +ia32_install_gate_page (struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *pg = ia32_gate_page; + get_page(pg); + if (type) + *type = VM_FAULT_MINOR; + return pg; +} + + static struct vm_operations_struct ia32_shared_page_vm_ops = { .nopage = ia32_install_shared_page }; +static struct vm_operations_struct ia32_gate_page_vm_ops = { + .nopage = ia32_install_gate_page +}; + void ia64_elf32_init (struct pt_regs *regs) { @@ -89,6 +105,29 @@ ia64_elf32_init (struct pt_regs *regs) up_write(¤t->mm->mmap_sem); } + /* + * When user stack is not executable, push sigreturn code to stack makes + * segmentation fault raised when returning to kernel. So now sigreturn + * code is locked in specific gate page, which is pointed by pretcode + * when setup_frame_ia32 + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_start = IA32_GATE_OFFSET; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = PAGE_COPY_EXEC; + vma->vm_flags = VM_READ | VM_MAYREAD | VM_EXEC + | VM_MAYEXEC | VM_RESERVED; + vma->vm_ops = &ia32_gate_page_vm_ops; + down_write(¤t->mm->mmap_sem); + { + insert_vm_struct(current->mm, vma); + } + up_write(¤t->mm->mmap_sem); + } + /* * Install LDT as anonymous memory. This gives us all-zero segment descriptors * until a task modifies them via modify_ldt(). @@ -187,7 +226,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)? PAGE_COPY_EXEC: PAGE_COPY; insert_vm_struct(current->mm, mpnt); - current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff --git a/arch/ia64/ia32/elfcore32.h b/arch/ia64/ia32/elfcore32.h index 36f8d42e3..b68534d18 100644 --- a/arch/ia64/ia32/elfcore32.h +++ b/arch/ia64/ia32/elfcore32.h @@ -103,11 +103,15 @@ static inline int elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpregset_t *fpu) { struct ia32_user_i387_struct *fpstate = (void*)fpu; + mm_segment_t old_fs; if (!tsk->used_math) return 0; - - save_ia32_fpstate(tsk, fpstate); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + save_ia32_fpstate(tsk, (struct ia32_user_i387_struct __user *) fpstate); + set_fs(old_fs); return 1; } @@ -117,11 +121,15 @@ static inline int elf_core_copy_task_xfpregs(struct task_struct *tsk, elf_fpxregset_t *xfpu) { struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu; + mm_segment_t old_fs; if (!tsk->used_math) return 0; - save_ia32_fpxstate(tsk, fpxstate); + old_fs = get_fs(); + set_fs(KERNEL_DS); + save_ia32_fpxstate(tsk, (struct ia32_user_fxsr_struct __user *) fpxstate); + set_fs(old_fs); return 1; } diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index fa3ac962a..4a6319c6d 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 = ®s - 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 @@ -311,7 +311,7 @@ ia32_syscall_table: data8 sys_ni_syscall /* old profil syscall holder */ data8 compat_sys_statfs data8 compat_sys_fstatfs /* 100 */ - data8 sys32_ioperm + data8 sys_ni_syscall /* ioperm */ data8 compat_sys_socketcall data8 sys_syslog data8 compat_sys_setitimer @@ -320,7 +320,7 @@ ia32_syscall_table: data8 compat_sys_newlstat data8 compat_sys_newfstat data8 sys_ni_syscall - data8 sys32_iopl /* 110 */ + data8 sys_ni_syscall /* iopl */ /* 110 */ data8 sys_vhangup data8 sys_ni_syscall /* used to be sys_idle */ data8 sys_ni_syscall @@ -493,6 +493,8 @@ ia32_syscall_table: data8 compat_sys_mq_timedreceive /* 280 */ data8 compat_sys_mq_notify data8 compat_sys_mq_getsetattr + data8 sys_ni_syscall /* reserved for kexec */ + data8 sys32_waitid // guard against failures to increase IA32_NR_syscalls .org ia32_syscall_table + 8*IA32_NR_syscalls diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c index 4cc8242de..a152738c7 100644 --- a/arch/ia64/ia32/ia32_ldt.c +++ b/arch/ia64/ia32/ia32_ldt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001, 2004 Hewlett-Packard Co * David Mosberger-Tang * * Adapted from arch/i386/kernel/ldt.c @@ -17,25 +17,24 @@ #include "ia32priv.h" -#define P(p) ((void *) (unsigned long) (p)) - /* * read_ldt() is not really atomic - this is not a problem since synchronization of reads * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic, * to protect the security checks done on new descriptors. */ static int -read_ldt (void *ptr, unsigned long bytecount) +read_ldt (void __user *ptr, unsigned long bytecount) { - char *src, *dst, buf[256]; /* temporary buffer (don't overflow kernel stack!) */ unsigned long bytes_left, n; + char __user *src, *dst; + char buf[256]; /* temporary buffer (don't overflow kernel stack!) */ if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE) bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE; bytes_left = bytecount; - src = (void *) IA32_LDT_OFFSET; + src = (void __user *) IA32_LDT_OFFSET; dst = ptr; while (bytes_left) { @@ -61,7 +60,7 @@ read_ldt (void *ptr, unsigned long bytecount) } static int -read_default_ldt (void * ptr, unsigned long bytecount) +read_default_ldt (void __user * ptr, unsigned long bytecount) { unsigned long size; int err; @@ -80,7 +79,7 @@ read_default_ldt (void * ptr, unsigned long bytecount) } static int -write_ldt (void * ptr, unsigned long bytecount, int oldmode) +write_ldt (void __user * ptr, unsigned long bytecount, int oldmode) { struct ia32_user_desc ldt_info; __u64 entry; @@ -120,7 +119,7 @@ write_ldt (void * ptr, unsigned long bytecount, int oldmode) * memory, but we still need to guard against out-of-memory, hence we must use * put_user(). */ - ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); + ret = __put_user(entry, (__u64 __user *) IA32_LDT_OFFSET + ldt_info.entry_number); ia32_load_segment_descriptors(current); return ret; } @@ -132,16 +131,16 @@ sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount) switch (func) { case 0: - ret = read_ldt(P(ptr), bytecount); + ret = read_ldt(compat_ptr(ptr), bytecount); break; case 1: - ret = write_ldt(P(ptr), bytecount, 1); + ret = write_ldt(compat_ptr(ptr), bytecount, 1); break; case 2: - ret = read_default_ldt(P(ptr), bytecount); + ret = read_default_ldt(compat_ptr(ptr), bytecount); break; case 0x11: - ret = write_ldt(P(ptr), bytecount, 0); + ret = write_ldt(compat_ptr(ptr), bytecount, 0); break; } return ret; diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index 793ec3f76..7f2fc2704 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -66,7 +66,7 @@ struct rt_sigframe_ia32 }; int -copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) +copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 __user *from) { unsigned long tmp; int err; @@ -78,10 +78,10 @@ copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); - if (from->si_code < 0) + if (to->si_code < 0) err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { - switch (from->si_code >> 16) { + switch (to->si_code >> 16) { case __SI_CHLD >> 16: err |= __get_user(to->si_utime, &from->si_utime); err |= __get_user(to->si_stime, &from->si_stime); @@ -92,7 +92,7 @@ copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) break; case __SI_FAULT >> 16: err |= __get_user(tmp, &from->si_addr); - to->si_addr = (void *) tmp; + to->si_addr = (void __user *) tmp; break; case __SI_POLL >> 16: err |= __get_user(to->si_band, &from->si_band); @@ -110,7 +110,7 @@ copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) } int -copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) +copy_siginfo_to_user32 (siginfo_t32 __user *to, siginfo_t *from) { unsigned int addr; int err; @@ -141,7 +141,8 @@ copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: - err |= __put_user((long)from->si_addr, &to->si_addr); + /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */ + err |= __put_user(from->_sifields._pad[0], &to->si_addr); break; case __SI_POLL >> 16: err |= __put_user(from->si_band, &to->si_band); @@ -202,7 +203,7 @@ copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) */ static int -save_ia32_fpstate_live (struct _fpstate_ia32 *save) +save_ia32_fpstate_live (struct _fpstate_ia32 __user *save) { struct task_struct *tsk = current; struct pt_regs *ptp; @@ -310,7 +311,7 @@ save_ia32_fpstate_live (struct _fpstate_ia32 *save) } static int -restore_ia32_fpstate_live (struct _fpstate_ia32 *save) +restore_ia32_fpstate_live (struct _fpstate_ia32 __user *save) { struct task_struct *tsk = current; struct pt_regs *ptp; @@ -339,37 +340,37 @@ restore_ia32_fpstate_live (struct _fpstate_ia32 *save) fir = ia64_getreg(_IA64_REG_AR_FIR); fdr = ia64_getreg(_IA64_REG_AR_FDR); - __get_user(mxcsr, (unsigned int *)&save->mxcsr); + __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); /* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */ - __get_user(lo, (unsigned int *)&save->cw); + __get_user(lo, (unsigned int __user *)&save->cw); num64 = mxcsr & 0xff10; num64 = (num64 << 32) | (lo & 0x1f3f); - fcr = (fcr & (~0xff1000001f3f)) | num64; + fcr = (fcr & (~0xff1000001f3fUL)) | num64; /* setting bits 0..31 with sw and tag and 32..37 from mxcsr */ - __get_user(lo, (unsigned int *)&save->sw); + __get_user(lo, (unsigned int __user *)&save->sw); /* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */ if ( !(lo & 0x7f) ) lo &= (~0x8080); - __get_user(hi, (unsigned int *)&save->tag); + __get_user(hi, (unsigned int __user *)&save->tag); num64 = mxcsr & 0x3f; num64 = (num64 << 16) | (hi & 0xffff); num64 = (num64 << 16) | (lo & 0xffff); - fsr = (fsr & (~0x3fffffffff)) | num64; + fsr = (fsr & (~0x3fffffffffUL)) | num64; /* setting bits 0..47 with cssel and ipoff */ - __get_user(lo, (unsigned int *)&save->ipoff); - __get_user(hi, (unsigned int *)&save->cssel); + __get_user(lo, (unsigned int __user *)&save->ipoff); + __get_user(hi, (unsigned int __user *)&save->cssel); num64 = hi & 0xffff; num64 = (num64 << 32) | lo; - fir = (fir & (~0xffffffffffff)) | num64; + fir = (fir & (~0xffffffffffffUL)) | num64; /* setting bits 0..47 with datasel and dataoff */ - __get_user(lo, (unsigned int *)&save->dataoff); - __get_user(hi, (unsigned int *)&save->datasel); + __get_user(lo, (unsigned int __user *)&save->dataoff); + __get_user(hi, (unsigned int __user *)&save->datasel); num64 = hi & 0xffff; num64 = (num64 << 32) | lo; - fdr = (fdr & (~0xffffffffffff)) | num64; + fdr = (fdr & (~0xffffffffffffUL)) | num64; ia64_setreg(_IA64_REG_AR_FSR, fsr); ia64_setreg(_IA64_REG_AR_FCR, fcr); @@ -452,8 +453,8 @@ sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int r sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler); } -asmlinkage long -ia32_rt_sigsuspend (compat_sigset_t *uset, unsigned int sigsetsize, struct sigscratch *scr) +long +__ia32_rt_sigsuspend (compat_sigset_t *sset, unsigned int sigsetsize, struct sigscratch *scr) { extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall); sigset_t oldset, set; @@ -461,10 +462,7 @@ ia32_rt_sigsuspend (compat_sigset_t *uset, unsigned int sigsetsize, struct sigsc scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ memset(&set, 0, sizeof(&set)); - if (sigsetsize > sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) + if (memcpy(&set.sig, &sset->sig, sigsetsize)) return -EFAULT; sigdelsetmask(&set, ~_BLOCKABLE); @@ -491,10 +489,24 @@ ia32_rt_sigsuspend (compat_sigset_t *uset, unsigned int sigsetsize, struct sigsc } } +asmlinkage long +ia32_rt_sigsuspend (compat_sigset_t __user *uset, unsigned int sigsetsize, struct sigscratch *scr) +{ + compat_sigset_t set; + + if (sigsetsize > sizeof(compat_sigset_t)) + return -EINVAL; + + if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) + return -EFAULT; + + return __ia32_rt_sigsuspend(&set, sigsetsize, scr); +} + asmlinkage long ia32_sigsuspend (unsigned int mask, struct sigscratch *scr) { - return ia32_rt_sigsuspend((compat_sigset_t *)&mask, sizeof(mask), scr); + return __ia32_rt_sigsuspend((compat_sigset_t *) &mask, sizeof(mask), scr); } asmlinkage long @@ -512,8 +524,8 @@ sys32_signal (int sig, unsigned int handler) } asmlinkage long -sys32_rt_sigaction (int sig, struct sigaction32 *act, - struct sigaction32 *oact, unsigned int sigsetsize) +sys32_rt_sigaction (int sig, struct sigaction32 __user *act, + struct sigaction32 __user *oact, unsigned int sigsetsize) { struct k_sigaction new_ka, old_ka; unsigned int handler, restorer; @@ -547,7 +559,8 @@ sys32_rt_sigaction (int sig, struct sigaction32 *act, asmlinkage long -sys32_rt_sigprocmask (int how, compat_sigset_t *set, compat_sigset_t *oset, unsigned int sigsetsize) +sys32_rt_sigprocmask (int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, + unsigned int sigsetsize) { mm_segment_t old_fs = get_fs(); sigset_t s; @@ -562,7 +575,9 @@ sys32_rt_sigprocmask (int how, compat_sigset_t *set, compat_sigset_t *oset, unsi return -EFAULT; } set_fs(KERNEL_DS); - ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s)); + ret = sys_rt_sigprocmask(how, + set ? (sigset_t __user *) &s : NULL, + oset ? (sigset_t __user *) &s : NULL, sizeof(s)); set_fs(old_fs); if (ret) return ret; @@ -574,10 +589,9 @@ sys32_rt_sigprocmask (int how, compat_sigset_t *set, compat_sigset_t *oset, unsi } asmlinkage long -sys32_rt_sigtimedwait (compat_sigset_t *uthese, siginfo_t32 *uinfo, - struct compat_timespec *uts, unsigned int sigsetsize) +sys32_rt_sigtimedwait (compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, + struct compat_timespec __user *uts, unsigned int sigsetsize) { - extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *); mm_segment_t old_fs = get_fs(); struct timespec t; siginfo_t info; @@ -589,8 +603,10 @@ sys32_rt_sigtimedwait (compat_sigset_t *uthese, siginfo_t32 *uinfo, if (uts && get_compat_timespec(&t, uts)) return -EFAULT; set_fs(KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL, - sigsetsize); + ret = sys_rt_sigtimedwait((sigset_t __user *) &s, + uinfo ? (siginfo_t __user *) &info : NULL, + uts ? (struct timespec __user *) &t : NULL, + sigsetsize); set_fs(old_fs); if (ret >= 0 && uinfo) { if (copy_siginfo_to_user32(uinfo, &info)) @@ -600,7 +616,7 @@ sys32_rt_sigtimedwait (compat_sigset_t *uthese, siginfo_t32 *uinfo, } asmlinkage long -sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo) +sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 __user *uinfo) { mm_segment_t old_fs = get_fs(); siginfo_t info; @@ -609,13 +625,13 @@ sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo) if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs(KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, &info); + ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); set_fs(old_fs); return ret; } asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; unsigned int handler, restorer; @@ -648,7 +664,7 @@ sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *o } static int -setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, +setup_sigcontext_ia32 (struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __user *fpstate, struct pt_regs *regs, unsigned long mask) { int err = 0; @@ -657,10 +673,10 @@ setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc))) return -EFAULT; - err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs); - err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs); - err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es); - err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); + err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int __user *)&sc->fs); + err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int __user *)&sc->gs); + err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int __user *)&sc->es); + err |= __put_user(regs->r16 & 0xffff, (unsigned int __user *)&sc->ds); err |= __put_user(regs->r15, &sc->edi); err |= __put_user(regs->r14, &sc->esi); err |= __put_user(regs->r13, &sc->ebp); @@ -674,14 +690,14 @@ setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate err |= __put_user(current->tss.error_code, &sc->err); #endif err |= __put_user(regs->cr_iip, &sc->eip); - err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); + err |= __put_user(regs->r17 & 0xffff, (unsigned int __user *)&sc->cs); /* * `eflags' is in an ar register for this context */ flag = ia64_getreg(_IA64_REG_AR_EFLAG); err |= __put_user((unsigned int)flag, &sc->eflags); err |= __put_user(regs->r12, &sc->esp_at_signal); - err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); + err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int __user *)&sc->ss); if ( save_ia32_fpstate_live(fpstate) < 0 ) err = -EFAULT; @@ -705,7 +721,7 @@ setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate } static int -restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) +restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 __user *sc, int *peax) { unsigned int err = 0; @@ -775,10 +791,10 @@ restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int * } { - struct _fpstate_ia32 *buf = NULL; + struct _fpstate_ia32 __user *buf = NULL; u32 fpstate_ptr; err |= get_user(fpstate_ptr, &(sc->fpstate)); - buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr; + buf = compat_ptr(fpstate_ptr); if (buf) { err |= restore_ia32_fpstate_live(buf); } @@ -808,7 +824,7 @@ restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int * /* * Determine which stack to use.. */ -static inline void * +static inline void __user * get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long esp; @@ -823,14 +839,14 @@ get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) } /* Legacy stack switching not supported */ - return (void *)((esp - frame_size) & -8ul); + return (void __user *)((esp - frame_size) & -8ul); } static int setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { struct exec_domain *ed = current_thread_info()->exec_domain; - struct sigframe_ia32 *frame; + struct sigframe_ia32 __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -853,14 +869,19 @@ setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs unsigned int restorer = IA32_SA_RESTORER(ka); err |= __put_user(restorer, &frame->pretcode); } else { - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is popl %eax ; movl $,%eax ; int $0x80 */ - err |= __put_user(0xb858, (short *)(frame->retcode+0)); - err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); - err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); - err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + /* Pointing to restorer in ia32 gate page */ + err |= __put_user(IA32_GATE_OFFSET, &frame->pretcode); } + /* This is popl %eax ; movl $,%eax ; int $0x80 + * and there for historical reasons only. + * See arch/i386/kernel/signal.c + */ + + err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_sigreturn, (int __user *)(frame->retcode+2)); + err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); + if (err) goto give_sigsegv; @@ -882,9 +903,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; } @@ -893,7 +912,8 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { struct exec_domain *ed = current_thread_info()->exec_domain; - struct rt_sigframe_ia32 *frame; + compat_uptr_t pinfo, puc; + struct rt_sigframe_ia32 __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -903,8 +923,11 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user((ed && ed->signal_invmap && sig < 32 ? ed->signal_invmap[sig] : sig), &frame->sig); - err |= __put_user((long)&frame->info, &frame->pinfo); - err |= __put_user((long)&frame->uc, &frame->puc); + + pinfo = (long __user) &frame->info; + puc = (long __user) &frame->uc; + err |= __put_user(pinfo, &frame->pinfo); + err |= __put_user(puc, &frame->puc); err |= copy_siginfo_to_user32(&frame->info, info); /* Create the ucontext. */ @@ -924,13 +947,19 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, unsigned int restorer = IA32_SA_RESTORER(ka); err |= __put_user(restorer, &frame->pretcode); } else { - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is movl $,%eax ; int $0x80 */ - err |= __put_user(0xb8, (char *)(frame->retcode+0)); - err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + /* Pointing to rt_restorer in ia32 gate page */ + err |= __put_user(IA32_GATE_OFFSET + 8, &frame->pretcode); } + /* This is movl $,%eax ; int $0x80 + * and there for historical reasons only. + * See arch/i386/kernel/signal.c + */ + + err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_rt_sigreturn, (int __user *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); + if (err) goto give_sigsegv; @@ -952,9 +981,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; } @@ -975,7 +1002,7 @@ sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int { struct pt_regs *regs = (struct pt_regs *) &stack; unsigned long esp = (unsigned int) regs->r12; - struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(esp - 8); + struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(esp - 8); sigset_t set; int eax; @@ -989,7 +1016,7 @@ sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); - current->blocked = (sigset_t) set; + current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); @@ -1008,9 +1035,8 @@ sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, { struct pt_regs *regs = (struct pt_regs *) &stack; unsigned long esp = (unsigned int) regs->r12; - struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(esp - 4); + struct rt_sigframe_ia32 __user *frame = (struct rt_sigframe_ia32 __user *)(esp - 4); sigset_t set; - stack_t st; int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -1027,11 +1053,9 @@ sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) goto badframe; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, esp); + do_sigaltstack((stack_t __user *) &frame->uc.uc_stack, NULL, esp); return eax; diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c index 4b43f1753..4f630043b 100644 --- a/arch/ia64/ia32/ia32_support.c +++ b/arch/ia64/ia32/ia32_support.c @@ -33,6 +33,7 @@ struct exec_domain ia32_exec_domain; struct page *ia32_shared_page[NR_CPUS]; unsigned long *ia32_boot_gdt; unsigned long *cpu_gdt_table[NR_CPUS]; +struct page *ia32_gate_page; static unsigned long load_desc (u16 selector) @@ -75,7 +76,7 @@ ia32_clone_tls (struct task_struct *child, struct pt_regs *childregs) struct ia32_user_desc info; int idx; - if (copy_from_user(&info, (void *)(childregs->r14 & 0xffffffff), sizeof(info))) + if (copy_from_user(&info, (void __user *)(childregs->r14 & 0xffffffff), sizeof(info))) return -EFAULT; if (LDT_empty(&info)) return -EINVAL; @@ -145,6 +146,9 @@ ia32_gdt_init (void) int cpu = smp_processor_id(); ia32_shared_page[cpu] = alloc_page(GFP_KERNEL); + if (!ia32_shared_page[cpu]) + panic("failed to allocate ia32_shared_page[%d]\n", cpu); + cpu_gdt_table[cpu] = page_address(ia32_shared_page[cpu]); /* Copy from the boot cpu's GDT */ @@ -155,23 +159,26 @@ ia32_gdt_init (void) /* * Setup IA32 GDT and TSS */ -void +static void ia32_boot_gdt_init (void) { unsigned long ldt_size; ia32_shared_page[0] = alloc_page(GFP_KERNEL); + if (!ia32_shared_page[0]) + panic("failed to allocate ia32_shared_page[0]\n"); + ia32_boot_gdt = page_address(ia32_shared_page[0]); cpu_gdt_table[0] = ia32_boot_gdt; /* CS descriptor in IA-32 (scrambled) format */ ia32_boot_gdt[__USER_CS >> 3] - = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT, 0xb, 1, 3, 1, 1, 1, 1); /* DS descriptor in IA-32 (scrambled) format */ ia32_boot_gdt[__USER_DS >> 3] - = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT, 0x3, 1, 3, 1, 1, 1, 1); ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); @@ -181,6 +188,27 @@ ia32_boot_gdt_init (void) 0x2, 0, 3, 1, 1, 1, 0); } +static void +ia32_gate_page_init(void) +{ + unsigned long *sr; + + ia32_gate_page = alloc_page(GFP_KERNEL); + sr = page_address(ia32_gate_page); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + *sr++ = 0xb858 | (__IA32_NR_sigreturn << 16) | (0x80cdUL << 48); + + /* This is movl $,%eax ; int $0x80 */ + *sr = 0xb8 | (__IA32_NR_rt_sigreturn << 8) | (0x80cdUL << 40); +} + +void +ia32_mem_init(void) +{ + ia32_boot_gdt_init(); + ia32_gate_page_init(); +} + /* * Handle bad IA32 interrupt via syscall */ @@ -195,7 +223,7 @@ ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */ siginfo.si_flags = 0; siginfo.si_isr = 0; - siginfo.si_addr = 0; + siginfo.si_addr = NULL; siginfo.si_imm = 0; siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); diff --git a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h index ba875e0bb..59c500b23 100644 --- a/arch/ia64/ia32/ia32priv.h +++ b/arch/ia64/ia32/ia32priv.h @@ -168,6 +168,9 @@ struct ia32_user_fxsr_struct { #define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) #define IA32_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32) +#define __IA32_NR_sigreturn 119 +#define __IA32_NR_rt_sigreturn 173 + struct sigaction32 { unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ unsigned int sa_flags; @@ -324,14 +327,16 @@ struct old_linux32_dirent { #define IA32_PAGE_OFFSET 0xc0000000 #define IA32_STACK_TOP IA32_PAGE_OFFSET +#define IA32_GATE_OFFSET IA32_PAGE_OFFSET +#define IA32_GATE_END IA32_PAGE_OFFSET + PAGE_SIZE /* * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can * access them. */ -#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET) -#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) -#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) +#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) +#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) +#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 3*PAGE_SIZE) #define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE @@ -356,7 +361,7 @@ void ia64_elf32_init(struct pt_regs *regs); /* This macro yields a string that ld.so will use to load implementation specific libraries for optimization. Not terribly relevant until we have real hardware to play with... */ -#define ELF_PLATFORM 0 +#define ELF_PLATFORM NULL #ifdef __KERNEL__ # define SET_PERSONALITY(EX,IBCS2) \ @@ -434,7 +439,7 @@ void ia64_elf32_init(struct pt_regs *regs); | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB) \ | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G)) -#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ +#define IA32_IOBASE 0x2000000000000000UL /* Virtual address for I/O space */ #define IA32_CR0 0x80000001 /* Enable PG and PE bits */ #define IA32_CR4 0x600 /* MMXEX and FXSR on */ @@ -551,8 +556,8 @@ struct user_regs_struct32 { }; /* Prototypes for use in elfcore32.h */ -extern int save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save); -extern int save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save); +extern int save_ia32_fpstate (struct task_struct *, struct ia32_user_i387_struct __user *); +extern int save_ia32_fpxstate (struct task_struct *, struct ia32_user_fxsr_struct __user *); #endif /* !CONFIG_IA32_SUPPORT */ diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index a97402c01..1b653dadb 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -70,10 +70,7 @@ # define DBG(fmt...) #endif -#define A(__x) ((unsigned long)(__x)) -#define AA(__x) ((unsigned long)(__x)) #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define OFFSET4K(a) ((a) & 0xfff) #define PAGE_START(addr) ((addr) & PAGE_MASK) @@ -82,9 +79,6 @@ #define high2lowuid(uid) ((uid) > 65535 ? 65534 : (uid)) #define high2lowgid(gid) ((gid) > 65535 ? 65534 : (gid)) -extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long, - unsigned long, unsigned long); - /* * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore * while doing so. @@ -93,7 +87,8 @@ extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsig static DECLARE_MUTEX(ia32_mmap_sem); asmlinkage long -sys32_execve (char *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, struct pt_regs *regs) +sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, + struct pt_regs *regs) { long error; char *filename; @@ -128,7 +123,7 @@ sys32_execve (char *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp return error; } -int cp_compat_stat(struct kstat *stat, struct compat_stat *ubuf) +int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) { int err; @@ -199,7 +194,7 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro /* Optimize the case where the old mmap and the new mmap are both anonymous */ if ((old_prot & PROT_WRITE) && (flags & MAP_ANONYMOUS) && !vma->vm_file) { - if (clear_user((void *) start, end - start)) { + if (clear_user((void __user *) start, end - start)) { ret = -EFAULT; goto out; } @@ -211,11 +206,11 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro return -ENOMEM; if (old_prot) - copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE); + copy_from_user(page, (void __user *) PAGE_START(start), PAGE_SIZE); down_write(¤t->mm->mmap_sem); { - ret = do_mmap(0, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE, + ret = do_mmap(NULL, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE, flags | MAP_FIXED | MAP_ANONYMOUS, 0); } up_write(¤t->mm->mmap_sem); @@ -226,9 +221,10 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro if (old_prot) { /* copy back the old page contents. */ if (offset_in_page(start)) - copy_to_user((void *) PAGE_START(start), page, offset_in_page(start)); + copy_to_user((void __user *) PAGE_START(start), page, + offset_in_page(start)); if (offset_in_page(end)) - copy_to_user((void *) end, page + offset_in_page(end), + copy_to_user((void __user *) end, page + offset_in_page(end), PAGE_SIZE - offset_in_page(end)); } @@ -236,7 +232,7 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro /* read the file contents */ inode = file->f_dentry->d_inode; if (!inode->i_fop || !file->f_op->read - || ((*file->f_op->read)(file, (char *) start, end - start, &off) < 0)) + || ((*file->f_op->read)(file, (char __user *) start, end - start, &off) < 0)) { ret = -EINVAL; goto out; @@ -266,9 +262,9 @@ ia32_init_pp_list(void) if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) return p; - p->pp_head = 0; + p->pp_head = NULL; p->ppl_rb = RB_ROOT; - p->pp_hint = 0; + p->pp_hint = NULL; atomic_set(&p->pp_count, 1); return p; } @@ -825,7 +821,7 @@ emulate_mmap (struct file *file, unsigned long start, unsigned long len, int pro if (!(flags & MAP_ANONYMOUS) && is_congruent) ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff); else - ret = do_mmap(0, pstart, pend - pstart, + ret = do_mmap(NULL, pstart, pend - pstart, prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE), flags | MAP_FIXED | MAP_ANONYMOUS, 0); } @@ -838,7 +834,8 @@ emulate_mmap (struct file *file, unsigned long start, unsigned long len, int pro /* read the file contents */ inode = file->f_dentry->d_inode; if (!inode->i_fop || !file->f_op->read - || ((*file->f_op->read)(file, (char *) pstart, pend - pstart, &poff) < 0)) + || ((*file->f_op->read)(file, (char __user *) pstart, pend - pstart, &poff) + < 0)) { sys_munmap(pstart, pend - pstart); return -EINVAL; @@ -927,7 +924,7 @@ struct mmap_arg_struct { }; asmlinkage long -sys32_mmap (struct mmap_arg_struct *arg) +sys32_mmap (struct mmap_arg_struct __user *arg) { struct mmap_arg_struct a; struct file *file = NULL; @@ -1140,7 +1137,7 @@ sys32_mremap (unsigned int addr, unsigned int old_len, unsigned int new_len, } asmlinkage long -sys32_pipe (int *fd) +sys32_pipe (int __user *fd) { int retval; int fds[2]; @@ -1155,14 +1152,14 @@ sys32_pipe (int *fd) } static inline long -get_tv32 (struct timeval *o, struct compat_timeval *i) +get_tv32 (struct timeval *o, struct compat_timeval __user *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); } static inline long -put_tv32 (struct compat_timeval *o, struct timeval *i) +put_tv32 (struct compat_timeval __user *o, struct timeval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec))); @@ -1192,7 +1189,7 @@ sys32_alarm (unsigned int seconds) extern struct timezone sys_tz; asmlinkage long -sys32_gettimeofday (struct compat_timeval *tv, struct timezone *tz) +sys32_gettimeofday (struct compat_timeval __user *tv, struct timezone __user *tz) { if (tv) { struct timeval ktv; @@ -1208,7 +1205,7 @@ sys32_gettimeofday (struct compat_timeval *tv, struct timezone *tz) } asmlinkage long -sys32_settimeofday (struct compat_timeval *tv, struct timezone *tz) +sys32_settimeofday (struct compat_timeval __user *tv, struct timezone __user *tz) { struct timeval ktv; struct timespec kts; @@ -1229,14 +1226,14 @@ sys32_settimeofday (struct compat_timeval *tv, struct timezone *tz) } struct getdents32_callback { - struct compat_dirent * current_dir; - struct compat_dirent * previous; + struct compat_dirent __user *current_dir; + struct compat_dirent __user *previous; int count; int error; }; struct readdir32_callback { - struct old_linux32_dirent * dirent; + struct old_linux32_dirent __user * dirent; int count; }; @@ -1244,9 +1241,9 @@ static int filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { - struct compat_dirent * dirent; + struct compat_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; - int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); + int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) @@ -1263,17 +1260,17 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, || copy_to_user(dirent->d_name, name, namlen) || put_user(0, dirent->d_name + namlen)) return -EFAULT; - dirent = (struct compat_dirent *) ((char *) dirent + reclen); + dirent = (struct compat_dirent __user *) ((char __user *) dirent + reclen); buf->current_dir = dirent; buf->count -= reclen; return 0; } asmlinkage long -sys32_getdents (unsigned int fd, struct compat_dirent *dirent, unsigned int count) +sys32_getdents (unsigned int fd, struct compat_dirent __user *dirent, unsigned int count) { struct file * file; - struct compat_dirent * lastdirent; + struct compat_dirent __user * lastdirent; struct getdents32_callback buf; int error; @@ -1310,7 +1307,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t unsigned int d_type) { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; - struct old_linux32_dirent * dirent; + struct old_linux32_dirent __user * dirent; if (buf->count) return -EINVAL; @@ -1326,7 +1323,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t } asmlinkage long -sys32_readdir (unsigned int fd, void *dirent, unsigned int count) +sys32_readdir (unsigned int fd, void __user *dirent, unsigned int count) { int error; struct file * file; @@ -1357,7 +1354,7 @@ struct sel_arg_struct { }; asmlinkage long -sys32_old_select (struct sel_arg_struct *arg) +sys32_old_select (struct sel_arg_struct __user *arg) { struct sel_arg_struct a; @@ -1434,7 +1431,7 @@ sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) * so we have to implement this system call here. */ asmlinkage long -sys32_time (int *tloc) +sys32_time (int __user *tloc) { int i; struct timeval tv; @@ -1564,8 +1561,8 @@ putreg (struct task_struct *child, int regno, unsigned int value) } static void -put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, - int tos) +put_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp, + struct switch_stack *swp, int tos) { struct _fpreg_ia32 *f; char buf[32]; @@ -1597,8 +1594,8 @@ put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switc } static void -get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, - int tos) +get_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp, + struct switch_stack *swp, int tos) { if ((regno += tos) >= 8) @@ -1627,7 +1624,7 @@ get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switc } int -save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) +save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1656,7 +1653,7 @@ save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) } static int -restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) +restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1666,15 +1663,15 @@ restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *sav if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); - __get_user(num32, (unsigned int *)&save->cwd); + __get_user(num32, (unsigned int __user *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); - __get_user(fsrlo, (unsigned int *)&save->swd); - __get_user(fsrhi, (unsigned int *)&save->twd); + __get_user(fsrlo, (unsigned int __user *)&save->swd); + __get_user(fsrhi, (unsigned int __user *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->fip); + __get_user(num32, (unsigned int __user *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->foo); + __get_user(num32, (unsigned int __user *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* @@ -1689,7 +1686,7 @@ restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *sav } int -save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) +save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1715,7 +1712,7 @@ save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + put_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos); mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f); __put_user(mxcsr & 0xffff, &save->mxcsr); @@ -1728,7 +1725,7 @@ save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) } static int -restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) +restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -1741,15 +1738,15 @@ restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *sa if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); - __get_user(num32, (unsigned int *)&save->cwd); + __get_user(num32, (unsigned int __user *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); - __get_user(fsrlo, (unsigned int *)&save->swd); - __get_user(fsrhi, (unsigned int *)&save->twd); + __get_user(fsrlo, (unsigned int __user *)&save->swd); + __get_user(fsrhi, (unsigned int __user *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->fip); + __get_user(num32, (unsigned int __user *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; - __get_user(num32, (unsigned int *)&save->foo); + __get_user(num32, (unsigned int __user *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* @@ -1759,13 +1756,13 @@ restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *sa ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + get_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos); - __get_user(mxcsr, (unsigned int *)&save->mxcsr); + __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); num64 = mxcsr & 0xff10; - tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32); + tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000UL)) | (num64<<32); num64 = mxcsr & 0x3f; - tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32); + tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000UL)) | (num64<<32); for (i = 0; i < 8; i++) { copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32)); @@ -1823,7 +1820,7 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(regs, child, addr, &value); if (ret == 0) - ret = put_user(value, (unsigned int *) A(data)); + ret = put_user(value, (unsigned int __user *) compat_ptr(data)); else ret = -EIO; goto out_tsk; @@ -1839,7 +1836,7 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, break; tmp = getreg(child, addr); - if (!put_user(tmp, (unsigned int *) A(data))) + if (!put_user(tmp, (unsigned int __user *) compat_ptr(data))) ret = 0; break; @@ -1853,24 +1850,24 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, break; case IA32_PTRACE_GETREGS: - if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) { + if (!access_ok(VERIFY_WRITE, compat_ptr(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { - put_user(getreg(child, i), (unsigned int *) A(data)); + put_user(getreg(child, i), (unsigned int __user *) compat_ptr(data)); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: - if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) { + if (!access_ok(VERIFY_READ, compat_ptr(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { - get_user(tmp, (unsigned int *) A(data)); + get_user(tmp, (unsigned int __user *) compat_ptr(data)); putreg(child, i, tmp); data += sizeof(int); } @@ -1878,19 +1875,23 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, break; case IA32_PTRACE_GETFPREGS: - ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data)); + ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct __user *) + compat_ptr(data)); break; case IA32_PTRACE_GETFPXREGS: - ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data)); + ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *) + compat_ptr(data)); break; case IA32_PTRACE_SETFPREGS: - ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data)); + ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct __user *) + compat_ptr(data)); break; case IA32_PTRACE_SETFPXREGS: - ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data)); + ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *) + compat_ptr(data)); break; case PTRACE_SYSCALL: /* continue, stop after next syscall */ @@ -1913,73 +1914,6 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, return ret; } -/* - * The IA64 maps 4 I/O ports for each 4K page - */ -#define IOLEN ((65536 / 4) * 4096) - -asmlinkage long -sys32_iopl (int level) -{ - extern unsigned long ia64_iobase; - int fd; - struct file * file; - unsigned int old; - unsigned long addr; - mm_segment_t old_fs = get_fs (); - - if (level != 3) - return(-EINVAL); - /* Trying to gain more privileges? */ - old = ia64_getreg(_IA64_REG_AR_EFLAG); - if ((unsigned int) level > ((old >> 12) & 3)) { - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - } - set_fs(KERNEL_DS); - fd = sys_open("/dev/mem", O_SYNC | O_RDWR, 0); - set_fs(old_fs); - if (fd < 0) - return fd; - file = fget(fd); - if (file == NULL) { - sys_close(fd); - return(-EFAULT); - } - - down_write(¤t->mm->mmap_sem); - addr = do_mmap_pgoff(file, IA32_IOBASE, - IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, - (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); - - if (addr >= 0) { - old = (old & ~0x3000) | (level << 12); - ia64_setreg(_IA64_REG_AR_EFLAG, old); - } - - fput(file); - sys_close(fd); - return 0; -} - -asmlinkage long -sys32_ioperm (unsigned int from, unsigned int num, int on) -{ - - /* - * Since IA64 doesn't have permission bits we'd have to go to - * a lot of trouble to simulate them in software. There's - * no point, only trusted programs can make this call so we'll - * just turn it into an iopl call and let the process have - * access to all I/O ports. - * - * XXX proper ioperm() support should be emulated by - * manipulating the page protections... - */ - return sys32_iopl(3); -} - typedef struct { unsigned int ss_sp; unsigned int ss_flags; @@ -1987,7 +1921,7 @@ typedef struct { } ia32_stack_t; asmlinkage long -sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, +sys32_sigaltstack (ia32_stack_t __user *uss32, ia32_stack_t __user *uoss32, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt = (struct pt_regs *) &stack; @@ -1999,9 +1933,9 @@ sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, if (uss32) { if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) return -EFAULT; - uss.ss_sp = (void *) (long) buf32.ss_sp; + uss.ss_sp = (void __user *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; - /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the + /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the check and set it to the user requested value later */ if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) { ret = -ENOMEM; @@ -2010,14 +1944,15 @@ sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, uss.ss_size = MINSIGSTKSZ; } set_fs(KERNEL_DS); - ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); - current->sas_ss_size = buf32.ss_size; + ret = do_sigaltstack(uss32 ? (stack_t __user *) &uss : NULL, + (stack_t __user *) &uoss, pt->r12); + current->sas_ss_size = buf32.ss_size; set_fs(old_fs); out: if (ret < 0) return(ret); if (uoss32) { - buf32.ss_sp = (long) uoss.ss_sp; + buf32.ss_sp = (long __user) uoss.ss_sp; buf32.ss_flags = uoss.ss_flags; buf32.ss_size = uoss.ss_size; if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t))) @@ -2056,14 +1991,14 @@ struct sysctl32 { }; asmlinkage long -sys32_sysctl (struct sysctl32 *args) +sys32_sysctl (struct sysctl32 __user *args) { #ifdef CONFIG_SYSCTL struct sysctl32 a32; mm_segment_t old_fs = get_fs (); - void *oldvalp, *newvalp; + void __user *oldvalp, *newvalp; size_t oldlen; - int *namep; + int __user *namep; long ret; if (copy_from_user(&a32, args, sizeof(a32))) @@ -2076,11 +2011,11 @@ sys32_sysctl (struct sysctl32 *args) * addresses, we KNOW that access_ok() will always succeed, so this is an * expensive NOP, but so what... */ - namep = (int *) A(a32.name); - oldvalp = (void *) A(a32.oldval); - newvalp = (void *) A(a32.newval); + namep = (int __user *) compat_ptr(a32.name); + oldvalp = compat_ptr(a32.oldval); + newvalp = compat_ptr(a32.newval); - if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp))) + if ((oldvalp && get_user(oldlen, (int __user *) compat_ptr(a32.oldlenp))) || !access_ok(VERIFY_WRITE, namep, 0) || !access_ok(VERIFY_WRITE, oldvalp, 0) || !access_ok(VERIFY_WRITE, newvalp, 0)) @@ -2088,11 +2023,12 @@ sys32_sysctl (struct sysctl32 *args) set_fs(KERNEL_DS); lock_kernel(); - ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen); + ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *) &oldlen, + newvalp, (size_t) a32.newlen); unlock_kernel(); set_fs(old_fs); - if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp))) + if (oldvalp && put_user (oldlen, (int __user *) compat_ptr(a32.oldlenp))) return -EFAULT; return ret; @@ -2102,7 +2038,7 @@ sys32_sysctl (struct sysctl32 *args) } asmlinkage long -sys32_newuname (struct new_utsname *name) +sys32_newuname (struct new_utsname __user *name) { int ret = sys_newuname(name); @@ -2113,14 +2049,14 @@ sys32_newuname (struct new_utsname *name) } asmlinkage long -sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid) +sys32_getresuid16 (u16 __user *ruid, u16 __user *euid, u16 __user *suid) { uid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getresuid(&a, &b, &c); + ret = sys_getresuid((uid_t __user *) &a, (uid_t __user *) &b, (uid_t __user *) &c); set_fs(old_fs); if (put_user(a, ruid) || put_user(b, euid) || put_user(c, suid)) @@ -2129,14 +2065,14 @@ sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid) } asmlinkage long -sys32_getresgid16 (u16 *rgid, u16 *egid, u16 *sgid) +sys32_getresgid16 (u16 __user *rgid, u16 __user *egid, u16 __user *sgid) { gid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getresgid(&a, &b, &c); + ret = sys_getresgid((gid_t __user *) &a, (gid_t __user *) &b, (gid_t __user *) &c); set_fs(old_fs); if (ret) @@ -2153,7 +2089,7 @@ sys32_lseek (unsigned int fd, int offset, unsigned int whence) } static int -groups16_to_user(short *grouplist, struct group_info *group_info) +groups16_to_user(short __user *grouplist, struct group_info *group_info) { int i; short group; @@ -2168,7 +2104,7 @@ groups16_to_user(short *grouplist, struct group_info *group_info) } static int -groups16_from_user(struct group_info *group_info, short *grouplist) +groups16_from_user(struct group_info *group_info, short __user *grouplist) { int i; short group; @@ -2183,7 +2119,7 @@ groups16_from_user(struct group_info *group_info, short *grouplist) } asmlinkage long -sys32_getgroups16 (int gidsetsize, short *grouplist) +sys32_getgroups16 (int gidsetsize, short __user *grouplist) { int i; @@ -2208,7 +2144,7 @@ out: } asmlinkage long -sys32_setgroups16 (int gidsetsize, short *grouplist) +sys32_setgroups16 (int gidsetsize, short __user *grouplist) { struct group_info *group_info; int retval; @@ -2236,7 +2172,7 @@ sys32_setgroups16 (int gidsetsize, short *grouplist) asmlinkage long sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi) { - return sys_truncate((const char *) A(path), ((unsigned long) len_hi << 32) | len_lo); + return sys_truncate(compat_ptr(path), ((unsigned long) len_hi << 32) | len_lo); } asmlinkage long @@ -2246,7 +2182,7 @@ sys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi) } static int -putstat64 (struct stat64 *ubuf, struct kstat *kbuf) +putstat64 (struct stat64 __user *ubuf, struct kstat *kbuf) { int err; u64 hdev; @@ -2255,8 +2191,8 @@ putstat64 (struct stat64 *ubuf, struct kstat *kbuf) return -EFAULT; hdev = huge_encode_dev(kbuf->dev); - err = __put_user(hdev, (u32*)&ubuf->st_dev); - err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_dev) + 1); + err = __put_user(hdev, (u32 __user*)&ubuf->st_dev); + err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_dev) + 1); err |= __put_user(kbuf->ino, &ubuf->__st_ino); err |= __put_user(kbuf->ino, &ubuf->st_ino_lo); err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi); @@ -2265,8 +2201,8 @@ putstat64 (struct stat64 *ubuf, struct kstat *kbuf) err |= __put_user(kbuf->uid, &ubuf->st_uid); err |= __put_user(kbuf->gid, &ubuf->st_gid); hdev = huge_encode_dev(kbuf->rdev); - err = __put_user(hdev, (u32*)&ubuf->st_rdev); - err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_rdev) + 1); + err = __put_user(hdev, (u32 __user*)&ubuf->st_rdev); + err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_rdev) + 1); err |= __put_user(kbuf->size, &ubuf->st_size_lo); err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi); err |= __put_user(kbuf->atime.tv_sec, &ubuf->st_atime); @@ -2281,7 +2217,7 @@ putstat64 (struct stat64 *ubuf, struct kstat *kbuf) } asmlinkage long -sys32_stat64 (char *filename, struct stat64 *statbuf) +sys32_stat64 (char __user *filename, struct stat64 __user *statbuf) { struct kstat s; long ret = vfs_stat(filename, &s); @@ -2291,7 +2227,7 @@ sys32_stat64 (char *filename, struct stat64 *statbuf) } asmlinkage long -sys32_lstat64 (char *filename, struct stat64 *statbuf) +sys32_lstat64 (char __user *filename, struct stat64 __user *statbuf) { struct kstat s; long ret = vfs_lstat(filename, &s); @@ -2301,7 +2237,7 @@ sys32_lstat64 (char *filename, struct stat64 *statbuf) } asmlinkage long -sys32_fstat64 (unsigned int fd, struct stat64 *statbuf) +sys32_fstat64 (unsigned int fd, struct stat64 __user *statbuf) { struct kstat s; long ret = vfs_fstat(fd, &s); @@ -2328,7 +2264,7 @@ struct sysinfo32 { }; asmlinkage long -sys32_sysinfo (struct sysinfo32 *info) +sys32_sysinfo (struct sysinfo32 __user *info) { struct sysinfo s; long ret, err; @@ -2336,7 +2272,7 @@ sys32_sysinfo (struct sysinfo32 *info) mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_sysinfo(&s); + ret = sys_sysinfo((struct sysinfo __user *) &s); set_fs(old_fs); /* Check to see if any memory value is too large for 32-bit and * scale down if needed. @@ -2379,14 +2315,14 @@ sys32_sysinfo (struct sysinfo32 *info) } asmlinkage long -sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec *interval) +sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval) { mm_segment_t old_fs = get_fs(); struct timespec t; long ret; set_fs(KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, &t); + ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t); set_fs(old_fs); if (put_compat_timespec(&t, interval)) return -EFAULT; @@ -2394,19 +2330,19 @@ sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec *interval) } asmlinkage long -sys32_pread (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) +sys32_pread (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi) { return sys_pread64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); } asmlinkage long -sys32_pwrite (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) +sys32_pwrite (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi) { return sys_pwrite64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); } asmlinkage long -sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count) +sys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count) { mm_segment_t old_fs = get_fs(); long ret; @@ -2416,7 +2352,7 @@ sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count) return -EFAULT; set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count); set_fs(old_fs); if (!ret && offset && put_user(of, offset)) @@ -2447,7 +2383,7 @@ sys32_brk (unsigned int brk) obrk = mm->brk; ret = sys_brk(brk); if (ret < obrk) - clear_user((void *) ret, PAGE_ALIGN(ret) - ret); + clear_user(compat_ptr(ret), PAGE_ALIGN(ret) - ret); return ret; } @@ -2455,7 +2391,7 @@ sys32_brk (unsigned int brk) * Exactly like fs/open.c:sys_open(), except that it doesn't set the O_LARGEFILE flag. */ asmlinkage long -sys32_open (const char * filename, int flags, int mode) +sys32_open (const char __user * filename, int flags, int mode) { char * tmp; int fd, error; @@ -2487,10 +2423,10 @@ struct epoll_event32 { u32 events; u32 data[2]; -}; +}; asmlinkage long -sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 *event) +sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 __user *event) { mm_segment_t old_fs = get_fs(); struct epoll_event event64; @@ -2508,14 +2444,14 @@ sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 *event) event64.data |= (u64)data_halfword << 32; set_fs(KERNEL_DS); - error = sys_epoll_ctl(epfd, op, fd, &event64); + error = sys_epoll_ctl(epfd, op, fd, (struct epoll_event __user *) &event64); set_fs(old_fs); return error; } asmlinkage long -sys32_epoll_wait(int epfd, struct epoll_event32 *events, int maxevents, +sys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents, int timeout) { struct epoll_event *events64 = NULL; @@ -2533,8 +2469,8 @@ sys32_epoll_wait(int epfd, struct epoll_event32 *events, int maxevents, maxevents * sizeof(struct epoll_event32)))) return error; - /* - * Allocate space for the intermediate copy. If the space needed + /* + * Allocate space for the intermediate copy. If the space needed * is large enough to cause kmalloc to fail, then try again with * __get_free_pages. */ @@ -2543,14 +2479,15 @@ sys32_epoll_wait(int epfd, struct epoll_event32 *events, int maxevents, if (events64 == NULL) { events64 = (struct epoll_event *) __get_free_pages(GFP_KERNEL, get_order(size)); - if (events64 == NULL) + if (events64 == NULL) return -ENOMEM; do_free_pages = 1; } /* Do the system call */ set_fs(KERNEL_DS); /* copy_to/from_user should work on kernel mem*/ - numevents = sys_epoll_wait(epfd, events64, maxevents, timeout); + numevents = sys_epoll_wait(epfd, (struct epoll_event __user *) events64, + maxevents, timeout); set_fs(old_fs); /* Don't modify userspace memory if we're returning an error */ @@ -2593,7 +2530,7 @@ get_free_idx (void) * Set a given TLS descriptor: */ asmlinkage int -sys32_set_thread_area (struct ia32_user_desc *u_info) +sys32_set_thread_area (struct ia32_user_desc __user *u_info) { struct thread_struct *t = ¤t->thread; struct ia32_user_desc info; @@ -2654,7 +2591,7 @@ sys32_set_thread_area (struct ia32_user_desc *u_info) #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) asmlinkage int -sys32_get_thread_area (struct ia32_user_desc *u_info) +sys32_get_thread_area (struct ia32_user_desc __user *u_info) { struct ia32_user_desc info; struct desc_struct *desc; @@ -2682,12 +2619,8 @@ sys32_get_thread_area (struct ia32_user_desc *u_info) return 0; } -extern asmlinkage long -sys_timer_create(clockid_t which_clock, struct sigevent *timer_event_spec, - timer_t * created_timer_id); - asmlinkage long -sys32_timer_create(u32 clock, struct sigevent32 *se32, timer_t *timer_id) +sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id) { struct sigevent se; mm_segment_t oldfs; @@ -2710,7 +2643,7 @@ sys32_timer_create(u32 clock, struct sigevent32 *se32, timer_t *timer_id) oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_timer_create(clock, &se, &t); + err = sys_timer_create(clock, (struct sigevent __user *) &se, (timer_t __user *) &t); set_fs(oldfs); if (!err) @@ -2728,6 +2661,32 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, advice); } +asmlinkage long sys32_waitid(int which, compat_pid_t pid, + siginfo_t32 __user *uinfo, int options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid) diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 7d1e2f3d4..265ae83da 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ @@ -17,29 +17,31 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o obj-$(CONFIG_IA64_CYCLONE) += cyclone.o +obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o +mca_recovery-y += mca_drv.o mca_drv_asm.o # The gate DSO image is built using a special linker script. targets += gate.so gate-syms.o -extra-y += gate.so gate-syms.o gate.lds.s gate.o +extra-y += gate.so gate-syms.o gate.lds gate.o # fp_emulate() expects f2-f5,f16-f31 to contain the user-level state. CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31 -AFLAGS_gate.lds.o += -P -C -U$(ARCH) +CPPFLAGS_gate.lds := -P -C -U$(ARCH) quiet_cmd_gate = GATE $@ cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@ GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 -$(obj)/gate.so: $(obj)/gate.lds.s $(obj)/gate.o FORCE +$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE $(call if_changed,gate) $(obj)/built-in.o: $(obj)/gate-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o GATECFLAGS_gate-syms.o = -r -$(obj)/gate-syms.o: $(src)/gate.lds.s $(obj)/gate.o FORCE +$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE $(call if_changed,gate) # gate-data.o contains the gate DSO image as data in section .data.gate. diff --git a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c index b70f6de25..2623df5e2 100644 --- a/arch/ia64/kernel/acpi-ext.c +++ b/arch/ia64/kernel/acpi-ext.c @@ -62,7 +62,7 @@ acpi_find_vendor_resource(acpi_handle obj, struct acpi_vendor_descriptor *id, struct acpi_vendor_info info; info.descriptor = id; - info.data = 0; + info.data = NULL; acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, &info); if (!info.data) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index cf61f3e2a..6e012ba55 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -61,10 +61,16 @@ void (*pm_idle) (void); EXPORT_SYMBOL(pm_idle); void (*pm_power_off) (void); +EXPORT_SYMBOL(pm_power_off); unsigned char acpi_kbd_controller_present = 1; unsigned char acpi_legacy_devices; +#define MAX_SAPICS 256 +u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = + { [0 ... MAX_SAPICS - 1] = -1 }; +EXPORT_SYMBOL(ia64_acpiid_to_sapicid); + const char * acpi_get_sysname (void) { @@ -172,8 +178,8 @@ acpi_parse_lapic_addr_ovr ( return -EINVAL; if (lapic->address) { - iounmap((void *) ipi_base_addr); - ipi_base_addr = (unsigned long) ioremap(lapic->address, 0); + iounmap(ipi_base_addr); + ipi_base_addr = ioremap(lapic->address, 0); } return 0; } @@ -193,6 +199,7 @@ acpi_parse_lsapic (acpi_table_entry_header *header, const unsigned long end) #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; #endif + ia64_acpiid_to_sapicid[lsapic->acpi_id] = (lsapic->id << 8) | lsapic->eid; ++available_cpus; } @@ -329,9 +336,9 @@ acpi_parse_madt (unsigned long phys_addr, unsigned long size) /* Get base address of IPI Message Block */ if (acpi_madt->lapic_address) - ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0); + ipi_base_addr = ioremap(acpi_madt->lapic_address, 0); - printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr); + printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr); acpi_madt_oem_check(acpi_madt->header.oem_id, acpi_madt->header.oem_table_id); @@ -430,8 +437,9 @@ acpi_numa_arch_fixup (void) { int i, j, node_from, node_to; - /* If there's no SRAT, fix the phys_id */ + /* If there's no SRAT, fix the phys_id and mark node 0 online */ if (srat_num_cpus == 0) { + node_set_online(0); node_cpuid[0].phys_id = hard_smp_processor_id(); return; } @@ -643,4 +651,71 @@ acpi_gsi_to_irq (u32 gsi, unsigned int *irq) return 0; } +#ifdef CONFIG_NUMA +acpi_status __init +acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + struct acpi_table_iosapic *iosapic; + unsigned int gsi_base; + int node; + + /* Only care about objects w/ a method that returns the MADT */ + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + return AE_OK; + + if (!buffer.length || !buffer.pointer) + return AE_OK; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(*iosapic)) { + acpi_os_free(buffer.pointer); + return AE_OK; + } + + iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer; + + if (iosapic->header.type != ACPI_MADT_IOSAPIC) { + acpi_os_free(buffer.pointer); + return AE_OK; + } + + gsi_base = iosapic->global_irq_base; + + acpi_os_free(buffer.pointer); + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + + /* + * OK, it's an IOSAPIC MADT entry, look for a _PXM method to tell + * us which node to associate this with. + */ + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer))) + return AE_OK; + + if (!buffer.length || !buffer.pointer) + return AE_OK; + + obj = buffer.pointer; + + if (obj->type != ACPI_TYPE_INTEGER || + obj->integer.value >= MAX_PXM_DOMAINS) { + acpi_os_free(buffer.pointer); + return AE_OK; + } + + node = pxm_to_nid_map[obj->integer.value]; + acpi_os_free(buffer.pointer); + + if (node >= MAX_NUMNODES || !node_online(node) || + cpus_empty(node_to_cpumask(node))) + return AE_OK; + + /* We know a gsi to node mapping! */ + map_iosapic_to_node(gsi_base, node); + return AE_OK; +} +#endif /* CONFIG_NUMA */ #endif /* CONFIG_ACPI_BOOT */ diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index f166571ec..b1ab994b2 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c @@ -34,6 +34,11 @@ void foo(void) BLANK(); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); + + BLANK(); + DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked)); DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); @@ -188,18 +193,10 @@ void foo(void) DEFINE(IA64_CLONE_VM, CLONE_VM); BLANK(); - /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ - DEFINE(IA64_CPUINFO_ITM_DELTA_OFFSET, offsetof (struct cpuinfo_ia64, itm_delta)); - DEFINE(IA64_CPUINFO_ITM_NEXT_OFFSET, offsetof (struct cpuinfo_ia64, itm_next)); DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); 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" @@ -207,5 +204,21 @@ void foo(void) BLANK(); DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof (struct ia64_mca_tlb_info)); + /* used by head.S */ + DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); + BLANK(); + /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ + DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr)); + DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source)); + DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift)); + DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc)); + DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset)); + DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle)); + DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter)); + DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter)); + DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU); + DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64); + DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32); + DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); } diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c index 19300e958..f8261d3a9 100644 --- a/arch/ia64/kernel/cyclone.c +++ b/arch/ia64/kernel/cyclone.c @@ -1,6 +1,8 @@ +#include #include #include #include +#include /* IBM Summit (EXA) Cyclone counter code*/ #define CYCLONE_CBAR_ADDR 0xFEB00CD0 @@ -15,62 +17,10 @@ void __init cyclone_setup(void) use_cyclone = 1; } -static u32* volatile cyclone_timer; /* Cyclone MPMC0 register */ -static u32 last_update_cyclone; - -static unsigned long offset_base; - -static unsigned long get_offset_cyclone(void) -{ - u32 now; - unsigned long offset; - - /* Read the cyclone timer */ - now = readl(cyclone_timer); - /* .. relative to previous update*/ - offset = now - last_update_cyclone; - - /* convert cyclone ticks to nanoseconds */ - offset = (offset*NSEC_PER_SEC)/CYCLONE_TIMER_FREQ; - - /* our adjusted time in nanoseconds */ - return offset_base + offset; -} - -static void update_cyclone(long delta_nsec) -{ - u32 now; - unsigned long offset; - - /* Read the cyclone timer */ - now = readl(cyclone_timer); - /* .. relative to previous update*/ - offset = now - last_update_cyclone; - - /* convert cyclone ticks to nanoseconds */ - offset = (offset*NSEC_PER_SEC)/CYCLONE_TIMER_FREQ; - - offset += offset_base; - - /* Be careful about signed/unsigned comparisons here: */ - if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) - offset_base = offset - delta_nsec; - else - offset_base = 0; - - last_update_cyclone = now; -} - -static void reset_cyclone(void) -{ - offset_base = 0; - last_update_cyclone = readl(cyclone_timer); -} struct time_interpolator cyclone_interpolator = { - .get_offset = get_offset_cyclone, - .update = update_cyclone, - .reset = reset_cyclone, + .source = TIME_SOURCE_MMIO32, + .shift = 32, .frequency = CYCLONE_TIMER_FREQ, .drift = -100, }; @@ -81,6 +31,7 @@ int __init init_cyclone_clock(void) u64 base; /* saved cyclone base address */ u64 offset; /* offset from pageaddr to cyclone_timer register */ int i; + u32* volatile cyclone_timer; /* Cyclone MPMC0 register */ if (!use_cyclone) return -ENODEV; @@ -148,7 +99,7 @@ int __init init_cyclone_clock(void) } } /* initialize last tick */ - last_update_cyclone = readl(cyclone_timer); + cyclone_interpolator.addr = cyclone_timer; register_time_interpolator(&cyclone_interpolator); return 0; diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index e1e7d91c9..7b23f4dfa 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -48,7 +48,7 @@ static efi_status_t \ prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \ { \ struct ia64_fpreg fr[6]; \ - efi_time_cap_t *atc = 0; \ + efi_time_cap_t *atc = NULL; \ efi_status_t ret; \ \ if (tc) \ @@ -91,7 +91,7 @@ static efi_status_t \ prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \ { \ struct ia64_fpreg fr[6]; \ - efi_time_t *atm = 0; \ + efi_time_t *atm = NULL; \ efi_status_t ret; \ \ if (tm) \ @@ -109,7 +109,7 @@ prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, \ unsigned long *data_size, void *data) \ { \ struct ia64_fpreg fr[6]; \ - u32 *aattr = 0; \ + u32 *aattr = NULL; \ efi_status_t ret; \ \ if (attr) \ @@ -172,7 +172,7 @@ prefix##_reset_system (int reset_type, efi_status_t status, \ unsigned long data_size, efi_char16_t *data) \ { \ struct ia64_fpreg fr[6]; \ - efi_char16_t *adata = 0; \ + efi_char16_t *adata = NULL; \ \ if (data) \ adata = adjust_arg(data); \ @@ -214,7 +214,7 @@ efi_gettimeofday (struct timespec *ts) efi_time_t tm; memset(ts, 0, sizeof(ts)); - if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS) + if ((*efi.get_time)(&tm, NULL) != EFI_SUCCESS) return; ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); @@ -357,8 +357,10 @@ efi_memmap_walk (efi_freemem_callback_t callback, void *arg) if (total_mem >= mem_limit) continue; total_mem += (md->num_pages << EFI_PAGE_SHIFT); - if (total_mem > mem_limit) + if (total_mem > mem_limit) { md->num_pages -= ((total_mem - mem_limit) >> EFI_PAGE_SHIFT); + max_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); + } if (md->num_pages == 0) continue; diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 52576c34c..1fe9575c7 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 = ®s - 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 = ®s - 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/fsys.S b/arch/ia64/kernel/fsys.S index 0f8e5b5fd..4895559ee 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -8,6 +8,8 @@ * 18-Feb-03 louisk Implement fsys_gettimeofday(). * 28-Feb-03 davidm Fixed several bugs in fsys_gettimeofday(). Tuned it some more, * probably broke it along the way... ;-) + * 13-Jul-04 clameter Implement fsys_clock_gettime and revise fsys_gettimeofday to make + * it capable of using memory based clocks without falling back to C code. */ #include @@ -144,195 +146,206 @@ ENTRY(fsys_set_tid_address) END(fsys_set_tid_address) /* - * Note 1: This routine uses floating-point registers, but only with registers that - * operate on integers. Because of that, we don't need to set ar.fpsr to the - * kernel default value. - * - * Note 2: For now, we will assume that all CPUs run at the same clock-frequency. - * If that wasn't the case, we would have to disable preemption (e.g., - * by disabling interrupts) between reading the ITC and reading - * local_cpu_data->nsec_per_cyc. - * - * Note 3: On platforms where the ITC-drift bit is set in the SAL feature vector, - * we ought to either skip the ITC-based interpolation or run an ntp-like - * daemon to keep the ITCs from drifting too far apart. + * Ensure that the time interpolator structure is compatible with the asm code */ +#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \ + || IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4 +#error fsys_gettimeofday incompatible with changes to struct time_interpolator +#endif +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_DIVIDE_BY_1000 0x4000 +#define CLOCK_ADD_MONOTONIC 0x8000 ENTRY(fsys_gettimeofday) .prologue .altrp b6 .body - add r9=TI_FLAGS+IA64_TASK_SIZE,r16 - addl r3=THIS_CPU(cpu_info),r0 - -#ifdef CONFIG_SMP - movl r10=__per_cpu_offset - movl r2=sal_platform_features - ;; - - ld8 r2=[r2] - movl r19=xtime // xtime is a timespec struct - - ld8 r10=[r10] // r10 <- __per_cpu_offset[0] - addl r21=THIS_CPU(cpu_info),r0 - ;; - add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id) - tbit.nz p8,p0 = r2, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT -(p8) br.spnt.many fsys_fallback_syscall -#else - ;; - mov r10=r3 - movl r19=xtime // xtime is a timespec struct -#endif - ld4 r9=[r9] - movl r17=xtime_lock - ;; - - // r32, r33 should contain the 2 args of gettimeofday - adds r21=IA64_CPUINFO_ITM_NEXT_OFFSET, r10 - mov r2=-1 - tnat.nz p6,p7=r32 // guard against NaT args - ;; - - adds r10=IA64_CPUINFO_ITM_DELTA_OFFSET, r10 -(p7) tnat.nz p6,p0=r33 -(p6) br.cond.spnt.few .fail_einval - - adds r8=IA64_CPUINFO_NSEC_PER_CYC_OFFSET, r3 - movl r24=2361183241434822607 // for division hack (only for / 1000) - ;; - - ldf8 f7=[r10] // f7 now contains itm_delta - setf.sig f11=r2 - adds r10=8, r32 - - adds r20=IA64_TIMESPEC_TV_NSEC_OFFSET, r19 // r20 = &xtime->tv_nsec - movl r26=jiffies - - setf.sig f9=r24 // f9 is used for division hack - movl r27=wall_jiffies - - and r9=TIF_ALLWORK_MASK,r9 - movl r25=last_nsec_offset - ;; - - /* - * Verify that we have permission to write to struct timeval. Note: - * Another thread might unmap the mapping before we actually get - * to store the result. That's OK as long as the stores are also - * protect by EX(). - */ -EX(.fail_efault, probe.w.fault r32, 3) // this must come _after_ NaT-check -EX(.fail_efault, probe.w.fault r10, 3) // this must come _after_ NaT-check - nop 0 - - ldf8 f10=[r8] // f10 <- local_cpu_data->nsec_per_cyc value - cmp.ne p8, p0=0, r9 -(p8) br.spnt.many fsys_fallback_syscall - ;; -.retry: // *** seq = read_seqbegin(&xtime_lock); *** - ld4.acq r23=[r17] // since &xtime_lock == &xtime_lock->sequence - ld8 r14=[r25] // r14 (old) = last_nsec_offset - - ld8 r28=[r26] // r28 = jiffies - ld8 r29=[r27] // r29 = wall_jiffies - ;; - - ldf8 f8=[r21] // f8 now contains itm_next - mov.m r31=ar.itc // put time stamp into r31 (ITC) == now - sub r28=r29, r28, 1 // r28 now contains "-(lost + 1)" - ;; - - ld8 r2=[r19] // r2 = sec = xtime.tv_sec - ld8 r29=[r20] // r29 = nsec = xtime.tv_nsec - tbit.nz p9, p10=r23, 0 // p9 <- is_odd(r23), p10 <- is_even(r23) - - setf.sig f6=r28 // f6 <- -(lost + 1) (6 cyc) - ;; - + mov r31 = r32 + tnat.nz p6,p0 = r33 // guard against NaT argument +(p6) br.cond.spnt.few .fail_einval + mov r30 = CLOCK_DIVIDE_BY_1000 + ;; +.gettime: + // Register map + // Incoming r31 = pointer to address where to place result + // r30 = flags determining how time is processed + // r2,r3 = temp r4-r7 preserved + // r8 = result nanoseconds + // r9 = result seconds + // r10 = temporary storage for clock difference + // r11 = preserved: saved ar.pfs + // r12 = preserved: memory stack + // r13 = preserved: thread pointer + // r14 = debug pointer / usable + // r15 = preserved: system call number + // r16 = preserved: current task pointer + // r17 = wall to monotonic use + // r18 = time_interpolator->offset + // r19 = address of wall_to_monotonic + // r20 = pointer to struct time_interpolator / pointer to time_interpolator->address + // r21 = shift factor + // r22 = address of time interpolator->last_counter + // r23 = address of time_interpolator->last_cycle + // r24 = adress of time_interpolator->offset + // r25 = last_cycle value + // r26 = last_counter value + // r27 = pointer to xtime + // r28 = sequence number at the beginning of critcal section + // r29 = address of seqlock + // r30 = time processing flags / memory address + // r31 = pointer to result + // Predicates + // p6,p7 short term use + // p8 = timesource ar.itc + // p9 = timesource mmio64 + // p10 = timesource mmio32 + // p11 = timesource not to be handled by asm code + // p12 = memory time source ( = p9 | p10) + // p13 = do cmpxchg with time_interpolator_last_cycle + // p14 = Divide by 1000 + // p15 = Add monotonic + // + // Note that instructions are optimized for McKinley. McKinley can process two + // bundles simultaneously and therefore we continuously try to feed the CPU + // two bundles and then a stop. + tnat.nz p6,p0 = r31 // branch deferred since it does not fit into bundle structure + mov pr = r30,0xc000 // Set predicates according to function + add r2 = TI_FLAGS+IA64_TASK_SIZE,r16 + movl r20 = time_interpolator + ;; + ld8 r20 = [r20] // get pointer to time_interpolator structure + movl r29 = xtime_lock + ld4 r2 = [r2] // process work pending flags + movl r27 = xtime + ;; // only one bundle here + ld8 r21 = [r20] // first quad with control information + and r2 = TIF_ALLWORK_MASK,r2 +(p6) br.cond.spnt.few .fail_einval // deferred branch + ;; + add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20 + extr r3 = r21,32,32 // time_interpolator->nsec_per_cyc + extr r8 = r21,0,16 // time_interpolator->source + nop.i 123 + cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled +(p6) br.cond.spnt.many fsys_fallback_syscall + ;; + cmp.eq p8,p12 = 0,r8 // Check for cpu timer + cmp.eq p9,p0 = 1,r8 // MMIO64 ? + extr r2 = r21,24,8 // time_interpolator->jitter + cmp.eq p10,p0 = 2,r8 // MMIO32 ? + cmp.ltu p11,p0 = 2,r8 // function or other clock +(p11) br.cond.spnt.many fsys_fallback_syscall + ;; + setf.sig f7 = r3 // Setup for scaling of counter +(p15) movl r19 = wall_to_monotonic +(p12) ld8 r30 = [r10] + cmp.ne p13,p0 = r2,r0 // need jitter compensation? + extr r21 = r21,16,8 // shift factor + ;; +.time_redo: + .pred.rel.mutex p8,p9,p10 + ld4.acq r28 = [r29] // xtime_lock.sequence. Must come first for locking purposes +(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!! + add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20 +(p9) ld8 r2 = [r30] // readq(ti->address). Could also have latency issues.. +(p10) ld4 r2 = [r30] // readw(ti->address) +(p13) add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20 + ;; // could be removed by moving the last add upward + ld8 r26 = [r22] // time_interpolator->last_counter +(p13) ld8 r25 = [r23] // time interpolator->last_cycle + add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20 +(p15) ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET + ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET + nop.i 123 + ;; + ld8 r18 = [r24] // time_interpolator->offset + ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET // xtime.tv_nsec +(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm) + ;; +(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared + sub r10 = r2,r26 // current_counter - last_counter + ;; +(p6) sub r10 = r25,r26 // time we got was less than last_cycle +(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg + ;; + setf.sig f8 = r10 + nop.i 123 + ;; +(p7) cmpxchg8.rel r3 = [r23],r2,ar.ccv +EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time + xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter) +(p15) add r9 = r9,r17 // Add wall to monotonic.secs to result secs + ;; +(p15) ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET +(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful redo + // simulate tbit.nz.or p7,p0 = r28,0 + and r28 = ~1,r28 // Make sequence even to force retry if odd + getf.sig r2 = f8 mf - xma.l f8=f6, f7, f8 // f8 (last_tick) <- -(lost + 1)*itm_delta + itm_next (5 cyc) - nop 0 - - setf.sig f12=r31 // f12 <- ITC (6 cyc) - // *** if (unlikely(read_seqretry(&xtime_lock, seq))) continue; *** - ld4 r24=[r17] // r24 = xtime_lock->sequence (re-read) - nop 0 - ;; - - xma.l f8=f11, f8, f12 // f8 (elapsed_cycles) <- (-1*last_tick + now) = (now - last_tick) - nop 0 - ;; - - getf.sig r18=f8 // r18 <- (now - last_tick) - xmpy.l f8=f8, f10 // f8 <- elapsed_cycles*nsec_per_cyc (5 cyc) - add r3=r29, r14 // r3 = (nsec + old) - ;; - - cmp.lt p7, p8=r18, r0 // if now < last_tick, set p7 = 1, p8 = 0 - getf.sig r18=f8 // r18 = elapsed_cycles*nsec_per_cyc (6 cyc) - nop 0 - ;; - -(p10) cmp.ne p9, p0=r23, r24 // if xtime_lock->sequence != seq, set p9 - shr.u r18=r18, IA64_NSEC_PER_CYC_SHIFT // r18 <- offset -(p9) br.spnt.many .retry - ;; - - mov ar.ccv=r14 // ar.ccv = old (1 cyc) - cmp.leu p7, p8=r18, r14 // if (offset <= old), set p7 = 1, p8 = 0 - ;; - -(p8) cmpxchg8.rel r24=[r25], r18, ar.ccv // compare-and-exchange (atomic!) -(p8) add r3=r29, r18 // r3 = (nsec + offset) - ;; - shr.u r3=r3, 3 // initiate dividing r3 by 1000 - ;; - setf.sig f8=r3 // (6 cyc) - mov r10=1000000 // r10 = 1000000 - ;; -(p8) cmp.ne.unc p9, p0=r24, r14 - xmpy.hu f6=f8, f9 // (5 cyc) -(p9) br.spnt.many .retry - ;; - - getf.sig r3=f6 // (6 cyc) - ;; - shr.u r3=r3, 4 // end of division, r3 is divided by 1000 (=usec) - ;; - -1: cmp.geu p7, p0=r3, r10 // while (usec >= 1000000) - ;; -(p7) sub r3=r3, r10 // usec -= 1000000 -(p7) adds r2=1, r2 // ++sec -(p7) br.spnt.many 1b - - // finally: r2 = sec, r3 = usec -EX(.fail_efault, st8 [r32]=r2) - adds r9=8, r32 - mov r8=r0 // success - ;; -EX(.fail_efault, st8 [r9]=r3) // store them in the timeval struct - mov r10=0 + add r8 = r8,r18 // Add time interpolator offset + ;; + ld4 r10 = [r29] // xtime_lock.sequence +(p15) add r8 = r8, r17 // Add monotonic.nsecs to nsecs + shr.u r2 = r2,r21 + ;; // overloaded 3 bundles! + // End critical section. + add r8 = r8,r2 // Add xtime.nsecs + cmp4.ne.or p7,p0 = r28,r10 +(p7) br.cond.dpnt.few .time_redo // sequence number changed ? + // Now r8=tv->tv_nsec and r9=tv->tv_sec + mov r10 = r0 + movl r2 = 1000000000 + add r23 = IA64_TIMESPEC_TV_NSEC_OFFSET, r31 +(p14) movl r3 = 2361183241434822607 // Prep for / 1000 hack + ;; +.time_normalize: + mov r21 = r8 + cmp.ge p6,p0 = r8,r2 +(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting some time + ;; +(p14) setf.sig f8 = r20 +(p6) sub r8 = r8,r2 +(p6) add r9 = 1,r9 // two nops before the branch. +(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod +(p6) br.cond.dpnt.few .time_normalize + ;; + // Divided by 8 though shift. Now divide by 125 + // The compiler was able to do that with a multiply + // and a shift and we do the same +EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles +(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it... + ;; + mov r8 = r0 +(p14) getf.sig r2 = f8 + ;; +(p14) shr.u r21 = r2, 4 + ;; +EX(.fail_efault, st8 [r31] = r9) +EX(.fail_efault, st8 [r23] = r21) FSYS_RETURN - /* - * Note: We are NOT clearing the scratch registers here. Since the only things - * in those registers are time-related variables and some addresses (which - * can be obtained from System.map), none of this should be security-sensitive - * and we should be fine. - */ - .fail_einval: - mov r8=EINVAL // r8 = EINVAL - mov r10=-1 // r10 = -1 + mov r8 = EINVAL + mov r10 = -1 FSYS_RETURN - .fail_efault: - mov r8=EFAULT // r8 = EFAULT - mov r10=-1 // r10 = -1 + mov r8 = EFAULT + mov r10 = -1 FSYS_RETURN END(fsys_gettimeofday) +ENTRY(fsys_clock_gettime) + .prologue + .altrp b6 + .body + cmp4.ltu p6, p0 = CLOCK_MONOTONIC, r32 + // Fallback if this is not CLOCK_REALTIME or CLOCK_MONOTONIC +(p6) br.spnt.few fsys_fallback_syscall + mov r31 = r33 + shl r30 = r32,15 + br.many .gettime +END(fsys_clock_gettime) + /* * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize). */ @@ -838,7 +851,7 @@ fsyscall_table: data8 0 // timer_getoverrun data8 0 // timer_delete data8 0 // clock_settime - data8 0 // clock_gettime + data8 fsys_clock_gettime // clock_gettime data8 0 // clock_getres // 1255 data8 0 // clock_nanosleep data8 0 // fstatfs64 diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 032defb0f..0e821d0c3 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -781,8 +781,7 @@ GLOBAL_ENTRY(ia64_switch_mode_virt) // going to virtual // - for code addresses, set upper bits of addr to KERNEL_START - // - for stack addresses, set upper 3 bits to 0xe.... Dont change any of the - // lower bits since we want it to stay identity mapped + // - for stack addresses, copy from input argument movl r18=KERNEL_START dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index f032ea1b3..51548a8c5 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -104,7 +104,7 @@ static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ static struct iosapic_intr_info { - char *addr; /* base address of IOSAPIC */ + char __iomem *addr; /* base address of IOSAPIC */ u32 low32; /* current value of low word of Redirection table entry */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ @@ -114,9 +114,12 @@ static struct iosapic_intr_info { } iosapic_intr_info[IA64_NUM_VECTORS]; static struct iosapic { - char *addr; /* base address of IOSAPIC */ + char __iomem *addr; /* base address of IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */ +#ifdef CONFIG_NUMA + unsigned short node; /* numa node association via pxm */ +#endif } iosapic_lists[NR_IOSAPICS]; static int num_iosapic; @@ -176,7 +179,7 @@ set_rte (unsigned int vector, unsigned int dest, int mask) { unsigned long pol, trigger, dmode, flags; u32 low32, high32; - char *addr; + char __iomem *addr; int rte_index; char redir; @@ -234,7 +237,7 @@ static void mask_irq (unsigned int irq) { unsigned long flags; - char *addr; + char __iomem *addr; u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); @@ -258,7 +261,7 @@ static void unmask_irq (unsigned int irq) { unsigned long flags; - char *addr; + char __iomem *addr; u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); @@ -284,7 +287,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) unsigned long flags; u32 high32, low32; int dest, rte_index; - char *addr; + char __iomem *addr; int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; ia64_vector vec; @@ -409,7 +412,7 @@ struct hw_interrupt_type irq_type_iosapic_edge = { }; unsigned int -iosapic_version (char *addr) +iosapic_version (char __iomem *addr) { /* * IOSAPIC Version Register return 32 bit structure like: @@ -454,7 +457,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, int rte_index; int index; unsigned long gsi_base; - char *iosapic_address; + void __iomem *iosapic_address; index = find_iosapic(gsi); if (index < 0) { @@ -488,7 +491,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, } static unsigned int -get_target_cpu (void) +get_target_cpu (unsigned int gsi, int vector) { #ifdef CONFIG_SMP static int cpu = -1; @@ -507,6 +510,34 @@ get_target_cpu (void) if (!cpu_online(smp_processor_id())) return hard_smp_processor_id(); +#ifdef CONFIG_NUMA + { + int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; + cpumask_t cpu_mask; + + iosapic_index = find_iosapic(gsi); + if (iosapic_index < 0 || + iosapic_lists[iosapic_index].node == MAX_NUMNODES) + goto skip_numa_setup; + + cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node); + + num_cpus = cpus_weight(cpu_mask); + + if (!num_cpus) + goto skip_numa_setup; + + /* Use vector assigment to distribute across cpus in node */ + cpu_index = vector % num_cpus; + + for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) + numa_cpu = next_cpu(numa_cpu, cpu_mask); + + if (numa_cpu != NR_CPUS) + return cpu_physical_id(numa_cpu); + } +skip_numa_setup: +#endif /* * Otherwise, round-robin interrupt vectors across all the * processors. (It'd be nice if we could be smarter in the @@ -550,7 +581,7 @@ iosapic_register_intr (unsigned int gsi, } vector = assign_irq_vector(AUTO_ASSIGN); - dest = get_target_cpu(); + dest = get_target_cpu(gsi, vector); register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); } @@ -665,7 +696,7 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) { int num_rte; unsigned int isa_irq, ver; - char *addr; + char __iomem *addr; addr = ioremap(phys_addr, 0); ver = iosapic_version(addr); @@ -680,6 +711,9 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) iosapic_lists[num_iosapic].addr = addr; iosapic_lists[num_iosapic].gsi_base = gsi_base; iosapic_lists[num_iosapic].num_rte = num_rte; +#ifdef CONFIG_NUMA + iosapic_lists[num_iosapic].node = MAX_NUMNODES; +#endif num_iosapic++; if ((gsi_base == 0) && pcat_compat) { @@ -692,3 +726,20 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); } } + +#ifdef CONFIG_NUMA +void __init +map_iosapic_to_node(unsigned int gsi_base, int node) +{ + int index; + + index = find_iosapic(gsi_base); + if (index < 0) { + printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", + __FUNCTION__, gsi_base); + return; + } + iosapic_lists[index].node = node; + return; +} +#endif diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 9ec161c63..f779d97a4 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -84,11 +84,13 @@ irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { } }; +#ifdef CONFIG_SMP /* * This is updated when the user sets irq affinity via /proc */ cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)]; +#endif #ifdef CONFIG_IA64_GENERIC irq_desc_t * __ia64_irq_desc (unsigned int irq) @@ -255,14 +257,16 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -962,7 +966,7 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, return len; } -static int irq_affinity_write_proc (struct file *file, const char *buffer, +static int irq_affinity_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned int irq = (unsigned long) data; @@ -1137,31 +1141,6 @@ void fixup_irqs(void) } #endif -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -1196,26 +1175,15 @@ static void register_irq_proc (unsigned int irq) #endif } -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); + root_irq_dir = proc_mkdir("irq", NULL); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index e853159b8..335d827ce 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -47,7 +47,8 @@ #define IRQ_DEBUG 0 /* default base addr of IPI table */ -unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR); +void __iomem *ipi_base_addr = ((void __iomem *) + (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR)); /* * Legacy IRQ to IA-64 vector translation table. @@ -254,7 +255,7 @@ init_IRQ (void) void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) { - unsigned long ipi_addr; + void __iomem *ipi_addr; unsigned long ipi_data; unsigned long phys_cpu_id; @@ -269,7 +270,7 @@ ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) */ ipi_data = (delivery_mode << 8) | (vector & 0xff); - ipi_addr = ipi_base_addr | (phys_cpu_id << 4) | ((redirect & 1) << 3); + ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3)); writeq(ipi_data, ipi_addr); } diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 9c5104cc5..aa76ea054 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -82,11 +82,6 @@ # define IA64_MCA_DEBUG(fmt...) #endif -typedef struct ia64_fptr { - unsigned long fp; - unsigned long gp; -} ia64_fptr_t; - /* Used by mca_asm.S */ ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; @@ -831,6 +826,31 @@ ia64_return_to_sal_check(int recover) } +/* Function pointer for extra MCA recovery */ +int (*ia64_mca_ucmc_extension) + (void*,ia64_mca_sal_to_os_state_t*,ia64_mca_os_to_sal_state_t*) + = NULL; + +int +ia64_reg_MCA_extension(void *fn) +{ + if (ia64_mca_ucmc_extension) + return 1; + + ia64_mca_ucmc_extension = fn; + return 0; +} + +void +ia64_unreg_MCA_extension(void) +{ + if (ia64_mca_ucmc_extension) + ia64_mca_ucmc_extension = NULL; +} + +EXPORT_SYMBOL(ia64_reg_MCA_extension); +EXPORT_SYMBOL(ia64_unreg_MCA_extension); + /* * ia64_mca_ucmc_handler * @@ -852,11 +872,20 @@ ia64_mca_ucmc_handler(void) { pal_processor_state_info_t *psp = (pal_processor_state_info_t *) &ia64_sal_to_os_handoff_state.proc_state_param; - int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc); + int recover; /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); + /* TLB error is only exist in this SAL error record */ + recover = (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc)) + /* other error recovery */ + || (ia64_mca_ucmc_extension + && ia64_mca_ucmc_extension( + IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA), + &ia64_sal_to_os_handoff_state, + &ia64_os_to_sal_handoff_state)); + /* * Wakeup all the processors which are spinning in the rendezvous * loop. diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c new file mode 100644 index 000000000..90ed84b72 --- /dev/null +++ b/arch/ia64/kernel/mca_drv.c @@ -0,0 +1,639 @@ +/* + * File: mca_drv.c + * Purpose: Generic MCA handling layer + * + * Copyright (C) 2004 FUJITSU LIMITED + * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mca_drv.h" + +/* max size of SAL error record (default) */ +static int sal_rec_max = 10000; + +/* from mca.c */ +static ia64_mca_sal_to_os_state_t *sal_to_os_handoff_state; +static ia64_mca_os_to_sal_state_t *os_to_sal_handoff_state; + +/* from mca_drv_asm.S */ +extern void *mca_handler_bhhook(void); + +static spinlock_t mca_bh_lock = SPIN_LOCK_UNLOCKED; + +typedef enum { + MCA_IS_LOCAL = 0, + MCA_IS_GLOBAL = 1 +} mca_type_t; + +#define MAX_PAGE_ISOLATE 32 + +static struct page *page_isolate[MAX_PAGE_ISOLATE]; +static int num_page_isolate = 0; + +typedef enum { + ISOLATE_NG = 0, + ISOLATE_OK = 1 +} isolate_status_t; + +/* + * This pool keeps pointers to the section part of SAL error record + */ +static struct { + slidx_list_t *buffer; /* section pointer list pool */ + int cur_idx; /* Current index of section pointer list pool */ + int max_idx; /* Maximum index of section pointer list pool */ +} slidx_pool; + +/** + * mca_page_isolate - isolate a poisoned page in order not to use it later + * @paddr: poisoned memory location + * + * Return value: + * ISOLATE_OK / ISOLATE_NG + */ + +static isolate_status_t +mca_page_isolate(unsigned long paddr) +{ + int i; + struct page *p; + + /* whether physical address is valid or not */ + if ( !ia64_phys_addr_valid(paddr) ) + return ISOLATE_NG; + + /* convert physical address to physical page number */ + p = pfn_to_page(paddr>>PAGE_SHIFT); + + /* check whether a page number have been already registered or not */ + for( i = 0; i < num_page_isolate; i++ ) + if( page_isolate[i] == p ) + return ISOLATE_OK; /* already listed */ + + /* limitation check */ + if( num_page_isolate == MAX_PAGE_ISOLATE ) + return ISOLATE_NG; + + /* kick pages having attribute 'SLAB' or 'Reserved' */ + if( PageSlab(p) || PageReserved(p) ) + return ISOLATE_NG; + + /* add attribute 'Reserved' and register the page */ + SetPageReserved(p); + page_isolate[num_page_isolate++] = p; + + return ISOLATE_OK; +} + +/** + * mca_hanlder_bh - Kill the process which occurred memory read error + * @paddr: poisoned address received from MCA Handler + */ + +void +mca_handler_bh(unsigned long paddr) +{ + printk(KERN_DEBUG "OS_MCA: process [pid: %d](%s) encounters MCA.\n", + current->pid, current->comm); + + spin_lock(&mca_bh_lock); + if (mca_page_isolate(paddr) == ISOLATE_OK) { + printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr); + } else { + printk(KERN_DEBUG "Page isolation: ( %lx ) failure.\n", paddr); + } + spin_unlock(&mca_bh_lock); + + /* This process is about to be killed itself */ + force_sig(SIGKILL, current); + schedule(); +} + +/** + * mca_make_peidx - Make index of processor error section + * @slpi: pointer to record of processor error section + * @peidx: pointer to index of processor error section + */ + +static void +mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx) +{ + /* + * calculate the start address of + * "struct cpuid_info" and "sal_processor_static_info_t". + */ + u64 total_check_num = slpi->valid.num_cache_check + + slpi->valid.num_tlb_check + + slpi->valid.num_bus_check + + slpi->valid.num_reg_file_check + + slpi->valid.num_ms_check; + u64 head_size = sizeof(sal_log_mod_error_info_t) * total_check_num + + sizeof(sal_log_processor_info_t); + u64 mid_size = slpi->valid.cpuid_info * sizeof(struct sal_cpuid_info); + + peidx_head(peidx) = slpi; + peidx_mid(peidx) = (struct sal_cpuid_info *) + (slpi->valid.cpuid_info ? ((char*)slpi + head_size) : NULL); + peidx_bottom(peidx) = (sal_processor_static_info_t *) + (slpi->valid.psi_static_struct ? + ((char*)slpi + head_size + mid_size) : NULL); +} + +/** + * mca_make_slidx - Make index of SAL error record + * @buffer: pointer to SAL error record + * @slidx: pointer to index of SAL error record + * + * Return value: + * 1 if record has platform error / 0 if not + */ +#define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \ + { slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \ + hl->hdr = ptr; \ + list_add(&hl->list, &(sect)); \ + slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; } + +static int +mca_make_slidx(void *buffer, slidx_table_t *slidx) +{ + int platform_err = 0; + int record_len = ((sal_log_record_header_t*)buffer)->len; + u32 ercd_pos; + int sects; + sal_log_section_hdr_t *sp; + + /* + * Initialize index referring current record + */ + INIT_LIST_HEAD(&(slidx->proc_err)); + INIT_LIST_HEAD(&(slidx->mem_dev_err)); + INIT_LIST_HEAD(&(slidx->sel_dev_err)); + INIT_LIST_HEAD(&(slidx->pci_bus_err)); + INIT_LIST_HEAD(&(slidx->smbios_dev_err)); + INIT_LIST_HEAD(&(slidx->pci_comp_err)); + INIT_LIST_HEAD(&(slidx->plat_specific_err)); + INIT_LIST_HEAD(&(slidx->host_ctlr_err)); + INIT_LIST_HEAD(&(slidx->plat_bus_err)); + INIT_LIST_HEAD(&(slidx->unsupported)); + + /* + * Extract a Record Header + */ + slidx->header = buffer; + + /* + * Extract each section records + * (arranged from "int ia64_log_platform_info_print()") + */ + for (ercd_pos = sizeof(sal_log_record_header_t), sects = 0; + ercd_pos < record_len; ercd_pos += sp->len, sects++) { + sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos); + if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) { + LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp); + } else if (!efi_guidcmp(sp->guid, SAL_PLAT_BUS_ERR_SECT_GUID)) { + platform_err = 1; + LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp); + } else { + LOG_INDEX_ADD_SECT_PTR(slidx->unsupported, sp); + } + } + slidx->n_sections = sects; + + return platform_err; +} + +/** + * init_record_index_pools - Initialize pool of lists for SAL record index + * + * Return value: + * 0 on Success / -ENOMEM on Failure + */ +static int +init_record_index_pools(void) +{ + int i; + int rec_max_size; /* Maximum size of SAL error records */ + int sect_min_size; /* Minimum size of SAL error sections */ + /* minimum size table of each section */ + static int sal_log_sect_min_sizes[] = { + sizeof(sal_log_processor_info_t) + sizeof(sal_processor_static_info_t), + sizeof(sal_log_mem_dev_err_info_t), + sizeof(sal_log_sel_dev_err_info_t), + sizeof(sal_log_pci_bus_err_info_t), + sizeof(sal_log_smbios_dev_err_info_t), + sizeof(sal_log_pci_comp_err_info_t), + sizeof(sal_log_plat_specific_err_info_t), + sizeof(sal_log_host_ctlr_err_info_t), + sizeof(sal_log_plat_bus_err_info_t), + }; + + /* + * MCA handler cannot allocate new memory on flight, + * so we preallocate enough memory to handle a SAL record. + * + * Initialize a handling set of slidx_pool: + * 1. Pick up the max size of SAL error records + * 2. Pick up the min size of SAL error sections + * 3. Allocate the pool as enough to 2 SAL records + * (now we can estimate the maxinum of section in a record.) + */ + + /* - 1 - */ + rec_max_size = sal_rec_max; + + /* - 2 - */ + sect_min_size = sal_log_sect_min_sizes[0]; + for (i = 1; i < sizeof sal_log_sect_min_sizes/sizeof(size_t); i++) + if (sect_min_size > sal_log_sect_min_sizes[i]) + sect_min_size = sal_log_sect_min_sizes[i]; + + /* - 3 - */ + slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1; + slidx_pool.buffer = (slidx_list_t *) kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL); + + return slidx_pool.buffer ? 0 : -ENOMEM; +} + + +/***************************************************************************** + * Recovery functions * + *****************************************************************************/ + +/** + * is_mca_global - Check whether this MCA is global or not + * @peidx: pointer of index of processor error section + * @pbci: pointer to pal_bus_check_info_t + * + * Return value: + * MCA_IS_LOCAL / MCA_IS_GLOBAL + */ + +static mca_type_t +is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + + /* + * PAL can request a rendezvous, if the MCA has a global scope. + * If "rz_always" flag is set, SAL requests MCA rendezvous + * in spite of global MCA. + * Therefore it is local MCA when rendezvous has not been requested. + * Failed to rendezvous, the system must be down. + */ + switch (sal_to_os_handoff_state->imsto_rendez_state) { + case -1: /* SAL rendezvous unsuccessful */ + return MCA_IS_GLOBAL; + case 0: /* SAL rendezvous not required */ + return MCA_IS_LOCAL; + case 1: /* SAL rendezvous successful int */ + case 2: /* SAL rendezvous successful int with init */ + default: + break; + } + + /* + * If One or more Cache/TLB/Reg_File/Uarch_Check is here, + * it would be a local MCA. (i.e. processor internal error) + */ + if (psp->tc || psp->cc || psp->rc || psp->uc) + return MCA_IS_LOCAL; + + /* + * Bus_Check structure with Bus_Check.ib (internal bus error) flag set + * would be a global MCA. (e.g. a system bus address parity error) + */ + if (!pbci || pbci->ib) + return MCA_IS_GLOBAL; + + /* + * Bus_Check structure with Bus_Check.eb (external bus error) flag set + * could be either a local MCA or a global MCA. + * + * Referring Bus_Check.bsi: + * 0: Unknown/unclassified + * 1: BERR# + * 2: BINIT# + * 3: Hard Fail + * (FIXME: Are these SGI specific or generic bsi values?) + */ + if (pbci->eb) + switch (pbci->bsi) { + case 0: + /* e.g. a load from poisoned memory */ + return MCA_IS_LOCAL; + case 1: + case 2: + case 3: + return MCA_IS_GLOBAL; + } + + return MCA_IS_GLOBAL; +} + +/** + * recover_from_read_error - Try to recover the errors which type are "read"s. + * @slidx: pointer of index of SAL error record + * @peidx: pointer of index of processor error section + * @pbci: pointer of pal_bus_check_info + * + * Return value: + * 1 on Success / 0 on Failure + */ + +static int +recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + sal_log_mod_error_info_t *smei; + pal_min_state_area_t *pmsa; + struct ia64_psr *psr1, *psr2; + ia64_fptr_t *mca_hdlr_bh = (ia64_fptr_t*)mca_handler_bhhook; + + /* Is target address valid? */ + if (!pbci->tv) + return 0; + + /* + * cpu read or memory-mapped io read + * + * offending process affected process OS MCA do + * kernel mode kernel mode down system + * kernel mode user mode kill the process + * user mode kernel mode down system (*) + * user mode user mode kill the process + * + * (*) You could terminate offending user-mode process + * if (pbci->pv && pbci->pl != 0) *and* if you sure + * the process not have any locks of kernel. + */ + + psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr); + + /* + * Check the privilege level of interrupted context. + * If it is user-mode, then terminate affected process. + */ + if (psr1->cpl != 0) { + smei = peidx_bus_check(peidx, 0); + if (smei->valid.target_identifier) { + /* + * setup for resume to bottom half of MCA, + * "mca_handler_bhhook" + */ + pmsa = (pal_min_state_area_t *)(sal_to_os_handoff_state->pal_min_state | (6ul<<61)); + /* pass to bhhook as 1st argument (gr8) */ + pmsa->pmsa_gr[8-1] = smei->target_identifier; + /* set interrupted return address (but no use) */ + pmsa->pmsa_br0 = pmsa->pmsa_iip; + /* change resume address to bottom half */ + pmsa->pmsa_iip = mca_hdlr_bh->fp; + pmsa->pmsa_gr[1-1] = mca_hdlr_bh->gp; + /* set cpl with kernel mode */ + psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr; + psr2->cpl = 0; + psr2->ri = 0; + + return 1; + } + + } + + return 0; +} + +/** + * recover_from_platform_error - Recover from platform error. + * @slidx: pointer of index of SAL error record + * @peidx: pointer of index of processor error section + * @pbci: pointer of pal_bus_check_info + * + * Return value: + * 1 on Success / 0 on Failure + */ + +static int +recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + int status = 0; + pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + + if (psp->bc && pbci->eb && pbci->bsi == 0) { + switch(pbci->type) { + case 1: /* partial read */ + case 3: /* full line(cpu) read */ + case 9: /* I/O space read */ + status = recover_from_read_error(slidx, peidx, pbci); + break; + case 0: /* unknown */ + case 2: /* partial write */ + case 4: /* full line write */ + case 5: /* implicit or explicit write-back operation */ + case 6: /* snoop probe */ + case 7: /* incoming or outgoing ptc.g */ + case 8: /* write coalescing transactions */ + case 10: /* I/O space write */ + case 11: /* inter-processor interrupt message(IPI) */ + case 12: /* interrupt acknowledge or external task priority cycle */ + default: + break; + } + } + + return status; +} + +/** + * recover_from_processor_error + * @platform: whether there are some platform error section or not + * @slidx: pointer of index of SAL error record + * @peidx: pointer of index of processor error section + * @pbci: pointer of pal_bus_check_info + * + * Return value: + * 1 on Success / 0 on Failure + */ +/* + * Later we try to recover when below all conditions are satisfied. + * 1. Only one processor error section is exist. + * 2. BUS_CHECK is exist and the others are not exist.(Except TLB_CHECK) + * 3. The entry of BUS_CHECK_INFO is 1. + * 4. "External bus error" flag is set and the others are not set. + */ + +static int +recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +{ + pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + + /* + * We cannot recover errors with other than bus_check. + */ + if (psp->cc || psp->rc || psp->uc) + return 0; + + /* + * If there is no bus error, record is weird but we need not to recover. + */ + if (psp->bc == 0 || pbci == NULL) + return 1; + + /* + * Sorry, we cannot handle so many. + */ + if (peidx_bus_check_num(peidx) > 1) + return 0; + /* + * Well, here is only one bus error. + */ + if (pbci->ib || pbci->cc) + return 0; + if (pbci->eb && pbci->bsi > 0) + return 0; + if (psp->ci == 0) + return 0; + + /* + * This is a local MCA and estimated as recoverble external bus error. + * (e.g. a load from poisoned memory) + * This means "there are some platform errors". + */ + if (platform) + return recover_from_platform_error(slidx, peidx, pbci); + /* + * On account of strange SAL error record, we cannot recover. + */ + return 0; +} + +/** + * mca_try_to_recover - Try to recover from MCA + * @rec: pointer to a SAL error record + * + * Return value: + * 1 on Success / 0 on Failure + */ + +static int +mca_try_to_recover(void *rec, + ia64_mca_sal_to_os_state_t *sal_to_os_state, + ia64_mca_os_to_sal_state_t *os_to_sal_state) +{ + int platform_err; + int n_proc_err; + slidx_table_t slidx; + peidx_table_t peidx; + pal_bus_check_info_t pbci; + + /* handoff state from/to mca.c */ + sal_to_os_handoff_state = sal_to_os_state; + os_to_sal_handoff_state = os_to_sal_state; + + /* Make index of SAL error record */ + platform_err = mca_make_slidx(rec, &slidx); + + /* Count processor error sections */ + n_proc_err = slidx_count(&slidx, proc_err); + + /* Now, OS can recover when there is one processor error section */ + if (n_proc_err > 1) + return 0; + else if (n_proc_err == 0) { + /* Weird SAL record ... We need not to recover */ + + return 1; + } + + /* Make index of processor error section */ + mca_make_peidx((sal_log_processor_info_t*)slidx_first_entry(&slidx.proc_err)->hdr, &peidx); + + /* Extract Processor BUS_CHECK[0] */ + *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0); + + /* Check whether MCA is global or not */ + if (is_mca_global(&peidx, &pbci)) + return 0; + + /* Try to recover a processor error */ + return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci); +} + +/* + * ============================================================================= + */ + +int __init mca_external_handler_init(void) +{ + if (init_record_index_pools()) + return -ENOMEM; + + /* register external mca handlers */ + if (ia64_reg_MCA_extension(mca_try_to_recover)){ + printk(KERN_ERR "ia64_reg_MCA_extension failed.\n"); + kfree(slidx_pool.buffer); + return -EFAULT; + } + return 0; +} + +void __exit mca_external_handler_exit(void) +{ + /* unregister external mca handlers */ + ia64_unreg_MCA_extension(); + kfree(slidx_pool.buffer); +} + +module_init(mca_external_handler_init); +module_exit(mca_external_handler_exit); + +module_param(sal_rec_max, int, 0644); +MODULE_PARM_DESC(sal_rec_max, "Max size of SAL error record"); + +MODULE_DESCRIPTION("ia64 platform dependent mca handler driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h new file mode 100644 index 000000000..0227b761f --- /dev/null +++ b/arch/ia64/kernel/mca_drv.h @@ -0,0 +1,113 @@ +/* + * File: mca_drv.h + * Purpose: Define helpers for Generic MCA handling + * + * Copyright (C) 2004 FUJITSU LIMITED + * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + */ +/* + * Processor error section: + * + * +-sal_log_processor_info_t *info-------------+ + * | sal_log_section_hdr_t header; | + * | ... | + * | sal_log_mod_error_info_t info[0]; | + * +-+----------------+-------------------------+ + * | CACHE_CHECK | ^ num_cache_check v + * +----------------+ + * | TLB_CHECK | ^ num_tlb_check v + * +----------------+ + * | BUS_CHECK | ^ num_bus_check v + * +----------------+ + * | REG_FILE_CHECK | ^ num_reg_file_check v + * +----------------+ + * | MS_CHECK | ^ num_ms_check v + * +-struct cpuid_info *id----------------------+ + * | regs[5]; | + * | reserved; | + * +-sal_processor_static_info_t *regs----------+ + * | valid; | + * | ... | + * | fr[128]; | + * +--------------------------------------------+ + */ + +/* peidx: index of processor error section */ +typedef struct peidx_table { + sal_log_processor_info_t *info; + struct sal_cpuid_info *id; + sal_processor_static_info_t *regs; +} peidx_table_t; + +#define peidx_head(p) (((p)->info)) +#define peidx_mid(p) (((p)->id)) +#define peidx_bottom(p) (((p)->regs)) + +#define peidx_psp(p) (&(peidx_head(p)->proc_state_parameter)) +#define peidx_field_valid(p) (&(peidx_head(p)->valid)) +#define peidx_minstate_area(p) (&(peidx_bottom(p)->min_state_area)) + +#define peidx_cache_check_num(p) (peidx_head(p)->valid.num_cache_check) +#define peidx_tlb_check_num(p) (peidx_head(p)->valid.num_tlb_check) +#define peidx_bus_check_num(p) (peidx_head(p)->valid.num_bus_check) +#define peidx_reg_file_check_num(p) (peidx_head(p)->valid.num_reg_file_check) +#define peidx_ms_check_num(p) (peidx_head(p)->valid.num_ms_check) + +#define peidx_cache_check_idx(p, n) (n) +#define peidx_tlb_check_idx(p, n) (peidx_cache_check_idx(p, peidx_cache_check_num(p)) + n) +#define peidx_bus_check_idx(p, n) (peidx_tlb_check_idx(p, peidx_tlb_check_num(p)) + n) +#define peidx_reg_file_check_idx(p, n) (peidx_bus_check_idx(p, peidx_bus_check_num(p)) + n) +#define peidx_ms_check_idx(p, n) (peidx_reg_file_check_idx(p, peidx_reg_file_check_num(p)) + n) + +#define peidx_mod_error_info(p, name, n) \ +({ int __idx = peidx_##name##_idx(p, n); \ + sal_log_mod_error_info_t *__ret = NULL; \ + if (peidx_##name##_num(p) > n) /*BUG*/ \ + __ret = &(peidx_head(p)->info[__idx]); \ + __ret; }) + +#define peidx_cache_check(p, n) peidx_mod_error_info(p, cache_check, n) +#define peidx_tlb_check(p, n) peidx_mod_error_info(p, tlb_check, n) +#define peidx_bus_check(p, n) peidx_mod_error_info(p, bus_check, n) +#define peidx_reg_file_check(p, n) peidx_mod_error_info(p, reg_file_check, n) +#define peidx_ms_check(p, n) peidx_mod_error_info(p, ms_check, n) + +#define peidx_check_info(proc, name, n) \ +({ \ + sal_log_mod_error_info_t *__info = peidx_mod_error_info(proc, name, n);\ + u64 __temp = __info && __info->valid.check_info \ + ? __info->check_info : 0; \ + __temp; }) + +/* slidx: index of SAL log error record */ + +typedef struct slidx_list { + struct list_head list; + sal_log_section_hdr_t *hdr; +} slidx_list_t; + +typedef struct slidx_table { + sal_log_record_header_t *header; + int n_sections; /* # of section headers */ + struct list_head proc_err; + struct list_head mem_dev_err; + struct list_head sel_dev_err; + struct list_head pci_bus_err; + struct list_head smbios_dev_err; + struct list_head pci_comp_err; + struct list_head plat_specific_err; + struct list_head host_ctlr_err; + struct list_head plat_bus_err; + struct list_head unsupported; /* list of unsupported sections */ +} slidx_table_t; + +#define slidx_foreach_entry(pos, head) \ + list_for_each_entry(pos, head, list) +#define slidx_first_entry(head) \ + (((head)->next != (head)) ? list_entry((head)->next, typeof(slidx_list_t), list) : NULL) +#define slidx_count(slidx, sec) \ +({ int __count = 0; \ + slidx_list_t *__pos; \ + slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\ + __count; }) + diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S new file mode 100644 index 000000000..bcfa05acc --- /dev/null +++ b/arch/ia64/kernel/mca_drv_asm.S @@ -0,0 +1,45 @@ +/* + * File: mca_drv_asm.S + * Purpose: Assembly portion of Generic MCA handling + * + * Copyright (C) 2004 FUJITSU LIMITED + * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + */ +#include +#include + +#include +#include + +GLOBAL_ENTRY(mca_handler_bhhook) + invala // clear RSE ? + ;; // + cover // + ;; // + clrrrb // + ;; + alloc r16=ar.pfs,0,2,1,0 // make a new frame + ;; + mov r13=IA64_KR(CURRENT) // current task pointer + ;; + adds r12=IA64_TASK_THREAD_KSP_OFFSET,r13 + ;; + ld8 r12=[r12] // stack pointer + ;; + mov loc0=r16 + movl loc1=mca_handler_bh // recovery C function + ;; + mov out0=r8 // poisoned address + mov b6=loc1 + ;; + mov loc1=rp + ;; + br.call.sptk.many rp=b6 // not return ... + ;; + mov ar.pfs=loc0 + mov rp=loc1 + ;; + mov r8=r0 + br.ret.sptk.many rp + ;; +END(mca_handler_bhhook) diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h index 540301f6e..b1460dcc3 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h @@ -54,8 +54,7 @@ (pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ #define MINSTATE_END_SAVE_MIN_PHYS \ - or r12=r12,r14; /* make sp a kernel virtual address */ \ - or r13=r13,r14; /* make `current' a kernel virtual address */ \ + dep r12=-1,r12,61,3; /* make sp a kernel virtual address */ \ ;; #ifdef MINSTATE_VIRT @@ -65,7 +64,7 @@ #endif #ifdef MINSTATE_PHYS -# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; dep reg=0,reg,61,3 +# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; tpa reg=reg # define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS # define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS #endif @@ -172,7 +171,6 @@ ;; \ .mem.offset 0,0; st8.spill [r16]=r15,16; \ .mem.offset 8,0; st8.spill [r17]=r14,16; \ - dep r14=-1,r0,61,3; \ ;; \ .mem.offset 0,0; st8.spill [r16]=r2,16; \ .mem.offset 8,0; st8.spill [r17]=r3,16; \ diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 2ee61a213..febc091c2 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -195,10 +195,10 @@ apply_imm22 (struct module *mod, struct insn *insn, uint64_t val) printk(KERN_ERR "%s: value %li out of IMM22 range\n", mod->name, (int64_t)val); return 0; } - ia64_patch((u64) insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */ - | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x00007f) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x01fffcfe000UL, ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); return 1; } @@ -209,8 +209,8 @@ apply_imm21b (struct module *mod, struct insn *insn, uint64_t val) printk(KERN_ERR "%s: value %li out of IMM21b range\n", mod->name, (int64_t)val); return 0; } - ia64_patch((u64) insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */ - | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x11ffffe000UL, ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ + | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); return 1; } @@ -253,9 +253,9 @@ plt_target (struct plt_entry *plt) long off; b0 = b[0]; b1 = b[1]; - off = ( ((b1 & 0x00fffff000000000) >> 36) /* imm20b -> bit 0 */ - | ((b0 >> 48) << 20) | ((b1 & 0x7fffff) << 36) /* imm39 -> bit 20 */ - | ((b1 & 0x0800000000000000) << 0)); /* i -> bit 59 */ + off = ( ((b1 & 0x00fffff000000000UL) >> 36) /* imm20b -> bit 0 */ + | ((b0 >> 48) << 20) | ((b1 & 0x7fffffUL) << 36) /* imm39 -> bit 20 */ + | ((b1 & 0x0800000000000000UL) << 0)); /* i -> bit 59 */ return (long) plt->bundle[1] + 16*off; } @@ -739,7 +739,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend, if (gp_addressable(mod, val)) { /* turn "ld8" into "mov": */ DEBUGP("%s: patching ld8 at %p to mov\n", __FUNCTION__, location); - ia64_patch((u64) location, 0x1fff80fe000, 0x10000000000); + ia64_patch((u64) location, 0x1fff80fe000UL, 0x10000000000UL); } return 0; diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index 3cbe961ed..25e7c8344 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -446,7 +446,7 @@ register_info(char *page) "RSE stacked physical registers : %ld\n" "RSE load/store hints : %ld (%s)\n", phys_stacked, hints.ph_data, - hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)"); if (ia64_pal_debug_info(&iregs, &dregs)) return 0; @@ -479,7 +479,7 @@ static const char *proc_features[]={ "Enable CMCI promotion", "Enable MCA to BINIT promotion", "Enable MCA promotion", - "Enable BEER promotion" + "Enable BERR promotion" }; diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c index ef04f5df0..367804a60 100644 --- a/arch/ia64/kernel/patch.c +++ b/arch/ia64/kernel/patch.c @@ -65,21 +65,21 @@ void ia64_patch_imm64 (u64 insn_addr, u64 val) { ia64_patch(insn_addr, - 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */ - | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */ - | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1ffffffffff, val >> 22); + 0x01fffefe000UL, ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ + | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ + | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1ffffffffffUL, val >> 22); } void ia64_patch_imm60 (u64 insn_addr, u64 val) { ia64_patch(insn_addr, - 0x011ffffe000, ( ((val & 0x0800000000000000) >> 23) /* bit 59 -> 36 */ - | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1fffffffffc, val >> 18); + 0x011ffffe000UL, ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ + | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); } /* @@ -130,10 +130,10 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end) while (offp < (s32 *) end) { wp = (u64 *) ia64_imva((char *) offp + *offp); - wp[0] = 0x0000000100000000; /* nop.m 0; nop.i 0; nop.i 0 */ - wp[1] = 0x0004000000000200; - wp[2] = 0x0000000100000011; /* nop.m 0; nop.i 0; br.ret.sptk.many b6 */ - wp[3] = 0x0084006880000200; + wp[0] = 0x0000000100000000UL; /* nop.m 0; nop.i 0; nop.i 0 */ + wp[1] = 0x0004000000000200UL; + wp[2] = 0x0000000100000011UL; /* nop.m 0; nop.i 0; br.ret.sptk.many b6 */ + wp[3] = 0x0084006880000200UL; ia64_fc(wp); ia64_fc(wp + 2); ++offp; } diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 3a6ebc736..204e42037 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -1513,7 +1513,7 @@ exit_pfm_fs(void) } static ssize_t -pfm_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { pfm_context_t *ctx; pfm_msg_t *msg; @@ -1606,7 +1606,7 @@ abort: } static ssize_t -pfm_write(struct file *file, const char *ubuf, +pfm_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos) { DPRINT(("pfm_write called\n")); @@ -1678,7 +1678,6 @@ static int pfm_fasync(int fd, struct file *filp, int on) { pfm_context_t *ctx; - unsigned long flags; int ret; if (PFM_IS_FILE(filp) == 0) { @@ -1691,19 +1690,21 @@ pfm_fasync(int fd, struct file *filp, int on) printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", current->pid); return -EBADF; } - - - PROTECT_CTX(ctx, flags); - + /* + * we cannot mask interrupts during this call because this may + * may go to sleep if memory is not readily avalaible. + * + * We are protected from the conetxt disappearing by the get_fd()/put_fd() + * done in caller. Serialization of this function is ensured by caller. + */ ret = pfm_do_fasync(fd, filp, ctx, on); + DPRINT(("pfm_fasync called on ctx_fd=%d on=%d async_queue=%p ret=%d\n", fd, on, ctx->ctx_async_queue, ret)); - UNPROTECT_CTX(ctx, flags); - return ret; } @@ -2227,6 +2228,15 @@ out: static void pfm_free_fd(int fd, struct file *file) { + struct files_struct *files = current->files; + + /* + * there ie no fd_uninstall(), so we do it here + */ + spin_lock(&files->file_lock); + files->fd[fd] = NULL; + spin_unlock(&files->file_lock); + if (file) put_filp(file); put_unused_fd(fd); } @@ -2277,7 +2287,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur) * return -ENOMEM; */ - if (size > task->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; + if (size > task->rlim[RLIMIT_MEMLOCK].rlim_cur) return -ENOMEM; /* * We do the easy to undo allocations first. @@ -2352,7 +2362,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon insert_vm_struct(mm, vma); mm->total_vm += size >> PAGE_SHIFT; - + vm_stat_account(vma); up_write(&task->mm->mmap_sem); /* @@ -2592,7 +2602,7 @@ pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task) */ if (task == current) return 0; - if (task->state != TASK_STOPPED) { + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { DPRINT(("cannot attach to non-stopped task [%d] state=%ld\n", task->pid, task->state)); return -EBUSY; } @@ -2659,8 +2669,10 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg ctx = pfm_context_alloc(); if (!ctx) goto error; - req->ctx_fd = ctx->ctx_fd = pfm_alloc_fd(&filp); - if (req->ctx_fd < 0) goto error_file; + ret = pfm_alloc_fd(&filp); + if (ret < 0) goto error_file; + + req->ctx_fd = ctx->ctx_fd = ret; /* * attach context to file @@ -3985,7 +3997,10 @@ pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) state = ctx->ctx_state; is_system = ctx->ctx_fl_system; - if (state != PFM_CTX_LOADED && state != PFM_CTX_MASKED) return -EINVAL; + /* + * context must be attached to issue the stop command (includes LOADED,MASKED,ZOMBIE) + */ + if (state == PFM_CTX_UNLOADED) return -EINVAL; /* * In system wide and when the context is loaded, access can only happen @@ -4741,7 +4756,7 @@ recheck: * the task must be stopped. */ if (PFM_CMD_STOPPED(cmd)) { - if (task->state != TASK_STOPPED) { + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { DPRINT(("[%d] task not in stopped state\n", task->pid)); return -EBUSY; } @@ -4782,7 +4797,7 @@ recheck: * system-call entry point (must return long) */ asmlinkage long -sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, long arg7, +sys_perfmonctl (int fd, int cmd, void __user *arg, int count, long arg5, long arg6, long arg7, long arg8, long stack) { struct pt_regs *regs = (struct pt_regs *)&stack; @@ -6312,15 +6327,15 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) */ is_self = ctx->ctx_task == task ? 1 : 0; -#ifdef CONFIG_SMP - if (task == current) { -#else /* - * in UP, the state can still be in the registers + * can access PMU is task is the owner of the PMU state on the current CPU + * or if we are running on the CPU bound to the context in system-wide mode + * (that is not necessarily the task the context is attached to in this mode). + * In system-wide we always have can_access_pmu true because a task running on an + * invalid processor is flagged earlier in the call stack (see pfm_stop). */ - if (task == current || GET_PMU_OWNER() == task) { -#endif - can_access_pmu = 1; + can_access_pmu = (GET_PMU_OWNER() == task) || (ctx->ctx_fl_system && ctx->ctx_cpu == smp_processor_id()); + if (can_access_pmu) { /* * Mark the PMU as not owned * This will cause the interrupt handler to do nothing in case an overflow @@ -6330,6 +6345,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) * on. */ SET_PMU_OWNER(NULL, NULL); + DPRINT(("releasing ownership\n")); /* * read current overflow status: diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 842c95b8a..56ffa1a5d 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -74,12 +74,12 @@ void show_stack (struct task_struct *task, unsigned long *sp) { if (!task) - unw_init_running(ia64_do_show_stack, 0); + unw_init_running(ia64_do_show_stack, NULL); else { struct unw_frame_info info; unw_init_from_blocked_task(&info, task); - ia64_do_show_stack(&info, 0); + ia64_do_show_stack(&info, NULL); } } @@ -138,7 +138,7 @@ show_regs (struct pt_regs *regs) ndirty = (regs->loadrs >> 19); bsp = ia64_rse_skip_regs((unsigned long *) regs->ar_bspstore, ndirty); for (i = 0; i < sof; ++i) { - get_user(val, ia64_rse_skip_regs(bsp, i)); + get_user(val, (unsigned long __user *) ia64_rse_skip_regs(bsp, i)); printk("r%-3u:%c%016lx%s", 32 + i, is_nat ? '*' : ' ', val, ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } @@ -228,18 +228,26 @@ cpu_idle (void *unused) /* endless idle loop with no priority at all */ while (1) { - void (*idle)(void) = pm_idle; - if (!idle) - idle = default_idle; - #ifdef CONFIG_SMP if (!need_resched()) min_xtp(); #endif while (!need_resched()) { + void (*idle)(void); + if (mark_idle) (*mark_idle)(1); + /* + * Mark this as an RCU critical section so that + * synchronize_kernel() in the unload path waits + * for our completion. + */ + rcu_read_lock(); + idle = pm_idle; + if (!idle) + idle = default_idle; (*idle)(); + rcu_read_unlock(); } if (mark_idle) @@ -602,16 +610,18 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) } asmlinkage long -sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs) +sys_execve (char __user *filename, char __user * __user *argv, char __user * __user *envp, + struct pt_regs *regs) { + char *fname; int error; - filename = getname(filename); - error = PTR_ERR(filename); - if (IS_ERR(filename)) + fname = getname(filename); + error = PTR_ERR(fname); + if (IS_ERR(fname)) goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); + error = do_execve(fname, argv, envp, regs); + putname(fname); out: return error; } @@ -743,7 +753,7 @@ cpu_halt (void) void machine_restart (char *restart_cmd) { - (*efi.reset_system)(EFI_RESET_WARM, 0, 0, 0); + (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL); } EXPORT_SYMBOL(machine_restart); diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 56ce1d458..d8ff70dfd 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -152,7 +152,7 @@ ia64_increment_ip (struct pt_regs *regs) ri = 0; regs->cr_iip += 16; } else if (ri == 2) { - get_user(w0, (char *) regs->cr_iip + 0); + get_user(w0, (char __user *) regs->cr_iip + 0); if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) { /* * rfi'ing to slot 2 of an MLX bundle causes @@ -174,7 +174,7 @@ ia64_decrement_ip (struct pt_regs *regs) if (ia64_psr(regs)->ri == 0) { regs->cr_iip -= 16; ri = 2; - get_user(w0, (char *) regs->cr_iip + 0); + get_user(w0, (char __user *) regs->cr_iip + 0); if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) { /* * rfi'ing to slot 2 of an MLX bundle causes @@ -833,7 +833,7 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data case PT_CFM: urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); if (write_access) { - if (((cfm ^ *data) & 0x3fffffffffU) != 0) { + if (((cfm ^ *data) & 0x3fffffffffUL) != 0) { if (ia64_sync_user_rbs(child, sw, pt->ar_bspstore, urbs_end) < 0) return -1; @@ -997,12 +997,14 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data } static long -ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) +ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { + unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val; + struct unw_frame_info info; + struct ia64_fpreg fpval; struct switch_stack *sw; struct pt_regs *pt; long ret, retval; - struct unw_frame_info info; char nat = 0; int i; @@ -1023,12 +1025,21 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) return -EIO; } + if (access_uarea(child, PT_CR_IPSR, &psr, 0) < 0 + || access_uarea(child, PT_AR_EC, &ec, 0) < 0 + || access_uarea(child, PT_AR_LC, &lc, 0) < 0 + || access_uarea(child, PT_AR_RNAT, &rnat, 0) < 0 + || access_uarea(child, PT_AR_BSP, &bsp, 0) < 0 + || access_uarea(child, PT_CFM, &cfm, 0) + || access_uarea(child, PT_NAT_BITS, &nat_bits, 0)) + return -EIO; + retval = 0; /* control regs */ retval |= __put_user(pt->cr_iip, &ppr->cr_iip); - retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 0); + retval |= __put_user(psr, &ppr->cr_ipsr); /* app regs */ @@ -1039,11 +1050,11 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); - retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 0); - retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 0); - retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 0); - retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 0); - retval |= access_uarea(child, PT_CFM, &ppr->cfm, 0); + retval |= __put_user(ec, &ppr->ar[PT_AUR_EC]); + retval |= __put_user(lc, &ppr->ar[PT_AUR_LC]); + retval |= __put_user(rnat, &ppr->ar[PT_AUR_RNAT]); + retval |= __put_user(bsp, &ppr->ar[PT_AUR_BSP]); + retval |= __put_user(cfm, &ppr->cfm); /* gr1-gr3 */ @@ -1053,7 +1064,9 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* gr4-gr7 */ for (i = 4; i < 8; i++) { - retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 0); + if (unw_access_gr(&info, i, &val, &nat, 0) < 0) + return -EIO; + retval |= __put_user(val, &ppr->gr[i]); } /* gr8-gr11 */ @@ -1077,7 +1090,9 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* b1-b5 */ for (i = 1; i < 6; i++) { - retval |= unw_access_br(&info, i, &ppr->br[i], 0); + if (unw_access_br(&info, i, &val, 0) < 0) + return -EIO; + __put_user(val, &ppr->br[i]); } /* b6-b7 */ @@ -1088,8 +1103,9 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* fr2-fr5 */ for (i = 2; i < 6; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); + if (unw_get_fr(&info, i, &fpval) < 0) + return -EIO; + retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } /* fr6-fr11 */ @@ -1103,8 +1119,9 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* fr16-fr31 */ for (i = 16; i < 32; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); + if (unw_get_fr(&info, i, &fpval) < 0) + return -EIO; + retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } /* fph */ @@ -1118,22 +1135,25 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* nat bits */ - retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 0); + retval |= __put_user(nat_bits, &ppr->nat); ret = retval ? -EIO : 0; return ret; } static long -ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) +ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { + unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; + struct unw_frame_info info; struct switch_stack *sw; + struct ia64_fpreg fpval; struct pt_regs *pt; long ret, retval; - struct unw_frame_info info; - char nat = 0; int i; + memset(&fpval, 0, sizeof(fpval)); + retval = verify_area(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs)); if (retval != 0) { return -EIO; @@ -1156,7 +1176,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* control regs */ retval |= __get_user(pt->cr_iip, &ppr->cr_iip); - retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 1); + retval |= __get_user(psr, &ppr->cr_ipsr); /* app regs */ @@ -1167,11 +1187,11 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); - retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 1); - retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 1); - retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 1); - retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 1); - retval |= access_uarea(child, PT_CFM, &ppr->cfm, 1); + retval |= __get_user(ec, &ppr->ar[PT_AUR_EC]); + retval |= __get_user(lc, &ppr->ar[PT_AUR_LC]); + retval |= __get_user(rnat, &ppr->ar[PT_AUR_RNAT]); + retval |= __get_user(bsp, &ppr->ar[PT_AUR_BSP]); + retval |= __get_user(cfm, &ppr->cfm); /* gr1-gr3 */ @@ -1181,11 +1201,9 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* gr4-gr7 */ for (i = 4; i < 8; i++) { - long ret = unw_get_gr(&info, i, &ppr->gr[i], &nat); - if (ret < 0) { - return ret; - } - retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 1); + retval |= __get_user(val, &ppr->gr[i]); + if (unw_set_gr(&info, i, val, 0) < 0) /* NaT bit will be set via PT_NAT_BITS */ + return -EIO; } /* gr8-gr11 */ @@ -1209,7 +1227,8 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* b1-b5 */ for (i = 1; i < 6; i++) { - retval |= unw_access_br(&info, i, &ppr->br[i], 1); + retval |= __get_user(val, &ppr->br[i]); + unw_set_br(&info, i, val); } /* b6-b7 */ @@ -1220,8 +1239,9 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* fr2-fr5 */ for (i = 2; i < 6; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); + retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); + if (unw_set_fr(&info, i, fpval) < 0) + return -EIO; } /* fr6-fr11 */ @@ -1235,8 +1255,9 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* fr16-fr31 */ for (i = 16; i < 32; i++) { - retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1); - retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); + retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); + if (unw_set_fr(&info, i, fpval) < 0) + return -EIO; } /* fph */ @@ -1250,7 +1271,15 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* nat bits */ - retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 1); + retval |= __get_user(nat_bits, &ppr->nat); + + retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); + retval |= access_uarea(child, PT_AR_EC, &ec, 1); + retval |= access_uarea(child, PT_AR_LC, &lc, 1); + retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); + retval |= access_uarea(child, PT_AR_BSP, &bsp, 1); + retval |= access_uarea(child, PT_CFM, &cfm, 1); + retval |= access_uarea(child, PT_NAT_BITS, &nat_bits, 1); ret = retval ? -EIO : 0; return ret; @@ -1429,11 +1458,11 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, goto out_tsk; case PTRACE_GETREGS: - ret = ptrace_getregs(child, (struct pt_all_user_regs*) data); + ret = ptrace_getregs(child, (struct pt_all_user_regs __user *) data); goto out_tsk; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (struct pt_all_user_regs*) data); + ret = ptrace_setregs(child, (struct pt_all_user_regs __user *) data); goto out_tsk; default: diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c index dcbc07ec3..3ec0d2d22 100644 --- a/arch/ia64/kernel/sal.c +++ b/arch/ia64/kernel/sal.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -262,3 +263,40 @@ ia64_sal_init (struct ia64_sal_systab *systab) p += SAL_DESC_SIZE(*p); } } + +int +ia64_sal_oemcall(struct ia64_sal_retval *isrvp, u64 oemfunc, u64 arg1, + u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +{ + if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) + return -1; + SAL_CALL(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + return 0; +} +EXPORT_SYMBOL(ia64_sal_oemcall); + +int +ia64_sal_oemcall_nolock(struct ia64_sal_retval *isrvp, u64 oemfunc, u64 arg1, + u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, + u64 arg7) +{ + if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) + return -1; + SAL_CALL_NOLOCK(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, + arg7); + return 0; +} +EXPORT_SYMBOL(ia64_sal_oemcall_nolock); + +int +ia64_sal_oemcall_reentrant(struct ia64_sal_retval *isrvp, u64 oemfunc, + u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, + u64 arg6, u64 arg7) +{ + if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) + return -1; + SAL_CALL_REENTRANT(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, + arg7); + return 0; +} +EXPORT_SYMBOL(ia64_sal_oemcall_reentrant); diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index a0420ae4d..500e1050c 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c @@ -268,7 +268,7 @@ salinfo_event_open(struct inode *inode, struct file *file) } static ssize_t -salinfo_event_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry *entry = PDE(inode); @@ -417,11 +417,16 @@ retry: if (!data->saved_num) call_on_cpu(cpu, salinfo_log_read_cpu, data); - data->state = data->log_size ? STATE_LOG_RECORD : STATE_NO_DATA; + if (!data->log_size) { + data->state = STATE_NO_DATA; + clear_bit(cpu, &data->cpu_event); + } else { + data->state = STATE_LOG_RECORD; + } } static ssize_t -salinfo_log_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry *entry = PDE(inode); @@ -478,7 +483,7 @@ salinfo_log_clear(struct salinfo_data *data, int cpu) } static ssize_t -salinfo_log_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry *entry = PDE(inode); diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 8aff39de1..da88d284e 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -680,7 +680,7 @@ cpu_init (void) break; } - if (ia64_pal_rse_info(&num_phys_stacked, 0) != 0) { + if (ia64_pal_rse_info(&num_phys_stacked, NULL) != 0) { printk(KERN_WARNING "cpu_init: PAL RSE info failed; assuming 96 physical " "stacked regs\n"); num_phys_stacked = 96; diff --git a/arch/ia64/kernel/sigframe.h b/arch/ia64/kernel/sigframe.h index 55e527527..37b986cb8 100644 --- a/arch/ia64/kernel/sigframe.h +++ b/arch/ia64/kernel/sigframe.h @@ -17,7 +17,7 @@ struct sigframe { * End of architected state. */ - void *handler; /* pointer to the plabel of the signal handler */ + void __user *handler; /* pointer to the plabel of the signal handler */ struct siginfo info; struct sigcontext sc; }; diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 5a609295a..135cb55b1 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 * * Derived from i386 and Alpha versions. @@ -43,7 +43,7 @@ #endif long -ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) +ia64_rt_sigsuspend (sigset_t __user *uset, size_t sigsetsize, struct sigscratch *scr) { sigset_t oldset, set; @@ -84,7 +84,7 @@ ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) } asmlinkage long -sys_sigaltstack (const stack_t *uss, stack_t *uoss, long arg2, long arg3, long arg4, +sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt = (struct pt_regs *) &stack; @@ -93,7 +93,7 @@ sys_sigaltstack (const stack_t *uss, stack_t *uoss, long arg2, long arg3, long a } static long -restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) +restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) { unsigned long ip, flags, nat, um, cfm; long err; @@ -155,7 +155,7 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) } int -copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) +copy_siginfo_to_user (siginfo_t __user *to, siginfo_t *from) { if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; @@ -211,12 +211,12 @@ long ia64_rt_sigreturn (struct sigscratch *scr) { extern char ia64_strace_leave_kernel, ia64_leave_kernel; - struct sigcontext *sc; + struct sigcontext __user *sc; struct siginfo si; sigset_t set; long retval; - sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc; + sc = &((struct sigframe __user *) (scr->pt.r12 + 16))->sc; /* * When we return to the previously executing context, r8 and r10 have already @@ -260,7 +260,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) * It is more difficult to avoid calling this function than to * call it and ignore errors. */ - do_sigaltstack(&sc->sc_stack, 0, scr->pt.r12); + do_sigaltstack(&sc->sc_stack, NULL, scr->pt.r12); return retval; give_sigsegv: @@ -281,7 +281,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) * trampoline starts. Everything else is done at the user-level. */ static long -setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) +setup_sigcontext (struct sigcontext __user *sc, sigset_t *mask, struct sigscratch *scr) { unsigned long flags = 0, ifs, cfm, nat; long err; @@ -335,7 +335,7 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); /* ar.ccv */ err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ err |= __put_user(scr->pt.r14, &sc->sc_gr[14]); /* r14 */ - err |= __copy_to_user(&scr->pt.ar_csd, &sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __copy_to_user(&sc->sc_ar25, &scr->pt.ar_csd, 2*8); /* ar.csd & ar.ssd */ err |= __copy_to_user(&sc->sc_gr[2], &scr->pt.r2, 2*8); /* r2-r3 */ err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ } @@ -351,21 +351,50 @@ rbs_on_sig_stack (unsigned long bsp) return (bsp - current->sas_ss_sp < current->sas_ss_size); } +static long +force_sigsegv_info (int sig, void __user *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(¤t->sighand->siglock, flags); + current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL; + spin_unlock_irqrestore(¤t->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; + struct sigframe __user *frame; long err; - frame = (void *) scr->pt.r12; + frame = (void __user *) scr->pt.r12; tramp_addr = (unsigned long) __kernel_sigtramp; if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) { - frame = (void *) ((current->sas_ss_sp + current->sas_ss_size) - & ~(STACK_ALIGN - 1)); + frame = (void __user *) ((current->sas_ss_sp + current->sas_ss_size) + & ~(STACK_ALIGN - 1)); /* * We need to check for the register stack being on the signal stack * separately, because it's switched separately (memory stack is switched @@ -374,10 +403,10 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, if (!rbs_on_sig_stack(scr->pt.ar_bspstore)) new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); } - frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1)); + frame = (void __user *) 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(¤t->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 = ¤t->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/smp.c b/arch/ia64/kernel/smp.c index 99f008853..14134f2e3 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -225,7 +225,7 @@ smp_send_reschedule (int cpu) void smp_flush_tlb_all (void) { - on_each_cpu((void (*)(void *))local_flush_tlb_all, 0, 1, 1); + on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); } EXPORT_SYMBOL(smp_flush_tlb_all); diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 9a0f79233..f0dd8c3dc 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 * __devinit 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/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index eddde6018..88d8b217f 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -93,7 +93,7 @@ sys_getpagesize (void) } asmlinkage unsigned long -ia64_shmat (int shmid, void *shmaddr, int shmflg) +ia64_shmat (int shmid, void __user *shmaddr, int shmflg) { unsigned long raddr; int retval; @@ -183,7 +183,7 @@ static inline unsigned long do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) { unsigned long roff; - struct file *file = 0; + struct file *file = NULL; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index e33bcb661..853d8dae7 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -45,192 +45,7 @@ EXPORT_SYMBOL(last_cli_ip); #endif -static void -itc_reset (void) -{ -} - -/* - * Adjust for the fact that xtime has been advanced by delta_nsec (may be negative and/or - * larger than NSEC_PER_SEC. - */ -static void -itc_update (long delta_nsec) -{ -} - -/* - * Return the number of nano-seconds that elapsed since the last - * update to jiffy. It is quite possible that the timer interrupt - * will interrupt this and result in a race for any of jiffies, - * wall_jiffies or itm_next. Thus, the xtime_lock must be at least - * read synchronised when calling this routine (see do_gettimeofday() - * below for an example). - */ -unsigned long -itc_get_offset (void) -{ - unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; - unsigned long now = ia64_get_itc(), last_tick; - - last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next - - (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta); - - elapsed_cycles = now - last_tick; - return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; -} - -static struct time_interpolator itc_interpolator = { - .get_offset = itc_get_offset, - .update = itc_update, - .reset = itc_reset -}; - -int -do_settimeofday (struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - { - /* - * This is revolting. We need to set "xtime" correctly. However, the value - * in this location is the value at the most recent update of wall time. - * Discover what correction gettimeofday would have done, and then undo - * it! - */ - nsec -= time_interpolator_get_offset(); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - time_interpolator_reset(); - } - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -void -do_gettimeofday (struct timeval *tv) -{ - unsigned long seq, nsec, usec, sec, old, offset; - - while (1) { - seq = read_seqbegin(&xtime_lock); - { - old = last_nsec_offset; - offset = time_interpolator_get_offset(); - sec = xtime.tv_sec; - nsec = xtime.tv_nsec; - } - if (unlikely(read_seqretry(&xtime_lock, seq))) - continue; - /* - * Ensure that for any pair of causally ordered gettimeofday() calls, time - * never goes backwards (even when ITC on different CPUs are not perfectly - * synchronized). (A pair of concurrent calls to gettimeofday() is by - * definition non-causal and hence it makes no sense to talk about - * time-continuity for such calls.) - * - * Doing this in a lock-free and race-free manner is tricky. Here is why - * it works (most of the time): read_seqretry() just succeeded, which - * implies we calculated a consistent (valid) value for "offset". If the - * cmpxchg() below succeeds, we further know that last_nsec_offset still - * has the same value as at the beginning of the loop, so there was - * presumably no timer-tick or other updates to last_nsec_offset in the - * meantime. This isn't 100% true though: there _is_ a possibility of a - * timer-tick occurring right right after read_seqretry() and then getting - * zero or more other readers which will set last_nsec_offset to the same - * value as the one we read at the beginning of the loop. If this - * happens, we'll end up returning a slightly newer time than we ought to - * (the jump forward is at most "offset" nano-seconds). There is no - * danger of causing time to go backwards, though, so we are safe in that - * sense. We could make the probability of this unlucky case occurring - * arbitrarily small by encoding a version number in last_nsec_offset, but - * even without versioning, the probability of this unlucky case should be - * so small that we won't worry about it. - */ - if (offset <= old) { - offset = old; - break; - } else if (likely(cmpxchg(&last_nsec_offset, old, offset) == old)) - break; - - /* someone else beat us to updating last_nsec_offset; try again */ - } - - usec = (nsec + offset) / 1000; - - while (unlikely(usec >= USEC_PER_SEC)) { - usec -= USEC_PER_SEC; - ++sec; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void -ia64_do_profile (struct pt_regs * regs) -{ - unsigned long ip, slot; - extern cpumask_t prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - ip = instruction_pointer(regs); - /* Conserve space in histogram by encoding slot bits in address - * bits 2 and 3 rather than bits 0 and 1. - */ - slot = ip & 3; - ip = (ip & ~3UL) + 4*slot; - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!cpu_isset(smp_processor_id(), prof_cpu_mask)) - return; - - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - /* - * Don't ignore out-of-bounds IP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (ip > prof_len-1) - ip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[ip]); -} +static struct time_interpolator itc_interpolator; static irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) @@ -249,7 +64,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", ia64_get_itc(), new_itm); - ia64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); while (1) { #ifdef CONFIG_SMP @@ -323,6 +138,18 @@ ia64_cpu_local_tick (void) ia64_set_itm(local_cpu_data->itm_next); } +static int nojitter; + +static int __init nojitter_setup(char *str) +{ + nojitter = 1; + printk("Jitter checking for ITC timers disabled\n"); + return 1; +} + +__setup("nojitter", nojitter_setup); + + void __devinit ia64_init_itm (void) { @@ -340,7 +167,7 @@ ia64_init_itm (void) if (status != 0) { printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status)); } else { - status = ia64_pal_freq_ratios(&proc_ratio, 0, &itc_ratio); + status = ia64_pal_freq_ratios(&proc_ratio, NULL, &itc_ratio); if (status != 0) printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status); } @@ -371,7 +198,7 @@ ia64_init_itm (void) itc_drift = -1; local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; - printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " + printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " "ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000, @@ -385,7 +212,23 @@ ia64_init_itm (void) if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { itc_interpolator.frequency = local_cpu_data->itc_freq; + itc_interpolator.shift = 16; itc_interpolator.drift = itc_drift; + itc_interpolator.source = TIME_SOURCE_CPU; +#ifdef CONFIG_SMP + /* On IA64 in an SMP configuration ITCs are never accurately synchronized. + * Jitter compensation requires a cmpxchg which may limit + * the scalability of the syscalls for retrieving time. + * The ITC synchronization is usually successful to within a few + * ITC ticks but this is not a sure thing. If you need to improve + * timer performance in SMP situations then boot the kernel with the + * "nojitter" option. However, doing so may result in time fluctuating (maybe + * even going backward) if the ITC offsets between the individual CPUs + * are too large. + */ + if (!nojitter) itc_interpolator.jitter = 1; +#endif + itc_interpolator.addr = NULL; register_time_interpolator(&itc_interpolator); } diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index f89913135..3dd9b1dc7 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -14,9 +14,9 @@ #include #include /* For unblank_screen() */ #include /* for EXPORT_SYMBOL */ +#include #include -#include #include #include #include @@ -112,7 +112,7 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) int sig, code; /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = break_num; siginfo.si_flags = 0; /* clear __ISR_VALID */ siginfo.si_isr = 0; @@ -282,7 +282,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) fault_ip = regs->cr_iip; if (!fp_fault && (ia64_psr(regs)->ri == 0)) fault_ip -= 16; - if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle))) + if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle))) return -1; if (jiffies - last_time > 5*HZ) @@ -312,7 +312,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = __SI_FAULT; /* default code */ - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); if (isr & 0x11) { siginfo.si_code = FPE_FLTINV; } else if (isr & 0x22) { @@ -336,7 +336,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = __SI_FAULT; /* default code */ - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); if (isr & 0x880) { siginfo.si_code = FPE_FLTOVF; } else if (isr & 0x1100) { @@ -383,7 +383,7 @@ ia64_illegal_op_fault (unsigned long ec, unsigned long arg1, unsigned long arg2, memset(&si, 0, sizeof(si)); si.si_signo = SIGILL; si.si_code = ILL_ILLOPC; - si.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + si.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); force_sig_info(SIGILL, &si, current); rv.fkt = 0; return rv; @@ -445,18 +445,18 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, case 26: /* NaT Consumption */ if (user_mode(regs)) { - void *addr; + void __user *addr; if (((isr >> 4) & 0xf) == 2) { /* NaT page consumption */ sig = SIGSEGV; code = SEGV_ACCERR; - addr = (void *) ifa; + addr = (void __user *) ifa; } else { /* register NaT consumption */ sig = SIGILL; code = ILL_ILLOPN; - addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); } siginfo.si_signo = sig; siginfo.si_code = code; @@ -477,7 +477,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, siginfo.si_signo = SIGILL; siginfo.si_code = ILL_ILLOPN; siginfo.si_errno = 0; - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = vector; siginfo.si_flags = __ISR_VALID; siginfo.si_isr = isr; @@ -524,7 +524,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, } siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0; - siginfo.si_addr = (void *) ifa; + siginfo.si_addr = (void __user *) ifa; siginfo.si_imm = 0; siginfo.si_flags = __ISR_VALID; siginfo.si_isr = isr; @@ -538,7 +538,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = FPE_FLTINV; - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_flags = __ISR_VALID; siginfo.si_isr = isr; siginfo.si_imm = 0; @@ -565,7 +565,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, siginfo.si_flags = 0; siginfo.si_isr = 0; siginfo.si_imm = 0; - siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_addr = (void __user *) + (regs->cr_iip + ia64_psr(regs)->ri); force_sig_info(SIGILL, &siginfo, current); return; } diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index b1a68e436..46dad0d21 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -760,7 +760,7 @@ emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) return -1; } /* this assumes little-endian byte-order: */ - if (copy_from_user(&val, (void *) ifa, len)) + if (copy_from_user(&val, (void __user *) ifa, len)) return -1; setreg(ld.r1, val, 0, regs); @@ -869,7 +869,7 @@ emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) * * extract the value to be stored */ - getreg(ld.imm, &r2, 0, regs); + getreg(ld.imm, &r2, NULL, regs); /* * we rely on the macros in unaligned.h for now i.e., @@ -887,7 +887,7 @@ emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) } /* this assumes little-endian byte-order: */ - if (copy_to_user((void *) ifa, &r2, len)) + if (copy_to_user((void __user *) ifa, &r2, len)) return -1; /* @@ -1036,8 +1036,8 @@ emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs * This assumes little-endian byte-order. Note that there is no "ldfpe" * instruction: */ - if (copy_from_user(&fpr_init[0], (void *) ifa, len) - || copy_from_user(&fpr_init[1], (void *) (ifa + len), len)) + if (copy_from_user(&fpr_init[0], (void __user *) ifa, len) + || copy_from_user(&fpr_init[1], (void __user *) (ifa + len), len)) return -1; DPRINT("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld.r1, ld.imm, ld.x6_sz); @@ -1138,7 +1138,7 @@ emulate_load_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs) * See comments in ldX for descriptions on how the various loads are handled. */ if (ld.x6_op != 0x2) { - if (copy_from_user(&fpr_init, (void *) ifa, len)) + if (copy_from_user(&fpr_init, (void __user *) ifa, len)) return -1; DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz); @@ -1230,7 +1230,7 @@ emulate_store_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs) DDUMP("fpr_init =", &fpr_init, len); DDUMP("fpr_final =", &fpr_final, len); - if (copy_to_user((void *) ifa, &fpr_final, len)) + if (copy_to_user((void __user *) ifa, &fpr_final, len)) return -1; /* @@ -1351,7 +1351,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) DPRINT("iip=%lx ifa=%lx isr=%lx (ei=%d, sp=%d)\n", regs->cr_iip, ifa, regs->cr_ipsr, ipsr->ri, ipsr->it); - if (__copy_from_user(bundle, (void *) regs->cr_iip, 16)) + if (__copy_from_user(bundle, (void __user *) regs->cr_iip, 16)) goto failure; /* @@ -1496,7 +1496,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; + si.si_addr = (void __user *) ifa; si.si_flags = 0; si.si_isr = 0; si.si_imm = 0; diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 769d880df..69e095abe 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -47,7 +47,6 @@ #include "entry.h" #include "unwind_i.h" -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define p5 5 #define UNW_LOG_CACHE_SIZE 7 /* each unw_script is ~256 bytes in size */ @@ -447,7 +446,7 @@ EXPORT_SYMBOL(unw_access_br); int unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write) { - struct ia64_fpreg *addr = 0; + struct ia64_fpreg *addr = NULL; struct pt_regs *pt; if ((unsigned) (regnum - 2) >= 126) { @@ -843,7 +842,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave } sr->gr_save_loc = grsave; sr->any_spills = 0; - sr->imask = 0; + sr->imask = NULL; sr->spill_offset = 0x10; /* default to psp+16 */ } } @@ -963,13 +962,13 @@ static inline void desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) { set_reg(sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, - sr->region_start + MIN((int)t, sr->region_len - 1), 16*size); + sr->region_start + min_t(int, t, sr->region_len - 1), 16*size); } static inline void desc_mem_stack_v (unw_word t, struct unw_state_record *sr) { - sr->curr.reg[UNW_REG_PSP].when = sr->region_start + MIN((int)t, sr->region_len - 1); + sr->curr.reg[UNW_REG_PSP].when = sr->region_start + min_t(int, t, sr->region_len - 1); } static inline void @@ -1005,7 +1004,7 @@ desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr) if (reg->where == UNW_WHERE_NONE) reg->where = UNW_WHERE_GR_SAVE; - reg->when = sr->region_start + MIN((int)t, sr->region_len - 1); + reg->when = sr->region_start + min_t(int, t, sr->region_len - 1); } static inline void @@ -1073,7 +1072,7 @@ desc_label_state (unw_word label, struct unw_state_record *sr) static inline int desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) { - if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) + if (sr->when_target <= sr->region_start + min_t(int, t, sr->region_len - 1)) return 0; if (qp > 0) { if ((sr->pr_val & (1UL << qp)) == 0) @@ -1114,7 +1113,7 @@ desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, unsigned ch r = sr->curr.reg + decode_abreg(abreg, 0); r->where = where; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = (ytreg & 0x7f); } @@ -1129,7 +1128,7 @@ desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_PSPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = 0x10 - 4*pspoff; } @@ -1144,7 +1143,7 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_SPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = 4*spoff; } @@ -1206,7 +1205,7 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word static inline unw_hash_index_t hash (unsigned long ip) { -# define hashmagic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */ +# define hashmagic 0x9e3779b97f4a7c16UL /* based on (sqrt(5)/2-1)*2^64 */ return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE); #undef hashmagic @@ -1231,7 +1230,7 @@ script_lookup (struct unw_frame_info *info) unsigned long ip, pr; if (UNW_DEBUG_ON(0)) - return 0; /* Always regenerate scripts in debug mode */ + return NULL; /* Always regenerate scripts in debug mode */ STAT(++unw.stat.cache.lookups); @@ -1245,7 +1244,7 @@ script_lookup (struct unw_frame_info *info) index = unw.hash[hash(ip)]; if (index >= UNW_CACHE_SIZE) - return 0; + return NULL; script = unw.cache + index; while (1) { @@ -1256,7 +1255,7 @@ script_lookup (struct unw_frame_info *info) return script; } if (script->coll_chain >= UNW_HASH_SIZE) - return 0; + return NULL; script = unw.cache + script->coll_chain; STAT(++unw.stat.cache.collision_chain_traversals); } @@ -1306,7 +1305,7 @@ script_new (unsigned long ip) if (script->ip) { index = hash(script->ip); tmp = unw.cache + unw.hash[index]; - prev = 0; + prev = NULL; while (1) { if (tmp == script) { if (prev) @@ -1511,7 +1510,7 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) static inline const struct unw_table_entry * lookup (struct unw_table *table, unsigned long rel_ip) { - const struct unw_table_entry *e = 0; + const struct unw_table_entry *e = NULL; unsigned long lo, hi, mid; /* do a binary search for right entry: */ @@ -1537,8 +1536,8 @@ lookup (struct unw_table *table, unsigned long rel_ip) static inline struct unw_script * build_script (struct unw_frame_info *info) { - const struct unw_table_entry *e = 0; - struct unw_script *script = 0; + const struct unw_table_entry *e = NULL; + struct unw_script *script = NULL; struct unw_labeled_state *ls, *next; unsigned long ip = info->ip; struct unw_state_record sr; @@ -1563,7 +1562,7 @@ build_script (struct unw_frame_info *info) if (!script) { UNW_DPRINT(0, "unwind.%s: failed to create unwind script\n", __FUNCTION__); STAT(unw.stat.script.build_time += ia64_get_itc() - start); - return 0; + return NULL; } unw.cache[info->prev_script].hint = script - unw.cache; @@ -1836,7 +1835,7 @@ find_save_locs (struct unw_frame_info *info) /* don't let obviously bad addresses pollute the cache */ /* FIXME: should really be level 0 but it occurs too often. KAO */ UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip); - info->rp_loc = 0; + info->rp_loc = NULL; return -1; } @@ -2093,12 +2092,12 @@ unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned lon if (end - start <= 0) { UNW_DPRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n", __FUNCTION__); - return 0; + return NULL; } table = kmalloc(sizeof(*table), GFP_USER); if (!table) - return 0; + return NULL; init_unwind_table(table, name, segment_base, gp, table_start, table_end); @@ -2300,7 +2299,7 @@ unw_init (void) * EFAULT BUF points outside your accessible address space. */ asmlinkage long -sys_getunwind (void *buf, size_t buf_size) +sys_getunwind (void __user *buf, size_t buf_size) { if (buf && buf_size >= unw.gate_table_size) if (copy_to_user(buf, unw.gate_table, unw.gate_table_size) != 0) diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 57912212b..b9f0db4c1 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -42,6 +42,7 @@ SECTIONS *(.text.ivt) *(.text) SCHED_TEXT + LOCK_TEXT *(.gnu.linkonce.t*) } .text2 : AT(ADDR(.text2) - LOAD_OFFSET) @@ -135,12 +136,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/lib/csum_partial_copy.c b/arch/ia64/lib/csum_partial_copy.c index 269dcc2cb..ca7ba1e9c 100644 --- a/arch/ia64/lib/csum_partial_copy.c +++ b/arch/ia64/lib/csum_partial_copy.c @@ -1,7 +1,7 @@ /* * Network Checksum & Copy routine * - * Copyright (C) 1999, 2003 Hewlett-Packard Co + * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co * Stephane Eranian * * Most of the code has been imported from Linux/Alpha @@ -105,7 +105,7 @@ out: extern unsigned long do_csum(const unsigned char *, long); static unsigned int -do_csum_partial_copy_from_user (const char *src, char *dst, int len, +do_csum_partial_copy_from_user (const char __user *src, char *dst, int len, unsigned int psum, int *errp) { unsigned long result; @@ -129,10 +129,10 @@ do_csum_partial_copy_from_user (const char *src, char *dst, int len, } unsigned int -csum_partial_copy_from_user(const char *src, char *dst, int len, - unsigned int sum, int *errp) +csum_partial_copy_from_user (const char __user *src, char *dst, int len, + unsigned int sum, int *errp) { - if (!access_ok(src, len, VERIFY_READ)) { + if (!access_ok(VERIFY_READ, src, len)) { *errp = -EFAULT; memset(dst, 0, len); return sum; @@ -142,7 +142,7 @@ csum_partial_copy_from_user(const char *src, char *dst, int len, } unsigned int -csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum) +csum_partial_copy_nocheck(const char __user *src, char *dst, int len, unsigned int sum) { return do_csum_partial_copy_from_user(src, dst, len, sum, NULL); } diff --git a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c index 90f0f3061..2bc5be82d 100644 --- a/arch/ia64/lib/io.c +++ b/arch/ia64/lib/io.c @@ -9,7 +9,7 @@ * This needs to be optimized. */ void -__ia64_memcpy_fromio (void *to, unsigned long from, long count) +__ia64_memcpy_fromio (void *to, volatile void __iomem *from, long count) { char *dst = to; @@ -25,7 +25,7 @@ EXPORT_SYMBOL(__ia64_memcpy_fromio); * This needs to be optimized. */ void -__ia64_memcpy_toio (unsigned long to, void *from, long count) +__ia64_memcpy_toio (volatile void __iomem *to, void *from, long count) { char *src = from; @@ -41,7 +41,7 @@ EXPORT_SYMBOL(__ia64_memcpy_toio); * This needs to be optimized. */ void -__ia64_memset_c_io (unsigned long dst, unsigned long c, long count) +__ia64_memset_c_io (volatile void __iomem *dst, unsigned long c, long count) { unsigned char ch = (char)(c & 0xff); @@ -111,49 +111,49 @@ __ia64_outl (unsigned int val, unsigned long port) } unsigned char -__ia64_readb (void *addr) +__ia64_readb (void __iomem *addr) { return ___ia64_readb (addr); } unsigned short -__ia64_readw (void *addr) +__ia64_readw (void __iomem *addr) { return ___ia64_readw (addr); } unsigned int -__ia64_readl (void *addr) +__ia64_readl (void __iomem *addr) { return ___ia64_readl (addr); } unsigned long -__ia64_readq (void *addr) +__ia64_readq (void __iomem *addr) { return ___ia64_readq (addr); } unsigned char -__ia64_readb_relaxed (void *addr) +__ia64_readb_relaxed (void __iomem *addr) { return ___ia64_readb (addr); } unsigned short -__ia64_readw_relaxed (void *addr) +__ia64_readw_relaxed (void __iomem *addr) { return ___ia64_readw (addr); } unsigned int -__ia64_readl_relaxed (void *addr) +__ia64_readl_relaxed (void __iomem *addr) { return ___ia64_readl (addr); } unsigned long -__ia64_readq_relaxed (void *addr) +__ia64_readq_relaxed (void __iomem *addr) { return ___ia64_readq (addr); } diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c index 781e23e66..9d4486f87 100644 --- a/arch/ia64/lib/swiotlb.c +++ b/arch/ia64/lib/swiotlb.c @@ -11,6 +11,7 @@ * 03/05/07 davidm Switch from PCI-DMA to generic device DMA API. * 00/12/13 davidm Rename to swiotlb.c and add mark_clean() to avoid * unnecessary i-cache flushing. + * 04/07/.. ak Better overflow handling. Assorted fixes. */ #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -46,6 +48,8 @@ */ #define IO_TLB_SHIFT 11 +int swiotlb_force; + /* * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single_*, to see * if the memory was in fact allocated by this API. @@ -55,8 +59,16 @@ static char *io_tlb_start, *io_tlb_end; /* * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and io_tlb_end. * This is command line adjustable via setup_io_tlb_npages. + * Default to 64MB. + */ +static unsigned long io_tlb_nslabs = 32768; + +/* + * When the IOMMU overflows we return a fallback buffer. This sets the size. */ -static unsigned long io_tlb_nslabs = 1024; +static unsigned long io_tlb_overflow = 32*1024; + +void *io_tlb_overflow_buffer; /* * This is a free list describing the number of free entries available from each index @@ -78,15 +90,19 @@ static spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED; static int __init setup_io_tlb_npages (char *str) { - io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); - - /* avoid tail segment of size < IO_TLB_SEGSIZE */ - io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); - + if (isdigit(*str)) { + io_tlb_nslabs = simple_strtoul(str, &str, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); + /* avoid tail segment of size < IO_TLB_SEGSIZE */ + io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); + } + if (*str == ',') + ++str; + if (!strcmp(str, "force")) + swiotlb_force = 1; return 1; } __setup("swiotlb=", setup_io_tlb_npages); - +/* make io_tlb_overflow tunable too? */ /* * Statically reserve bounce buffer space and initialize bounce buffer data structures for @@ -102,7 +118,7 @@ swiotlb_init (void) */ io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); if (!io_tlb_start) - BUG(); + panic("Cannot allocate SWIOTLB buffer"); io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); /* @@ -115,11 +131,23 @@ swiotlb_init (void) io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); io_tlb_index = 0; io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); - - printk(KERN_INFO "Placing software IO TLB between 0x%p - 0x%p\n", - (void *) io_tlb_start, (void *) io_tlb_end); + + /* + * Get the overflow emergency buffer + */ + io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); + printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n", + virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end)); } +static inline int address_needs_mapping(struct device *hwdev, dma_addr_t addr) +{ + dma_addr_t mask = 0xffffffff; + if (hwdev && hwdev->dma_mask) + mask = *hwdev->dma_mask; + return (addr & ~mask) != 0; +} + /* * Allocates bounce buffer and returns its kernel virtual address. */ @@ -184,11 +212,8 @@ map_single (struct device *hwdev, char *buffer, size_t size, int dir) index = 0; } while (index != wrap); - /* - * XXX What is a suitable recovery mechanism here? We cannot - * sleep because we are called from with in interrupts! - */ - panic("map_single: could not allocate software IO TLB (%ld bytes)", size); + spin_unlock_irqrestore(&io_tlb_lock, flags); + return NULL; } found: spin_unlock_irqrestore(&io_tlb_lock, flags); @@ -285,7 +310,7 @@ swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handl memset(ret, 0, size); dev_addr = virt_to_phys(ret); - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) + if (address_needs_mapping(hwdev,dev_addr)) panic("swiotlb_alloc_consistent: allocated memory is out of range for device"); *dma_handle = dev_addr; return ret; @@ -297,6 +322,28 @@ swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_ free_pages((unsigned long) vaddr, get_order(size)); } +static void swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) +{ + /* + * Ran out of IOMMU space for this operation. This is very bad. + * Unfortunately the drivers cannot handle this operation properly. + * unless they check for pci_dma_mapping_error (most don't) + * When the mapping is small enough return a static buffer to limit + * the damage, or panic when the transfer is too big. + */ + + printk(KERN_ERR + "PCI-DMA: Out of SW-IOMMU space for %lu bytes at device %s\n", + size, dev ? dev->bus_id : "?"); + + if (size > io_tlb_overflow && do_panic) { + if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Memory would be corrupted\n"); + if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Random memory would be DMAed\n"); + } +} + /* * Map a single buffer of the indicated size for DMA in streaming mode. The PCI address * to use is returned. @@ -308,13 +355,14 @@ dma_addr_t swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir) { unsigned long dev_addr = virt_to_phys(ptr); + void *map; if (dir == DMA_NONE) BUG(); /* * Check if the PCI device can DMA to ptr... if so, just return ptr */ - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) == 0) + if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force) /* * Device is bit capable of DMA'ing to the buffer... just return the PCI * address of ptr @@ -324,12 +372,18 @@ swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir) /* * get a bounce buffer: */ - dev_addr = virt_to_phys(map_single(hwdev, ptr, size, dir)); + map = map_single(hwdev, ptr, size, dir); + if (!map) { + swiotlb_full(hwdev, size, dir, 1); + map = io_tlb_overflow_buffer; + } + + dev_addr = virt_to_phys(map); /* * Ensure that the address returned is DMA'ble: */ - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) + if (address_needs_mapping(hwdev, dev_addr)) panic("map_single: bounce buffer is not DMA'ble"); return dev_addr; @@ -437,9 +491,17 @@ swiotlb_map_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int di for (i = 0; i < nelems; i++, sg++) { addr = SG_ENT_VIRT_ADDRESS(sg); dev_addr = virt_to_phys(addr); - if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) - sg->dma_address = (dma_addr_t) map_single(hwdev, addr, sg->length, dir); - else + if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) { + sg->dma_address = (dma_addr_t) virt_to_phys(map_single(hwdev, addr, sg->length, dir)); + if (!sg->dma_address) { + /* Don't panic here, we expect pci_map_sg users + to do proper error handling. */ + swiotlb_full(hwdev, sg->length, dir, 0); + swiotlb_unmap_sg(hwdev, sg - i, i, dir); + sg[0].dma_length = 0; + return 0; + } + } else sg->dma_address = dev_addr; sg->dma_length = sg->length; } @@ -460,7 +522,7 @@ swiotlb_unmap_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir); + unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir); else if (dir == DMA_FROM_DEVICE) mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } @@ -501,7 +563,7 @@ swiotlb_sync_sg_for_device (struct device *hwdev, struct scatterlist *sg, int ne int swiotlb_dma_mapping_error (dma_addr_t dma_addr) { - return 0; + return (dma_addr == virt_to_phys(io_tlb_overflow_buffer)); } /* diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index c0f8f4a3e..0f905a637 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -116,19 +116,19 @@ find_bootmap_location (unsigned long start, unsigned long end, void *arg) range_start = max(start, free_start); range_end = min(end, rsvd_region[i].start & PAGE_MASK); + free_start = PAGE_ALIGN(rsvd_region[i].end); + if (range_end <= range_start) continue; /* skip over empty range */ - if (range_end - range_start >= needed) { + if (range_end - range_start >= needed) { bootmap_start = __pa(range_start); - return 1; /* done */ + return -1; /* done */ } /* nothing more available in this segment */ if (range_end == end) return 0; - - free_start = PAGE_ALIGN(rsvd_region[i].end); } return 0; } @@ -267,9 +267,8 @@ 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 { unsigned long map_size; @@ -278,12 +277,12 @@ paging_init (void) map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page)); vmalloc_end -= map_size; vmem_map = (struct page *) vmalloc_end; - efi_memmap_walk(create_mem_map_page_table, 0); + efi_memmap_walk(create_mem_map_page_table, NULL); - free_area_init_node(0, &contig_page_data, vmem_map, zones_size, + mem_map = 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; printk("Virtual mem_map starts at 0x%p\n", mem_map); } #else /* !CONFIG_VIRTUAL_MEM_MAP */ diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 23a9490fc..eb464cbb9 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -53,11 +53,12 @@ static struct early_node_data mem_data[NR_NODES] __initdata; static void __init reassign_cpu_only_nodes(void) { struct node_memblk_s *p; - int i, j, k, nnode, nid, cpu, cpunid; + int i, j, k, nnode, nid, cpu, cpunid, pxm; u8 cslit, slit; static DECLARE_BITMAP(nodes_with_mem, NR_NODES) __initdata; static u8 numa_slit_fix[MAX_NUMNODES * MAX_NUMNODES] __initdata; static int node_flip[NR_NODES] __initdata; + static int old_nid_map[NR_CPUS] __initdata; for (nnode = 0, p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++) if (!test_bit(p->nid, (void *) nodes_with_mem)) { @@ -104,9 +105,14 @@ static void __init reassign_cpu_only_nodes(void) for (cpu = 0; cpu < NR_CPUS; cpu++) if (node_cpuid[cpu].nid == i) { - /* For nodes not being reassigned just fix the cpu's nid. */ + /* + * For nodes not being reassigned just + * fix the cpu's nid and reverse pxm map + */ if (cpunid < numnodes) { - node_cpuid[cpu].nid = cpunid; + pxm = nid_to_pxm_map[i]; + pxm_to_nid_map[pxm] = + node_cpuid[cpu].nid = cpunid; continue; } @@ -126,6 +132,8 @@ static void __init reassign_cpu_only_nodes(void) } } + /* save old nid map so we can update the pxm */ + old_nid_map[cpu] = node_cpuid[cpu].nid; node_cpuid[cpu].nid = k; } } @@ -134,14 +142,19 @@ static void __init reassign_cpu_only_nodes(void) * Fixup temporary nid values for CPU-only nodes. */ for (cpu = 0; cpu < NR_CPUS; cpu++) - if (node_cpuid[cpu].nid == (numnodes + numnodes)) - node_cpuid[cpu].nid = nnode - 1; - else - for (i = 0; i < nnode; i++) - if (node_flip[i] == (node_cpuid[cpu].nid - numnodes)) { - node_cpuid[cpu].nid = i; - break; - } + if (node_cpuid[cpu].nid == (numnodes + numnodes)) { + pxm = nid_to_pxm_map[old_nid_map[cpu]]; + pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = nnode - 1; + } else { + for (i = 0; i < nnode; i++) { + if (node_flip[i] != (node_cpuid[cpu].nid - numnodes)) + continue; + + pxm = nid_to_pxm_map[old_nid_map[cpu]]; + pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = i; + break; + } + } /* * Fix numa_slit by compressing from larger @@ -492,14 +505,17 @@ void *per_cpu_init(void) */ void show_mem(void) { - int i, reserved = 0; - int shared = 0, cached = 0; + int i, total_reserved = 0; + int total_shared = 0, total_cached = 0; + unsigned long total_present = 0; pg_data_t *pgdat; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { + unsigned long present = pgdat->node_present_pages; + int shared = 0, cached = 0, reserved = 0; printk("Node ID: %d\n", pgdat->node_id); for(i = 0; i < pgdat->node_spanned_pages; i++) { if (!ia64_pfn_valid(pgdat->node_start_pfn+i)) @@ -511,11 +527,19 @@ void show_mem(void) else if (page_count(pgdat->node_mem_map+i)) shared += page_count(pgdat->node_mem_map+i)-1; } - printk("\t%ld pages of RAM\n", pgdat->node_present_pages); + total_present += present; + total_reserved += reserved; + total_cached += cached; + total_shared += shared; + printk("\t%ld pages of RAM\n", present); printk("\t%d reserved pages\n", reserved); printk("\t%d pages shared\n", shared); printk("\t%d pages swap cached\n", cached); } + printk("%ld pages of RAM\n", total_present); + printk("%d reserved pages\n", total_reserved); + printk("%d pages shared\n", total_shared); + printk("%d pages swap cached\n", total_cached); printk("Total of %ld pages in page table cache\n", pgtable_cache_size); printk("%d free buffer pages\n", nr_free_buffer_pages()); } @@ -607,12 +631,10 @@ void paging_init(void) unsigned long max_dma; unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; - unsigned long max_gap, pfn_offset = 0; + unsigned long pfn_offset = 0; int node; max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - max_gap = 0; - efi_memmap_walk(find_largest_hole, &max_gap); /* so min() will work in count_node_pages */ for (node = 0; node < numnodes; node++) @@ -664,8 +686,8 @@ 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, + NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset; + free_area_init_node(node, NODE_DATA(node), zones_size, pfn_offset, zholes_size); } diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c index 2353cc795..99edfed31 100644 --- a/arch/ia64/mm/extable.c +++ b/arch/ia64/mm/extable.c @@ -77,7 +77,7 @@ search_extable (const struct exception_table_entry *first, else last = mid - 1; } - return 0; + return NULL; } void diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index d823ff897..de73e3c91 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -14,7 +14,6 @@ #include #include #include -#include extern void die (char *, struct pt_regs *, long); @@ -40,6 +39,7 @@ expand_backing_store (struct vm_area_struct *vma, unsigned long address) vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) vma->vm_mm->locked_vm += grow; + __vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow); return 0; } @@ -196,7 +196,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re si.si_signo = signal; si.si_errno = 0; si.si_code = code; - si.si_addr = (void *) address; + si.si_addr = (void __user *) address; si.si_isr = isr; si.si_flags = __ISR_VALID; force_sig_info(signal, &si, current); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 3ab0b37e0..87a8016f5 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -67,9 +67,9 @@ check_pgt_cache (void) if (pgtable_cache_size > (u64) high) { do { if (pgd_quicklist) - free_page((unsigned long)pgd_alloc_one_fast(0)); + free_page((unsigned long)pgd_alloc_one_fast(NULL)); if (pmd_quicklist) - free_page((unsigned long)pmd_alloc_one_fast(0, 0)); + free_page((unsigned long)pmd_alloc_one_fast(NULL, 0)); } while (pgtable_cache_size > (u64) low); } preempt_enable(); @@ -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; @@ -458,9 +460,9 @@ ia64_pfn_valid (unsigned long pfn) char byte; struct page *pg = pfn_to_page(pfn); - return (__get_user(byte, (char *) pg) == 0) + return (__get_user(byte, (char __user *) pg) == 0) && ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK)) - || (__get_user(byte, (char *) (pg + 1) - 1) == 0)); + || (__get_user(byte, (char __user *) (pg + 1) - 1) == 0)); } EXPORT_SYMBOL(ia64_pfn_valid); @@ -585,6 +587,6 @@ mem_init (void) setup_gate(); #ifdef CONFIG_IA32_SUPPORT - ia32_boot_gdt_init(); + ia32_mem_init(); #endif } diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index dc15aa01c..0c5cb3c61 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -176,7 +176,7 @@ ia64_tlb_init (void) if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld;" "defaulting to architected purge page-sizes.\n", status); - purge.mask = 0x115557000; + purge.mask = 0x115557000UL; } purge.max_bits = ia64_fls(purge.mask); diff --git a/arch/ia64/oprofile/Kconfig b/arch/ia64/oprofile/Kconfig index bfac82f3e..56e6f614b 100644 --- a/arch/ia64/oprofile/Kconfig +++ b/arch/ia64/oprofile/Kconfig @@ -16,6 +16,10 @@ config OPROFILE whole system, include the kernel, kernel modules, libraries, and applications. + Due to firmware bugs, you may need to use the "nohalt" boot + option if you're using OProfile with the hardware performance + counters. + If unsure, say N. endmenu diff --git a/arch/ia64/oprofile/Makefile b/arch/ia64/oprofile/Makefile index 06e7c81ea..29aeef4f6 100644 --- a/arch/ia64/oprofile/Makefile +++ b/arch/ia64/oprofile/Makefile @@ -7,3 +7,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ timer_int.o ) oprofile-y := $(DRIVER_OBJS) init.o +oprofile-$(CONFIG_PERFMON) += perfmon.o diff --git a/arch/ia64/oprofile/init.c b/arch/ia64/oprofile/init.c index 558561d6d..6d0c132b0 100644 --- a/arch/ia64/oprofile/init.c +++ b/arch/ia64/oprofile/init.c @@ -12,14 +12,21 @@ #include #include -extern void timer_init(struct oprofile_operations ** ops); +extern int perfmon_init(struct oprofile_operations ** ops); +extern void perfmon_exit(void); int __init oprofile_arch_init(struct oprofile_operations ** ops) { +#ifdef CONFIG_PERFMON + return perfmon_init(ops); +#endif return -ENODEV; } void oprofile_arch_exit(void) { +#ifdef CONFIG_PERFMON + perfmon_exit(); +#endif } diff --git a/arch/ia64/oprofile/perfmon.c b/arch/ia64/oprofile/perfmon.c new file mode 100644 index 000000000..bfc82ccf5 --- /dev/null +++ b/arch/ia64/oprofile/perfmon.c @@ -0,0 +1,105 @@ +/** + * @file perfmon.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include +#include + +static int allow_ints; + +static int +perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, + struct pt_regs *regs, unsigned long stamp) +{ + int cpu = smp_processor_id(); + unsigned long eip = instruction_pointer(regs); + int event = arg->pmd_eventid; + + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; + + /* the owner of the oprofile event buffer may have exited + * without perfmon being shutdown (e.g. SIGSEGV) + */ + if (allow_ints) + oprofile_add_sample(eip, !user_mode(regs), event, cpu); + return 0; +} + + +static int perfmon_start(void) +{ + allow_ints = 1; + return 0; +} + + +static void perfmon_stop(void) +{ + allow_ints = 0; +} + + +#define OPROFILE_FMT_UUID { \ + 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } + +static pfm_buffer_fmt_t oprofile_fmt = { + .fmt_name = "oprofile_format", + .fmt_uuid = OPROFILE_FMT_UUID, + .fmt_handler = perfmon_handler, +}; + + +static char * get_cpu_type(void) +{ + __u8 family = local_cpu_data->family; + + switch (family) { + case 0x07: + return "ia64/itanium"; + case 0x1f: + return "ia64/itanium2"; + default: + return "ia64/ia64"; + } +} + + +/* all the ops are handled via userspace for IA64 perfmon */ +static struct oprofile_operations perfmon_ops = { + .start = perfmon_start, + .stop = perfmon_stop, +}; + +static int using_perfmon; + +int perfmon_init(struct oprofile_operations ** ops) +{ + int ret = pfm_register_buffer_fmt(&oprofile_fmt); + if (ret) + return -ENODEV; + + perfmon_ops.cpu_type = get_cpu_type(); + *ops = &perfmon_ops; + using_perfmon = 1; + printk(KERN_INFO "oprofile: using perfmon.\n"); + return 0; +} + + +void perfmon_exit(void) +{ + if (!using_perfmon) + return; + + pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); +} diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 82204f1bd..dd33eaf87 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -46,8 +46,6 @@ #define DBG(x...) #endif -struct pci_fixup pcibios_fixups[1]; - /* * Low-level SAL-based PCI configuration access functions. Note that SAL * calls are already serialized (via sal_lock), so we don't need another @@ -138,6 +136,11 @@ pci_acpi_init (void) printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); +#ifdef CONFIG_NUMA +extern acpi_status acpi_map_iosapic (acpi_handle, u32, void*, void**); + + acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL); +#endif /* * PCI IRQ routing is set up by pci_enable_device(), but we * also do it here in case there are still broken drivers that @@ -332,7 +335,7 @@ pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus) struct pci_window *window; int i, j; int limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? \ - PCI_ROM_RESOURCE : PCI_NUM_RESOURCES; + PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; for (i = 0; i < limit; i++) { if (!dev->resource[i].start) diff --git a/arch/ia64/sn/io/hwgfs/interface.c b/arch/ia64/sn/io/hwgfs/interface.c index caac7f067..4e1941805 100644 --- a/arch/ia64/sn/io/hwgfs/interface.c +++ b/arch/ia64/sn/io/hwgfs/interface.c @@ -42,7 +42,7 @@ walk_parents_mkdir( nd->dentry = lookup_create(nd, is_dir); nd->flags |= LOOKUP_PARENT; - if (unlikely(IS_ERR(nd->dentry))) + if (IS_ERR(nd->dentry)) return PTR_ERR(nd->dentry); if (!nd->dentry->d_inode) @@ -89,7 +89,7 @@ hwgfs_decode( *dentry = lookup_create(&nd, is_dir); - if (unlikely(IS_ERR(*dentry))) + if (IS_ERR(*dentry)) return PTR_ERR(*dentry); *parent_inode = (*dentry)->d_parent->d_inode; return 0; diff --git a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c index ba9e42c12..cb91a4d07 100644 --- a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c +++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c @@ -290,6 +290,7 @@ sn_pci_fixup_slot(struct pci_dev *dev) addr |= __IA64_UNCACHED_OFFSET; dev->resource[idx].start = addr; dev->resource[idx].end = addr + size; + dev->resource[idx].parent = &ioport_resource; } if (dev->resource[idx].flags & IORESOURCE_IO) @@ -322,6 +323,7 @@ sn_pci_fixup_slot(struct pci_dev *dev) addr |= __IA64_UNCACHED_OFFSET; dev->resource[idx].start = addr; dev->resource[idx].end = addr + size; + dev->resource[idx].parent = &iomem_resource; } if (dev->resource[idx].flags & IORESOURCE_MEM) @@ -351,10 +353,24 @@ sn_pci_fixup_slot(struct pci_dev *dev) addr |= __IA64_UNCACHED_OFFSET; dev->resource[PCI_ROM_RESOURCE].start = addr; dev->resource[PCI_ROM_RESOURCE].end = addr + size; + dev->resource[idx].parent = &iomem_resource; if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } - } + } else { + /* + * Remove other ROM resources since they don't have valid + * CPU addresses. + */ + size = dev->resource[PCI_ROM_RESOURCE].end - + dev->resource[PCI_ROM_RESOURCE].start; + + if (size) { + dev->resource[PCI_ROM_RESOURCE].start = 0; + dev->resource[PCI_ROM_RESOURCE].end = 0; + dev->resource[PCI_ROM_RESOURCE].flags = 0; + } + } /* * Update the Command Word on the Card. diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index e040fc3c4..94a99eeb1 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c @@ -421,9 +421,10 @@ bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda; for (i = 0; i < BTES_PER_NODE; i++) { - (u64) mynodepda->bte_if[i].bte_base_addr = - REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), - (i == 0 ? IIO_IBLS0 : IIO_IBLS1)); + /* Which link status register should we use? */ + unsigned long link_status = (i == 0 ? IIO_IBLS0 : IIO_IBLS1); + mynodepda->bte_if[i].bte_base_addr = (u64 *) + REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), link_status); /* * Initialize the notification and spinlock diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index d3830e338..4a0aa40c4 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -64,6 +64,8 @@ extern unsigned char acpi_kbd_controller_present; unsigned long sn_rtc_cycles_per_second; +EXPORT_SYMBOL(sn_rtc_cycles_per_second); + partid_t sn_partid = -1; char sn_system_serial_number_string[128]; u64 sn_partition_serial_number; diff --git a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile index 0143b8182..170bde454 100644 --- a/arch/ia64/sn/kernel/sn2/Makefile +++ b/arch/ia64/sn/kernel/sn2/Makefile @@ -10,4 +10,4 @@ # obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \ - prominfo_proc.o timer.o timer_interrupt.o + prominfo_proc.o timer.o timer_interrupt.o sn_hwperf.o diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c index bcc938b28..32db72ae7 100644 --- a/arch/ia64/sn/kernel/sn2/prominfo_proc.c +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c @@ -3,10 +3,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1999,2001-2004 Silicon Graphics, Inc. All Rights Reserved. * * Module to export the system's Firmware Interface Tables, including - * PROM revision numbers, in /proc + * PROM revision numbers and banners, in /proc */ #include #include @@ -14,41 +14,14 @@ #include #include #include -#include -#include - -/* to lookup nasids */ +#include #include +#include MODULE_DESCRIPTION("PROM version reporting for /proc"); MODULE_AUTHOR("Chad Talbott"); MODULE_LICENSE("GPL"); -#undef DEBUG_PROMINFO - -#define TRACE_PROMINFO - -#if defined(DEBUG_PROMINFO) -# define DPRINTK(x...) printk(KERN_DEBUG x) -#else -# define DPRINTK(x...) -#endif - -#if defined(TRACE_PROMINFO) && defined(DEBUG_PROMINFO) -# if defined(__GNUC__) -# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ - __FILE__, __LINE__, __FUNCTION__) -# else -# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) -# endif -#else -# define TRACE() -#endif - -/* Sub-regions determined by bits in Node Offset */ -#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ - -#define FIT_SIGNATURE 0x2020205f5449465ful /* Standard Intel FIT entry types */ #define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */ #define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */ @@ -81,12 +54,6 @@ MODULE_LICENSE("GPL"); #define FIT_TYPE(q) \ ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK) -#define FIT_ENTRY(type, maj, min, size) \ - ((((unsigned long)(maj) & FIT_MAJOR_MASK) << FIT_MAJOR_SHIFT) | \ - (((unsigned long)(min) & FIT_MINOR_MASK) << FIT_MINOR_SHIFT) | \ - (((unsigned long)(type) & FIT_TYPE_MASK) << FIT_TYPE_SHIFT) | \ - (size)) - struct fit_type_map_t { unsigned char type; const char *name; @@ -125,32 +92,148 @@ fit_type_name(unsigned char type) return "Unknown type"; } -/* These two routines read the FIT table directly from the FLASH PROM - * on a specific node. The PROM can only be accessed using aligned 64 - * bit reads, so we do that and then shift and mask the result to get - * at each field. + +/* ============ BEGIN temp til old PROMs are no longer supported ============= + * + * The OS should not make direct access to the PROM flash memory. Access to + * this region must be serialized with a PROM lock. If SAL on one cpu is + * updating the FLASH error log at the same time another cpu is accessing the + * PROM, data corruption will occur. + * + * To solve the problem, all flash PROM access has been moved to SAL. Because + * not all systems will have instant PROM updates, we need to support a new OS + * running on a system with old PROMs. + * + * This code should be deleted after 1 OS/PROM release has occurred & the OS + * no longer supports downrev PROMs. (PROM support should be in the 3.50 + * PROMs). + */ +#define SUPPORT_OLD_PROMS +#ifdef SUPPORT_OLD_PROMS + + +#define FIT_SIGNATURE 0x2020205f5449465ful + +/* Sub-regions determined by bits in Node Offset */ +#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ + +/* Offset of PROM banner pointers in SAL A and SAL B */ +#define SAL_A_BANNER_OFFSET (1 * 16) +#define SAL_B_BANNER_OFFSET (3 * 16) + +/* Architected IA64 firmware space */ +#define FW_BASE 0x00000000FF000000 +#define FW_TOP 0x0000000100000000 + +static unsigned long +convert_fw_addr(nasid_t nasid, unsigned long addr) +{ + /* snag just the node-relative offset */ + addr &= ~0ul >> (63-35); + /* the pointer to SAL A is relative to IA-64 compatibility + * space. However, the PROM is mapped at a different offset + * in MMR space (both local and global) + */ + addr += 0x700000000; + return GLOBAL_MMR_ADDR(nasid, addr); +} + +static int +valid_fw_addr(unsigned long addr) +{ + addr &= ~(1ul << 63); /* Clear cached/uncached bit */ + return (addr >= FW_BASE && addr < FW_TOP); +} + +static unsigned long * +lookup_fit(int nasid) +{ + unsigned long *fitp; + unsigned long fit_paddr; + unsigned long *fit_vaddr; + + fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); + fit_paddr = readq(fitp); + fit_vaddr = (unsigned long *) convert_fw_addr(nasid, fit_paddr); + return fit_vaddr; +} +#endif /* SUPPORT_OLD_PROMS */ +/* ============ END temp til old PROMs are no longer supported ============= */ + +static int +get_fit_entry(unsigned long nasid, int index, unsigned long *fentry, + char *banner, int banlen) +{ + int ret; + + ret = ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen); + +#ifdef SUPPORT_OLD_PROMS + /* The following is hack is temporary until PROMs are updated */ + if (ret == SALRET_NOT_IMPLEMENTED) { + unsigned long *fitadr = lookup_fit(nasid); + int nentries; + + if (readq(fitadr) != FIT_SIGNATURE) { + printk(KERN_WARNING "Unrecognized FIT signature"); + return -2; + } + + nentries = (unsigned int) (readq(fitadr + 1) & 0xffffff); + if (index >= nentries) + return -2; + + fentry[0] = readq(fitadr + 2 * index); + fentry[1] = readq(fitadr + 2 * index + 1); + ret = 0; + + if (banner && FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A) { + unsigned long i, qw, *bwp, *qwp; + + banner[0] = '\0'; + qw = fentry[0]; /* Address of SAL A */ + if (!valid_fw_addr(qw)) + return 0; + + qw += SAL_A_BANNER_OFFSET; + qw = convert_fw_addr(nasid, qw); + + qw = readq(qw); /* Address of banner */ + if (!valid_fw_addr(qw)) + return 0; + qw = convert_fw_addr(nasid, qw); + qwp = (unsigned long *) qw; + bwp = (unsigned long *) banner; + for (i=0; i PAGE_SIZE); - p = page; - for (fentry = 0; fentry < nentries; fentry++) - /* each FIT entry is two 64 bit words */ - p += dump_fit_entry(p, fit + 2 * fentry); + for (index=0;;index++) { + BUG_ON(index * 60 > PAGE_SIZE); + if (get_fit_entry(nasid, index, fentry, NULL, 0)) + break; + p += dump_fit_entry(p, fentry); + } return p - page; } static int -dump_version(char *page, unsigned long *fit) +dump_version(char *page, unsigned long nasid) { - int nentries; - int fentry; - unsigned long qw; + unsigned long fentry[2]; + char banner[128]; + int index; + int len; + + for (index = 0; ; index++) { + if (get_fit_entry(nasid, index, fentry, banner, + sizeof(banner))) + return 0; + if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A) + break; + } - TRACE(); + len = sprintf(page, "%x.%02x\n", FIT_MAJOR(fentry[1]), + FIT_MINOR(fentry[1])); + page += len; - nentries = (unsigned)readq(fit + 1); - BUG_ON(nentries * 60 > PAGE_SIZE); + if (banner[0]) + len += snprintf(page, PAGE_SIZE-len, "%s\n", banner); - for (fentry = 0; fentry < nentries; fentry++) { - qw = readq(fit + 2 * fentry + 1); - if (FIT_TYPE(qw) == FIT_ENTRY_SAL_A) - return sprintf(page, "%x.%02x\n", - FIT_MAJOR(qw), FIT_MINOR(qw)); - } - return 0; + return len; } /* same as in proc_misc.c */ @@ -228,8 +303,8 @@ read_version_entry(char *page, char **start, off_t off, int count, int *eof, { int len = 0; - /* data holds the pointer to this node's FIT */ - len = dump_version(page, (unsigned long *)data); + /* data holds the NASID of the node */ + len = dump_version(page, (unsigned long)data); len = proc_calc_metrics(page, start, off, count, eof, len); return len; } @@ -240,56 +315,13 @@ read_fit_entry(char *page, char **start, off_t off, int count, int *eof, { int len = 0; - /* data holds the pointer to this node's FIT */ - len = dump_fit(page, (unsigned long *)data); + /* data holds the NASID of the node */ + len = dump_fit(page, (unsigned long)data); len = proc_calc_metrics(page, start, off, count, eof, len); return len; } -/* this is a fake FIT that's used on the medusa simulator which - * doesn't usually run a complete PROM. - */ -#ifdef CONFIG_IA64_SGI_SN_SIM -static unsigned long fakefit[] = { - /* this is all we need to satisfy the code below */ - FIT_SIGNATURE, - FIT_ENTRY(FIT_ENTRY_FIT_HEADER, 0x02, 0x60, 2), - /* dump something arbitrary for - * /proc/sgi_prominfo/nodeX/version */ - 0xbadbeef00fa3ef17ul, - FIT_ENTRY(FIT_ENTRY_SAL_A, 0, 0x99, 0x100) -}; -#endif - -static unsigned long * -lookup_fit(int nasid) -{ - unsigned long *fitp; - unsigned long fit_paddr; - unsigned long *fit_vaddr; - -#ifdef CONFIG_IA64_SGI_SN_SIM - if (IS_RUNNING_ON_SIMULATOR()) - return fakefit; -#endif - - fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); - DPRINTK("pointer to fit at %p\n", (void *)fitp); - fit_paddr = readq(fitp); - DPRINTK("fit pointer contains %lx\n", fit_paddr); - /* snag just the node-relative offset */ - fit_paddr &= ~0ul >> (63-35); - /* the pointer to the FIT is relative to IA-64 compatibility - * space. However, the PROM is mapped at a different offset - * in MMR space (both local and global) - */ - fit_paddr += 0x700000000; - fit_vaddr = (void *)GLOBAL_MMR_ADDR(nasid, fit_paddr); - DPRINTK("fit at %p\n", (void *)fit_vaddr); - return fit_vaddr; -} - /* module entry points */ int __init prominfo_init(void); void __exit prominfo_exit(void); @@ -308,17 +340,12 @@ prominfo_init(void) struct proc_dir_entry **entp; struct proc_dir_entry *p; cnodeid_t cnodeid; - nasid_t nasid; + unsigned long nasid; char name[NODE_NAME_LEN]; if (!ia64_platform_is("sn2")) return 0; - TRACE(); - - DPRINTK("running on cpu %d\n", smp_processor_id()); - DPRINTK("numnodes %d\n", numnodes); - proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *), GFP_KERNEL); @@ -332,12 +359,12 @@ prominfo_init(void) nasid = cnodeid_to_nasid(cnodeid); p = create_proc_read_entry( "fit", 0, *entp, read_fit_entry, - lookup_fit(nasid)); + (void *)nasid); if (p) p->owner = THIS_MODULE; p = create_proc_read_entry( "version", 0, *entp, read_version_entry, - lookup_fit(nasid)); + (void *)nasid); if (p) p->owner = THIS_MODULE; } @@ -352,8 +379,6 @@ prominfo_exit(void) unsigned cnodeid; char name[NODE_NAME_LEN]; - TRACE(); - for (cnodeid = 0, entp = proc_entries; cnodeid < numnodes; cnodeid++, entp++) { diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c new file mode 100644 index 000000000..8a810d339 --- /dev/null +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -0,0 +1,652 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + * + * SGI Altix topology and hardware performance monitoring API. + * Mark Goodwin . + * + * Creates /proc/sgi_sn/sn_topology (read-only) to export + * info about Altix nodes, routers, CPUs and NumaLink + * interconnection/topology. + * + * Also creates a dynamic misc device named "sn_hwperf" + * that supports an ioctl interface to call down into SAL + * to discover hw objects, topology and to read/write + * memory mapped registers, e.g. for performance monitoring. + * The "sn_hwperf" device is registered only after the procfs + * file is first opened, i.e. only if/when it's needed. + * + * This API is used by SGI Performance Co-Pilot and other + * tools, see http://oss.sgi.com/projects/pcp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void *sn_hwperf_salheap = NULL; +static int sn_hwperf_obj_cnt = 0; +static nasid_t sn_hwperf_master_nasid = INVALID_NASID; +static int sn_hwperf_init(void); +static DECLARE_MUTEX(sn_hwperf_init_mutex); + +static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) +{ + int e; + u64 sz; + struct sn_hwperf_object_info *objbuf = NULL; + + if ((e = sn_hwperf_init()) < 0) { + printk("sn_hwperf_init failed: err %d\n", e); + goto out; + } + + sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info); + if ((objbuf = (struct sn_hwperf_object_info *) vmalloc(sz)) == NULL) { + printk("sn_hwperf_enum_objects: vmalloc(%d) failed\n", (int)sz); + e = -ENOMEM; + goto out; + } + + e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, SN_HWPERF_ENUM_OBJECTS, + 0, sz, (u64) objbuf, 0, 0, NULL); + if (e != SN_HWPERF_OP_OK) { + e = -EINVAL; + vfree(objbuf); + } + +out: + *nobj = sn_hwperf_obj_cnt; + *ret = objbuf; + return e; +} + +static int sn_hwperf_geoid_to_cnode(char *location) +{ + int cnode; + int mod, slot, slab; + int cmod, cslot, cslab; + + if (sscanf(location, "%03dc%02d#%d", &mod, &slot, &slab) != 3) + return -1; + for (cnode = 0; cnode < numnodes; cnode++) { + /* XXX: need a better way than this ... */ + if (sscanf(NODEPDA(cnode)->hwg_node_name, + "hw/module/%03dc%02d/slab/%d", &cmod, &cslot, &cslab) == 3) { + if (mod == cmod && slot == cslot && slab == cslab) + break; + } + } + + return cnode < numnodes ? cnode : -1; +} + +static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) +{ + if (!obj->sn_hwp_this_part) + return -1; + return sn_hwperf_geoid_to_cnode(obj->location); +} + +static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj, + struct sn_hwperf_object_info *objs) +{ + int ordinal; + struct sn_hwperf_object_info *p; + + for (ordinal=0, p=objs; p != obj; p++) { + if (SN_HWPERF_FOREIGN(p)) + continue; + if (p->location[3] == obj->location[3]) + ordinal++; + } + + return ordinal; +} + +#ifndef MODULE_IOBRICK +/* this will be available when ioif TIO support is added */ +#define MODULE_IOBRICK (MODULE_OPUSBRICK+1) +#endif + +static const char *sn_hwperf_get_brickname(struct sn_hwperf_object_info *obj, + struct sn_hwperf_object_info *objs, int *ordinal) +{ + int i; + const char *objtype = NULL; + + for (i=0; i < MAX_BRICK_TYPES; i++) { + if (brick_types[i] != obj->location[3]) + continue; + switch (i) { + case MODULE_CBRICK: + objtype = "node"; + *ordinal = sn_hwperf_obj_to_cnode(obj); /* cnodeid */ + break; + + case MODULE_RBRICK: + objtype = "router"; + *ordinal = sn_hwperf_generic_ordinal(obj, objs); + break; + + case MODULE_IOBRICK: + objtype = "ionode"; + *ordinal = sn_hwperf_generic_ordinal(obj, objs); + break; + } + break; + } + + if (i == MAX_BRICK_TYPES) { + objtype = "other"; + *ordinal = sn_hwperf_generic_ordinal(obj, objs); + } + + return objtype; +} + +static int sn_topology_show(struct seq_file *s, void *d) +{ + int sz; + int pt; + int e; + int i; + int j; + const char *brickname; + int ordinal; + cpumask_t cpumask; + char slice; + struct cpuinfo_ia64 *c; + struct sn_hwperf_port_info *ptdata; + struct sn_hwperf_object_info *p; + struct sn_hwperf_object_info *obj = d; /* this object */ + struct sn_hwperf_object_info *objs = s->private; /* all objects */ + + if (obj == objs) { + seq_printf(s, "# sn_topology version 1\n"); + seq_printf(s, "# objtype ordinal location partition" + " [attribute value [, ...]]\n"); + } + + if (SN_HWPERF_FOREIGN(obj)) { + /* private in another partition: not interesting */ + return 0; + } + + for (i = 0; obj->name[i]; i++) { + if (obj->name[i] == ' ') + obj->name[i] = '_'; + } + + brickname = sn_hwperf_get_brickname(obj, objs, &ordinal); + seq_printf(s, "%s %d %s %s asic %s", brickname, ordinal, obj->location, + obj->sn_hwp_this_part ? "local" : "shared", obj->name); + + if (obj->location[3] != 'c') + seq_putc(s, '\n'); + else { + seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); + for (i=0; i < numnodes; i++) { + seq_printf(s, i ? ":%d" : ", dist %d", + node_distance(ordinal, i)); + } + seq_putc(s, '\n'); + + /* + * CPUs on this node + */ + cpumask = node_to_cpumask(ordinal); + for_each_online_cpu(i) { + if (cpu_isset(i, cpumask)) { + slice = 'a' + cpuid_to_slice(i); + c = cpu_data(i); + seq_printf(s, "cpu %d %s%c local" + " freq %luMHz, arch ia64", + i, obj->location, slice, + c->proc_freq / 1000000); + for_each_online_cpu(j) { + seq_printf(s, j ? ":%d" : ", dist %d", + node_distance( + cpuid_to_cnodeid(i), + cpuid_to_cnodeid(j))); + } + seq_putc(s, '\n'); + } + } + } + + if (obj->ports) { + /* + * numalink ports + */ + sz = obj->ports * sizeof(struct sn_hwperf_port_info); + if ((ptdata = vmalloc(sz)) == NULL) + return -ENOMEM; + e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + SN_HWPERF_ENUM_PORTS, obj->id, sz, + (u64) ptdata, 0, 0, NULL); + if (e != SN_HWPERF_OP_OK) + return -EINVAL; + for (ordinal=0, p=objs; p != obj; p++) { + if (!SN_HWPERF_FOREIGN(p)) + ordinal += p->ports; + } + for (pt = 0; pt < obj->ports; pt++) { + for (p = objs, i = 0; i < sn_hwperf_obj_cnt; i++, p++) { + if (ptdata[pt].conn_id == p->id) { + break; + } + } + if (i >= sn_hwperf_obj_cnt) + continue; + seq_printf(s, "numalink %d %s-%d", + ordinal+pt, obj->location, ptdata[pt].port); + + if (obj->sn_hwp_this_part && p->sn_hwp_this_part) + /* both ends local to this partition */ + seq_puts(s, " local"); + else if (!obj->sn_hwp_this_part && !p->sn_hwp_this_part) + /* both ends of the link in foreign partiton */ + seq_puts(s, " foreign"); + else + /* link straddles a partition */ + seq_puts(s, " shared"); + + /* + * Unlikely, but strictly should query the LLP config + * registers because an NL4R can be configured to run + * NL3 protocol, even when not talking to an NL3 router. + * Ditto for node-node. + */ + seq_printf(s, " endpoint %s-%d, protocol %s\n", + p->location, ptdata[pt].conn_port, + strcmp(obj->name, "NL3Router") == 0 || + strcmp(p->name, "NL3Router") == 0 ? + "LLP3" : "LLP4"); + } + vfree(ptdata); + } + + return 0; +} + +static void *sn_topology_start(struct seq_file *s, loff_t * pos) +{ + struct sn_hwperf_object_info *objs = s->private; + + if (*pos < sn_hwperf_obj_cnt) + return (void *)(objs + *pos); + + return NULL; +} + +static void *sn_topology_next(struct seq_file *s, void *v, loff_t * pos) +{ + ++*pos; + return sn_topology_start(s, pos); +} + +static void sn_topology_stop(struct seq_file *m, void *v) +{ + return; +} + +/* + * /proc/sgi_sn/sn_topology, read-only using seq_file + */ +static struct seq_operations sn_topology_seq_ops = { + .start = sn_topology_start, + .next = sn_topology_next, + .stop = sn_topology_stop, + .show = sn_topology_show +}; + +struct sn_hwperf_op_info { + u64 op; + struct sn_hwperf_ioctl_args *a; + void *p; + int *v0; + int ret; +}; + +static void sn_hwperf_call_sal(void *info) +{ + struct sn_hwperf_op_info *op_info = info; + int r; + + r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op_info->op, + op_info->a->arg, op_info->a->sz, + (u64) op_info->p, 0, 0, op_info->v0); + op_info->ret = r; +} + +static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info) +{ + u32 cpu; + u32 use_ipi; + int r = 0; + cpumask_t save_allowed; + + cpu = (op_info->a->arg & SN_HWPERF_ARG_CPU_MASK) >> 32; + use_ipi = op_info->a->arg & SN_HWPERF_ARG_USE_IPI_MASK; + op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK; + + if (cpu != SN_HWPERF_ARG_ANY_CPU) { + if (cpu >= num_online_cpus() || !cpu_online(cpu)) { + r = -EINVAL; + goto out; + } + } + + if (cpu == SN_HWPERF_ARG_ANY_CPU || cpu == get_cpu()) { + /* don't care, or already on correct cpu */ + sn_hwperf_call_sal(op_info); + } + else { + if (use_ipi) { + /* use an interprocessor interrupt to call SAL */ + smp_call_function_single(cpu, sn_hwperf_call_sal, + op_info, 1, 1); + } + else { + /* migrate the task before calling SAL */ + save_allowed = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + sn_hwperf_call_sal(op_info); + set_cpus_allowed(current, save_allowed); + } + } + r = op_info->ret; + +out: + return r; +} + +/* + * ioctl for "sn_hwperf" misc device + */ +static int +sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) +{ + struct sn_hwperf_ioctl_args a; + struct cpuinfo_ia64 *cdata; + struct sn_hwperf_object_info *objs; + struct sn_hwperf_object_info *cpuobj; + struct sn_hwperf_op_info op_info; + void *p = NULL; + int nobj; + char slice; + int node; + int r; + int v0; + int i; + int j; + + unlock_kernel(); + + /* only user requests are allowed here */ + if ((op & SN_HWPERF_OP_MASK) < 10) { + r = -EINVAL; + goto error; + } + r = copy_from_user(&a, (const void *)arg, + sizeof(struct sn_hwperf_ioctl_args)); + if (r != 0) { + r = -EFAULT; + goto error; + } + + /* + * Allocate memory to hold a kernel copy of the user buffer. The + * buffer contents are either copied in or out (or both) of user + * space depending on the flags encoded in the requested operation. + */ + if (a.ptr) { + p = vmalloc(a.sz); + if (!p) { + r = -ENOMEM; + goto error; + } + } + + if (op & SN_HWPERF_OP_MEM_COPYIN) { + r = copy_from_user(p, (const void *)a.ptr, a.sz); + if (r != 0) { + r = -EFAULT; + goto error; + } + } + + switch (op) { + case SN_HWPERF_GET_CPU_INFO: + if (a.sz == sizeof(u64)) { + /* special case to get size needed */ + *(u64 *) p = (u64) num_online_cpus() * + sizeof(struct sn_hwperf_object_info); + } else + if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) { + r = -ENOMEM; + goto error; + } else + if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { + memset(p, 0, a.sz); + for (i = 0; i < nobj; i++) { + node = sn_hwperf_obj_to_cnode(objs + i); + for_each_online_cpu(j) { + if (node != cpu_to_node(j)) + continue; + cpuobj = (struct sn_hwperf_object_info *) p + j; + slice = 'a' + cpuid_to_slice(j); + cdata = cpu_data(j); + cpuobj->id = j; + snprintf(cpuobj->name, + sizeof(cpuobj->name), + "CPU %luMHz %s", + cdata->proc_freq / 1000000, + cdata->vendor); + snprintf(cpuobj->location, + sizeof(cpuobj->location), + "%s%c", objs[i].location, + slice); + } + } + + vfree(objs); + } + break; + + case SN_HWPERF_GET_NODE_NASID: + if (a.sz != sizeof(u64) || + (node = a.arg) < 0 || node >= numnodes) { + r = -EINVAL; + goto error; + } + *(u64 *)p = (u64)cnodeid_to_nasid(node); + break; + + case SN_HWPERF_GET_OBJ_NODE: + if (a.sz != sizeof(u64) || a.arg < 0) { + r = -EINVAL; + goto error; + } + if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { + if (a.arg >= nobj) { + r = -EINVAL; + vfree(objs); + goto error; + } + if (objs[(i = a.arg)].id != a.arg) { + for (i = 0; i < nobj; i++) { + if (objs[i].id == a.arg) + break; + } + } + if (i == nobj) { + r = -EINVAL; + vfree(objs); + goto error; + } + *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); + vfree(objs); + } + break; + + case SN_HWPERF_GET_MMRS: + case SN_HWPERF_SET_MMRS: + case SN_HWPERF_OBJECT_DISTANCE: + op_info.p = p; + op_info.a = &a; + op_info.v0 = &v0; + op_info.op = op; + r = sn_hwperf_op_cpu(&op_info); + break; + + default: + /* all other ops are a direct SAL call */ + r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op, + a.arg, a.sz, (u64) p, 0, 0, &v0); + a.v0 = v0; + break; + } + + if (op & SN_HWPERF_OP_MEM_COPYOUT) { + r = copy_to_user((void *)a.ptr, p, a.sz); + if (r != 0) { + r = -EFAULT; + goto error; + } + } + +error: + if (p) + vfree(p); + + lock_kernel(); + return r; +} + +static struct file_operations sn_hwperf_fops = { + .ioctl = sn_hwperf_ioctl, +}; + +static struct miscdevice sn_hwperf_dev = { + MISC_DYNAMIC_MINOR, + "sn_hwperf", + &sn_hwperf_fops +}; + +static int sn_hwperf_init(void) +{ + u64 v; + int salr; + int e = 0; + + /* single threaded, once-only initialization */ + down(&sn_hwperf_init_mutex); + if (sn_hwperf_salheap) { + up(&sn_hwperf_init_mutex); + return e; + } + + /* + * The PROM code needs a fixed reference node. For convenience the + * same node as the console I/O is used. + */ + sn_hwperf_master_nasid = (nasid_t) ia64_sn_get_console_nasid(); + + /* + * Request the needed size and install the PROM scratch area. + * The PROM keeps various tracking bits in this memory area. + */ + salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + (u64) SN_HWPERF_GET_HEAPSIZE, 0, + (u64) sizeof(u64), (u64) &v, 0, 0, NULL); + if (salr != SN_HWPERF_OP_OK) { + e = -EINVAL; + goto out; + } + + if ((sn_hwperf_salheap = vmalloc(v)) == NULL) { + e = -ENOMEM; + goto out; + } + salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + SN_HWPERF_INSTALL_HEAP, 0, v, + (u64) sn_hwperf_salheap, 0, 0, NULL); + if (salr != SN_HWPERF_OP_OK) { + e = -EINVAL; + goto out; + } + + salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, + SN_HWPERF_OBJECT_COUNT, 0, + sizeof(u64), (u64) &v, 0, 0, NULL); + if (salr != SN_HWPERF_OP_OK) { + e = -EINVAL; + goto out; + } + sn_hwperf_obj_cnt = (int)v; + +out: + if (e < 0 && sn_hwperf_salheap) { + vfree(sn_hwperf_salheap); + sn_hwperf_salheap = NULL; + sn_hwperf_obj_cnt = 0; + } + + if (!e) { + /* + * Register a dynamic misc device for ioctl. Platforms + * supporting hotplug will create /dev/sn_hwperf, else + * user can to look up the minor number in /proc/misc. + */ + if ((e = misc_register(&sn_hwperf_dev)) != 0) { + printk(KERN_ERR "sn_hwperf_init: misc register " + "for \"sn_hwperf\" failed, err %d\n", e); + } + } + + up(&sn_hwperf_init_mutex); + return e; +} + +int sn_topology_open(struct inode *inode, struct file *file) +{ + int e; + struct seq_file *seq; + struct sn_hwperf_object_info *objbuf; + int nobj; + + if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) { + e = seq_open(file, &sn_topology_seq_ops); + seq = file->private_data; + seq->private = objbuf; + } + + return e; +} + +int sn_topology_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + + if (seq->private) + vfree(seq->private); + return seq_release(inode, file); +} diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 14840791a..55c1065e9 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c @@ -3,74 +3,48 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. */ #include #include #ifdef CONFIG_PROC_FS #include +#include #include #include - -static int partition_id_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - - return sprintf(page, "%d\n", sn_local_partid()); +static int partition_id_show(struct seq_file *s, void *p) +{ + seq_printf(s, "%d\n", sn_local_partid()); + return 0; } -static struct proc_dir_entry * sgi_proc_dir; - -void -register_sn_partition_id(void) { - struct proc_dir_entry *entry; - - if (!sgi_proc_dir) { - sgi_proc_dir = proc_mkdir("sgi_sn", 0); - } - entry = create_proc_entry("partition_id", 0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = partition_id_read_proc; - entry->write_proc = NULL; - } +static int partition_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, partition_id_show, NULL); } -static int -system_serial_number_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - return sprintf(page, "%s\n", sn_system_serial_number()); +static int system_serial_number_show(struct seq_file *s, void *p) +{ + seq_printf(s, "%s\n", sn_system_serial_number()); + return 0; } -static int -licenseID_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - return sprintf(page, "0x%lx\n",sn_partition_serial_number_val()); +static int system_serial_number_open(struct inode *inode, struct file *file) +{ + return single_open(file, system_serial_number_show, NULL); } -void -register_sn_serial_numbers(void) { - struct proc_dir_entry *entry; +static int licenseID_show(struct seq_file *s, void *p) +{ + seq_printf(s, "0x%lx\n", sn_partition_serial_number_val()); + return 0; +} - if (!sgi_proc_dir) { - sgi_proc_dir = proc_mkdir("sgi_sn", 0); - } - entry = create_proc_entry("system_serial_number", 0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = system_serial_number_read_proc; - entry->write_proc = NULL; - } - entry = create_proc_entry("licenseID", 0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = licenseID_read_proc; - entry->write_proc = NULL; - } +static int licenseID_open(struct inode *inode, struct file *file) +{ + return single_open(file, licenseID_show, NULL); } /* @@ -81,48 +55,90 @@ register_sn_serial_numbers(void) { */ int sn_force_interrupt_flag = 1; -static int -sn_force_interrupt_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) { - if (sn_force_interrupt_flag) { - return sprintf(page, "Force interrupt is enabled\n"); - } - return sprintf(page, "Force interrupt is disabled\n"); +static int sn_force_interrupt_show(struct seq_file *s, void *p) +{ + seq_printf(s, "Force interrupt is %s\n", + sn_force_interrupt_flag ? "enabled" : "disabled"); + return 0; } -static int -sn_force_interrupt_write_proc(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t sn_force_interrupt_write_proc(struct file *file, + const __user char *buffer, size_t count, loff_t *data) { - if (*buffer == '0') { - sn_force_interrupt_flag = 0; - } else { - sn_force_interrupt_flag = 1; - } - return 1; + sn_force_interrupt_flag = (*buffer == '0') ? 0 : 1; + return count; } -void -register_sn_force_interrupt(void) { - struct proc_dir_entry *entry; +static int sn_force_interrupt_open(struct inode *inode, struct file *file) +{ + return single_open(file, sn_force_interrupt_show, NULL); +} - if (!sgi_proc_dir) { - sgi_proc_dir = proc_mkdir("sgi_sn", 0); - } - entry = create_proc_entry("sn_force_interrupt",0444, sgi_proc_dir); - if (entry) { - entry->nlink = 1; - entry->data = 0; - entry->read_proc = sn_force_interrupt_read_proc; - entry->write_proc = sn_force_interrupt_write_proc; +static int coherence_id_show(struct seq_file *s, void *p) +{ + seq_printf(s, "%d\n", cpuid_to_coherence_id(smp_processor_id())); + return 0; +} + +static int coherence_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, coherence_id_show, NULL); +} + +static struct proc_dir_entry *sn_procfs_create_entry( + const char *name, struct proc_dir_entry *parent, + int (*openfunc)(struct inode *, struct file *), + int (*releasefunc)(struct inode *, struct file *)) +{ + struct proc_dir_entry *e = create_proc_entry(name, 0444, parent); + + if (e) { + e->proc_fops = (struct file_operations *)kmalloc( + sizeof(struct file_operations), GFP_KERNEL); + if (e->proc_fops) { + memset(e->proc_fops, 0, sizeof(struct file_operations)); + e->proc_fops->open = openfunc; + e->proc_fops->read = seq_read; + e->proc_fops->llseek = seq_lseek; + e->proc_fops->release = releasefunc; + } } + + return e; } -void -register_sn_procfs(void) { - register_sn_partition_id(); - register_sn_serial_numbers(); - register_sn_force_interrupt(); +/* /proc/sgi_sn/sn_topology uses seq_file, see sn_hwperf.c */ +extern int sn_topology_open(struct inode *, struct file *); +extern int sn_topology_release(struct inode *, struct file *); + +void register_sn_procfs(void) +{ + static struct proc_dir_entry *sgi_proc_dir = NULL; + struct proc_dir_entry *e; + + BUG_ON(sgi_proc_dir != NULL); + if (!(sgi_proc_dir = proc_mkdir("sgi_sn", 0))) + return; + + sn_procfs_create_entry("partition_id", sgi_proc_dir, + partition_id_open, single_release); + + sn_procfs_create_entry("system_serial_number", sgi_proc_dir, + system_serial_number_open, single_release); + + sn_procfs_create_entry("licenseID", sgi_proc_dir, + licenseID_open, single_release); + + e = sn_procfs_create_entry("sn_force_interrupt", sgi_proc_dir, + sn_force_interrupt_open, single_release); + if (e) + e->proc_fops->write = sn_force_interrupt_write_proc; + + sn_procfs_create_entry("coherence_id", sgi_proc_dir, + coherence_id_open, single_release); + + sn_procfs_create_entry("sn_topology", sgi_proc_dir, + sn_topology_open, sn_topology_release); } #endif /* CONFIG_PROC_FS */ diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c index 57844feea..85f7d215a 100644 --- a/arch/ia64/sn/kernel/sn2/timer.c +++ b/arch/ia64/sn/kernel/sn2/timer.c @@ -20,57 +20,16 @@ extern unsigned long sn_rtc_cycles_per_second; -static volatile unsigned long last_wall_rtc; -static unsigned long rtc_offset; /* updated only when xtime write-lock is held! */ -static long rtc_nsecs_per_cycle; -static long rtc_per_timer_tick; - -static unsigned long -getoffset(void) -{ - return rtc_offset + (GET_RTC_COUNTER() - last_wall_rtc)*rtc_nsecs_per_cycle; -} - - -static void -update(long delta_nsec) -{ - unsigned long rtc_counter = GET_RTC_COUNTER(); - unsigned long offset = rtc_offset + (rtc_counter - last_wall_rtc)*rtc_nsecs_per_cycle; - - /* Be careful about signed/unsigned comparisons here: */ - if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) - rtc_offset = offset - delta_nsec; - else - rtc_offset = 0; - last_wall_rtc = rtc_counter; -} - - -static void -reset(void) -{ - rtc_offset = 0; - last_wall_rtc = GET_RTC_COUNTER(); -} - - -static struct time_interpolator sn2_interpolator = { - .get_offset = getoffset, - .update = update, - .reset = reset -}; +static struct time_interpolator sn2_interpolator; void __init sn_timer_init(void) { sn2_interpolator.frequency = sn_rtc_cycles_per_second; sn2_interpolator.drift = -1; /* unknown */ + sn2_interpolator.shift = 10; /* RTC is 54 bits maximum shift is 10 */ + sn2_interpolator.addr = RTC_COUNTER_ADDR; + sn2_interpolator.source = TIME_SOURCE_MMIO64; register_time_interpolator(&sn2_interpolator); - - rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ; - rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second; - - last_wall_rtc = GET_RTC_COUNTER(); } diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig new file mode 100644 index 000000000..bacc0b298 --- /dev/null +++ b/arch/m32r/Kconfig @@ -0,0 +1,441 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux Kernel Configuration" + +config M32R + bool + default y + +config SBUS + bool + +config UID16 + bool + default y + +config GENERIC_ISA_DMA + bool + default y + +source "init/Kconfig" + + +menu "Processor type and features" + +choice + prompt "Platform Type" + default PLAT_MAPPI + +config PLAT_MAPPI + bool "Mappi-I" + help + The Mappi-I is an FPGA board for SOC (System-On-a-Chip) prototyping. + You can operate a Linux system on this board by using an M32R + softmacro core, which is a fully-synthesizable functional model + described in Verilog-HDL. + + The Mappi-I board was the first platform, which had been used + to port and develop a Linux system for the M32R processor. + Currently, the Mappi-II, an heir to the Mappi-I, is available. + +config PLAT_USRV + bool "uServer" + +config PLAT_M32700UT + bool "M32700UT" + help + The M3T-M32700UT is an evaluation board based on uT-Engine + specification. This board has an M32700 (Chaos) evaluation chip. + You can say Y for SMP, because the M32700 is a single chip + multiprocessor. + +config PLAT_OPSPUT + bool "OPSPUT" + help + The OPSPUT is an evaluation board based on uT-Engine + specification. This board has a OPSP-REP chip. + +config PLAT_OAKS32R + bool "OAKS32R" + help + The OAKS32R is a tiny, inexpensive evaluation board. + Please note that if you say Y here and choose chip "M32102", + say N for MMU and select a no-MMU version kernel, otherwise + a kernel with MMU support will not work, because the M32102 + is a microcontroller for embedded systems and it has no MMU. + +config PLAT_MAPPI2 + bool "Mappi-II(M3A-ZA36/M3A-ZA52)" + +endchoice + +choice + prompt "Processor family" + default CHIP_M32700 + +config CHIP_M32700 + bool "M32700 (Chaos)" + +config CHIP_M32102 + bool "M32102" + +config CHIP_VDEC2 + bool "VDEC2" + +config CHIP_OPSP + bool "OPSP" + +endchoice + +config MMU + bool "Support for memory management hardware" + depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP + default y + +config TLB_ENTRIES + int "TLB Entries" + depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP + default 32 if CHIP_M32700 || CHIP_OPSP + default 16 if CHIP_VDEC2 + + +config ISA_M32R + bool + depends on CHIP_M32102 + default y + +config ISA_M32R2 + bool + depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP + default y + +config ISA_DSP_LEVEL2 + bool + depends on CHIP_M32700 || CHIP_OPSP + default y + +config ISA_DUAL_ISSUE + bool + depends on CHIP_M32700 || CHIP_OPSP + default y + +config BUS_CLOCK + int "Bus Clock [Hz] (integer)" + default "70000000" if PLAT_MAPPI + default "25000000" if PLAT_USRV + default "50000000" if PLAT_M32700UT + default "50000000" if PLAT_OPSPUT + default "33333333" if PLAT_OAKS32R + default "20000000" if PLAT_MAPPI2 + +config TIMER_DIVIDE + int "Timer divider (integer)" + default "128" + +config CPU_LITTLE_ENDIAN + bool "Generate little endian code" + default n + +config MEMORY_START + hex "Physical memory start address (hex)" + default "08000000" if PLAT_MAPPI || PLAT_MAPPI2 + default "08000000" if PLAT_USRV + default "08000000" if PLAT_M32700UT + default "08000000" if PLAT_OPSPUT + default "01000000" if PLAT_OAKS32R + +config MEMORY_SIZE + hex "Physical memory size (hex)" + default "04000000" if PLAT_MAPPI || PLAT_MAPPI2 + default "02000000" if PLAT_USRV + default "01000000" if PLAT_M32700UT + default "01000000" if PLAT_OPSPUT + default "00800000" if PLAT_OAKS32R + +config NOHIGHMEM + bool + default y + +config DISCONTIGMEM + bool "Internal RAM Support" + depends on CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP + default y + +config IRAM_START + hex "Internal memory start address (hex)" + default "00f00000" + depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM + +config IRAM_SIZE + hex "Internal memory size (hex)" + depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM + default "00080000" if CHIP_M32700 + default "00010000" if CHIP_M32102 || CHIP_OPSP + default "00008000" if CHIP_VDEC2 + +# +# Define implied options from the CPU selection here +# + +config RWSEM_GENERIC_SPINLOCK + bool + depends on M32R + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + default n + +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + +config HAVE_DEC_LOCK + bool + depends on (SMP || PREEMPT) + default n + +config SMP + bool "Symmetric multi-processing support" + ---help--- + This enables support for systems with more than one CPU. If you have + a system with only one CPU, like most personal computers, say N. If + you have a system with more than one CPU, say Y. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on many, but not all, + singleprocessor machines. On a singleprocessor machine, the kernel + will run faster if you say N here. + + People using multiprocessor machines who say Y here should also say + Y to "Enhanced Real Time Clock Support", below. The "Advanced Power + Management" code will be disabled if you say Y here. + + See also the , + and the SMP-HOWTO available at + . + + If you don't know what to do here, say N. + +config CHIP_M32700_TS1 + bool "Workaround code for the M32700 TS1 chip's bug" + depends on (CHIP_M32700 && SMP) + default n + +config NR_CPUS + int "Maximum number of CPUs (2-32)" + range 2 32 + depends on SMP + default "2" + help + This allows you to specify the maximum number of CPUs which this + kernel will support. The maximum supported value is 32 and the + minimum value which makes sense is 2. + + This is purely to save memory - each supported CPU adds + approximately eight kilobytes to the kernel image. + +# Common NUMA Features +config NUMA + bool "Numa Memory Allocation Support" + depends on SMP + default n + +# turning this on wastes a bunch of space. +# Summit needs it only when NUMA is on +config BOOT_IOREMAP + bool + depends on NUMA + default n + +endmenu + + +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +config PCI + bool "PCI support" + default n + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or + VESA. If you have PCI, say Y, otherwise N. + + The PCI-HOWTO, available from + , contains valuable + information about which PCI hardware does work under Linux and which + doesn't. + +choice + prompt "PCI access mode" + depends on PCI + default PCI_GOANY + +config PCI_GOBIOS + bool "BIOS" + ---help--- + On PCI systems, the BIOS can be used to detect the PCI devices and + determine their configuration. However, some old PCI motherboards + have BIOS bugs and may crash if this is done. Also, some embedded + PCI-based systems don't have any BIOS at all. Linux can also try to + detect the PCI hardware directly without using the BIOS. + + With this option, you can specify how Linux should detect the PCI + devices. If you choose "BIOS", the BIOS will be used, if you choose + "Direct", the BIOS won't be used, and if you choose "Any", the + kernel will try the direct access method and falls back to the BIOS + if that doesn't work. If unsure, go with the default, which is + "Any". + +config PCI_GODIRECT + bool "Direct" + +config PCI_GOANY + bool "Any" + +endchoice + +config PCI_BIOS + bool + depends on PCI && (PCI_GOBIOS || PCI_GOANY) + default y + +config PCI_DIRECT + bool + depends on PCI && (PCI_GODIRECT || PCI_GOANY) + default y + +source "drivers/pci/Kconfig" + +config ISA + bool "ISA support" + help + Find out whether you have ISA slots on your motherboard. ISA is the + name of a bus system, i.e. the way the CPU talks to the other stuff + inside your box. If you have ISA, say Y, otherwise N. + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/m32r/oprofile/Kconfig" + +menu "Kernel hacking" + +config DEBUG_KERNEL + bool "Kernel debugging" + help + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config DEBUG_SLAB + bool "Debug memory allocations" + depends on DEBUG_KERNEL + help + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +config DEBUG_IOVIRT + bool "Memory mapped I/O debugging" + depends on DEBUG_KERNEL + help + Say Y here to get warned whenever an attempt is made to do I/O on + obviously invalid addresses such as those generated when ioremap() + calls are forgotten. Memory mapped I/O will go through an extra + check to catch access to unmapped ISA addresses, an access method + that can still be used by old drivers that are being ported from + 2.0/2.2. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + depends on DEBUG_KERNEL + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in . Don't say Y + unless you really know what this hack does. + +config DEBUG_SPINLOCK + bool "Spinlock debugging" + depends on DEBUG_KERNEL + help + Say Y here and build SMP to catch missing spinlock initialization + and certain other kinds of spinlock errors commonly made. This is + best used in conjunction with the NMI watchdog so that spinlock + deadlocks are also debuggable. + +config DEBUG_PAGEALLOC + bool "Page alloc debugging" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a large slowdown, but helps to find certain types + of memory corruptions. + +config DEBUG_INFO + bool "Compile the kernel with debug info" + depends on DEBUG_KERNEL + help + If you say Y here the resulting kernel image will include + debugging info resulting in a larger kernel image. + Say Y here only if you plan to use gdb to debug the kernel. + If you don't debug the kernel, you can say N. + +config DEBUG_SPINLOCK_SLEEP + bool "Sleep-inside-spinlock checking" + help + If you say Y here, various routines which may sleep will become very + noisy if they are called with a spinlock held. + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + help + If you say Y here the resulting kernel image will be slightly larger + and slower, but it will give very useful debugging information. + If you don't debug the kernel, you can say N, but we may not be able + to solve problems without frame pointers. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile new file mode 100644 index 000000000..63ea62a5d --- /dev/null +++ b/arch/m32r/Makefile @@ -0,0 +1,55 @@ +# +# m32r/Makefile +# + +LDFLAGS := +OBJCOPYFLAGS := -O binary -R .note -R .comment -S +LDFLAGS_vmlinux := -e startup_32 +LDFLAGS_BLOB := --format binary --oformat elf32-m32r + +CFLAGS += -pipe -fno-schedule-insns +CFLAGS_KERNEL += -mmodel=medium +CFLAGS_MODULE += -mmodel=large + +ifdef CONFIG_CHIP_VDEC2 +cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst +aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst +else +cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 +aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 +endif + +cflags-$(CONFIG_ISA_M32R) += -DNO_FPU +aflags-$(CONFIG_ISA_M32R) += -DNO_FPU -Wa,-no-bitinst + +CFLAGS += $(cflags-y) +AFLAGS += $(aflags-y) + +CHECKFLAGS := $(CHECK) -D__m32r__ + +head-y := arch/m32r/kernel/head.o arch/m32r/kernel/init_task.o + +LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +libs-y += arch/m32r/lib/ $(LIBGCC) +core-y += arch/m32r/kernel/ \ + arch/m32r/mm/ \ + arch/m32r/boot/ + +drivers-$(CONFIG_OPROFILE) += arch/m32r/oprofile/ + +boot := arch/m32r/boot + +.PHONY: zImage + +zImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +compressed: zImage + +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +define archhelp + @echo ' zImage - Compressed kernel image (arch/m32r/boot/zImage)' +endef diff --git a/arch/m32r/boot/Makefile b/arch/m32r/boot/Makefile new file mode 100644 index 000000000..af2cef475 --- /dev/null +++ b/arch/m32r/boot/Makefile @@ -0,0 +1,19 @@ +# +# arch/m32r/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. + +targets := zImage +subdir- := compressed + +obj-y := setup.o + +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo 'Kernel: $@ is ready' + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + diff --git a/arch/m32r/boot/compressed/Makefile b/arch/m32r/boot/compressed/Makefile new file mode 100644 index 000000000..a8f130d5e --- /dev/null +++ b/arch/m32r/boot/compressed/Makefile @@ -0,0 +1,38 @@ +# +# linux/arch/sh/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \ + m32r-sio.o piggy.o vmlinux.lds +EXTRA_AFLAGS := -traditional + +OBJECTS = $(obj)/head.o $(obj)/misc.o $(obj)/m32r_sio.o + +# +# IMAGE_OFFSET is the load offset of the compression loader +# +#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x2000]) +#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x00400000]) + +LDFLAGS_vmlinux := -T + +$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.S FORCE + $(CPP) $(EXTRA_AFLAGS) -C -P -I include $< >$@ + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T +OBJCOPYFLAGS += -R .empty_zero_page + +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) diff --git a/arch/m32r/boot/compressed/boot.h b/arch/m32r/boot/compressed/boot.h new file mode 100644 index 000000000..9272e38d1 --- /dev/null +++ b/arch/m32r/boot/compressed/boot.h @@ -0,0 +1,59 @@ +/* + * 1. load vmlinuz + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinuz | + * +-----------------------+ + * 2. decompressed + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinuz | + * +-----------------------+ + * | | + * BOOT_RELOC_ADDR +-----------------------+ + * | | + * KERNEL_DECOMPRESS_ADDR +-----------------------+ + * | vmlinux | + * +-----------------------+ + * + * 3. relocate copy & jump code + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinuz | + * +-----------------------+ + * | | + * BOOT_RELOC_ADDR +-----------------------+ + * | boot(copy&jump) | + * KERNEL_DECOMPRESS_ADDR +-----------------------+ + * | vmlinux | + * +-----------------------+ + * + * 4. relocate decompressed kernel + * + * CONFIG_MEMORY_START +-----------------------+ + * | vmlinux | + * +-----------------------+ + * | | + * BOOT_RELOC_ADDR +-----------------------+ + * | boot(copy&jump) | + * KERNEL_DECOMPRESS_ADDR +-----------------------+ + * | | + * +-----------------------+ + * + */ +#ifdef __ASSEMBLY__ +#define __val(x) x +#else +#define __val(x) (x) +#endif + +#define DECOMPRESS_OFFSET_BASE __val(0x00900000) +#define BOOT_RELOC_SIZE __val(0x00001000) + +#define KERNEL_EXEC_ADDR __val(CONFIG_MEMORY_START) +#define KERNEL_DECOMPRESS_ADDR __val(CONFIG_MEMORY_START + \ + DECOMPRESS_OFFSET_BASE + BOOT_RELOC_SIZE) +#define KERNEL_ENTRY __val(CONFIG_MEMORY_START + 0x1000) + +#define BOOT_EXEC_ADDR __val(CONFIG_MEMORY_START) +#define BOOT_RELOC_ADDR __val(CONFIG_MEMORY_START + DECOMPRESS_OFFSET_BASE) diff --git a/arch/m32r/boot/compressed/head.S b/arch/m32r/boot/compressed/head.S new file mode 100644 index 000000000..28de481bd --- /dev/null +++ b/arch/m32r/boot/compressed/head.S @@ -0,0 +1,115 @@ +/* + * linux/arch/m32r/boot/compressed/head.S + * + * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * Copyright (c) 2004 Hirokazu Takata + */ + + .text +#include +#include +#include +#include +#include + + .global startup + __ALIGN +startup: + ldi r0, #0x0000 /* SPI, disable EI */ + mvtc r0, psw + +/* + * Clear BSS first so that there are no surprises... + */ +#ifdef CONFIG_ISA_DUAL_ISSUE + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + ; R4 = BSS size in longwords (rounded down) + mv r4, r3 || ldi r1, #0 + srli r4, #4 || addi r2, #-4 + beqz r4, .Lendloop1 +.Lloop1: +#ifndef CONFIG_CHIP_M32310 + ; Touch memory for the no-write-allocating cache. + ld r0, @(4,r2) +#endif + st r1, @+r2 || addi r4, #-1 + st r1, @+r2 + st r1, @+r2 + st r1, @+r2 || cmpeq r1, r4 ; R4 = 0? + bnc .Lloop1 +.Lendloop1: + and3 r4, r3, #15 + addi r2, #4 + beqz r4, .Lendloop2 +.Lloop2: + stb r1, @r2 || addi r4, #-1 + addi r2, #1 + bnez r4, .Lloop2 +.Lendloop2: + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + mv r4, r3 + srli r4, #2 ; R4 = BSS size in longwords (rounded down) + ldi r1, #0 ; clear R1 for longwords store + addi r2, #-4 ; account for pre-inc store + beqz r4, .Lendloop1 ; any more to go? +.Lloop1: + st r1, @+r2 ; yep, zero out another longword + addi r4, #-1 ; decrement count + bnez r4, .Lloop1 ; go do some more +.Lendloop1: + and3 r4, r3, #3 ; get no. of remaining BSS bytes to clear + addi r2, #4 ; account for pre-inc store + beqz r4, .Lendloop2 ; any more to go? +.Lloop2: + stb r1, @r2 ; yep, zero out another byte + addi r2, #1 ; bump address + addi r4, #-1 ; decrement count + bnez r4, .Lloop2 ; go do some more +.Lendloop2: + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + seth r0, #shigh(stack_start) + ld sp, @(r0, low(stack_start)) /* set stack point */ + +/* + * decompress the kernel + */ + bl decompress_kernel + +#if defined(CONFIG_CHIP_M32700) + /* Cache flush */ + ldi r0, -1 + ldi r1, 0xd0 ; invalidate i-cache, copy back d-cache + stb r1, @r0 +#else +#error "put your cache flush function, please" +#endif + seth r0, #high(CONFIG_MEMORY_START) + or3 r0, r0, #0x2000 + jmp r0 + + .balign 512 +fake_headers_as_bzImage: + .short 0 + .ascii "HdrS" + .short 0x0202 + .short 0 + .short 0 + .byte 0x00, 0x10 + .short 0 + .byte 0 + .byte 1 + .byte 0x00, 0x80 + .long 0 + .long 0 + diff --git a/arch/m32r/boot/compressed/install.sh b/arch/m32r/boot/compressed/install.sh new file mode 100644 index 000000000..6d72e9e72 --- /dev/null +++ b/arch/m32r/boot/compressed/install.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# arch/sh/boot/install.sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy +# Adapted from code in arch/sh/boot/install.sh by Takeo Takahashi +# +# "make install" script for sh architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x /sbin/installkernel ]; then + exec /sbin/installkernel "$@" +fi + +if [ "$2" = "zImage" ]; then +# Compressed install + echo "Installing compressed kernel" + if [ -f $4/vmlinuz-$1 ]; then + mv $4/vmlinuz-$1 $4/vmlinuz.old + fi + + if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.old + fi + + cat $2 > $4/vmlinuz-$1 + cp $3 $4/System.map-$1 +else +# Normal install + echo "Installing normal kernel" + if [ -f $4/vmlinux-$1 ]; then + mv $4/vmlinux-$1 $4/vmlinux.old + fi + + if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old + fi + + cat $2 > $4/vmlinux-$1 + cp $3 $4/System.map +fi diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c new file mode 100644 index 000000000..469c4dce5 --- /dev/null +++ b/arch/m32r/boot/compressed/m32r_sio.c @@ -0,0 +1,53 @@ +/* + * arch/m32r/boot/compressed/m32r_sio.c + * + * 2003-02-12: Takeo Takahashi + * + */ + +#include +#include +#include + +void putc(char c); + +int puts(const char *s) +{ + char c; + while ((c = *s++)) putc(c); + return 0; +} + +#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) +#define USE_FPGA_MAP 0 + +#if USE_FPGA_MAP +/* + * fpga configuration program uses MMU, and define map as same as + * M32104 uT-Engine board. + */ +#define BOOT_SIO0STS (volatile unsigned short *)(0x02c00000 + 0x20006) +#define BOOT_SIO0TXB (volatile unsigned short *)(0x02c00000 + 0x2000c) +#else +#undef PLD_BASE +#define PLD_BASE 0xa4c00000 +#define BOOT_SIO0STS PLD_ESIO0STS +#define BOOT_SIO0TXB PLD_ESIO0TXB +#endif + +void putc(char c) +{ + + while ((*BOOT_SIO0STS & 0x3) != 0x3) ; + if (c == '\n') { + *BOOT_SIO0TXB = '\r'; + while ((*BOOT_SIO0STS & 0x3) != 0x3) ; + } + *BOOT_SIO0TXB = c; +} +#else +void putc(char c) +{ + /* do nothing */ +} +#endif diff --git a/arch/m32r/boot/compressed/misc.c b/arch/m32r/boot/compressed/misc.c new file mode 100644 index 000000000..4661d38d9 --- /dev/null +++ b/arch/m32r/boot/compressed/misc.c @@ -0,0 +1,223 @@ +/* + * arch/m32r/boot/compressed/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Adapted for SH by Stuart Menefy, Aug 1999 + * + * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000 + * + * 2003-02-12: Support M32R by Takeo Takahashi + * This is based on arch/sh/boot/compressed/misc.c. + */ + +#include +#include + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern int input_len; + +static long bytes_out; +static uch *output_data; +static unsigned long output_ptr; + + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern int puts(const char *); + +extern int _text; /* Defined in vmlinux.lds.S */ +extern int _end; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr == 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) +long user_stack [STACK_SIZE]; +long* stack_start = &user_stack[STACK_SIZE]; + +/* return decompressed size */ +long decompress_kernel(void) +{ + insize = 0; + inptr = 0; + bytes_out = 0; + outcnt = 0; + output_data = 0; + output_ptr = CONFIG_MEMORY_START + 0x2000; + free_mem_ptr = (unsigned long)&_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux... "); + gunzip(); + puts("Ok, booting the kernel.\n"); + return bytes_out; +} diff --git a/arch/m32r/boot/compressed/vmlinux.lds.S b/arch/m32r/boot/compressed/vmlinux.lds.S new file mode 100644 index 000000000..20a9e9450 --- /dev/null +++ b/arch/m32r/boot/compressed/vmlinux.lds.S @@ -0,0 +1,23 @@ +#include + +OUTPUT_ARCH(m32r) +ENTRY(startup) +SECTIONS +{ + . = CONFIG_MEMORY_START + 0x00400000; + + _text = .; + .text : { *(.text) } = 0 + .rodata : { *(.rodata) } + _etext = .; + + . = ALIGN(32) + (. & (32 - 1)); + .data : { *(.data) } + _edata = .; + + . = ALIGN(32 / 8); + __bss_start = .; + .bss : { *(.bss) } + . = ALIGN(32 / 8); + _end = . ; +} diff --git a/arch/m32r/boot/compressed/vmlinux.scr b/arch/m32r/boot/compressed/vmlinux.scr new file mode 100644 index 000000000..a08490360 --- /dev/null +++ b/arch/m32r/boot/compressed/vmlinux.scr @@ -0,0 +1,9 @@ +SECTIONS +{ + .data : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + input_data_end = .; + } +} diff --git a/arch/m32r/boot/setup.S b/arch/m32r/boot/setup.S new file mode 100644 index 000000000..9be591710 --- /dev/null +++ b/arch/m32r/boot/setup.S @@ -0,0 +1,162 @@ +/* + * linux/arch/m32r/boot/setup.S -- A setup code. + * + * Copyright (C) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * and Hitoshi Yamamoto + * + */ +/* $Id$ */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * References to members of the boot_cpu_data structure. + */ + +#define CPU_PARAMS boot_cpu_data +#define M32R_MCICAR 0xfffffff0 +#define M32R_MCDCAR 0xfffffff4 +#define M32R_MCCR 0xfffffffc +#define M32R_BSCR0 0xffffffd2 + +;BSEL +#define BSEL0CR0 0x00ef5000 +#define BSEL0CR1 0x00ef5004 +#define BSEL1CR0 0x00ef5100 +#define BSEL1CR1 0x00ef5104 +#define BSEL0CR0_VAL 0x00000000 +#define BSEL0CR1_VAL 0x01200100 +#define BSEL1CR0_VAL 0x01018000 +#define BSEL1CR1_VAL 0x00200001 + +;SDRAMC +#define SDRAMC_SDRF0 0x00ef6000 +#define SDRAMC_SDRF1 0x00ef6004 +#define SDRAMC_SDIR0 0x00ef6008 +#define SDRAMC_SDIR1 0x00ef600c +#define SDRAMC_SD0ADR 0x00ef6020 +#define SDRAMC_SD0ER 0x00ef6024 +#define SDRAMC_SD0TR 0x00ef6028 +#define SDRAMC_SD0MOD 0x00ef602c +#define SDRAMC_SD1ADR 0x00ef6040 +#define SDRAMC_SD1ER 0x00ef6044 +#define SDRAMC_SD1TR 0x00ef6048 +#define SDRAMC_SD1MOD 0x00ef604c +#define SDRAM0 0x18000000 +#define SDRAM1 0x1c000000 + +/*------------------------------------------------------------------------ + * start up + */ + +/*------------------------------------------------------------------------ + * Kernel entry + */ + .section .boot, "ax" +ENTRY(boot) + +/* Set cache mode */ +#if defined(CONFIG_CHIP_XNUX2) + ldi r0, #-2 ;LDIMM (r0, M32R_MCCR) + ldi r1, #0x0101 ; cache on (with invalidation) +; ldi r1, #0x00 ; cache off + sth r1, @r0 +#elif defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_VDEC2) \ + || defined(CONFIG_CHIP_OPSP) + ldi r0, #-4 ;LDIMM (r0, M32R_MCCR) + ldi r1, #0x73 ; cache on (with invalidation) +; ldi r1, #0x00 ; cache off + st r1, @r0 +#else +#error unknown chip configuration +#endif + +#ifdef CONFIG_SMP + ;; if not BSP (CPU#0) goto AP_loop + seth r5, #shigh(M32R_CPUID_PORTL) + ld r5, @(low(M32R_CPUID_PORTL), r5) + bnez r5, AP_loop +#if !defined(CONFIG_PLAT_USRV) + ;; boot AP + ld24 r5, #0xeff2f8 ; IPICR7 + ldi r6, #0x2 ; IPI to CPU1 + st r6, @r5 +#endif +#endif + +/* + * Now, Jump to stext + * if with MMU, TLB on. + * if with no MMU, only jump. + */ + .global eit_vector +mmu_on: + LDIMM (r13, stext) +#ifdef CONFIG_MMU + bl init_tlb + LDIMM (r2, eit_vector) ; set EVB(cr5) + mvtc r2, cr5 + seth r0, #high(MMU_REG_BASE) ; Set MMU_REG_BASE higher + or3 r0, r0, #low(MMU_REG_BASE) ; Set MMU_REG_BASE lower + ldi r1, #0x01 + st r1, @(MATM_offset,r0) ; Set MATM (T bit ON) + ld r0, @(MATM_offset,r0) ; Check +#else + seth r0,#high(M32R_MCDCAR) + or3 r0,r0,#low(M32R_MCDCAR) + ld24 r1,#0x8080 + st r1,@r0 +#endif /* CONFIG_MMU */ + jmp r13 + nop + nop + +#ifdef CONFIG_SMP +/* + * AP wait loop + */ +ENTRY(AP_loop) + ;; disable interrupt + clrpsw #0x40 + ;; reset EVB + LDIMM (r4, _AP_RE) + seth r5, #high(__PAGE_OFFSET) + or3 r5, r5, #low(__PAGE_OFFSET) + not r5, r5 + and r4, r5 + mvtc r4, cr5 + ;; disable maskable interrupt + seth r4, #high(M32R_ICU_IMASK_PORTL) + or3 r4, r4, #low(M32R_ICU_IMASK_PORTL) + ldi r5, #0 + st r5, @r4 + ld r5, @r4 + ;; enable only IPI + setpsw #0x40 + ;; LOOOOOOOOOOOOOOP!!! + .fillinsn +2: + nop + nop + bra 2b + nop + nop + +#ifdef CONFIG_CHIP_M32700_TS1 + .global dcache_dummy + .balign 16, 0 +dcache_dummy: + .byte 16 +#endif /* CONFIG_CHIP_M32700_TS1 */ +#endif /* CONFIG_SMP */ + + .end + diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig new file mode 100644 index 000000000..984701b73 --- /dev/null +++ b/arch/m32r/defconfig @@ -0,0 +1,635 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=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=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_CFC=y +CONFIG_M32700UT_CFC=y +CONFIG_CFC_NUM=1 +# CONFIG_MTD_M32R is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +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_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# 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_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 device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# 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=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +CONFIG_M32R_AR=y +CONFIG_M32R_AR_VGA=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# 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 is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/kernel/Makefile b/arch/m32r/kernel/Makefile new file mode 100644 index 000000000..cfd690bf6 --- /dev/null +++ b/arch/m32r/kernel/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for the Linux/M32R kernel. +# + +extra-y := head.o init_task.o vmlinux.lds + +obj-y := process.o entry.o traps.o align.o irq.o setup.o time.o \ + m32r_ksyms.o sys_m32r.o semaphore.o signal.o ptrace.o + +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_PLAT_MAPPI) += setup_mappi.o io_mappi.o +obj-$(CONFIG_PLAT_MAPPI2) += setup_mappi2.o io_mappi2.o +obj-$(CONFIG_PLAT_USRV) += setup_usrv.o io_usrv.o +obj-$(CONFIG_PLAT_M32700UT) += setup_m32700ut.o io_m32700ut.o +obj-$(CONFIG_PLAT_OPSPUT) += setup_opsput.o io_opsput.o +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_PLAT_OAKS32R) += setup_oaks32r.o io_oaks32r.o + +EXTRA_AFLAGS := -traditional + diff --git a/arch/m32r/kernel/align.c b/arch/m32r/kernel/align.c new file mode 100644 index 000000000..48ec29714 --- /dev/null +++ b/arch/m32r/kernel/align.c @@ -0,0 +1,585 @@ +/* + * align.c - address exception handler for M32R + * + * Copyright (c) 2003 Hitoshi Yamamoto + */ + +#include +#include +#include + +static int get_reg(struct pt_regs *regs, int nr) +{ + int val; + + if (nr < 4) + val = *(unsigned long *)(®s->r0 + nr); + else if (nr < 7) + val = *(unsigned long *)(®s->r4 + (nr - 4)); + else if (nr < 13) + val = *(unsigned long *)(®s->r7 + (nr - 7)); + else + val = *(unsigned long *)(®s->fp + (nr - 13)); + + return val; +} + +static void set_reg(struct pt_regs *regs, int nr, int val) +{ + if (nr < 4) + *(unsigned long *)(®s->r0 + nr) = val; + else if (nr < 7) + *(unsigned long *)(®s->r4 + (nr - 4)) = val; + else if (nr < 13) + *(unsigned long *)(®s->r7 + (nr - 7)) = val; + else + *(unsigned long *)(®s->fp + (nr - 13)) = val; +} + +#define REG1(insn) (((insn) & 0x0f00) >> 8) +#define REG2(insn) ((insn) & 0x000f) +#define PSW_BC 0x100 + +/* O- instruction */ +#define ISA_LD1 0x20c0 /* ld Rdest, @Rsrc */ +#define ISA_LD2 0x20e0 /* ld Rdest, @Rsrc+ */ +#define ISA_LDH 0x20a0 /* ldh Rdest, @Rsrc */ +#define ISA_LDUH 0x20b0 /* lduh Rdest, @Rsrc */ +#define ISA_ST1 0x2040 /* st Rsrc1, @Rsrc2 */ +#define ISA_ST2 0x2060 /* st Rsrc1, @+Rsrc2 */ +#define ISA_ST3 0x2070 /* st Rsrc1, @-Rsrc2 */ +#define ISA_STH1 0x2020 /* sth Rsrc1, @Rsrc2 */ +#define ISA_STH2 0x2030 /* sth Rsrc1, @Rsrc2+ */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +/* OS instruction */ +#define ISA_ADD 0x00a0 /* add Rdest, Rsrc */ +#define ISA_ADDI 0x4000 /* addi Rdest, #imm8 */ +#define ISA_ADDX 0x0090 /* addx Rdest, Rsrc */ +#define ISA_AND 0x00c0 /* and Rdest, Rsrc */ +#define ISA_CMP 0x0040 /* cmp Rsrc1, Rsrc2 */ +#define ISA_CMPEQ 0x0060 /* cmpeq Rsrc1, Rsrc2 */ +#define ISA_CMPU 0x0050 /* cmpu Rsrc1, Rsrc2 */ +#define ISA_CMPZ 0x0070 /* cmpz Rsrc */ +#define ISA_LDI 0x6000 /* ldi Rdest, #imm8 */ +#define ISA_MV 0x1080 /* mv Rdest, Rsrc */ +#define ISA_NEG 0x0030 /* neg Rdest, Rsrc */ +#define ISA_NOP 0x7000 /* nop */ +#define ISA_NOT 0x00b0 /* not Rdest, Rsrc */ +#define ISA_OR 0x00e0 /* or Rdest, Rsrc */ +#define ISA_SUB 0x0020 /* sub Rdest, Rsrc */ +#define ISA_SUBX 0x0010 /* subx Rdest, Rsrc */ +#define ISA_XOR 0x00d0 /* xor Rdest, Rsrc */ + +/* -S instruction */ +#define ISA_MUL 0x1060 /* mul Rdest, Rsrc */ +#define ISA_MULLO_A0 0x3010 /* mullo Rsrc1, Rsrc2, A0 */ +#define ISA_MULLO_A1 0x3090 /* mullo Rsrc1, Rsrc2, A1 */ +#define ISA_MVFACMI_A0 0x50f2 /* mvfacmi Rdest, A0 */ +#define ISA_MVFACMI_A1 0x50f6 /* mvfacmi Rdest, A1 */ + +static int emu_addi(unsigned short insn, struct pt_regs *regs) +{ + char imm = (char)(insn & 0xff); + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val += imm; + set_reg(regs, dest, val); + + return 0; +} + +static int emu_ldi(unsigned short insn, struct pt_regs *regs) +{ + char imm = (char)(insn & 0xff); + + set_reg(regs, REG1(insn), (int)imm); + + return 0; +} + +static int emu_add(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int src = REG2(insn); + int val; + + val = get_reg(regs, dest); + val += get_reg(regs, src); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_addx(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + unsigned int val, tmp; + + val = regs->psw & PSW_BC ? 1 : 0; + tmp = get_reg(regs, dest); + val += tmp; + val += (unsigned int)get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + /* C bit set */ + if (val < tmp) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_and(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val &= get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_cmp(unsigned short insn, struct pt_regs *regs) +{ + if (get_reg(regs, REG1(insn)) < get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_cmpeq(unsigned short insn, struct pt_regs *regs) +{ + if (get_reg(regs, REG1(insn)) == get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_cmpu(unsigned short insn, struct pt_regs *regs) +{ + if ((unsigned int)get_reg(regs, REG1(insn)) + < (unsigned int)get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_cmpz(unsigned short insn, struct pt_regs *regs) +{ + if (!get_reg(regs, REG2(insn))) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_mv(unsigned short insn, struct pt_regs *regs) +{ + int val; + + val = get_reg(regs, REG2(insn)); + set_reg(regs, REG1(insn), val); + + return 0; +} + +static int emu_neg(unsigned short insn, struct pt_regs *regs) +{ + int val; + + val = get_reg(regs, REG2(insn)); + set_reg(regs, REG1(insn), 0 - val); + + return 0; +} + +static int emu_not(unsigned short insn, struct pt_regs *regs) +{ + int val; + + val = get_reg(regs, REG2(insn)); + set_reg(regs, REG1(insn), ~val); + + return 0; +} + +static int emu_or(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val |= get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_sub(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int val; + + val = get_reg(regs, dest); + val -= get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_subx(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + unsigned int val, tmp; + + val = tmp = get_reg(regs, dest); + val -= (unsigned int)get_reg(regs, REG2(insn)); + val -= regs->psw & PSW_BC ? 1 : 0; + set_reg(regs, dest, val); + + /* C bit set */ + if (val > tmp) + regs->psw |= PSW_BC; + else + regs->psw &= ~(PSW_BC); + + return 0; +} + +static int emu_xor(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + unsigned int val; + + val = (unsigned int)get_reg(regs, dest); + val ^= (unsigned int)get_reg(regs, REG2(insn)); + set_reg(regs, dest, val); + + return 0; +} + +static int emu_mul(unsigned short insn, struct pt_regs *regs) +{ + int dest = REG1(insn); + int reg1, reg2; + + reg1 = get_reg(regs, dest); + reg2 = get_reg(regs, REG2(insn)); + + __asm__ __volatile__ ( + "mul %0, %1; \n\t" + : "+r" (reg1) : "r" (reg2) + ); + + set_reg(regs, dest, reg1); + + return 0; +} + +static int emu_mullo_a0(unsigned short insn, struct pt_regs *regs) +{ + int reg1, reg2; + + reg1 = get_reg(regs, REG1(insn)); + reg2 = get_reg(regs, REG2(insn)); + + __asm__ __volatile__ ( + "mullo %0, %1, a0; \n\t" + "mvfachi %0, a0; \n\t" + "mvfaclo %1, a0; \n\t" + : "+r" (reg1), "+r" (reg2) + ); + + regs->acc0h = reg1; + regs->acc0l = reg2; + + return 0; +} + +static int emu_mullo_a1(unsigned short insn, struct pt_regs *regs) +{ + int reg1, reg2; + + reg1 = get_reg(regs, REG1(insn)); + reg2 = get_reg(regs, REG2(insn)); + + __asm__ __volatile__ ( + "mullo %0, %1, a0; \n\t" + "mvfachi %0, a0; \n\t" + "mvfaclo %1, a0; \n\t" + : "+r" (reg1), "+r" (reg2) + ); + + regs->acc1h = reg1; + regs->acc1l = reg2; + + return 0; +} + +static int emu_mvfacmi_a0(unsigned short insn, struct pt_regs *regs) +{ + unsigned long val; + + val = (regs->acc0h << 16) | (regs->acc0l >> 16); + set_reg(regs, REG1(insn), (int)val); + + return 0; +} + +static int emu_mvfacmi_a1(unsigned short insn, struct pt_regs *regs) +{ + unsigned long val; + + val = (regs->acc1h << 16) | (regs->acc1l >> 16); + set_reg(regs, REG1(insn), (int)val); + + return 0; +} + +static int emu_m32r2(unsigned short insn, struct pt_regs *regs) +{ + int res = -1; + + if ((insn & 0x7fff) == ISA_NOP) /* nop */ + return 0; + + switch(insn & 0x7000) { + case ISA_ADDI: /* addi Rdest, #imm8 */ + res = emu_addi(insn, regs); + break; + case ISA_LDI: /* ldi Rdest, #imm8 */ + res = emu_ldi(insn, regs); + break; + default: + break; + } + + if (!res) + return 0; + + switch(insn & 0x70f0) { + case ISA_ADD: /* add Rdest, Rsrc */ + res = emu_add(insn, regs); + break; + case ISA_ADDX: /* addx Rdest, Rsrc */ + res = emu_addx(insn, regs); + break; + case ISA_AND: /* and Rdest, Rsrc */ + res = emu_and(insn, regs); + break; + case ISA_CMP: /* cmp Rsrc1, Rsrc2 */ + res = emu_cmp(insn, regs); + break; + case ISA_CMPEQ: /* cmpeq Rsrc1, Rsrc2 */ + res = emu_cmpeq(insn, regs); + break; + case ISA_CMPU: /* cmpu Rsrc1, Rsrc2 */ + res = emu_cmpu(insn, regs); + break; + case ISA_CMPZ: /* cmpz Rsrc */ + res = emu_cmpz(insn, regs); + break; + case ISA_MV: /* mv Rdest, Rsrc */ + res = emu_mv(insn, regs); + break; + case ISA_NEG: /* neg Rdest, Rsrc */ + res = emu_neg(insn, regs); + break; + case ISA_NOT: /* not Rdest, Rsrc */ + res = emu_not(insn, regs); + break; + case ISA_OR: /* or Rdest, Rsrc */ + res = emu_or(insn, regs); + break; + case ISA_SUB: /* sub Rdest, Rsrc */ + res = emu_sub(insn, regs); + break; + case ISA_SUBX: /* subx Rdest, Rsrc */ + res = emu_subx(insn, regs); + break; + case ISA_XOR: /* xor Rdest, Rsrc */ + res = emu_xor(insn, regs); + break; + case ISA_MUL: /* mul Rdest, Rsrc */ + res = emu_mul(insn, regs); + break; + case ISA_MULLO_A0: /* mullo Rsrc1, Rsrc2 */ + res = emu_mullo_a0(insn, regs); + break; + case ISA_MULLO_A1: /* mullo Rsrc1, Rsrc2 */ + res = emu_mullo_a1(insn, regs); + break; + default: + break; + } + + if (!res) + return 0; + + switch(insn & 0x70ff) { + case ISA_MVFACMI_A0: /* mvfacmi Rdest */ + res = emu_mvfacmi_a0(insn, regs); + break; + case ISA_MVFACMI_A1: /* mvfacmi Rdest */ + res = emu_mvfacmi_a1(insn, regs); + break; + default: + break; + } + + return res; +} + +#endif /* CONFIG_ISA_DUAL_ISSUE */ + +/* + * ld : ?010 dest 1100 src + * 0010 dest 1110 src : ld Rdest, @Rsrc+ + * ldh : ?010 dest 1010 src + * lduh : ?010 dest 1011 src + * st : ?010 src1 0100 src2 + * 0010 src1 0110 src2 : st Rsrc1, @+Rsrc2 + * 0010 src1 0111 src2 : st Rsrc1, @-Rsrc2 + * sth : ?010 src1 0010 src2 + */ + +static int insn_check(unsigned long insn, struct pt_regs *regs, + unsigned char **ucp) +{ + int res = 0; + + /* + * 32bit insn + * ld Rdest, @(disp16, Rsrc) + * st Rdest, @(disp16, Rsrc) + */ + if (insn & 0x80000000) { /* 32bit insn */ + *ucp += (short)(insn & 0x0000ffff); + regs->bpc += 4; + } else { /* 16bit insn */ +#ifdef CONFIG_ISA_DUAL_ISSUE + /* parallel exec check */ + if (!(regs->bpc & 0x2) && insn & 0x8000) { + res = emu_m32r2((unsigned short)insn, regs); + regs->bpc += 4; + } else +#endif /* CONFIG_ISA_DUAL_ISSUE */ + regs->bpc += 2; + } + + return res; +} + +static int emu_ld(unsigned long insn32, struct pt_regs *regs) +{ + unsigned char *ucp; + unsigned long val; + unsigned short insn16; + int size, src; + + insn16 = insn32 >> 16; + src = REG2(insn16); + ucp = (unsigned char *)get_reg(regs, src); + + if (insn_check(insn32, regs, &ucp)) + return -1; + + size = insn16 & 0x0040 ? 4 : 2; + if (copy_from_user(&val, ucp, size)) + return -1; + + if (size == 2) + val >>= 16; + + /* ldh sign check */ + if ((insn16 & 0x00f0) == 0x00a0 && (val & 0x8000)) + val |= 0xffff0000; + + set_reg(regs, REG1(insn16), val); + + /* ld increment check */ + if ((insn16 & 0xf0f0) == ISA_LD2) /* ld Rdest, @Rsrc+ */ + set_reg(regs, src, (unsigned long)(ucp + 4)); + + return 0; +} + +static int emu_st(unsigned long insn32, struct pt_regs *regs) +{ + unsigned char *ucp; + unsigned long val; + unsigned short insn16; + int size, src2; + + insn16 = insn32 >> 16; + src2 = REG2(insn16); + + ucp = (unsigned char *)get_reg(regs, src2); + + if (insn_check(insn32, regs, &ucp)) + return -1; + + size = insn16 & 0x0040 ? 4 : 2; + val = get_reg(regs, REG1(insn16)); + if (size == 2) + val <<= 16; + + /* st inc/dec check */ + if ((insn16 & 0xf0e0) == 0x2060) { + if (insn16 & 0x0010) + ucp -= 4; + else + ucp += 4; + + set_reg(regs, src2, (unsigned long)ucp); + } + + if (copy_to_user(ucp, &val, size)) + return -1; + + /* sth inc check */ + if ((insn16 & 0xf0f0) == ISA_STH2) { + ucp += 2; + set_reg(regs, src2, (unsigned long)ucp); + } + + return 0; +} + +int handle_unaligned_access(unsigned long insn32, struct pt_regs *regs) +{ + unsigned short insn16; + int res; + + insn16 = insn32 >> 16; + + /* ld or st check */ + if ((insn16 & 0x7000) != 0x2000) + return -1; + + /* insn alignment check */ + if ((insn16 & 0x8000) && (regs->bpc & 3)) + return -1; + + if (insn16 & 0x0080) /* ld */ + res = emu_ld(insn32, regs); + else /* st */ + res = emu_st(insn32, regs); + + return res; +} + diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S new file mode 100644 index 000000000..29b0d8d0c --- /dev/null +++ b/arch/m32r/kernel/entry.S @@ -0,0 +1,999 @@ +/* + * linux/arch/m32r/kernel/entry.S + * + * Copyright (c) 2001, 2002 Hirokazu Takata, Hitoshi Yamamoto, H. Kondo + * Copyright (c) 2003 Hitoshi Yamamoto + * Copyright (c) 2004 Hirokazu Takata + * + * Taken from i386 version. + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * Stack layout in 'ret_from_system_call': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in fork.c:copy_process, signal.c:do_signal, + * ptrace.c and ptrace.h + * + * M32Rx/M32R2 M32R + * @(sp) - r4 ditto + * @(0x04,sp) - r5 ditto + * @(0x08,sp) - r6 ditto + * @(0x0c,sp) - *pt_regs ditto + * @(0x10,sp) - r0 ditto + * @(0x14,sp) - r1 ditto + * @(0x18,sp) - r2 ditto + * @(0x1c,sp) - r3 ditto + * @(0x20,sp) - r7 ditto + * @(0x24,sp) - r8 ditto + * @(0x28,sp) - r9 ditto + * @(0x2c,sp) - r10 ditto + * @(0x30,sp) - r11 ditto + * @(0x34,sp) - r12 ditto + * @(0x38,sp) - syscall_nr ditto + * @(0x3c,sp) - acc0h @(0x3c,sp) - acch + * @(0x40,sp) - acc0l @(0x40,sp) - accl + * @(0x44,sp) - acc1h @(0x44,sp) - psw + * @(0x48,sp) - acc1l @(0x48,sp) - bpc + * @(0x4c,sp) - psw @(0x4c,sp) - bbpsw + * @(0x50,sp) - bpc @(0x50,sp) - bbpc + * @(0x54,sp) - bbpsw @(0x54,sp) - spu (cr3) + * @(0x58,sp) - bbpc @(0x58,sp) - fp (r13) + * @(0x5c,sp) - spu (cr3) @(0x5c,sp) - lr (r14) + * @(0x60,sp) - fp (r13) @(0x60,sp) - spi (cr12) + * @(0x64,sp) - lr (r14) @(0x64,sp) - orig_r0 + * @(0x68,sp) - spi (cr2) + * @(0x6c,sp) - orig_r0 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_MMU) +#define sys_madvise sys_ni_syscall +#define sys_readahead sys_ni_syscall +#define sys_mprotect sys_ni_syscall +#define sys_msync sys_ni_syscall +#define sys_mlock sys_ni_syscall +#define sys_munlock sys_ni_syscall +#define sys_mlockall sys_ni_syscall +#define sys_munlockall sys_ni_syscall +#define sys_mremap sys_ni_syscall +#define sys_mincore sys_ni_syscall +#endif /* CONFIG_MMU */ + +#define R4(reg) @reg +#define R5(reg) @(0x04,reg) +#define R6(reg) @(0x08,reg) +#define PTREGS(reg) @(0x0C,reg) +#define R0(reg) @(0x10,reg) +#define R1(reg) @(0x14,reg) +#define R2(reg) @(0x18,reg) +#define R3(reg) @(0x1C,reg) +#define R7(reg) @(0x20,reg) +#define R8(reg) @(0x24,reg) +#define R9(reg) @(0x28,reg) +#define R10(reg) @(0x2C,reg) +#define R11(reg) @(0x30,reg) +#define R12(reg) @(0x34,reg) +#define SYSCALL_NR(reg) @(0x38,reg) +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) +#define ACC0H(reg) @(0x3C,reg) +#define ACC0L(reg) @(0x40,reg) +#define ACC1H(reg) @(0x44,reg) +#define ACC1L(reg) @(0x48,reg) +#define PSW(reg) @(0x4C,reg) +#define BPC(reg) @(0x50,reg) +#define BBPSW(reg) @(0x54,reg) +#define BBPC(reg) @(0x58,reg) +#define SPU(reg) @(0x5C,reg) +#define FP(reg) @(0x60,reg) /* FP = R13 */ +#define LR(reg) @(0x64,reg) +#define SP(reg) @(0x68,reg) +#define ORIG_R0(reg) @(0x6C,reg) +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) +#define ACCH(reg) @(0x3C,reg) +#define ACCL(reg) @(0x40,reg) +#define PSW(reg) @(0x44,reg) +#define BPC(reg) @(0x48,reg) +#define BBPSW(reg) @(0x4C,reg) +#define BBPC(reg) @(0x50,reg) +#define SPU(reg) @(0x54,reg) +#define FP(reg) @(0x58,reg) /* FP = R13 */ +#define LR(reg) @(0x5C,reg) +#define SP(reg) @(0x60,reg) +#define ORIG_R0(reg) @(0x64,reg) +#else +#error unknown isa configuration +#endif + +CF_MASK = 0x00000001 +TF_MASK = 0x00000100 +IF_MASK = 0x00000200 +DF_MASK = 0x00000400 +NT_MASK = 0x00004000 +VM_MASK = 0x00020000 + +#ifdef CONFIG_PREEMPT +#define preempt_stop(x) CLI(x) +#else +#define preempt_stop(x) +#define resume_kernel restore_all +#endif + +ENTRY(ret_from_fork) + ld r0, @sp+ + bl schedule_tail + GET_THREAD_INFO(r8) + bra syscall_exit + +/* + * Return to user mode is not as complex as all this looks, + * but we want the default path for a system call return to + * go as quickly as possible which is why some of this is + * less clear than it otherwise should be. + */ + + ; userspace resumption stub bypassing syscall exit tracing + ALIGN +ret_from_exception: + preempt_stop(r4) +ret_from_intr: + ld r4, PSW(sp) +#ifdef CONFIG_ISA_M32R2 + and3 r4, r4, #0x8800 ; check BSM and BPM bits +#else + and3 r4, r4, #0x8000 ; check BSM bit +#endif + beqz r4, resume_kernel +ENTRY(resume_userspace) + CLI(r4) ; make sure we don't miss an interrupt + ; setting need_resched or sigpending + ; between sampling and the iret + GET_THREAD_INFO(r8) + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done on + ; int/exception return? + bnez r4, work_pending + bra restore_all + +#ifdef CONFIG_PREEMPT +ENTRY(resume_kernel) + GET_THREAD_INFO(r8) + ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ? + bnez r9, restore_all +need_resched: + ld r9, @(TI_FLAGS, r8) ; need_resched set ? + and3 r4, r9, #_TIF_NEED_RESCHED + beqz r4, restore_all + ld r4, PSW(sp) ; interrupts off (exception path) ? + and3 r4, r4, #0x4000 + beqz r4, restore_all + LDIMM (r4, PREEMPT_ACTIVE) + st r4, @(TI_PRE_COUNT, r8) + STI(r4) + bl schedule + ldi r4, #0 + st r4, @(TI_PRE_COUNT, r8) + CLI(r4) + bra need_resched +#endif + + ; system call handler stub +ENTRY(system_call) + SWITCH_TO_KERNEL_STACK + SAVE_ALL + STI(r4) ; Enable interrupt + st sp, PTREGS(sp) ; implicit pt_regs parameter + cmpui r7, #NR_syscalls + bnc syscall_badsys + st r7, SYSCALL_NR(sp) ; syscall_nr + ; system call tracing in operation + GET_THREAD_INFO(r8) + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_SYSCALL_TRACE + bnez r4, syscall_trace_entry +syscall_call: + slli r7, #2 ; table jump for the system call + LDIMM (r4, sys_call_table) + add r7, r4 + ld r7, @r7 + jl r7 ; execute system call + st r0, R0(sp) ; save the return value +syscall_exit: + CLI(r4) ; make sure we don't miss an interrupt + ; setting need_resched or sigpending + ; between sampling and the iret + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_ALLWORK_MASK ; current->work + bnez r4, syscall_exit_work +restore_all: + RESTORE_ALL + + # perform work that needs to be done immediately before resumption + # r9 : frags + ALIGN +work_pending: + and3 r4, r9, #_TIF_NEED_RESCHED + beqz r4, work_notifysig +work_resched: + bl schedule + CLI(r4) ; make sure we don't miss an interrupt + ; setting need_resched or sigpending + ; between sampling and the iret + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done other + ; than syscall tracing? + beqz r4, restore_all + and3 r4, r4, #_TIF_NEED_RESCHED + bnez r4, work_resched + +work_notifysig: ; deal with pending signals and + ; notify-resume requests + mv r0, sp ; arg1 : struct pt_regs *regs + ldi r1, #0 ; arg2 : sigset_t *oldset + mv r2, r9 ; arg3 : __u32 thread_info_flags + bl do_notify_resume + bra restore_all + + ; perform syscall exit tracing + ALIGN +syscall_trace_entry: + ldi r4, #-ENOSYS + st r4, R0(sp) + bl do_syscall_trace + ld r0, ORIG_R0(sp) + ld r1, R1(sp) + ld r2, R2(sp) + ld r3, R3(sp) + ld r4, R4(sp) + ld r5, R5(sp) + ld r6, R6(sp) + ld r7, SYSCALL_NR(sp) + cmpui r7, #NR_syscalls + bc syscall_call + bra syscall_exit + + ; perform syscall exit tracing + ALIGN +syscall_exit_work: + ld r9, @(TI_FLAGS, r8) + and3 r4, r9, #_TIF_SYSCALL_TRACE + beqz r4, work_pending + STI(r4) ; could let do_syscall_trace() call + ; schedule() instead + bl do_syscall_trace + bra resume_userspace + + ALIGN +syscall_fault: + SAVE_ALL + GET_THREAD_INFO(r8) + ldi r4, #-EFAULT + st r4, R0(sp) + bra resume_userspace + + ALIGN +syscall_badsys: + ldi r4, #-ENOSYS + st r4, R0(sp) + bra resume_userspace + + .global eit_vector + + .equ ei_vec_table, eit_vector + 0x0200 + +/* + * EI handler routine + */ +ENTRY(ei_handler) +#if defined(CONFIG_CHIP_M32700) + SWITCH_TO_KERNEL_STACK + ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI). +#endif + SAVE_ALL + mv r1, sp ; arg1(regs) +#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ + || defined(CONFIG_CHIP_OPSP) + +; GET_ICU_STATUS; + seth r0, #shigh(M32R_ICU_ISTS_ADDR) + ld r0, @(low(M32R_ICU_ISTS_ADDR),r0) + st r0, @-sp +#if defined(CONFIG_SMP) + /* + * If IRQ == 0 --> Nothing to do, Not write IMASK + * If IRQ == IPI --> Do IPI handler, Not write IMASK + * If IRQ != 0, IPI --> Do do_IRQ(), Write IMASK + */ + slli r0, #4 + srli r0, #24 ; r0(irq_num<<2) + ;; IRQ exist check +#if defined(CONFIG_CHIP_M32700) + /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ + beqz r0, 3f ; if (!irq_num) goto exit +#else + beqz r0, 1f ; if (!irq_num) goto exit +#endif /* WORKAROUND */ + ;; IPI check + cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check + bc 2f + cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check + bnc 2f + LDIMM (r2, ei_vec_table) + add r2, r0 + ld r2, @r2 + beqz r2, 1f ; if (no IPI handler) goto exit + mv r0, r1 ; arg0(regs) + jl r2 + .fillinsn +1: + addi sp, #4 + bra ret_to_intr +#if defined(CONFIG_CHIP_M32700) + /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ + .fillinsn +3: + ld24 r14, #0x00070000 + seth r0, #shigh(M32R_ICU_IMASK_ADDR) + st r14, @(low(M32R_ICU_IMASK_ADDR), r0) + addi sp, #4 + bra ret_to_intr +#endif /* WORKAROUND */ + ;; do_IRQ + .fillinsn +2: + srli r0, #2 +#if defined(CONFIG_PLAT_USRV) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, 9f + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + .fillinsn +9: +#elif defined(CONFIG_PLAT_M32700UT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(M32700UT_LAN_ICUISTS) + or3 r0, r0, #low(M32700UT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(M32700UT_LCD_ICUISTS) + or3 r0, r0, #low(M32700UT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#elif defined(CONFIG_PLAT_OPSPUT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(OPSPUT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(OPSPUT_LAN_ICUISTS) + or3 r0, r0, #low(OPSPUT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(OPSPUT_LCD_ICUISTS) + or3 r0, r0, #low(OPSPUT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#endif /* CONFIG_PLAT_OPSPUT */ + bl do_IRQ ; r0(irq), r1(regs) +#else /* not CONFIG_SMP */ + srli r0, #22 ; r0(irq) +#if defined(CONFIG_PLAT_USRV) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, 1f + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + .fillinsn +1: +#elif defined(CONFIG_PLAT_M32700UT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(M32700UT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(M32700UT_LAN_ICUISTS) + or3 r0, r0, #low(M32700UT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(M32700UT_LCD_ICUISTS) + or3 r0, r0, #low(M32700UT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#elif defined(CONFIG_PLAT_OPSPUT) + add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt + bnez r2, check_int0 + ; read ICU status register of PLD + seth r0, #high(PLD_ICUISTS) + or3 r0, r0, #low(PLD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + addi r0, #(OPSPUT_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int0: + add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt + bnez r2, check_int2 + ; read ICU status of LAN-board + seth r0, #high(OPSPUT_LAN_ICUISTS) + or3 r0, r0, #low(OPSPUT_LAN_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_int2: + add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt + bnez r2, check_end + ; read ICU status of LCD-board + seth r0, #high(OPSPUT_LCD_ICUISTS) + or3 r0, r0, #low(OPSPUT_LCD_ICUISTS) + lduh r0, @r0 + slli r0, #21 + srli r0, #27 ; ISN + add3 r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE) + bra check_end + .fillinsn +check_end: +#endif /* CONFIG_PLAT_OPSPUT */ + bl do_IRQ +#endif /* CONFIG_SMP */ + ld r14, @sp+ + seth r0, #shigh(M32R_ICU_IMASK_ADDR) + st r14, @(low(M32R_ICU_IMASK_ADDR),r0) +#else +#error no chip configuration +#endif +ret_to_intr: + bra ret_from_intr + +/* + * Default EIT handler + */ + ALIGN +int_msg: + .asciz "Unknown interrupt\n" + .byte 0 + +ENTRY(default_eit_handler) + push r0 + mvfc r0, psw + push r1 + push r2 + push r3 + push r0 + LDIMM (r0, __KERNEL_DS) + mv r0, r1 + mv r0, r2 + LDIMM (r0, int_msg) + bl printk + pop r0 + pop r3 + pop r2 + pop r1 + mvtc r0, psw + pop r0 +infinit: + bra infinit + +#ifdef CONFIG_MMU +/* + * Access Exception handler + */ +ENTRY(ace_handler) + SWITCH_TO_KERNEL_STACK + SAVE_ALL + + seth r2, #shigh(MMU_REG_BASE) /* Check status register */ + ld r4, @(low(MESTS_offset),r2) + st r4, @(low(MESTS_offset),r2) + srl3 r1, r4, #4 +#ifdef CONFIG_CHIP_M32700 + and3 r1, r1, #0x0000ffff + ; WORKAROUND: ignore TME bit for the M32700(TS1). +#endif /* CONFIG_CHIP_M32700 */ + beqz r1, inst +oprand: + ld r2, @(low(MDEVA_offset),r2) ; set address + srli r2, #12 + slli r2, #12 + srli r1, #1 + bra 1f +inst: + and3 r1, r4, #2 + srli r1, #1 + or3 r1, r1, #8 + mvfc r2, bpc ; set address + .fillinsn +1: + mvfc r3, psw + mv r0, sp + and3 r3, r3, 0x800 + srli r3, #9 + or r1, r3 + /* + * do_page_fault(): + * r0 : struct pt_regs *regs + * r1 : unsigned long error-code + * r2 : unsigned long address + * error-code: + * +------+------+------+------+ + * | bit3 | bit2 | bit1 | bit0 | + * +------+------+------+------+ + * bit 3 == 0:means data, 1:means instruction + * bit 2 == 0:means kernel, 1:means user-mode + * bit 1 == 0:means read, 1:means write + * bit 0 == 0:means no page found 1:means protection fault + * + */ + bl do_page_fault + bra ret_from_intr +#endif /* CONFIG_MMU */ + + +ENTRY(alignment_check) +/* void alignment_check(int error_code) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + ldi r1, #0x30 ; error_code + mv r0, sp ; pt_regs + bl do_alignment_check +error_code: + bra ret_from_exception + +ENTRY(rie_handler) +/* void rie_handler(int error_code) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + mvfc r0, bpc + ld r1, @r0 + seth r0, #0xa0f0 + st r1, @r0 + ldi r1, #0x20 ; error_code + mv r0, sp ; pt_regs + bl do_rie_handler + bra error_code + +ENTRY(pie_handler) +/* void pie_handler(int error_code) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + ldi r1, #0 ; error_code ; FIXME + mv r0, sp ; pt_regs + bl do_pie_handler + bra error_code + +ENTRY(debug_trap) + .global withdraw_debug_trap + /* void debug_trap(void) */ + SWITCH_TO_KERNEL_STACK + SAVE_ALL + mv r0, sp ; pt_regs + bl withdraw_debug_trap + ldi r1, #0 ; error_code + mv r0, sp ; pt_regs + bl do_debug_trap + bra error_code + + +/* Cache flushing handler */ +ENTRY(cache_flushing_handler) + .global _flush_cache_all + /* void _flush_cache_all(void); */ + SWITCH_TO_KERNEL_STACK + push r0 + push r1 + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push lr + bl _flush_cache_all + pop lr + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + pop r0 + rte + +.data +ENTRY(sys_call_table) + .long sys_restart_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_lchown + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid + .long sys_getuid + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_cacheflush /* for M32R */ /* old stty syscall holder */ + .long sys_cachectl /* for M32R */ /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 - old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid + .long sys_getgid + .long sys_signal + .long sys_geteuid + .long sys_getegid /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall /* sys_olduname */ + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid /* 70 */ + .long sys_setregid + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups /* 80 */ + .long sys_setgroups + .long sys_ni_syscall /* sys_oldselect */ + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir + .long sys_ni_syscall /* 90 - old_mmap syscall holder */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm */ + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_uname + .long sys_ni_syscall /* 110 - iopl */ + .long sys_vhangup + .long sys_ni_syscall /* for idle */ + .long sys_ni_syscall /* for vm86old */ + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* sys_create_module */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130 sys_get_kernel_syms */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid + .long sys_setfsgid + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid + .long sys_getresuid /* 165 */ + .long sys_tas /* vm86 */ + .long sys_ni_syscall /* sys_query_module */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid /* 170 */ + .long sys_getresgid + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_chown + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_lchown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_chown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_mincore + .long sys_madvise + .long sys_getdents64 /* 220 */ + .long sys_fcntl64 + .long sys_ni_syscall /* reserved for TUX */ + .long sys_ni_syscall /* Reserved for Security */ + .long sys_gettid + .long sys_readahead /* 225 */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_ni_syscall /* reserved for "set_thread_area" system call */ + .long sys_ni_syscall /* reserved for "get_thread_area" system call */ + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 /* 250 */ + .long sys_ni_syscall + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 255 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 270 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_ni_syscall /* Reserved for sys_vserver */ + .long sys_ni_syscall /* Reserved for sys_mbind */ + .long sys_ni_syscall /* Reserved for sys_get_mempolicy */ + .long sys_ni_syscall /* Reserved for sys_set_mempolicy */ + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive /* 280 */ + .long sys_mq_notify + .long sys_mq_getsetattr + .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid + +syscall_table_size=(.-sys_call_table) + diff --git a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S new file mode 100644 index 000000000..3e8317399 --- /dev/null +++ b/arch/m32r/kernel/head.S @@ -0,0 +1,287 @@ +/* + * linux/arch/m32r/kernel/head.S + * + * M32R startup code. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +/* $Id$ */ + +#include +__INIT +__INITDATA + + .text +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * References to members of the boot_cpu_data structure. + */ + .text + .global start_kernel + .global __bss_start + .global _end +ENTRY(stext) +ENTRY(_stext) +ENTRY(startup_32) + /* Setup up the stack pointer */ + LDIMM (r0, spi_stack_top) + LDIMM (r1, spu_stack_top) + mvtc r0, spi + mvtc r1, spu + + /* Initilalize PSW */ + ldi r0, #0x0000 /* use SPI, disable EI */ + mvtc r0, psw + + /* Set up the stack pointer */ + LDIMM (r0, stack_start) + ld r0, @r0 + mvtc r0, spi + +/* + * Clear BSS first so that there are no surprises... + */ +#ifdef CONFIG_ISA_DUAL_ISSUE + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + ; R4 = BSS size in longwords (rounded down) + mv r4, r3 || ldi r1, #0 + srli r4, #4 || addi r2, #-4 + beqz r4, .Lendloop1 +.Lloop1: +#ifndef CONFIG_CHIP_M32310 + ; Touch memory for the no-write-allocating cache. + ld r0, @(4,r2) +#endif + st r1, @+r2 || addi r4, #-1 + st r1, @+r2 + st r1, @+r2 + st r1, @+r2 || cmpeq r1, r4 ; R4 = 0? + bnc .Lloop1 +.Lendloop1: + and3 r4, r3, #15 + addi r2, #4 + beqz r4, .Lendloop2 +.Lloop2: + stb r1, @r2 || addi r4, #-1 + addi r2, #1 + bnez r4, .Lloop2 +.Lendloop2: + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + LDIMM (r2, __bss_start) + LDIMM (r3, _end) + sub r3, r2 ; BSS size in bytes + mv r4, r3 + srli r4, #2 ; R4 = BSS size in longwords (rounded down) + ldi r1, #0 ; clear R1 for longwords store + addi r2, #-4 ; account for pre-inc store + beqz r4, .Lendloop1 ; any more to go? +.Lloop1: + st r1, @+r2 ; yep, zero out another longword + addi r4, #-1 ; decrement count + bnez r4, .Lloop1 ; go do some more +.Lendloop1: + and3 r4, r3, #3 ; get no. of remaining BSS bytes to clear + addi r2, #4 ; account for pre-inc store + beqz r4, .Lendloop2 ; any more to go? +.Lloop2: + stb r1, @r2 ; yep, zero out another byte + addi r2, #1 ; bump address + addi r4, #-1 ; decrement count + bnez r4, .Lloop2 ; go do some more +.Lendloop2: + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +#if 0 /* M32R_FIXME */ +/* + * Copy data segment from ROM to RAM. + */ + .global ROM_D, TOP_DATA, END_DATA + + LDIMM (r1, ROM_D) + LDIMM (r2, TOP_DATA) + LDIMM (r3, END_DATA) + addi r2, #-4 + addi r3, #-4 +loop1: + ld r0, @r1+ + st r0, @+r2 + cmp r2, r3 + bc loop1 +#endif /* 0 */ + +/* Jump to kernel */ + LDIMM (r2, start_kernel) + jl r2 + .fillinsn +1: + bra 1b ; main should never return here, but + ; just in case, we know what happens. + +#ifdef CONFIG_SMP +/* + * AP startup routine + */ + .text + .global eit_vector +ENTRY(startup_AP) +;; setup EVB + LDIMM (r4, eit_vector) + mvtc r4, cr5 + +;; enable MMU + LDIMM (r2, init_tlb) + jl r2 + seth r4, #high(MATM) + or3 r4, r4, #low(MATM) + ldi r5, #0x01 + st r5, @r4 ; Set MATM Reg(T bit ON) + ld r6, @r4 ; MATM Check + LDIMM (r5, 1f) + jmp r5 ; enable MMU + nop + .fillinsn +1: +;; ISN check + ld r6, @r4 ; MATM Check + seth r4, #high(M32R_ICU_ISTS_ADDR) + or3 r4, r4, #low(M32R_ICU_ISTS_ADDR) + ld r5, @r4 ; Read ISTSi reg. + mv r6, r5 + slli r5, #13 ; PIML check + srli r5, #13 ; + seth r4, #high(M32R_ICU_IMASK_ADDR) + or3 r4, r4, #low(M32R_ICU_IMASK_ADDR) + st r5, @r4 ; Write IMASKi reg. + slli r6, #4 ; ISN check + srli r6, #26 ; + seth r4, #high(M32R_IRQ_IPI5) + or3 r4, r4, #low(M32R_IRQ_IPI5) + bne r4, r6, 2f ; if (ISN != CPU_BOOT_IPI) goto sleep; + +;; check cpu_bootout_map and set cpu_bootin_map + LDIMM (r4, cpu_bootout_map) + ld r4, @r4 + seth r5, #high(M32R_CPUID_PORTL) + or3 r5, r5, #low(M32R_CPUID_PORTL) + ld r5, @r5 + ldi r6, #1 + sll r6, r5 + and r4, r6 + beqz r4, 2f + LDIMM (r4, cpu_bootin_map) + ld r5, @r4 + or r5, r6 + st r6, @r4 + +;; clear PSW + ldi r4, #0 + mvtc r4, psw + +;; setup SPI + LDIMM (r4, stack_start) + ld r4, @r4 + mvtc r4, spi + +;; setup BPC (start_secondary) + LDIMM (r4, start_secondary) + mvtc r4, bpc + + rte ; goto startup_secondary + nop + nop + + .fillinsn +2: + ;; disable MMU + seth r4, #high(MATM) + or3 r4, r4, #low(MATM) + ldi r5, #0 + st r5, @r4 ; Set MATM Reg(T bit OFF) + ld r6, @r4 ; MATM Check + LDIMM (r4, 3f) + seth r5, #high(__PAGE_OFFSET) + or3 r5, r5, #low(__PAGE_OFFSET) + not r5, r5 + and r4, r5 + jmp r4 ; disable MMU + nop + .fillinsn +3: + ;; SLEEP and wait IPI + LDIMM (r4, AP_loop) + seth r5, #high(__PAGE_OFFSET) + or3 r5, r5, #low(__PAGE_OFFSET) + not r5, r5 + and r4, r5 + jmp r4 + nop + nop +#endif /* CONFIG_SMP */ + +ENTRY(stack_start) + .long init_thread_union+8192 + .long __KERNEL_DS + +/* + * This is initialized to create a identity-mapping at 0-4M (for bootup + * purposes) and another mapping of the 0-4M area at virtual address + * PAGE_OFFSET. + */ + .text + +#define MOUNT_ROOT_RDONLY 1 +#define RAMDISK_FLAGS 0 ; 1024KB +#define ORIG_ROOT_DEV 0x0100 ; /dev/ram0 (major:01, minor:00) +#define LOADER_TYPE 1 ; (??? - non-zero value seems + ; to be needed to boot from initrd) + +#define COMMAND_LINE "" + + .section .empty_zero_page, "aw" +ENTRY(empty_zero_page) + .long MOUNT_ROOT_RDONLY /* offset: +0x00 */ + .long RAMDISK_FLAGS + .long ORIG_ROOT_DEV + .long LOADER_TYPE + .long 0 /* INITRD_START */ /* +0x10 */ + .long 0 /* INITRD_SIZE */ + .long 0 /* CPU_CLOCK */ + .long 0 /* BUS_CLOCK */ + .long 0 /* TIMER_DIVIDE */ /* +0x20 */ + .balign 256,0 + .asciz COMMAND_LINE + .byte 0 + .balign 4096,0,4096 + +/*------------------------------------------------------------------------ + * Stack area + */ + .section .spi + ALIGN + .global spi_stack_top + .zero 1024 +spi_stack_top: + + .section .spu + ALIGN + .global spu_stack_top + .zero 1024 +spu_stack_top: + + .end diff --git a/arch/m32r/kernel/init_task.c b/arch/m32r/kernel/init_task.c new file mode 100644 index 000000000..9e508fd9d --- /dev/null +++ b/arch/m32r/kernel/init_task.c @@ -0,0 +1,41 @@ +/* orig : i386 init_task.c */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct fs_struct init_fs = INIT_FS; +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); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); + diff --git a/arch/m32r/kernel/io_m32700ut.c b/arch/m32r/kernel/io_m32700ut.c new file mode 100644 index 000000000..501b75581 --- /dev/null +++ b/arch/m32r/kernel/io_m32700ut.c @@ -0,0 +1,455 @@ +/* + * linux/arch/m32r/kernel/io_mappi.c + * + * Typical I/O routines for M32700UT board. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) +static __inline__ void *__port2addr_ata(unsigned long port) +{ + static int dummy_reg; + + switch (port) { + case 0x1f0: return (void *)0xac002000; + case 0x1f1: return (void *)0xac012800; + case 0x1f2: return (void *)0xac012002; + case 0x1f3: return (void *)0xac012802; + case 0x1f4: return (void *)0xac012004; + case 0x1f5: return (void *)0xac012804; + case 0x1f6: return (void *)0xac012006; + case 0x1f7: return (void *)0xac012806; + case 0x3f6: return (void *)0xac01200e; + default: return (void *)&dummy_reg; + } +} +#endif + +/* + * M32700UT-LAN is located in the extended bus space + * from 0x10000000 to 0x13ffffff on physical address. + * The base address of LAN controller(LAN91C111) is 0x300. + */ +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} +static __inline__ void *_port2addr_usb(unsigned long port) +{ + return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return *(volatile unsigned char *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = (unsigned char *)addr; + + while (count--) *buf++ = _ne_inb(portp); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); + +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned char *)__port2addr_ata(port); + } +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned short *)__port2addr_ata(port); + } +#endif +#if defined(CONFIG_USB) + else if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned char *)__port2addr_ata(port); + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned short *)__port2addr_ata(port); + } else +#endif +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned char *)__port2addr_ata(port) = b; + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned short *)__port2addr_ata(port) = w; + } else +#endif +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned char *)__port2addr_ata(port) = b; + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned short *)__port2addr_ata(port) = w; + } else +#endif +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + unsigned char *buf = addr; + unsigned char *portp = __port2addr_ata(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to read data + * from the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while(count--) *(volatile unsigned char *)portp = *buf++; +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to write data + * into the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while(count--) *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while(count--) *(volatile unsigned short *)portp = *buf++; +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/io_mappi.c b/arch/m32r/kernel/io_mappi.c new file mode 100644 index 000000000..74aeca636 --- /dev/null +++ b/arch/m32r/kernel/io_mappi.c @@ -0,0 +1,368 @@ +/* + * linux/arch/m32r/kernel/io_mappi.c + * + * Typical I/O routines for Mappi board. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +/* $Id: io_mappi.c,v 1.9 2003/12/02 07:18:08 fujiwara Exp $ */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) +#define M32R_PCC_IOSTART1 0x2000 +#define M32R_PCC_IOEND1 (M32R_PCC_IOSTART1 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32RPCC */ + +#define PORT2ADDR(port) _port2addr(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)((port<<1) + NONCACHE_OFFSET + 0x0C000000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return (unsigned char) *(volatile unsigned short *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + unsigned short tmp; + + tmp = *(volatile unsigned short *)portp; + return le16_to_cpu(tmp); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned short *)portp = (unsigned short)b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread(0, port, &b, sizeof(b), 1, 0); + return b; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned char b; + pcc_ioread(1, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread(0, port, &w, sizeof(w), 1, 0); + return w; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned short w; + pcc_ioread(1, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread(0, port, &l, sizeof(l), 1, 0); + return l; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned short l; + pcc_ioread(1, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread(0, port, &b, sizeof(b), 1, 0); + return b; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned char b; + pcc_ioread(1, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread(0, port, &w, sizeof(w), 1, 0); + return w; + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + unsigned short w; + pcc_ioread(1, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &b, sizeof(b), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &w, sizeof(w), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &l, sizeof(l), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &b, sizeof(b), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, &w, sizeof(w), 1, 0); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320){ + portp = PORT2ADDR_NE(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_ioread(1, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = _ne_inw(portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_ioread(1, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outw(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1); + } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { + pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/io_mappi2.c b/arch/m32r/kernel/io_mappi2.c new file mode 100644 index 000000000..7705fb0bb --- /dev/null +++ b/arch/m32r/kernel/io_mappi2.c @@ -0,0 +1,370 @@ +/* + * linux/arch/m32r/kernel/io_mappi2.c + * + * Typical I/O routines for Mappi2 board. + * + * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +/* $Id:$ */ + +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_NE(port) _port2addr_ne(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +#ifdef CONFIG_CHIP_OPSP +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} +#else +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x04000000); +} +#endif +static __inline__ void *_port2addr_usb(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x14000000); +} +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return (unsigned char) *(volatile unsigned char *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ +#if 1 /* byte swap */ + unsigned short tmp,tmp2; + tmp = *(volatile unsigned short *)portp; + tmp2 = (tmp>>8|tmp<<8); + return tmp2; +#else + return *(volatile unsigned short *)portp; +#endif +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned short tmp; + unsigned char *buf = addr; + + tmp = *(volatile unsigned char *)portp; + while (count--) *buf++ = *(volatile unsigned char *)portp; +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = (unsigned char)b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = (w>>8|w<<8); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_USB) + else if (port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + v = *(volatile unsigned short *)PORT2ADDR_USB(port); + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + portp = PORT2ADDR_NE(port); + while (count--) *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/io_oaks32r.c b/arch/m32r/kernel/io_oaks32r.c new file mode 100644 index 000000000..7fcbf2047 --- /dev/null +++ b/arch/m32r/kernel/io_oaks32r.c @@ -0,0 +1,243 @@ +/* + * linux/arch/m32r/kernel/io_oaks32r.c + * + * Typical I/O routines for OAKS32R board. + * + * Copyright (c) 2001-2004 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +/* $Id$ */ + +#include +#include +#include +#include + +#define PORT2ADDR(port) _port2addr(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)((port<<1) + NONCACHE_OFFSET + 0x02000000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return *(volatile unsigned char *)(portp+1); +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + unsigned short tmp; + + tmp = *(unsigned short *)(portp) & 0xff; + tmp |= *(unsigned short *)(portp+2) << 8; + return tmp; +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = addr; + while (count--) *buf++ = *(volatile unsigned char *)(portp+1); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)(portp+1) = b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = (w >> 8); + *(volatile unsigned short *)(portp+2) = (w & 0xff); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inb(PORT2ADDR_NE(port)); + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + return _ne_inw(PORT2ADDR_NE(port)); + + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inb(PORT2ADDR_NE(port)); + else + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= 0x300 && port < 0x320) + v = _ne_inw(PORT2ADDR_NE(port)); + else + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outb(b, PORT2ADDR_NE(port)); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= 0x300 && port < 0x320) + _ne_outw(w, PORT2ADDR_NE(port)); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= 0x300 && port < 0x320) + _ne_insb(PORT2ADDR_NE(port), addr, count); + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = _ne_inw(portp); + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= 0x300 && port < 0x320) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outw(*buf++, portp); + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/io_opsput.c b/arch/m32r/kernel/io_opsput.c new file mode 100644 index 000000000..642376e3b --- /dev/null +++ b/arch/m32r/kernel/io_opsput.c @@ -0,0 +1,377 @@ +/* + * linux/arch/m32r/kernel/io_mappi.c + * + * Typical I/O routines for OPSPUT board. + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static __inline__ void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +/* + * OPSPUT-LAN is located in the extended bus space + * from 0x10000000 to 0x13ffffff on physical address. + * The base address of LAN controller(LAN91C111) is 0x300. + */ +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static __inline__ void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} +static __inline__ void *_port2addr_usb(unsigned long port) +{ + return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +#define PORT2ADDR_NE(port) _port2addr_ne(port) + +static __inline__ unsigned char _ne_inb(void *portp) +{ + return *(volatile unsigned char *)portp; +} + +static __inline__ unsigned short _ne_inw(void *portp) +{ + return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); +} + +static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = (unsigned char *)addr; + + while (count--) *buf++ = _ne_inb(portp); +} + +static __inline__ void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = b; +} + +static __inline__ void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_USB) + else if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inb(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + v = *(volatile unsigned char *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v; + + if (port >= LAN_IOSTART && port < LAN_IOEND) + v = _ne_inw(PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); + else +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + v = *(volatile unsigned short *)PORT2ADDR(port); + + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; + + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_USB) + if(port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; + + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to read data + * from the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) _ne_outb(*buf++, portp); +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + /* + * This portion is only used by smc91111.c to write data + * into the DATA_REG. Do not swap the data. + */ + portp = PORT2ADDR_NE(port); + while(count--) *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while(count--) *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/io_usrv.c b/arch/m32r/kernel/io_usrv.c new file mode 100644 index 000000000..cc77ced9f --- /dev/null +++ b/arch/m32r/kernel/io_usrv.c @@ -0,0 +1,247 @@ +/* + * linux/arch/m32r/kernel/io_usrv.c + * + * Typical I/O routines for uServer board. + * + * Copyright (c) 2001 - 2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + */ + +#include +#include +#include +#include + +#include +#include "../drivers/m32r_cfc.h" + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#define CFC_IOSTART CFC_IOPORT_BASE +#define CFC_IOEND (CFC_IOSTART + (M32R_PCC_MAPSIZE * M32R_MAX_PCC) - 1) + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) +#define UART0_REGSTART 0x04c20000 +#define UART1_REGSTART 0x04c20100 +#define UART_IOMAP_SIZE 8 +#define UART0_IOSTART 0x3f8 +#define UART0_IOEND (UART0_IOSTART + UART_IOMAP_SIZE - 1) +#define UART1_IOSTART 0x2f8 +#define UART1_IOEND (UART1_IOSTART + UART_IOMAP_SIZE - 1) +#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ + +#define PORT2ADDR(port) _port2addr(port) + +static __inline__ void *_port2addr(unsigned long port) +{ +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + if (port >= UART0_IOSTART && port <= UART0_IOEND) + port = ((port - UART0_IOSTART) << 1) + UART0_REGSTART; + else if (port >= UART1_IOSTART && port <= UART1_IOEND) + port = ((port - UART1_IOSTART) << 1) + UART1_REGSTART; +#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ + return (void *)(port + NONCACHE_OFFSET); +} + +static __inline__ void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char b; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else { + b = *(volatile unsigned char *)PORT2ADDR(port); + delay(); + return b; + } +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short w; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) { + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else { + w = *(volatile unsigned short *)PORT2ADDR(port); + delay(); + return w; + } +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v; + + v = *(volatile unsigned long *)PORT2ADDR(port); + delay(); + + return v; +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + else + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + else + *(volatile unsigned char *)PORT2ADDR(port) = b; + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + else + *(volatile unsigned short *)PORT2ADDR(port) = w; + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + *(volatile unsigned long *)PORT2ADDR(port) = l; + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_ioread_byte(0, port, addr, sizeof(unsigned char), count, 1); + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while(count--) *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_ioread_word(0, port, addr, sizeof(unsigned short), count, + 1); + else { + portp = PORT2ADDR(port); + while (count--) *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) + *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), + count, 1); + else { + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= CFC_IOSTART && port <= CFC_IOEND) + pcc_iowrite_word(0, port, (void *)addr, sizeof(unsigned short), + count, 1); + else { + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c new file mode 100644 index 000000000..ba1357733 --- /dev/null +++ b/arch/m32r/kernel/irq.c @@ -0,0 +1,1020 @@ +/* + * linux/arch/m32r/kernel/irq.c + * + * Copyright (c) 2003, 2004 Hitoshi Yamamoto + * + * Taken from i386 2.6.4 version. + */ + +/* + * linux/arch/i386/kernel/irq.c + * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + */ + +/* + * (mostly architecture independent, will move to kernel/irq.c in 2.5.) + * + * IRQs are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; + +static void register_irq_proc (unsigned int irq); + +/* + * Special irq handlers. + */ + +irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ return IRQ_NONE; } + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesn't deserve + * a generic callback i think. + */ + printk("unexpected IRQ trap at vector %02x\n", irq); +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +atomic_t irq_err_count; +atomic_t irq_mis_count; + +/* + * Generic, controller-independent functions: + */ + +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v, j; + struct irqaction * action; + unsigned long flags; + + if (i == 0) { + seq_printf(p, " "); + for (j=0; jtypename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + 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, "ERR: %10u\n", atomic_read(&irq_err_count)); + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + } + return 0; +} + +#ifdef CONFIG_SMP +inline void synchronize_irq(unsigned int irq) +{ + while (irq_desc[irq].status & IRQ_INPROGRESS) + cpu_relax(); +} +#endif + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, + struct pt_regs *regs, struct irqaction *action) +{ + int status = 1; /* Force the "do bottom halves" bit */ + int ret, retval = 0; + + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); + + do { + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + action = action->next; + retval |= ret; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + local_irq_disable(); + return retval; +} + +static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + struct irqaction *action; + + if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { + printk(KERN_ERR "irq event %d: bogus return value %x\n", + irq, action_ret); + } else { + printk(KERN_ERR "irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk(KERN_ERR "handlers:\n"); + action = desc->action; + do { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); +} + +static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + static int count = 100; + + if (count) { + count--; + __report_bad_irq(irq, desc, action_ret); + } +} + +static int noirqdebug; + +static int __init noirqdebug_setup(char *str) +{ + noirqdebug = 1; + printk("IRQ lockup detection disabled\n"); + return 1; +} + +__setup("noirqdebug", noirqdebug_setup); + +/* + * If 99,900 of the previous 100,000 interrupts have not been handled then + * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to + * turn the IRQ off. + * + * (The other 100-of-100,000 interrupts may have been a correctly-functioning + * device sharing an IRQ with the failing one) + * + * Called under desc->lock + */ +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + if (action_ret != IRQ_HANDLED) { + desc->irqs_unhandled++; + if (action_ret != IRQ_NONE) + report_bad_irq(irq, desc, action_ret); + } + + desc->irq_count++; + if (desc->irq_count < 100000) + return; + + desc->irq_count = 0; + if (desc->irqs_unhandled > 99900) { + /* + * The interrupt is stuck + */ + __report_bad_irq(irq, desc, action_ret); + /* + * Now kill the IRQ + */ + printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + desc->irqs_unhandled = 0; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +inline void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + disable_irq_nosync(irq); + if (desc->action) + synchronize_irq(irq); +} + +/** + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + unsigned int status; + + irq_enter(); + +#ifdef CONFIG_DEBUG_STACKOVERFLOW + /* FIXME M32R */ +#endif + kstat_this_cpu.irqs[irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (unlikely(!action)) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + irqreturn_t action_ret; + + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); + if (likely(!(desc->status & IRQ_PENDING))) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + irq_exit(); + +#if defined(CONFIG_SMP) + if (irq == M32R_IRQ_MFT2) + smp_send_timer(); +#endif /* CONFIG_SMP */ + + return 1; +} + +int can_request_irq(unsigned int irq, unsigned long irqflags) +{ + struct irqaction *action; + + if (irq >= NR_IRQS) + return 0; + action = irq_desc[irq].action; + if (action) { + if (irqflags & action->flags & SA_SHIRQ) + action = NULL; + } + return !action; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + cpus_clear(action->mask); + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +EXPORT_SYMBOL(request_irq); + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function must not be called from interrupt context. + */ + +void free_irq(unsigned int irq, void *dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + synchronize_irq(irq); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; + } +} + +EXPORT_SYMBOL(free_irq); + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + +unsigned long probe_irq_on(void) +{ + unsigned int i; + irq_desc_t *desc; + unsigned long val; + unsigned long delay; + + down(&probe_sem); + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ barrier(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; + } + spin_unlock_irq(&desc->lock); + } + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ barrier(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } + + return val; +} + +EXPORT_SYMBOL(probe_irq_on); + +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ + +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. + */ +unsigned int probe_irq_mask(unsigned long val) +{ + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (i < 16 && !(status & IRQ_WAITING)) + mask |= 1 << i; + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + return mask & val; +} + +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source). + */ + +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ + +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +EXPORT_SYMBOL(probe_irq_off); + +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + if (desc->handler == &no_irq_type) + return -ENOSYS; + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); + return 0; +} + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; + +#ifdef CONFIG_SMP + +static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; + +cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL }; + +static int irq_affinity_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int irq_affinity_write_proc(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int irq = (long)data, full_count = count, err; + cpumask_t new_value, tmp; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = cpumask_parse(buffer, count, new_value); + if (err) + return err; + + /* + * Do not allow disabling IRQs completely - it's a too easy + * 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; + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, + cpumask_of_cpu(first_cpu(new_value))); + + return full_count; +} + +#endif + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + cpumask_t *mask = (cpumask_t *)data; + unsigned long full_count = count, err; + cpumask_t new_value; + + err = cpumask_parse(buffer, count, new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || + irq_dir[irq]) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + +#ifdef CONFIG_SMP + { + struct proc_dir_entry *entry; + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + if (!entry) + return; + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) + register_irq_proc(i); +} + diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c new file mode 100644 index 000000000..f5aa0766f --- /dev/null +++ b/arch/m32r/kernel/m32r_ksyms.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +extern struct drive_info_struct drive_info; +EXPORT_SYMBOL(drive_info); +#endif + +/* platform dependent support */ +EXPORT_SYMBOL(boot_cpu_data); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down_trylock); + +/* Networking helper routines. */ +/* Delay loops */ +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__delay); +EXPORT_SYMBOL(__const_udelay); + +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); + +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); + +EXPORT_SYMBOL(strncpy_from_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(clear_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__generic_copy_from_user); +EXPORT_SYMBOL(__generic_copy_to_user); +EXPORT_SYMBOL(strnlen_user); + +#ifdef CONFIG_SMP +#ifdef CONFIG_CHIP_M32700_TS1 +extern void *dcache_dummy; +EXPORT_SYMBOL(dcache_dummy); +#endif +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(cpu_callout_map); + +/* Global SMP stuff */ +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(smp_call_function); + +/* TLB flushing */ +EXPORT_SYMBOL(smp_flush_tlb_page); +EXPORT_SYMBOL_GPL(smp_flush_tlb_all); +#endif + +/* compiler generated symbol */ +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __lshldi3(void); +extern void __lshrdi3(void); +extern void __muldi3(void); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__lshldi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__muldi3); + +/* memory and string operations */ +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(memcpy); +/* EXPORT_SYMBOL(memcpy_fromio); // not implement yet */ +/* EXPORT_SYMBOL(memcpy_toio); // not implement yet */ +EXPORT_SYMBOL(memset); +/* EXPORT_SYMBOL(memset_io); // not implement yet */ +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(copy_page); +EXPORT_SYMBOL(clear_page); + +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strncpy); + +EXPORT_SYMBOL(_inb); +EXPORT_SYMBOL(_inw); +EXPORT_SYMBOL(_inl); +EXPORT_SYMBOL(_outb); +EXPORT_SYMBOL(_outw); +EXPORT_SYMBOL(_outl); +EXPORT_SYMBOL(_inb_p); +EXPORT_SYMBOL(_inw_p); +EXPORT_SYMBOL(_inl_p); +EXPORT_SYMBOL(_outb_p); +EXPORT_SYMBOL(_outw_p); +EXPORT_SYMBOL(_outl_p); +EXPORT_SYMBOL(_insb); +EXPORT_SYMBOL(_insw); +EXPORT_SYMBOL(_insl); +EXPORT_SYMBOL(_outsb); +EXPORT_SYMBOL(_outsw); +EXPORT_SYMBOL(_outsl); +EXPORT_SYMBOL(_readb); +EXPORT_SYMBOL(_readw); +EXPORT_SYMBOL(_readl); +EXPORT_SYMBOL(_writeb); +EXPORT_SYMBOL(_writew); +EXPORT_SYMBOL(_writel); + diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c new file mode 100644 index 000000000..2d5c38448 --- /dev/null +++ b/arch/m32r/kernel/module.c @@ -0,0 +1,253 @@ +/* Kernel module help for M32R. + + 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 +*/ +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc_exec(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +#define COPY_UNALIGNED_WORD(sw, tw, align) \ +{ \ + void *__s = &(sw), *__t = &(tw); \ + unsigned short *__s2 = __s, *__t2 =__t; \ + unsigned char *__s1 = __s, *__t1 =__t; \ + switch ((align)) \ + { \ + case 0: \ + *(unsigned long *) __t = *(unsigned long *) __s; \ + break; \ + case 2: \ + *__t2++ = *__s2++; \ + *__t2 = *__s2; \ + break; \ + default: \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1 = *__s1; \ + break; \ + } \ +} + +#define COPY_UNALIGNED_HWORD(sw, tw, align) \ + { \ + void *__s = &(sw), *__t = &(tw); \ + unsigned short *__s2 = __s, *__t2 =__t; \ + unsigned char *__s1 = __s, *__t1 =__t; \ + switch ((align)) \ + { \ + case 0: \ + *__t2 = *__s2; \ + break; \ + default: \ + *__t1++ = *__s1++; \ + *__t1 = *__s1; \ + break; \ + } \ + } + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + Elf32_Addr relocation; + uint32_t *location; + uint32_t value; + unsigned short *hlocation; + unsigned short hvalue; + int svalue; + int align; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + relocation = sym->st_value + rel[i].r_addend; + align = (int)location & 3; + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_M32R_32_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_HI16_ULO_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + relocation = (relocation >>16) & 0xffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_HI16_SLO_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + if (relocation & 0x8000) relocation += 0x10000; + relocation = (relocation >>16) & 0xffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_16_RELA: + hlocation = (unsigned short *)location; + relocation = relocation & 0xffff; + /* RELA must has 0 at relocation field. */ + hvalue = relocation; + COPY_UNALIGNED_WORD (hvalue, *hlocation, align); + break; + case R_M32R_SDA16_RELA: + case R_M32R_LO16_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + relocation = relocation & 0xffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_24_RELA: + COPY_UNALIGNED_WORD (*location, value, align); + relocation = relocation & 0xffffff; + /* RELA must has 0 at relocation field. */ + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_18_PCREL_RELA: + relocation = (relocation - (Elf32_Addr) location); + if (relocation < -0x20000 || 0x1fffc < relocation) + { + printk(KERN_ERR "module %s: relocation overflow: %u\n", + me->name, relocation); + return -ENOEXEC; + } + COPY_UNALIGNED_WORD (*location, value, align); + if (value & 0xffff) + { + /* RELA must has 0 at relocation field. */ + printk(KERN_ERR "module %s: illegal relocation field: %u\n", + me->name, value); + return -ENOEXEC; + } + relocation = (relocation >> 2) & 0xffff; + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + case R_M32R_10_PCREL_RELA: + hlocation = (unsigned short *)location; + relocation = (relocation - (Elf32_Addr) location); + COPY_UNALIGNED_HWORD (*hlocation, hvalue, align); + svalue = (int)hvalue; + svalue = (signed char)svalue << 2; + relocation += svalue; + relocation = (relocation >> 2) & 0xff; + hvalue = hvalue & 0xff00; + hvalue += relocation; + COPY_UNALIGNED_HWORD (hvalue, *hlocation, align); + break; + case R_M32R_26_PCREL_RELA: + relocation = (relocation - (Elf32_Addr) location); + if (relocation < -0x2000000 || 0x1fffffc < relocation) + { + printk(KERN_ERR "module %s: relocation overflow: %u\n", + me->name, relocation); + return -ENOEXEC; + } + COPY_UNALIGNED_WORD (*location, value, align); + if (value & 0xffffff) + { + /* RELA must has 0 at relocation field. */ + printk(KERN_ERR "module %s: illegal relocation field: %u\n", + me->name, value); + return -ENOEXEC; + } + relocation = (relocation >> 2) & 0xffffff; + value += relocation; + COPY_UNALIGNED_WORD (value, *location, align); + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ +#if 0 + printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +#endif + return 0; + +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c new file mode 100644 index 000000000..9e7de27a8 --- /dev/null +++ b/arch/m32r/kernel/process.c @@ -0,0 +1,356 @@ +/* + * linux/arch/m32r/kernel/process.c + * orig : sh + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + * Taken from sh version. + * Copyright (C) 1995 Linus Torvalds + * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + */ + +#undef DEBUG_PROCESS +#ifdef DEBUG_PROCESS +#define DPRINTK(fmt, args...) printk("%s:%d:%s: " fmt, __FILE__, __LINE__, \ + __FUNCTION__, ##args) +#else +#define DPRINTK(fmt, args...) +#endif + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static int hlt_counter=0; + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + return tsk->thread.lr; +} + +/* + * Powermanagement idle function, if any.. + */ +void (*pm_idle)(void) = NULL; + +void disable_hlt(void) +{ + hlt_counter++; +} + +EXPORT_SYMBOL(disable_hlt); + +void enable_hlt(void) +{ + hlt_counter--; +} + +EXPORT_SYMBOL(enable_hlt); + +/* + * We use this is we don't have any better + * idle routine.. + */ +void default_idle(void) +{ + /* M32R_FIXME: Please use "cpu_sleep" mode. */ + cpu_relax(); +} + +/* + * On SMP it's slightly faster (but much more power-consuming!) + * to poll the ->work.need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +static void poll_idle (void) +{ + /* M32R_FIXME */ + cpu_relax(); +} + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) { + void (*idle)(void) = pm_idle; + + if (!idle) + idle = default_idle; + + idle(); + } + schedule(); + } +} + +void machine_restart(char *__unused) +{ + printk("Please push reset button!\n"); + while (1) + cpu_relax(); +} + +EXPORT_SYMBOL(machine_restart); + +void machine_halt(void) +{ + printk("Please push reset button!\n"); + while (1) + cpu_relax(); +} + +EXPORT_SYMBOL(machine_halt); + +void machine_power_off(void) +{ + /* M32R_FIXME */ +} + +EXPORT_SYMBOL(machine_power_off); + +static int __init idle_setup (char *str) +{ + if (!strncmp(str, "poll", 4)) { + printk("using poll in idle threads.\n"); + pm_idle = poll_idle; + } else if (!strncmp(str, "sleep", 4)) { + printk("using sleep in idle threads.\n"); + pm_idle = default_idle; + } + + return 1; +} + +__setup("idle=", idle_setup); + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("BPC[%08lx]:PSW[%08lx]:LR [%08lx]:FP [%08lx]\n", \ + regs->bpc, regs->psw, regs->lr, regs->fp); + printk("BBPC[%08lx]:BBPSW[%08lx]:SPU[%08lx]:SPI[%08lx]\n", \ + regs->bbpc, regs->bbpsw, regs->spu, regs->spi); + printk("R0 [%08lx]:R1 [%08lx]:R2 [%08lx]:R3 [%08lx]\n", \ + regs->r0, regs->r1, regs->r2, regs->r3); + printk("R4 [%08lx]:R5 [%08lx]:R6 [%08lx]:R7 [%08lx]\n", \ + regs->r4, regs->r5, regs->r6, regs->r7); + printk("R8 [%08lx]:R9 [%08lx]:R10[%08lx]:R11[%08lx]\n", \ + regs->r8, regs->r9, regs->r10, regs->r11); + printk("R12[%08lx]\n", \ + regs->r12); + +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + printk("ACC0H[%08lx]:ACC0L[%08lx]\n", \ + regs->acc0h, regs->acc0l); + printk("ACC1H[%08lx]:ACC1L[%08lx]\n", \ + regs->acc1h, regs->acc1l); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + printk("ACCH[%08lx]:ACCL[%08lx]\n", \ + regs->acch, regs->accl); +#else +#error unknown isa configuration +#endif +} + +/* + * Create a kernel thread + */ + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg) +{ + fn(arg); + do_exit(-1); +} + +int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof (regs)); + regs.r1 = (unsigned long)fn; + regs.r2 = (unsigned long)arg; + + regs.bpc = (unsigned long)kernel_thread_helper; + + regs.psw = M32R_PSW_BIE; + + /* Ok, create the new process. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, + NULL); +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* Nothing to do. */ + DPRINTK("pid = %d\n", current->pid); +} + +void flush_thread(void) +{ + DPRINTK("pid = %d\n", current->pid); + memset(¤t->thread.debug_trap, 0, sizeof(struct debug_trap)); +} + +void release_thread(struct task_struct *dead_task) +{ + /* do nothing */ + DPRINTK("pid = %d\n", dead_task->pid); +} + +/* Fill in the fpu structure for a core dump.. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) +{ + return 0; /* Task didn't use the fpu at all. */ +} + +int copy_thread(int nr, unsigned long clone_flags, unsigned long spu, + unsigned long unused, struct task_struct *tsk, struct pt_regs *regs) +{ + struct pt_regs *childregs; + unsigned long sp = (unsigned long)tsk->thread_info + THREAD_SIZE; + extern void ret_from_fork(void); + + tsk->set_child_tid = tsk->clear_child_tid = NULL; + + /* Copy registers */ + sp -= sizeof (struct pt_regs); + childregs = (struct pt_regs *)sp; + *childregs = *regs; + + childregs->spu = spu; + childregs->r0 = 0; /* Child gets zero as return value */ + regs->r0 = tsk->pid; + tsk->thread.sp = (unsigned long)childregs; + tsk->thread.lr = (unsigned long)ret_from_fork; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + /* M32R_FIXME */ +} + +/* + * Capture the user space registers if the task is not running (in user space) + */ +int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +{ + /* M32R_FIXME */ + return 1; +} + +asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, + struct pt_regs regs) +{ +#ifdef CONFIG_MMU + return do_fork(SIGCHLD, regs.spu, ®s, 0, NULL, NULL); +#else + return -EINVAL; +#endif /* CONFIG_MMU */ +} + +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, struct pt_regs regs) +{ + if (!newsp) + newsp = regs.spu; + + return do_fork(clone_flags, newsp, ®s, 0, NULL, NULL); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, + struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, ®s, 0, + NULL, NULL); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, char __user * __user *uenvp, + unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, + struct pt_regs regs) +{ + int error; + char *filename; + + filename = getname(ufilename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename, uargv, uenvp, ®s); + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); +out: + return error; +} + +/* + * These bracket the sleeping functions.. + */ +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + /* M32R_FIXME */ + return (0); +} + diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c new file mode 100644 index 000000000..ab4137a33 --- /dev/null +++ b/arch/m32r/kernel/ptrace.c @@ -0,0 +1,858 @@ +/* + * linux/arch/m32r/kernel/ptrace.c + * + * Copyright (C) 2002 Hirokazu Takata, Takeo Takahashi + * Copyright (C) 2004 Hirokazu Takata + * + * Original x86 implementation: + * By Ross Biro 1/23/92 + * edited by Linus Torvalds + * + * Some code taken from sh version: + * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka + * Some code taken from arm version: + * Copyright (C) 2000 Russell King + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + * + * Note: if a user thread is execve'd from kernel space, the + * kernel stack will not be empty on entry to the kernel, so + * ptracing these tasks will fail. + */ +static inline struct pt_regs * +get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task->thread_info + THREAD_SIZE + - sizeof(struct pt_regs)); +} + +/* + * This routine will get a word off of the process kernel stack. + */ +static inline unsigned long int +get_stack_long(struct task_struct *task, int offset) +{ + unsigned long *stack; + + stack = (unsigned long *)get_user_regs(task); + + return stack[offset]; +} + +/* + * This routine will put a word on the process kernel stack. + */ +static inline int +put_stack_long(struct task_struct *task, int offset, unsigned long data) +{ + unsigned long *stack; + + stack = (unsigned long *)get_user_regs(task); + stack[offset] = data; + + return 0; +} + +static int reg_offset[] = { + PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, + PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU, +}; + +/* + * Read the word at offset "off" into the "struct user". We + * actually access the pt_regs stored on the kernel stack. + */ +static int ptrace_read_user(struct task_struct *tsk, unsigned long off, + unsigned long __user *data) +{ + unsigned long tmp; +#ifndef NO_FPU + struct user * dummy = NULL; +#endif + + if ((off & 3) || (off < 0) || (off > sizeof(struct user) - 3)) + return -EIO; + + off >>= 2; + switch (off) { + case PT_EVB: + __asm__ __volatile__ ( + "mvfc %0, cr5 \n\t" + : "=r" (tmp) + ); + break; + case PT_CBR: { + unsigned long psw; + psw = get_stack_long(tsk, PT_PSW); + tmp = ((psw >> 8) & 1); + } + break; + case PT_PSW: { + unsigned long psw, bbpsw; + psw = get_stack_long(tsk, PT_PSW); + bbpsw = get_stack_long(tsk, PT_BBPSW); + tmp = ((psw >> 8) & 0xff) | ((bbpsw & 0xff) << 8); + } + break; + case PT_PC: + tmp = get_stack_long(tsk, PT_BPC); + break; + case PT_BPC: + off = PT_BBPC; + /* fall through */ + default: + if (off < (sizeof(struct pt_regs) >> 2)) + tmp = get_stack_long(tsk, off); +#ifndef NO_FPU + else if (off >= (long)(&dummy->fpu >> 2) && + off < (long)(&dummy->u_fpvalid >> 2)) { + if (!tsk->used_math) { + if (off == (long)(&dummy->fpu.fpscr >> 2)) + tmp = FPSCR_INIT; + else + tmp = 0; + } else + tmp = ((long *)(&tsk->thread.fpu >> 2)) + [off - (long)&dummy->fpu]; + } else if (off == (long)(&dummy->u_fpvalid >> 2)) + tmp = tsk->used_math; +#endif /* not NO_FPU */ + else + tmp = 0; + } + + return put_user(tmp, data); +} + +static int ptrace_write_user(struct task_struct *tsk, unsigned long off, + unsigned long data) +{ + int ret = -EIO; +#ifndef NO_FPU + struct user * dummy = NULL; +#endif + + if ((off & 3) || off < 0 || + off > sizeof(struct user) - 3) + return -EIO; + + off >>= 2; + switch (off) { + case PT_EVB: + case PT_BPC: + case PT_SPI: + /* We don't allow to modify evb. */ + ret = 0; + break; + case PT_PSW: + case PT_CBR: { + /* We allow to modify only cbr in psw */ + unsigned long psw; + psw = get_stack_long(tsk, PT_PSW); + psw = (psw & ~0x100) | ((data & 1) << 8); + ret = put_stack_long(tsk, PT_PSW, psw); + } + break; + case PT_PC: + off = PT_BPC; + data &= ~1; + /* fall through */ + default: + if (off < (sizeof(struct pt_regs) >> 2)) + ret = put_stack_long(tsk, off, data); +#ifndef NO_FPU + else if (off >= (long)(&dummy->fpu >> 2) && + off < (long)(&dummy->u_fpvalid >> 2)) { + tsk->used_math = 1; + ((long *)&tsk->thread.fpu) + [off - (long)&dummy->fpu] = data; + ret = 0; + } else if (off == (long)(&dummy->u_fpvalid >> 2)) { + tsk->used_math = data ? 1 : 0; + ret = 0; + } +#endif /* not NO_FPU */ + break; + } + + return ret; +} + +/* + * Get all user integer registers. + */ +static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs *regs = get_user_regs(tsk); + + return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; +} + +/* + * Set all user integer registers. + */ +static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs newregs; + int ret; + + ret = -EFAULT; + if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { + struct pt_regs *regs = get_user_regs(tsk); + *regs = newregs; + ret = 0; + } + + return ret; +} + + +static inline int +check_condition_bit(struct task_struct *child) +{ + return (int)((get_stack_long(child, PT_PSW) >> 8) & 1); +} + +static int +check_condition_src(unsigned long op, unsigned long regno1, + unsigned long regno2, struct task_struct *child) +{ + unsigned long reg1, reg2; + + reg2 = get_stack_long(child, reg_offset[regno2]); + + switch (op) { + case 0x0: /* BEQ */ + reg1 = get_stack_long(child, reg_offset[regno1]); + return reg1 == reg2; + case 0x1: /* BNE */ + reg1 = get_stack_long(child, reg_offset[regno1]); + return reg1 != reg2; + case 0x8: /* BEQZ */ + return reg2 == 0; + case 0x9: /* BNEZ */ + return reg2 != 0; + case 0xa: /* BLTZ */ + return (int)reg2 < 0; + case 0xb: /* BGEZ */ + return (int)reg2 >= 0; + case 0xc: /* BLEZ */ + return (int)reg2 <= 0; + case 0xd: /* BGTZ */ + return (int)reg2 > 0; + default: + /* never reached */ + return 0; + } +} + +static void +compute_next_pc_for_16bit_insn(unsigned long insn, unsigned long pc, + unsigned long *next_pc, + struct task_struct *child) +{ + unsigned long op, op2, op3; + unsigned long disp; + unsigned long regno; + int parallel = 0; + + if (insn & 0x00008000) + parallel = 1; + if (pc & 3) + insn &= 0x7fff; /* right slot */ + else + insn >>= 16; /* left slot */ + + op = (insn >> 12) & 0xf; + op2 = (insn >> 8) & 0xf; + op3 = (insn >> 4) & 0xf; + + if (op == 0x7) { + switch (op2) { + case 0xd: /* BNC */ + case 0x9: /* BNCL */ + if (!check_condition_bit(child)) { + disp = (long)(insn << 24) >> 22; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0x8: /* BCL */ + case 0xc: /* BC */ + if (check_condition_bit(child)) { + disp = (long)(insn << 24) >> 22; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0xe: /* BL */ + case 0xf: /* BRA */ + disp = (long)(insn << 24) >> 22; + *next_pc = (pc & ~0x3) + disp; + return; + break; + } + } else if (op == 0x1) { + switch (op2) { + case 0x0: + if (op3 == 0xf) { /* TRAP */ +#if 1 + /* pass through */ +#else + /* kernel space is not allowed as next_pc */ + unsigned long evb; + unsigned long trapno; + trapno = insn & 0xf; + __asm__ __volatile__ ( + "mvfc %0, cr5\n" + :"=r"(evb) + : + ); + *next_pc = evb + (trapno << 2); + return; +#endif + } else if (op3 == 0xd) { /* RTE */ + *next_pc = get_stack_long(child, PT_BPC); + return; + } + break; + case 0xc: /* JC */ + if (op3 == 0xc && check_condition_bit(child)) { + regno = insn & 0xf; + *next_pc = get_stack_long(child, + reg_offset[regno]); + return; + } + break; + case 0xd: /* JNC */ + if (op3 == 0xc && !check_condition_bit(child)) { + regno = insn & 0xf; + *next_pc = get_stack_long(child, + reg_offset[regno]); + return; + } + break; + case 0xe: /* JL */ + case 0xf: /* JMP */ + if (op3 == 0xc) { /* JMP */ + regno = insn & 0xf; + *next_pc = get_stack_long(child, + reg_offset[regno]); + return; + } + break; + } + } + if (parallel) + *next_pc = pc + 4; + else + *next_pc = pc + 2; +} + +static void +compute_next_pc_for_32bit_insn(unsigned long insn, unsigned long pc, + unsigned long *next_pc, + struct task_struct *child) +{ + unsigned long op; + unsigned long op2; + unsigned long disp; + unsigned long regno1, regno2; + + op = (insn >> 28) & 0xf; + if (op == 0xf) { /* branch 24-bit relative */ + op2 = (insn >> 24) & 0xf; + switch (op2) { + case 0xd: /* BNC */ + case 0x9: /* BNCL */ + if (!check_condition_bit(child)) { + disp = (long)(insn << 8) >> 6; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0x8: /* BCL */ + case 0xc: /* BC */ + if (check_condition_bit(child)) { + disp = (long)(insn << 8) >> 6; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + case 0xe: /* BL */ + case 0xf: /* BRA */ + disp = (long)(insn << 8) >> 6; + *next_pc = (pc & ~0x3) + disp; + return; + } + } else if (op == 0xb) { /* branch 16-bit relative */ + op2 = (insn >> 20) & 0xf; + switch (op2) { + case 0x0: /* BEQ */ + case 0x1: /* BNE */ + case 0x8: /* BEQZ */ + case 0x9: /* BNEZ */ + case 0xa: /* BLTZ */ + case 0xb: /* BGEZ */ + case 0xc: /* BLEZ */ + case 0xd: /* BGTZ */ + regno1 = ((insn >> 24) & 0xf); + regno2 = ((insn >> 16) & 0xf); + if (check_condition_src(op2, regno1, regno2, child)) { + disp = (long)(insn << 16) >> 14; + *next_pc = (pc & ~0x3) + disp; + return; + } + break; + } + } + *next_pc = pc + 4; +} + +static inline void +compute_next_pc(unsigned long insn, unsigned long pc, + unsigned long *next_pc, struct task_struct *child) +{ + if (insn & 0x80000000) + compute_next_pc_for_32bit_insn(insn, pc, next_pc, child); + else + compute_next_pc_for_16bit_insn(insn, pc, next_pc, child); +} + +static int +register_debug_trap(struct task_struct *child, unsigned long next_pc, + unsigned long next_insn, unsigned long *code) +{ + struct debug_trap *p = &child->thread.debug_trap; + unsigned long addr = next_pc & ~3; + + if (p->nr_trap != 0) { + printk("kernel BUG at %s %d: p->nr_trap = %d\n", + __FILE__, __LINE__, p->nr_trap); + return -1; + } + p->addr = addr; + p->insn = next_insn; + p->nr_trap++; + if (next_pc & 3) { + *code = (next_insn & 0xffff0000) | 0x10f1; + /* xxx --> TRAP1 */ + } else { + if ((next_insn & 0x80000000) || (next_insn & 0x8000)) { + *code = 0x10f17000; + /* TRAP1 --> NOP */ + } else { + *code = (next_insn & 0xffff) | 0x10f10000; + /* TRAP1 --> xxx */ + } + } + return 0; +} + +int withdraw_debug_trap_for_signal(struct task_struct *child) +{ + struct debug_trap *p = &child->thread.debug_trap; + int nr_trap = p->nr_trap; + + if (nr_trap) { + access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1); + p->nr_trap = 0; + p->addr = 0; + p->insn = 0; + } + return nr_trap; +} + +static int +unregister_debug_trap(struct task_struct *child, unsigned long addr, + unsigned long *code) +{ + struct debug_trap *p = &child->thread.debug_trap; + + if (p->nr_trap != 1 || p->addr != addr) { + /* The trap may be requested from debugger. + * ptrace should do nothing in this case. + */ + return 0; + } + *code = p->insn; + p->insn = 0; + p->addr = 0; + p->nr_trap--; + return 1; +} + +static void +unregister_all_debug_traps(struct task_struct *child) +{ + struct debug_trap *p = &child->thread.debug_trap; + + if (p->nr_trap) { + access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1); + p->addr = 0; + p->insn = 0; + p->nr_trap = 0; + } +} + +static inline void +invalidate_cache(void) +{ +#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP) + + _flush_cache_copyback_all(); + +#else /* ! CONFIG_CHIP_M32700 */ + + /* Invalidate cache */ + __asm__ __volatile__ ( + "ldi r0, #-1 \n\t" + "ldi r1, #0 \n\t" + "stb r1, @r0 ; cache off \n\t" + "; \n\t" + "ldi r0, #-2 \n\t" + "ldi r1, #1 \n\t" + "stb r1, @r0 ; cache invalidate \n\t" + ".fillinsn \n" + "0: \n\t" + "ldb r1, @r0 ; invalidate check \n\t" + "bnez r1, 0b \n\t" + "; \n\t" + "ldi r0, #-1 \n\t" + "ldi r1, #1 \n\t" + "stb r1, @r0 ; cache on \n\t" + : : : "r0", "r1", "memory" + ); + /* FIXME: copying-back d-cache and invalidating i-cache are needed. + */ +#endif /* CONFIG_CHIP_M32700 */ +} + +/* Embed a debug trap (TRAP1) code */ +static int +embed_debug_trap(struct task_struct *child, unsigned long next_pc) +{ + unsigned long next_insn, code; + unsigned long addr = next_pc & ~3; + + if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0) + != sizeof(next_insn)) { + return -1; /* error */ + } + + /* Set a trap code. */ + if (register_debug_trap(child, next_pc, next_insn, &code)) { + return -1; /* error */ + } + if (access_process_vm(child, addr, &code, sizeof(code), 1) + != sizeof(code)) { + return -1; /* error */ + } + return 0; /* success */ +} + +void +embed_debug_trap_for_signal(struct task_struct *child) +{ + unsigned long next_pc; + unsigned long pc, insn; + int ret; + + pc = get_stack_long(child, PT_BPC); + ret = access_process_vm(child, pc&~3, &insn, sizeof(insn), 0); + if (ret != sizeof(insn)) { + printk("kernel BUG at %s %d: access_process_vm returns %d\n", + __FILE__, __LINE__, ret); + return; + } + compute_next_pc(insn, pc, &next_pc, child); + if (next_pc & 0x80000000) { + printk("kernel BUG at %s %d: next_pc = 0x%08x\n", + __FILE__, __LINE__, (int)next_pc); + return; + } + if (embed_debug_trap(child, next_pc)) { + printk("kernel BUG at %s %d: embed_debug_trap error\n", + __FILE__, __LINE__); + return; + } + invalidate_cache(); +} + +void +withdraw_debug_trap(struct pt_regs *regs) +{ + unsigned long addr; + unsigned long code; + + addr = (regs->bpc - 2) & ~3; + regs->bpc -= 2; + if (unregister_debug_trap(current, addr, &code)) { + access_process_vm(current, addr, &code, sizeof(code), 1); + invalidate_cache(); + } +} + +static void +init_debug_traps(struct task_struct *child) +{ + struct debug_trap *p = &child->thread.debug_trap; + p->nr_trap = 0; + p->addr = 0; + p->insn = 0; +} + + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* nothing to do.. */ +} + +static int +do_ptrace(long request, struct task_struct *child, long addr, long data) +{ + unsigned long tmp; + int ret; + + switch (request) { + /* + * read word at location "addr" in the child process. + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (ret == sizeof(tmp)) + ret = put_user(tmp,(unsigned long __user *) data); + else + ret = -EIO; + break; + + /* + * read the word at location addr in the USER area. + */ + case PTRACE_PEEKUSR: + ret = ptrace_read_user(child, addr, + (unsigned long __user *)data); + break; + + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + ret = access_process_vm(child, addr, &data, sizeof(data), 1); + if (ret == sizeof(data)) { + ret = 0; + if (request == PTRACE_POKETEXT) { + invalidate_cache(); + } + } else { + ret = -EIO; + } + break; + + /* + * write the word at location addr in the USER area. + */ + case PTRACE_POKEUSR: + ret = ptrace_write_user(child, addr, data); + break; + + /* + * continue/restart and stop at next (return from) syscall + */ + case PTRACE_SYSCALL: + case PTRACE_CONT: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + ret = 0; + unregister_all_debug_traps(child); + invalidate_cache(); + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + } + + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: { + unsigned long next_pc; + unsigned long pc, insn; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + if ((child->ptrace & PT_DTRACE) == 0) { + /* Spurious delayed TF traps may occur */ + child->ptrace |= PT_DTRACE; + } + + /* Compute next pc. */ + pc = get_stack_long(child, PT_BPC); + + if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) + != sizeof(insn)) + break; + + compute_next_pc(insn, pc, &next_pc, child); + if (next_pc & 0x80000000) + break; + + if (embed_debug_trap(child, next_pc)) + break; + + invalidate_cache(); + child->exit_code = data; + + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + /* + * detach a process that was attached. + */ + case PTRACE_DETACH: + ret = 0; + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, (void __user *)data); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, (void __user *)data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + if (ret == 0) + init_debug_traps(child); + goto out_tsk; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret == 0) + ret = do_ptrace(request, child, addr, data); + +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + + return ret; +} + +/* notification of system call entry/exit + * - triggered by current->work.syscall_trace + */ +void do_syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + diff --git a/arch/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c new file mode 100644 index 000000000..358f217c5 --- /dev/null +++ b/arch/m32r/kernel/semaphore.c @@ -0,0 +1,186 @@ +/* + * linux/arch/m32r/semaphore.c + * orig : i386 2.6.4 + * + * M32R semaphore implementation. + * + * Copyright (c) 2002 - 2004 Hitoshi Yamamoto + */ + +/* + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + * + * Portions Copyright 1999 Red Hat, 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. + * + * rw semaphores implemented November 1999 by Benjamin LaHaise + */ +#include +#include +#include +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to acquire the semaphore, while the "sleeping" + * variable is a count of such acquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is protected + * by the spinlock in the semaphore's waitqueue head. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +asmlinkage void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +asmlinkage void __sched __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); + + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock in + * the wait_queue_head. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irqrestore(&sem->wait.lock, flags); + + schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); + tsk->state = TASK_UNINTERRUPTIBLE; + } + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + tsk->state = TASK_RUNNING; +} + +asmlinkage int __sched __down_interruptible(struct semaphore * sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); + + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + if (signal_pending(current)) { + retval = -EINTR; + sem->sleepers = 0; + atomic_add(sleepers, &sem->count); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock in + * wait_queue_head. The "-1" is because we're + * still hoping to get the semaphore. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irqrestore(&sem->wait.lock, flags); + + schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); + tsk->state = TASK_INTERRUPTIBLE; + } + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + + tsk->state = TASK_RUNNING; + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +asmlinkage int __down_trylock(struct semaphore * sem) +{ + int sleepers; + unsigned long flags; + + spin_lock_irqsave(&sem->wait.lock, flags); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock in the + * wait_queue_head. + */ + if (!atomic_add_negative(sleepers, &sem->count)) { + wake_up_locked(&sem->wait); + } + + spin_unlock_irqrestore(&sem->wait.lock, flags); + return 1; +} diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c new file mode 100644 index 000000000..db9589c24 --- /dev/null +++ b/arch/m32r/kernel/setup.c @@ -0,0 +1,403 @@ +/* + * linux/arch/m32r/kernel/setup.c + * + * Setup routines for Renesas M32R + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MMU +extern void init_mmu(void); +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) \ + || defined(CONFIG_BLK_DEV_IDE_MODULE) \ + || defined(CONFIG_BLK_DEV_HD_MODULE) +struct drive_info_struct { char dummy[32]; } drive_info; +#endif + +extern char _end[]; + +/* + * Machine setup.. + */ +struct cpuinfo_m32r boot_cpu_data; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +#if defined(CONFIG_VGA_CONSOLE) +struct screen_info screen_info = { + .orig_video_lines = 25, + .orig_video_cols = 80, + .orig_video_mode = 0, + .orig_video_ega_bx = 0, + .orig_video_isVGA = 1, + .orig_video_points = 8 +}; +#endif + +extern int root_mountflags; + +static char command_line[COMMAND_LINE_SIZE]; + +static struct resource data_resource = { + .name = "Kernel data", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +static struct resource code_resource = { + .name = "Kernel code", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +unsigned long memory_start; +unsigned long memory_end; + +void __init setup_arch(char **); +int get_cpuinfo(char *); + +static __inline__ void parse_mem_cmdline(char ** cmdline_p) +{ + char c = ' '; + char *to = command_line; + char *from = COMMAND_LINE; + int len = 0; + int usermem = 0; + + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + + memory_start = (unsigned long)CONFIG_MEMORY_START+PAGE_OFFSET; + memory_end = memory_start+(unsigned long)CONFIG_MEMORY_SIZE; + + for ( ; ; ) { + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + + { + unsigned long mem_size; + + usermem = 1; + mem_size = memparse(from+4, &from); + memory_end = memory_start + mem_size; + } + } + c = *(from++); + if (!c) + break; + + if (COMMAND_LINE_SIZE <= ++len) + break; + + *(to++) = c; + } + *to = '\0'; + *cmdline_p = command_line; + if (usermem) + printk(KERN_INFO "user-defined physical RAM map:\n"); +} + +#ifndef CONFIG_DISCONTIGMEM +static unsigned long __init setup_memory(void) +{ + unsigned long start_pfn, max_low_pfn, bootmap_size; + + start_pfn = PFN_UP( __pa(_end) ); + max_low_pfn = PFN_DOWN( __pa(memory_end) ); + + /* + * Initialize the boot-time allocator (with low memory only): + */ + bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, + CONFIG_MEMORY_START>>PAGE_SHIFT, max_low_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + { + unsigned long curr_pfn; + unsigned long last_pfn; + unsigned long pages; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(__pa(memory_start)); + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(__pa(memory_end)); + + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + + pages = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages)); + } + + /* + * Reserve the kernel text and + * Reserve the bootmem bitmap. We do this in two steps (first step + * was init_bootmem()), because this catches the (definitely buggy) + * case of us accidentally initializing the bootmem allocator with + * an invalid RAM area. + */ + reserve_bootmem(CONFIG_MEMORY_START + PAGE_SIZE, + (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE - 1) + - CONFIG_MEMORY_START); + + /* + * reserve physical page 0 - it's a special BIOS page on many boxes, + * enabling clean reboots, SMP operation, laptop functions. + */ + reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE); + + /* + * reserve memory hole + */ +#ifdef CONFIG_MEMHOLE + reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE); +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + if (LOADER_TYPE && INITRD_START) { + if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { + reserve_bootmem(INITRD_START, INITRD_SIZE); + initrd_start = INITRD_START ? + INITRD_START + PAGE_OFFSET : 0; + + initrd_end = initrd_start + INITRD_SIZE; + printk("initrd:start[%08lx],size[%08lx]\n", + initrd_start, INITRD_SIZE); + } else { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + INITRD_START + INITRD_SIZE, + max_low_pfn << PAGE_SHIFT); + + initrd_start = 0; + } + } +#endif + + return max_low_pfn; +} +#else /* CONFIG_DISCONTIGMEM */ +extern unsigned long setup_memory(void); +#endif /* CONFIG_DISCONTIGMEM */ + +#define M32R_PCC_PCATCR 0x00ef7014 /* will move to m32r.h */ + +void __init setup_arch(char **cmdline_p) +{ + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); + + boot_cpu_data.cpu_clock = M32R_CPUCLK; + boot_cpu_data.bus_clock = M32R_BUSCLK; + boot_cpu_data.timer_divide = M32R_TIMER_DIVIDE; + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; + +#ifdef CONFIG_VT +#if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif + +#ifdef CONFIG_DISCONTIGMEM + numnodes = 2; +#endif /* CONFIG_DISCONTIGMEM */ + + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + code_resource.start = virt_to_phys(_text); + code_resource.end = virt_to_phys(_etext)-1; + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; + + parse_mem_cmdline(cmdline_p); + + setup_memory(); + + paging_init(); +} + +#ifdef CONFIG_PROC_FS +/* + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + struct cpuinfo_m32r *c = v; + unsigned long cpu = c - cpu_data; + +#ifdef CONFIG_SMP + if (!cpu_online(cpu)) + return 0; +#endif /* CONFIG_SMP */ + + seq_printf(m, "processor\t: %ld\n", cpu); + +#ifdef CONFIG_CHIP_VDEC2 + seq_printf(m, "cpu family\t: VDEC2\n" + "cache size\t: Unknown\n"); +#elif CONFIG_CHIP_M32700 + seq_printf(m,"cpu family\t: M32700\n" + "cache size\t: I-8KB/D-8KB\n"); +#elif CONFIG_CHIP_M32102 + seq_printf(m,"cpu family\t: M32102\n" + "cache size\t: I-8KB\n"); +#elif CONFIG_CHIP_OPSP + seq_printf(m,"cpu family\t: OPSP\n" + "cache size\t: I-8KB/D-8KB\n"); +#elif CONFIG_CHIP_MP + seq_printf(m, "cpu family\t: M32R-MP\n" + "cache size\t: I-xxKB/D-xxKB\n"); +#else + seq_printf(m, "cpu family\t: Unknown\n"); +#endif + seq_printf(m, "bogomips\t: %lu.%02lu\n", + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); +#ifdef CONFIG_PLAT_MAPPI + seq_printf(m, "Machine\t\t: Mappi Evaluation board\n"); +#elif CONFIG_PLAT_MAPPI2 + seq_printf(m, "Machine\t\t: Mappi-II Evaluation board\n"); +#elif CONFIG_PLAT_M32700UT + seq_printf(m, "Machine\t\t: M32700UT Evaluation board\n"); +#elif CONFIG_PLAT_OPSPUT + seq_printf(m, "Machine\t\t: OPSPUT Evaluation board\n"); +#elif CONFIG_PLAT_USRV + seq_printf(m, "Machine\t\t: uServer\n"); +#elif CONFIG_PLAT_OAKS32R + seq_printf(m, "Machine\t\t: OAKS32R\n"); +#else + seq_printf(m, "Machine\t\t: Unknown\n"); +#endif + +#define PRINT_CLOCK(name, value) \ + seq_printf(m, name " clock\t: %d.%02dMHz\n", \ + ((value) / 1000000), ((value) % 1000000)/10000) + + PRINT_CLOCK("CPU", (int)c->cpu_clock); + PRINT_CLOCK("Bus", (int)c->bus_clock); + + seq_printf(m, "\n"); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? cpu_data + *pos : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; +#endif /* CONFIG_PROC_FS */ + +unsigned long cpu_initialized __initdata = 0; + +/* + * cpu_init() initializes state that is per-CPU. Some data is already + * initialized (naturally) in the bootstrap process. + * We reload them nevertheless, this function acts as a + * 'CPU state barrier', nothing should get across. + */ +#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ + || defined(CONFIG_CHIP_OPSP) +void __init cpu_init (void) +{ + int cpu_id = smp_processor_id(); + + if (test_and_set_bit(cpu_id, &cpu_initialized)) { + printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id); + for ( ; ; ) + local_irq_enable(); + } + printk(KERN_INFO "Initializing CPU#%d\n", cpu_id); + + /* Set up and load the per-CPU TSS and LDT */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + if (current->mm) + BUG(); + + /* Force FPU initialization */ + current_thread_info()->status = 0; + current->used_math = 0; + +#ifdef CONFIG_MMU + /* Set up MMU */ + init_mmu(); +#endif + + /* Set up ICUIMASK */ + outl(0x00070000, M32R_ICU_IMASK_PORTL); /* imask=111 */ +} +#endif /* defined(CONFIG_CHIP_VDEC2) ... */ + diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c new file mode 100644 index 000000000..5d0780b8b --- /dev/null +++ b/arch/m32r/kernel/setup_m32700ut.c @@ -0,0 +1,478 @@ +/* + * linux/arch/m32r/kernel/setup_m32700ut.c + * + * Setup routines for Renesas M32700UT Board + * + * Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * M32700 Interrupt Control Unit (Level 1) + */ +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +static icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; + +static void disable_m32700ut_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_m32700ut_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_m32700ut(unsigned int irq) +{ + disable_m32700ut_irq(irq); +} + +static void end_m32700ut_irq(unsigned int irq) +{ + enable_m32700ut_irq(irq); +} + +static unsigned int startup_m32700ut_irq(unsigned int irq) +{ + enable_m32700ut_irq(irq); + return (0); +} + +static void shutdown_m32700ut_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_irq_type = +{ + "M32700UT-IRQ", + startup_m32700ut_irq, + shutdown_m32700ut_irq, + enable_m32700ut_irq, + disable_m32700ut_irq, + mask_and_ack_m32700ut, + end_m32700ut_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT (Level 2) + */ +#define irq2pldirq(x) ((x) - M32700UT_PLD_IRQ_BASE) +#define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +typedef struct { + unsigned short icucr; /* ICU Control Register */ +} pld_icu_data_t; + +static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ]; + +static void disable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// disable_m32700ut_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// enable_m32700ut_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_pld(unsigned int irq) +{ + disable_m32700ut_pld_irq(irq); +// mask_and_ack_m32700ut(M32R_IRQ_INT1); +} + +static void end_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + end_m32700ut_irq(M32R_IRQ_INT1); +} + +static unsigned int startup_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + return (0); +} + +static void shutdown_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// shutdown_m32700ut_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_pld_irq_type = +{ + "M32700UT-PLD-IRQ", + startup_m32700ut_pld_irq, + shutdown_m32700ut_pld_irq, + enable_m32700ut_pld_irq, + disable_m32700ut_pld_irq, + mask_and_ack_m32700ut_pld, + end_m32700ut_pld_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT-LAN (Level 2) + */ +#define irq2lanpldirq(x) ((x) - M32700UT_LAN_PLD_IRQ_BASE) +#define lanpldirq2port(x) (unsigned long)((int)M32700UT_LAN_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lanpld_icu_data[M32700UT_NUM_LAN_PLD_IRQ]; + +static void disable_m32700ut_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_lanpld(unsigned int irq) +{ + disable_m32700ut_lanpld_irq(irq); +} + +static void end_m32700ut_lanpld_irq(unsigned int irq) +{ + enable_m32700ut_lanpld_irq(irq); + end_m32700ut_irq(M32R_IRQ_INT0); +} + +static unsigned int startup_m32700ut_lanpld_irq(unsigned int irq) +{ + enable_m32700ut_lanpld_irq(irq); + return (0); +} + +static void shutdown_m32700ut_lanpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_lanpld_irq_type = +{ + "M32700UT-PLD-LAN-IRQ", + startup_m32700ut_lanpld_irq, + shutdown_m32700ut_lanpld_irq, + enable_m32700ut_lanpld_irq, + disable_m32700ut_lanpld_irq, + mask_and_ack_m32700ut_lanpld, + end_m32700ut_lanpld_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT-LCD (Level 2) + */ +#define irq2lcdpldirq(x) ((x) - M32700UT_LCD_PLD_IRQ_BASE) +#define lcdpldirq2port(x) (unsigned long)((int)M32700UT_LCD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lcdpld_icu_data[M32700UT_NUM_LCD_PLD_IRQ]; + +static void disable_m32700ut_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_lcdpld(unsigned int irq) +{ + disable_m32700ut_lcdpld_irq(irq); +} + +static void end_m32700ut_lcdpld_irq(unsigned int irq) +{ + enable_m32700ut_lcdpld_irq(irq); + end_m32700ut_irq(M32R_IRQ_INT2); +} + +static unsigned int startup_m32700ut_lcdpld_irq(unsigned int irq) +{ + enable_m32700ut_lcdpld_irq(irq); + return (0); +} + +static void shutdown_m32700ut_lcdpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_lcdpld_irq_type = +{ + "M32700UT-PLD-LCD-IRQ", + startup_m32700ut_lcdpld_irq, + shutdown_m32700ut_lcdpld_irq, + enable_m32700ut_lcdpld_irq, + disable_m32700ut_lcdpld_irq, + mask_and_ack_m32700ut_lcdpld, + end_m32700ut_lcdpld_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/ + irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED; + irq_desc[M32700UT_LAN_IRQ_LAN].handler = &m32700ut_lanpld_irq_type; + irq_desc[M32700UT_LAN_IRQ_LAN].action = 0; + irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */ + lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ + disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_m32700ut_irq(M32R_IRQ_MFT2); + + /* SIO0 : receive */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO0_R); + + /* SIO0 : send */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO0_S); + + /* SIO1 : receive */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO1_R); + + /* SIO1 : send */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_SIO1_S); + + /* DMA1 : */ + irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_DMA1].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_DMA1].action = 0; + irq_desc[M32R_IRQ_DMA1].depth = 1; + icu_data[M32R_IRQ_DMA1].icucr = 0; + disable_m32700ut_irq(M32R_IRQ_DMA1); + +#ifdef CONFIG_SERIAL_M32R_PLDSIO + /* INT#1: SIO0 Receive on PLD */ + irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_RCV].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_RCV].action = 0; + irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV); + + /* INT#1: SIO0 Send on PLD */ + irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_SND].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_SND].action = 0; + irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND); +#endif /* CONFIG_SERIAL_M32R_PLDSIO */ + + /* INT#1: CFC IREQ on PLD */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ); + + /* INT#1: CFC Insert on PLD */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT); + + /* INT#1: CFC Eject on PLD */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT); + + /* + * INT0# is used for LAN, DIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_m32700ut_irq(M32R_IRQ_INT0); + + /* + * INT1# is used for UART, MMC, CF Controller in FPGA. + * We enable it here. + */ + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_m32700ut_irq(M32R_IRQ_INT1); + +#if defined(CONFIG_USB) + outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ + + irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED; + irq_desc[M32700UT_LCD_IRQ_USB_INT1].handler = &m32700ut_lcdpld_irq_type; + irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0; + irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1; + lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ + disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1); +#endif + /* + * INT2# is used for BAT, USB, AUDIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + enable_m32700ut_irq(M32R_IRQ_INT2); + +//#if defined(CONFIG_M32R_AR_VGA) + /* + * INT3# is used for AR + */ + irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT3].handler = &m32700ut_irq_type; + irq_desc[M32R_IRQ_INT3].action = 0; + irq_desc[M32R_IRQ_INT3].depth = 1; + icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_m32700ut_irq(M32R_IRQ_INT3); +//#endif /* CONFIG_M32R_ARV */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = M32700UT_LAN_IRQ_LAN, + .end = M32700UT_LAN_IRQ_LAN, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c new file mode 100644 index 000000000..523cee330 --- /dev/null +++ b/arch/m32r/kernel/setup_mappi.c @@ -0,0 +1,160 @@ +/* + * linux/arch/m32r/kernel/setup_mappi.c + * + * Setup routines for Renesas MAPPI Board + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi(unsigned int irq) +{ + disable_mappi_irq(irq); +} + +static void end_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); +} + +static unsigned int startup_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); + return (0); +} + +static void shutdown_mappi_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi_irq_type = +{ + "MAPPI-IRQ", + startup_mappi_irq, + shutdown_mappi_irq, + enable_mappi_irq, + disable_mappi_irq, + mask_and_ack_mappi, + end_mappi_irq +}; + +void __init init_IRQ(void) +{ + static int once = 0; + + if (once) + return; + else + once++; + +#ifdef CONFIG_NE2000 + /* INT0 : LAN controller (RTL8019AS) */ + irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT0].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_INT0].action = 0; + irq_desc[M32R_IRQ_INT0].depth = 1; + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_mappi_irq(M32R_IRQ_INT0); +#endif /* CONFIG_M32R_NE2000 */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_S); + + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_SERIAL_M32R_SIO */ + +#if defined(CONFIG_M32RPCC) + /* INT1 : pccard0 interrupt */ + irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_INT1].action = 0; + irq_desc[M32R_IRQ_INT1].depth = 1; + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; + disable_mappi_irq(M32R_IRQ_INT1); + + /* INT2 : pccard1 interrupt */ + irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_INT2].action = 0; + irq_desc[M32R_IRQ_INT2].depth = 1; + icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; + disable_mappi_irq(M32R_IRQ_INT2); +#endif /* CONFIG_M32RPCC */ +} diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c new file mode 100644 index 000000000..92eb06e85 --- /dev/null +++ b/arch/m32r/kernel/setup_mappi2.c @@ -0,0 +1,212 @@ +/* + * linux/arch/m32r/kernel/setup_mappi.c + * + * Setup routines for Renesas MAPPI-II(M3A-ZA36) Board + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_mappi2_irq(unsigned int irq) +{ + unsigned long port, data; + + if ((irq == 0) ||(irq >= NR_IRQS)) { + printk("bad irq 0x%08x\n", irq); + return; + } + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi2_irq(unsigned int irq) +{ + unsigned long port, data; + + if ((irq == 0) ||(irq >= NR_IRQS)) { + printk("bad irq 0x%08x\n", irq); + return; + } + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi2(unsigned int irq) +{ + disable_mappi2_irq(irq); +} + +static void end_mappi2_irq(unsigned int irq) +{ + enable_mappi2_irq(irq); +} + +static unsigned int startup_mappi2_irq(unsigned int irq) +{ + enable_mappi2_irq(irq); + return (0); +} + +static void shutdown_mappi2_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi2_irq_type = +{ + "MAPPI2-IRQ", + startup_mappi2_irq, + shutdown_mappi2_irq, + enable_mappi2_irq, + disable_mappi2_irq, + mask_and_ack_mappi2, + end_mappi2_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT0 : LAN controller (SMC91111) */ + irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT0].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_INT0].action = 0; + irq_desc[M32R_IRQ_INT0].depth = 1; + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_mappi2_irq(M32R_IRQ_INT0); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi2_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO0_S); + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi2_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_M32R_USE_DBG_CONSOLE */ + +#if defined(CONFIG_USB) + /* INT1 : USB Host controller interrupt */ + irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT1].handler = &mappi2_irq_type; + irq_desc[M32R_IRQ_INT1].action = 0; + irq_desc[M32R_IRQ_INT1].depth = 1; + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; + disable_mappi2_irq(M32R_IRQ_INT1); +#endif /* CONFIG_USB */ + +#if defined(CONFIG_M32R_CFC) + /* ICUCR40: CFC IREQ */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ +// icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; + icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + disable_mappi2_irq(PLD_IRQ_CFIREQ); + + /* ICUCR41: CFC Insert */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi2_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; +// icu_data[PLD_IRQ_CFC_INSERT].icucr = 0; + disable_mappi2_irq(PLD_IRQ_CFC_INSERT); + + /* ICUCR42: CFC Eject */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi2_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; +// icu_data[PLD_IRQ_CFC_EJECT].icucr = 0; + disable_mappi2_irq(PLD_IRQ_CFC_EJECT); + +#endif /* CONFIG_MAPPI2_CFC */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = M32R_IRQ_INT0, + .end = M32R_IRQ_INT0, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c new file mode 100644 index 000000000..b04834526 --- /dev/null +++ b/arch/m32r/kernel/setup_oaks32r.c @@ -0,0 +1,143 @@ +/* + * linux/arch/m32r/kernel/setup_oaks32r.c + * + * Setup routines for OAKS32R Board + * + * Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_oaks32r_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_oaks32r_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi(unsigned int irq) +{ + disable_oaks32r_irq(irq); +} + +static void end_oaks32r_irq(unsigned int irq) +{ + enable_oaks32r_irq(irq); +} + +static unsigned int startup_oaks32r_irq(unsigned int irq) +{ + enable_oaks32r_irq(irq); + return (0); +} + +static void shutdown_oaks32r_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type oaks32r_irq_type = +{ + "OAKS32R-IRQ", + startup_oaks32r_irq, + shutdown_oaks32r_irq, + enable_oaks32r_irq, + disable_oaks32r_irq, + mask_and_ack_mappi, + end_oaks32r_irq +}; + +void __init init_IRQ(void) +{ + static int once = 0; + + if (once) + return; + else + once++; + +#ifdef CONFIG_NE2000 + /* INT3 : LAN controller (RTL8019AS) */ + irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT3].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_INT3].action = 0; + irq_desc[M32R_IRQ_INT3].depth = 1; + icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_oaks32r_irq(M32R_IRQ_INT3); +#endif /* CONFIG_M32R_NE2000 */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_oaks32r_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO0_S); + + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &oaks32r_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_oaks32r_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_SERIAL_M32R_SIO */ + +} diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c new file mode 100644 index 000000000..17a4d3e52 --- /dev/null +++ b/arch/m32r/kernel/setup_opsput.c @@ -0,0 +1,482 @@ +/* + * linux/arch/m32r/kernel/setup_opsput.c + * + * Setup routines for Renesas OPSPUT Board + * + * Copyright (c) 2002-2004 + * Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * OPSP Interrupt Control Unit (Level 1) + */ +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +static icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ]; + +static void disable_opsput_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_opsput_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_opsput(unsigned int irq) +{ + disable_opsput_irq(irq); +} + +static void end_opsput_irq(unsigned int irq) +{ + enable_opsput_irq(irq); +} + +static unsigned int startup_opsput_irq(unsigned int irq) +{ + enable_opsput_irq(irq); + return (0); +} + +static void shutdown_opsput_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_irq_type = +{ + "OPSPUT-IRQ", + startup_opsput_irq, + shutdown_opsput_irq, + enable_opsput_irq, + disable_opsput_irq, + mask_and_ack_opsput, + end_opsput_irq +}; + +/* + * Interrupt Control Unit of PLD on OPSPUT (Level 2) + */ +#define irq2pldirq(x) ((x) - OPSPUT_PLD_IRQ_BASE) +#define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +typedef struct { + unsigned short icucr; /* ICU Control Register */ +} pld_icu_data_t; + +static pld_icu_data_t pld_icu_data[OPSPUT_NUM_PLD_IRQ]; + +static void disable_opsput_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// disable_opsput_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_opsput_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// enable_opsput_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_opsput_pld(unsigned int irq) +{ + disable_opsput_pld_irq(irq); +// mask_and_ack_opsput(M32R_IRQ_INT1); +} + +static void end_opsput_pld_irq(unsigned int irq) +{ + enable_opsput_pld_irq(irq); + end_opsput_irq(M32R_IRQ_INT1); +} + +static unsigned int startup_opsput_pld_irq(unsigned int irq) +{ + enable_opsput_pld_irq(irq); + return (0); +} + +static void shutdown_opsput_pld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); +// shutdown_opsput_irq(M32R_IRQ_INT1); + port = pldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_pld_irq_type = +{ + "OPSPUT-PLD-IRQ", + startup_opsput_pld_irq, + shutdown_opsput_pld_irq, + enable_opsput_pld_irq, + disable_opsput_pld_irq, + mask_and_ack_opsput_pld, + end_opsput_pld_irq +}; + +/* + * Interrupt Control Unit of PLD on OPSPUT-LAN (Level 2) + */ +#define irq2lanpldirq(x) ((x) - OPSPUT_LAN_PLD_IRQ_BASE) +#define lanpldirq2port(x) (unsigned long)((int)OPSPUT_LAN_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lanpld_icu_data[OPSPUT_NUM_LAN_PLD_IRQ]; + +static void disable_opsput_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_opsput_lanpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_opsput_lanpld(unsigned int irq) +{ + disable_opsput_lanpld_irq(irq); +} + +static void end_opsput_lanpld_irq(unsigned int irq) +{ + enable_opsput_lanpld_irq(irq); + end_opsput_irq(M32R_IRQ_INT0); +} + +static unsigned int startup_opsput_lanpld_irq(unsigned int irq) +{ + enable_opsput_lanpld_irq(irq); + return (0); +} + +static void shutdown_opsput_lanpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lanpldirq(irq); + port = lanpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_lanpld_irq_type = +{ + "OPSPUT-PLD-LAN-IRQ", + startup_opsput_lanpld_irq, + shutdown_opsput_lanpld_irq, + enable_opsput_lanpld_irq, + disable_opsput_lanpld_irq, + mask_and_ack_opsput_lanpld, + end_opsput_lanpld_irq +}; + +/* + * Interrupt Control Unit of PLD on OPSPUT-LCD (Level 2) + */ +#define irq2lcdpldirq(x) ((x) - OPSPUT_LCD_PLD_IRQ_BASE) +#define lcdpldirq2port(x) (unsigned long)((int)OPSPUT_LCD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +static pld_icu_data_t lcdpld_icu_data[OPSPUT_NUM_LCD_PLD_IRQ]; + +static void disable_opsput_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_opsput_lcdpld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_opsput_lcdpld(unsigned int irq) +{ + disable_opsput_lcdpld_irq(irq); +} + +static void end_opsput_lcdpld_irq(unsigned int irq) +{ + enable_opsput_lcdpld_irq(irq); + end_opsput_irq(M32R_IRQ_INT2); +} + +static unsigned int startup_opsput_lcdpld_irq(unsigned int irq) +{ + enable_opsput_lcdpld_irq(irq); + return (0); +} + +static void shutdown_opsput_lcdpld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2lcdpldirq(irq); + port = lcdpldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type opsput_lcdpld_irq_type = +{ + "OPSPUT-PLD-LCD-IRQ", + startup_opsput_lcdpld_irq, + shutdown_opsput_lcdpld_irq, + enable_opsput_lcdpld_irq, + disable_opsput_lcdpld_irq, + mask_and_ack_opsput_lcdpld, + end_opsput_lcdpld_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/ + irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED; + irq_desc[OPSPUT_LAN_IRQ_LAN].handler = &opsput_lanpld_irq_type; + irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0; + irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */ + lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ + disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_opsput_irq(M32R_IRQ_MFT2); + + /* SIO0 : receive */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO0_R); + + /* SIO0 : send */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO0_S); + + /* SIO1 : receive */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO1_R); + + /* SIO1 : send */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_opsput_irq(M32R_IRQ_SIO1_S); + + /* DMA1 : */ + irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_DMA1].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_DMA1].action = 0; + irq_desc[M32R_IRQ_DMA1].depth = 1; + icu_data[M32R_IRQ_DMA1].icucr = 0; + disable_opsput_irq(M32R_IRQ_DMA1); + +#ifdef CONFIG_SERIAL_M32R_PLDSIO + /* INT#1: SIO0 Receive on PLD */ + irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_RCV].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_RCV].action = 0; + irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV); + + /* INT#1: SIO0 Send on PLD */ + irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SIO0_SND].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_SIO0_SND].action = 0; + irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; + disable_opsput_pld_irq(PLD_IRQ_SIO0_SND); +#endif /* CONFIG_SERIAL_M32R_PLDSIO */ + +#if defined(CONFIG_M32R_CFC) + /* INT#1: CFC IREQ on PLD */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_opsput_pld_irq(PLD_IRQ_CFIREQ); + + /* INT#1: CFC Insert on PLD */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ + disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT); + + /* INT#1: CFC Eject on PLD */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &opsput_pld_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ + disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT); +#endif /* CONFIG_M32R_CFC */ + + + /* + * INT0# is used for LAN, DIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_opsput_irq(M32R_IRQ_INT0); + + /* + * INT1# is used for UART, MMC, CF Controller in FPGA. + * We enable it here. + */ + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; + enable_opsput_irq(M32R_IRQ_INT1); + +#if defined(CONFIG_USB) + outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ + + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED; + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].handler = &opsput_lcdpld_irq_type; + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0; + irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1; + lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ + disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1); +#endif + /* + * INT2# is used for BAT, USB, AUDIO + * We enable it here. + */ + icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + enable_opsput_irq(M32R_IRQ_INT2); + +//#if defined(CONFIG_M32R_AR_VGA) + /* + * INT3# is used for AR + */ + irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT3].handler = &opsput_irq_type; + irq_desc[M32R_IRQ_INT3].action = 0; + irq_desc[M32R_IRQ_INT3].depth = 1; + icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_opsput_irq(M32R_IRQ_INT3); +//#endif /* CONFIG_M32R_ARV */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OPSPUT_LAN_IRQ_LAN, + .end = OPSPUT_LAN_IRQ_LAN, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff --git a/arch/m32r/kernel/setup_usrv.c b/arch/m32r/kernel/setup_usrv.c new file mode 100644 index 000000000..fe417be5e --- /dev/null +++ b/arch/m32r/kernel/setup_usrv.c @@ -0,0 +1,256 @@ +/* + * linux/arch/m32r/kernel/setup_usrv.c + * + * Setup routines for MITSUBISHI uServer + * + * Copyright (c) 2001, 2002, 2003 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#if !defined(CONFIG_SMP) +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; + +static void disable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi_irq(unsigned int irq) +{ + unsigned long port, data; + + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi(unsigned int irq) +{ + disable_mappi_irq(irq); +} + +static void end_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); +} + +static unsigned int startup_mappi_irq(unsigned int irq) +{ + enable_mappi_irq(irq); + return 0; +} + +static void shutdown_mappi_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi_irq_type = +{ + "M32700-IRQ", + startup_mappi_irq, + shutdown_mappi_irq, + enable_mappi_irq, + disable_mappi_irq, + mask_and_ack_mappi, + end_mappi_irq +}; + +/* + * Interrupt Control Unit of PLD on M32700UT (Level 2) + */ +#define irq2pldirq(x) ((x) - M32700UT_PLD_IRQ_BASE) +#define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ + (((x) - 1) * sizeof(unsigned short))) + +typedef struct { + unsigned short icucr; /* ICU Control Register */ +} pld_icu_data_t; + +static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ]; + +static void disable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; + outw(data, port); +} + +static void enable_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port, data; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); + port = pldirq2port(pldirq); + data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; + outw(data, port); +} + +static void mask_and_ack_m32700ut_pld(unsigned int irq) +{ + disable_m32700ut_pld_irq(irq); +} + +static void end_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + end_mappi_irq(M32R_IRQ_INT1); +} + +static unsigned int startup_m32700ut_pld_irq(unsigned int irq) +{ + enable_m32700ut_pld_irq(irq); + return 0; +} + +static void shutdown_m32700ut_pld_irq(unsigned int irq) +{ + unsigned long port; + unsigned int pldirq; + + pldirq = irq2pldirq(irq); + port = pldirq2port(pldirq); + outw(PLD_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type m32700ut_pld_irq_type = +{ + "USRV-PLD-IRQ", + startup_m32700ut_pld_irq, + shutdown_m32700ut_pld_irq, + enable_m32700ut_pld_irq, + disable_m32700ut_pld_irq, + mask_and_ack_m32700ut_pld, + end_m32700ut_pld_irq +}; + +void __init init_IRQ(void) +{ + static int once = 0; + int i; + + if (once) + return; + else + once++; + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi_irq(M32R_IRQ_MFT2); + +#if defined(CONFIG_SERIAL_M32R_SIO) + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO0_S); + + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_SERIAL_M32R_SIO */ + + /* INT#67-#71: CFC#0 IREQ on PLD */ + for (i = 0 ; i < CONFIG_CFC_NUM ; i++ ) { + irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CF0 + i].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_CF0 + i].action = 0; + irq_desc[PLD_IRQ_CF0 + i].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr + = PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_CF0 + i); + } + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + /* INT#76: 16552D#0 IREQ on PLD */ + irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_UART0].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_UART0].action = 0; + irq_desc[PLD_IRQ_UART0].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr + = PLD_ICUCR_ISMOD03; /* 'H' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_UART0); + + /* INT#77: 16552D#1 IREQ on PLD */ + irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_UART1].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_UART1].action = 0; + irq_desc[PLD_IRQ_UART1].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr + = PLD_ICUCR_ISMOD03; /* 'H' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_UART1); +#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ + +#if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE) + /* INT#80: AK4524 IREQ on PLD */ + irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_SNDINT].handler = &m32700ut_pld_irq_type; + irq_desc[PLD_IRQ_SNDINT].action = 0; + irq_desc[PLD_IRQ_SNDINT].depth = 1; /* disable nested irq */ + pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr + = PLD_ICUCR_ISMOD01; /* 'L' level sense */ + disable_m32700ut_pld_irq(PLD_IRQ_SNDINT); +#endif /* CONFIG_IDC_AK4524 || CONFIG_IDC_AK4524_MODULE */ + + /* + * INT1# is used for UART, MMC, CF Controller in FPGA. + * We enable it here. + */ + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD11; + enable_mappi_irq(M32R_IRQ_INT1); +} + diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c new file mode 100644 index 000000000..cbfa6748e --- /dev/null +++ b/arch/m32r/kernel/signal.c @@ -0,0 +1,621 @@ +/* + * linux/arch/m32r/kernel/signal.c + * + * Copyright (c) 2003 Hitoshi Yamamoto + * + * Taken from i386 version. + * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +int do_signal(struct pt_regs *, sigset_t *); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int +sys_sigsuspend(old_sigset_t mask, unsigned long r1, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs.r0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(®s, &saveset)) + return regs.r0; + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs.r0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(®s, &saveset)) + return regs.r0; + } +} + +asmlinkage 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; +} + +asmlinkage int +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + return do_sigaltstack(uss, uoss, regs.spu); +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ +// char *pretcode; + int sig; + struct sigcontext sc; +// struct _fpstate fpstate; + unsigned long extramask[_NSIG_WORDS-1]; + char retcode[4]; +}; + +struct rt_sigframe +{ +// char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; +// struct _fpstate fpstate; + char retcode[8]; +}; + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, + int *r0_p) +{ + unsigned int err = 0; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + +#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) + COPY(r4); + COPY(r5); + COPY(r6); + COPY(pt_regs); + /* COPY(r0); Skip r0 */ + COPY(r1); + COPY(r2); + COPY(r3); + COPY(r7); + COPY(r8); + COPY(r9); + COPY(r10); + COPY(r11); + COPY(r12); +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + COPY(acc0h); + COPY(acc0l); + COPY(acc1h); + COPY(acc1l); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + COPY(acch); + COPY(accl); +#else +#error unknown isa configuration +#endif + COPY(psw); + COPY(bpc); + COPY(bbpsw); + COPY(bbpc); + COPY(spu); + COPY(fp); + COPY(lr); + COPY(spi); +#undef COPY + + regs->syscall_nr = -1; /* disable syscall checks */ + err |= __get_user(*r0_p, &sc->sc_r0); + + return err; +} + +asmlinkage int +sys_sigreturn(unsigned long r0, unsigned long r1, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + struct sigframe __user *frame = (struct sigframe __user *)regs.spu; + sigset_t set; + int result; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(®s, &frame->sc, &result)) + goto badframe; + return result; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int +sys_rt_sigreturn(unsigned long r0, unsigned long r1, + unsigned long r2, unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, struct pt_regs regs) +{ + struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.spu; + sigset_t set; + stack_t st; + int result; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &result)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs.spu); + + return result; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +/* + * Set up a signal frame. + */ + +static int +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(r4); + COPY(r5); + COPY(r6); + COPY(pt_regs); + COPY(r0); + COPY(r1); + COPY(r2); + COPY(r3); + COPY(r7); + COPY(r8); + COPY(r9); + COPY(r10); + COPY(r11); + COPY(r12); +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + COPY(acc0h); + COPY(acc0l); + COPY(acc1h); + COPY(acc1l); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + COPY(acch); + COPY(accl); +#else +#error unknown isa configuration +#endif + COPY(psw); + COPY(bpc); + COPY(bbpsw); + COPY(bbpc); + COPY(spu); + COPY(fp); + COPY(lr); + COPY(spi); +#undef COPY + + err |= __put_user(mask, &sc->oldmask); + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void __user * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (sas_ss_flags(sp) == 0) + sp = current->sas_ss_sp + current->sas_ss_size; + } + + return (void __user *)((sp - frame_size) & -8ul); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe __user *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->spu, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(signal, &frame->sig); + if (err) + goto give_sigsegv; + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + if (err) + goto give_sigsegv; + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + if (err) + goto give_sigsegv; + } + + if (ka->sa.sa_flags & SA_RESTORER) + regs->lr = (unsigned long)ka->sa.sa_restorer; + else { + /* This is : ldi r7, #__NR_sigreturn ; trap #2 */ + unsigned long code = 0x670010f2 | (__NR_sigreturn << 16); + + regs->lr = (unsigned long)frame->retcode; + err |= __put_user(code, (long __user *)(frame->retcode+0)); + if (err) + goto give_sigsegv; + flush_cache_sigtramp((unsigned long)frame->retcode); + } + + /* Set up registers for signal handler */ + regs->spu = (unsigned long)frame; + regs->r0 = signal; /* Arg for signal handler */ + regs->r1 = (unsigned long)&frame->sc; + regs->bpc = (unsigned long)ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p\n", + current->comm, current->pid, frame, regs->pc); +#endif + + return; + +give_sigsegv: + force_sigsegv(sig, current); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->spu, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(signal, &frame->sig); + if (err) + goto give_sigsegv; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto give_sigsegv; + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->spu), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->lr = (unsigned long)ka->sa.sa_restorer; + else { + /* This is : ldi r7, #__NR_rt_sigreturn ; trap #2 */ + unsigned long code1 = 0x97f00000 | (__NR_rt_sigreturn); + unsigned long code2 = 0x10f2f000; + + regs->lr = (unsigned long)frame->retcode; + err |= __put_user(code1, (long __user *)(frame->retcode+0)); + err |= __put_user(code2, (long __user *)(frame->retcode+4)); + if (err) + goto give_sigsegv; + flush_cache_sigtramp((unsigned long)frame->retcode); + } + + /* Set up registers for signal handler */ + regs->spu = (unsigned long)frame; + regs->r0 = signal; /* Arg for signal handler */ + regs->r1 = (unsigned long)&frame->info; + regs->r2 = (unsigned long)&frame->uc; + regs->bpc = (unsigned long)ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p\n", + current->comm, current->pid, frame, regs->pc); +#endif + + return; + +give_sigsegv: + force_sigsegv(sig, current); +} + +/* + * OK, we're invoking a handler + */ + +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + unsigned short inst; + + /* Are we from a system call? */ + if (regs->syscall_nr >= 0) { + /* If so, check system call restarting.. */ + switch (regs->r0) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + regs->r0 = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->r0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->r0 = regs->orig_r0; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + } + + /* 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_NODEFER)) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +int do_signal(struct pt_regs *regs, sigset_t *oldset) +{ + siginfo_t info; + int signr; + struct k_sigaction ka; + unsigned short inst; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + if (current->flags & PF_FREEZE) { + refrigerator(0); + goto no_signal; + } + + if (!oldset) + oldset = ¤t->blocked; + + 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 + * have been cleared if the watchpoint triggered + * inside the kernel. + */ + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &ka, &info, oldset, regs); + return 1; + } + + no_signal: + /* Did we come from a system call? */ + if (regs->syscall_nr >= 0) { + /* Restart the system call - no handlers present */ + if (regs->r0 == -ERESTARTNOHAND || + regs->r0 == -ERESTARTSYS || + regs->r0 == -ERESTARTNOINTR) { + regs->r0 = regs->orig_r0; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + if (regs->r0 == -ERESTART_RESTARTBLOCK){ + regs->r0 = regs->orig_r0; + regs->r7 = __NR_restart_syscall; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + } + return 0; +} + +/* + * notification of userspace execution resumption + * - triggered by current->work.notify_resume + */ +void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, + __u32 thread_info_flags) +{ + /* Pending single-step? */ + if (thread_info_flags & _TIF_SINGLESTEP) + clear_thread_flag(TIF_SINGLESTEP); + + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs,oldset); + + clear_thread_flag(TIF_IRET); +} diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c new file mode 100644 index 000000000..2dc542eb1 --- /dev/null +++ b/arch/m32r/kernel/smp.c @@ -0,0 +1,965 @@ +/* + * linux/arch/m32r/kernel/smp.c + * + * M32R SMP support routines. + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto + * + * Taken from i386 version. + * (c) 1995 Alan Cox, Building #3 + * (c) 1998-99, 2000 Ingo Molnar + * + * This code is released under the GNU General Public License version 2 or + * later. + */ + +#undef DEBUG_SMP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Data structures and variables */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + */ +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; + +struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); + +static struct call_data_struct *call_data; + +/* + * For flush_cache_all() + */ +static spinlock_t flushcache_lock = SPIN_LOCK_UNLOCKED; +static volatile unsigned long flushcache_cpumask = 0; + +/* + * For flush_tlb_others() + */ +static volatile cpumask_t flush_cpumask; +static struct mm_struct *flush_mm; +static struct vm_area_struct *flush_vma; +static volatile unsigned long flush_va; +static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED; +#define FLUSH_ALL 0xffffffff + +DECLARE_PER_CPU(int, prof_multiplier); +DECLARE_PER_CPU(int, prof_old_multiplier); +DECLARE_PER_CPU(int, prof_counter); + +extern spinlock_t ipi_lock[]; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Function Prototypes */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +void smp_send_reschedule(int); +void smp_reschedule_interrupt(void); + +void smp_flush_cache_all(void); +void smp_flush_cache_all_interrupt(void); + +void smp_flush_tlb_all(void); +static void flush_tlb_all_ipi(void *); + +void smp_flush_tlb_mm(struct mm_struct *); +void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \ + unsigned long); +void smp_flush_tlb_page(struct vm_area_struct *, unsigned long); +static void flush_tlb_others(cpumask_t, struct mm_struct *, + struct vm_area_struct *, unsigned long); +void smp_invalidate_interrupt(void); + +void smp_send_stop(void); +static void stop_this_cpu(void *); + +int smp_call_function(void (*) (void *), void *, int, int); +void smp_call_function_interrupt(void); + +void smp_send_timer(void); +void smp_ipi_timer_interrupt(struct pt_regs *); +void smp_local_timer_interrupt(struct pt_regs *); + +void send_IPI_allbutself(int, int); +static void send_IPI_mask(cpumask_t, int, int); +unsigned long send_IPI_mask_phys(cpumask_t, int, int); + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Rescheduling request Routines */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_send_reschedule + * + * Description: This routine requests other CPU to execute rescheduling. + * 1.Send 'RESCHEDULE_IPI' to other CPU. + * Request other CPU to execute 'smp_reschedule_interrupt()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpu_id - Target CPU ID + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_send_reschedule(int cpu_id) +{ + WARN_ON(cpu_is_offline(cpu_id)); + send_IPI_mask(cpumask_of_cpu(cpu_id), RESCHEDULE_IPI, 1); +} + +/*==========================================================================* + * Name: smp_reschedule_interrupt + * + * Description: This routine executes on CPU which received + * 'RESCHEDULE_IPI'. + * Rescheduling is processed at the exit of interrupt + * operation. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_reschedule_interrupt(void) +{ + /* nothing to do */ +} + +/*==========================================================================* + * Name: smp_flush_cache_all + * + * Description: This routine sends a 'INVALIDATE_CACHE_IPI' to all other + * CPUs in the system. + * + * Born on Date: 2003-05-28 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_cache_all(void) +{ + cpumask_t cpumask; + unsigned long *mask; + + preempt_disable(); + cpumask = cpu_online_map; + cpu_clear(smp_processor_id(), cpumask); + spin_lock(&flushcache_lock); + mask=cpus_addr(cpumask); + atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask); + send_IPI_mask(cpumask, INVALIDATE_CACHE_IPI, 0); + _flush_cache_copyback_all(); + while (flushcache_cpumask) + mb(); + spin_unlock(&flushcache_lock); + preempt_enable(); +} + +void smp_flush_cache_all_interrupt(void) +{ + _flush_cache_copyback_all(); + clear_bit(smp_processor_id(), &flushcache_cpumask); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* TLB flush request Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_flush_tlb_all + * + * Description: This routine flushes all processes TLBs. + * 1.Request other CPU to execute 'flush_tlb_all_ipi()'. + * 2.Execute 'do_flush_tlb_all_local()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_all(void) +{ + unsigned long flags; + + preempt_disable(); + local_irq_save(flags); + __flush_tlb_all(); + local_irq_restore(flags); + smp_call_function(flush_tlb_all_ipi, 0, 1, 1); + preempt_enable(); +} + +/*==========================================================================* + * Name: flush_tlb_all_ipi + * + * Description: This routine flushes all local TLBs. + * 1.Execute 'do_flush_tlb_all_local()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: *info - not used + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void flush_tlb_all_ipi(void *info) +{ + __flush_tlb_all(); +} + +/*==========================================================================* + * Name: smp_flush_tlb_mm + * + * Description: This routine flushes the specified mm context TLB's. + * + * Born on Date: 2002.02.05 + * + * Arguments: *mm - a pointer to the mm struct for flush TLB + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_mm(struct mm_struct *mm) +{ + int cpu_id = smp_processor_id(); + cpumask_t cpu_mask; + unsigned long *mmc = &mm->context[cpu_id]; + unsigned long flags; + + preempt_disable(); + cpu_mask = mm->cpu_vm_mask; + cpu_clear(cpu_id, cpu_mask); + + if (*mmc != NO_CONTEXT) { + local_irq_save(flags); + *mmc = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + else + cpu_clear(cpu_id, mm->cpu_vm_mask); + local_irq_restore(flags); + } + if (!cpus_empty(cpu_mask)) + flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL); + + preempt_enable(); +} + +/*==========================================================================* + * Name: smp_flush_tlb_range + * + * Description: This routine flushes a range of pages. + * + * Born on Date: 2002.02.05 + * + * Arguments: *mm - a pointer to the mm struct for flush TLB + * start - not used + * end - not used + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + smp_flush_tlb_mm(vma->vm_mm); +} + +/*==========================================================================* + * Name: smp_flush_tlb_page + * + * Description: This routine flushes one page. + * + * Born on Date: 2002.02.05 + * + * Arguments: *vma - a pointer to the vma struct include va + * va - virtual address for flush TLB + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va) +{ + struct mm_struct *mm = vma->vm_mm; + int cpu_id = smp_processor_id(); + cpumask_t cpu_mask; + unsigned long *mmc = &mm->context[cpu_id]; + unsigned long flags; + + preempt_disable(); + cpu_mask = mm->cpu_vm_mask; + cpu_clear(cpu_id, cpu_mask); + +#ifdef DEBUG_SMP + if (!mm) + BUG(); +#endif + + if (*mmc != NO_CONTEXT) { + local_irq_save(flags); + va &= PAGE_MASK; + va |= (*mmc & MMU_CONTEXT_ASID_MASK); + __flush_tlb_page(va); + local_irq_restore(flags); + } + if (!cpus_empty(cpu_mask)) + flush_tlb_others(cpu_mask, mm, vma, va); + + preempt_enable(); +} + +/*==========================================================================* + * Name: flush_tlb_others + * + * Description: This routine requests other CPU to execute flush TLB. + * 1.Setup parmeters. + * 2.Send 'INVALIDATE_TLB_IPI' to other CPU. + * Request other CPU to execute 'smp_invalidate_interrupt()'. + * 3.Wait for other CPUs operation finished. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpumask - bitmap of target CPUs + * *mm - a pointer to the mm struct for flush TLB + * *vma - a pointer to the vma struct include va + * va - virtual address for flush TLB + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, + struct vm_area_struct *vma, unsigned long va) +{ + unsigned long *mask; +#ifdef DEBUG_SMP + unsigned long flags; + __save_flags(flags); + if (!(flags & 0x0040)) /* Interrupt Disable NONONO */ + BUG(); +#endif /* DEBUG_SMP */ + + /* + * A couple of (to be removed) sanity checks: + * + * - we do not send IPIs to not-yet booted CPUs. + * - current CPU must not be in mask + * - mask must exist :) + */ + BUG_ON(cpus_empty(cpumask)); + + BUG_ON(cpu_isset(smp_processor_id(), cpumask)); + BUG_ON(!mm); + + /* If a CPU which we ran on has gone down, OK. */ + cpus_and(cpumask, cpumask, cpu_online_map); + if (cpus_empty(cpumask)) + return; + + /* + * i'm not happy about this global shared spinlock in the + * MM hot path, but we'll see how contended it is. + * Temporarily this turns IRQs off, so that lockups are + * detected by the NMI watchdog. + */ + spin_lock(&tlbstate_lock); + + flush_mm = mm; + flush_vma = vma; + flush_va = va; + mask=cpus_addr(cpumask); + atomic_set_mask(*mask, (atomic_t *)&flush_cpumask); + + /* + * We have to send the IPI only to + * CPUs affected. + */ + send_IPI_mask(cpumask, INVALIDATE_TLB_IPI, 0); + + while (!cpus_empty(flush_cpumask)) { + /* nothing. lockup detection does not belong here */ + mb(); + } + + flush_mm = NULL; + flush_vma = NULL; + flush_va = 0; + spin_unlock(&tlbstate_lock); +} + +/*==========================================================================* + * Name: smp_invalidate_interrupt + * + * Description: This routine executes on CPU which received + * 'INVALIDATE_TLB_IPI'. + * 1.Flush local TLB. + * 2.Report flush TLB process was finished. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_invalidate_interrupt(void) +{ + int cpu_id = smp_processor_id(); + unsigned long *mmc = &flush_mm->context[cpu_id]; + + if (!cpu_isset(cpu_id, flush_cpumask)) + return; + + if (flush_va == FLUSH_ALL) { + *mmc = NO_CONTEXT; + if (flush_mm == current->active_mm) + activate_context(flush_mm); + else + cpu_clear(cpu_id, flush_mm->cpu_vm_mask); + } else { + unsigned long va = flush_va; + + if (*mmc != NO_CONTEXT) { + va &= PAGE_MASK; + va |= (*mmc & MMU_CONTEXT_ASID_MASK); + __flush_tlb_page(va); + } + } + cpu_clear(cpu_id, flush_cpumask); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Stop CPU request Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_send_stop + * + * Description: This routine requests stop all CPUs. + * 1.Request other CPU to execute 'stop_this_cpu()'. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); +} + +/*==========================================================================* + * Name: stop_this_cpu + * + * Description: This routine halt CPU. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void stop_this_cpu(void *dummy) +{ + int cpu_id = smp_processor_id(); + + /* + * Remove this CPU: + */ + cpu_clear(cpu_id, cpu_online_map); + + /* + * PSW IE = 1; + * IMASK = 0; + * goto SLEEP + */ + local_irq_disable(); + outl(0, M32R_ICU_IMASK_PORTL); + inl(M32R_ICU_IMASK_PORTL); /* dummy read */ + local_irq_enable(); + + for ( ; ; ); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Call function Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_call_function + * + * Description: This routine sends a 'CALL_FUNCTION_IPI' to all other CPUs + * in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: *func - The function to run. This must be fast and + * non-blocking. + * *info - An arbitrary pointer to pass to the function. + * nonatomic - currently unused. + * wait - If true, wait (atomically) until function has + * completed on other CPUs. + * + * Returns: 0 on success, else a negative status code. Does not return + * until remote CPUs are nearly ready to execute <> or + * are or have executed. + * + * Cautions: You must not call this function with disabled interrupts or + * from a hardware interrupt handler, you may call it from a + * bottom half handler. + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +int smp_call_function(void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + struct call_data_struct data; + int cpus; + +#ifdef DEBUG_SMP + unsigned long flags; + __save_flags(flags); + if (!(flags & 0x0040)) /* Interrupt Disable NONONO */ + BUG(); +#endif /* DEBUG_SMP */ + + /* Holding any lock stops cpus from going down. */ + spin_lock(&call_lock); + cpus = num_online_cpus() - 1; + + if (!cpus) { + spin_unlock(&call_lock); + return 0; + } + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + call_data = &data; + mb(); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(CALL_FUNCTION_IPI, 0); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + barrier(); + + if (wait) + while (atomic_read(&data.finished) != cpus) + barrier(); + spin_unlock(&call_lock); + + return 0; +} + +/*==========================================================================* + * Name: smp_call_function_interrupt + * + * Description: This routine executes on CPU which received + * 'CALL_FUNCTION_IPI'. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function + */ + mb(); + atomic_inc(&call_data->started); + /* + * At this point the info structure may be out of scope unless wait==1 + */ + irq_enter(); + (*func)(info); + irq_exit(); + + if (wait) { + mb(); + atomic_inc(&call_data->finished); + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Timer Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: smp_send_timer + * + * Description: This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs + * in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_send_timer(void) +{ + send_IPI_allbutself(LOCAL_TIMER_IPI, 1); +} + +/*==========================================================================* + * Name: smp_send_timer + * + * Description: This routine executes on CPU which received + * 'LOCAL_TIMER_IPI'. + * + * Born on Date: 2002.02.05 + * + * Arguments: *regs - a pointer to the saved regster info + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void smp_ipi_timer_interrupt(struct pt_regs *regs) +{ + irq_enter(); + smp_local_timer_interrupt(regs); + irq_exit(); +} + +/*==========================================================================* + * Name: smp_local_timer_interrupt + * + * Description: Local timer interrupt handler. It does both profiling and + * process statistics/rescheduling. + * We do profiling in every local tick, statistics/rescheduling + * happen only every 'profiling multiplier' ticks. The default + * multiplier is 1 and it can be changed by writing the new + * multiplier value into /proc/profile. + * + * Born on Date: 2002.02.05 + * + * Arguments: *regs - a pointer to the saved regster info + * + * Returns: void (cannot fail) + * + * Original: arch/i386/kernel/apic.c + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy use per_cpu structure. + *==========================================================================*/ +void smp_local_timer_interrupt(struct pt_regs *regs) +{ + int user = user_mode(regs); + int cpu_id = smp_processor_id(); + + /* + * The profiling function is SMP safe. (nothing can mess + * around with "current", and the profiling counters are + * updated with atomic operations). This is especially + * useful with a profiling multiplier != 1 + */ + + profile_tick(CPU_PROFILING, regs); + + if (--per_cpu(prof_counter, cpu_id) <= 0) { + /* + * The multiplier may have changed since the last time we got + * to this point as a result of the user writing to + * /proc/profile. In this case we need to adjust the APIC + * timer accordingly. + * + * Interrupts are already masked off at this point. + */ + per_cpu(prof_counter, cpu_id) + = per_cpu(prof_multiplier, cpu_id); + if (per_cpu(prof_counter, cpu_id) + != per_cpu(prof_old_multiplier, cpu_id)) + { + per_cpu(prof_old_multiplier, cpu_id) + = per_cpu(prof_counter, cpu_id); + } + + update_process_times(user); + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Send IPI Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: send_IPI_allbutself + * + * Description: This routine sends a IPI to all other CPUs in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: ipi_num - Number of IPI + * try - 0 : Send IPI certainly. + * !0 : The following IPI is not sended when Target CPU + * has not received the before IPI. + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +void send_IPI_allbutself(int ipi_num, int try) +{ + cpumask_t cpumask; + + cpumask = cpu_online_map; + cpu_clear(smp_processor_id(), cpumask); + + send_IPI_mask(cpumask, ipi_num, try); +} + +/*==========================================================================* + * Name: send_IPI_mask + * + * Description: This routine sends a IPI to CPUs in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpu_mask - Bitmap of target CPUs logical ID + * ipi_num - Number of IPI + * try - 0 : Send IPI certainly. + * !0 : The following IPI is not sended when Target CPU + * has not received the before IPI. + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +static void send_IPI_mask(cpumask_t cpumask, int ipi_num, int try) +{ + cpumask_t physid_mask, tmp; + int cpu_id, phys_id; + int num_cpus = num_online_cpus(); + + if (num_cpus <= 1) /* NO MP */ + return; + + cpus_and(tmp, cpumask, cpu_online_map); + BUG_ON(!cpus_equal(cpumask, tmp)); + + physid_mask = CPU_MASK_NONE; + for_each_cpu_mask(cpu_id, cpumask){ + if ((phys_id = cpu_to_physid(cpu_id)) != -1) + cpu_set(phys_id, physid_mask); + } + + send_IPI_mask_phys(physid_mask, ipi_num, try); +} + +/*==========================================================================* + * Name: send_IPI_mask_phys + * + * Description: This routine sends a IPI to other CPUs in the system. + * + * Born on Date: 2002.02.05 + * + * Arguments: cpu_mask - Bitmap of target CPUs physical ID + * ipi_num - Number of IPI + * try - 0 : Send IPI certainly. + * !0 : The following IPI is not sended when Target CPU + * has not received the before IPI. + * + * Returns: IPICRi regster value. + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * + *==========================================================================*/ +unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num, + int try) +{ + spinlock_t *ipilock; + unsigned long flags = 0; + volatile unsigned long *ipicr_addr; + unsigned long ipicr_val; + unsigned long my_physid_mask; + unsigned long mask = cpus_addr(physid_mask)[0]; + + + if (mask & ~physids_coerce(phys_cpu_present_map)) + BUG(); + if (ipi_num >= NR_IPIS) + BUG(); + + mask <<= IPI_SHIFT; + ipilock = &ipi_lock[ipi_num]; + ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR + + (ipi_num << 2)); + my_physid_mask = ~(1 << smp_processor_id()); + + /* + * lock ipi_lock[i] + * check IPICRi == 0 + * write IPICRi (send IPIi) + * unlock ipi_lock[i] + */ + __asm__ __volatile__ ( + ";; LOCK ipi_lock[i] \n\t" + ".fillinsn \n" + "1: \n\t" + "mvfc %1, psw \n\t" + "clrpsw #0x40 -> nop \n\t" + DCACHE_CLEAR("r4", "r5", "%2") + "lock r4, @%2 \n\t" + "addi r4, #-1 \n\t" + "unlock r4, @%2 \n\t" + "mvtc %1, psw \n\t" + "bnez r4, 2f \n\t" + LOCK_SECTION_START(".balign 4 \n\t") + ".fillinsn \n" + "2: \n\t" + "ld r4, @%2 \n\t" + "blez r4, 2b \n\t" + "bra 1b \n\t" + LOCK_SECTION_END + ";; CHECK IPICRi == 0 \n\t" + ".fillinsn \n" + "3: \n\t" + "ld %0, @%3 \n\t" + "and %0, %6 \n\t" + "beqz %0, 4f \n\t" + "bnez %5, 5f \n\t" + "bra 3b \n\t" + ";; WRITE IPICRi (send IPIi) \n\t" + ".fillinsn \n" + "4: \n\t" + "st %4, @%3 \n\t" + ";; UNLOCK ipi_lock[i] \n\t" + ".fillinsn \n" + "5: \n\t" + "ldi r4, #1 \n\t" + "st r4, @%2 \n\t" + : "=&r"(ipicr_val) + : "r"(flags), "r"(&ipilock->lock), "r"(ipicr_addr), + "r"(mask), "r"(try), "r"(my_physid_mask) + : "memory", "r4" +#ifdef CONFIG_CHIP_M32700_TS1 + , "r5" +#endif /* CONFIG_CHIP_M32700_TS1 */ + ); + + return ipicr_val; +} diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c new file mode 100644 index 000000000..6ac4f705e --- /dev/null +++ b/arch/m32r/kernel/smpboot.c @@ -0,0 +1,635 @@ +/* + * linux/arch/m32r/kernel/smpboot.c + * orig : i386 2.4.10 + * + * M32R SMP booting functions + * + * Copyright (c) 2001, 2002, 2003 Hitoshi Yamamoto + * + * Taken from i386 version. + * (c) 1995 Alan Cox, Building #3 + * (c) 1998, 1999, 2000 Ingo Molnar + * + * Much of the core SMP work is based on previous work by Thomas Radke, to + * whom a great many thanks are extended. + * + * Thanks to Intel for making available several different Pentium, + * Pentium Pro and Pentium-II/Xeon MP machines. + * Original development of Linux SMP code supported by Caldera. + * + * This code is released under the GNU General Public License version 2 or + * later. + * + * Fixes + * Felix Koop : NR_CPUS used properly + * Jose Renau : Handle single CPU case. + * Alan Cox : By repeated request + * 8) - Total BogoMIP report. + * Greg Wright : Fix for kernel stacks panic. + * Erich Boleyn : MP v1.4 and additional changes. + * Matthias Sattler : Changes for 2.1 kernel map. + * Michel Lespinasse : Changes for 2.1 kernel map. + * Michael Chastain : Change trampoline.S to gnu as. + * Alan Cox : Dumb bug: 'B' step PPro's are fine + * Ingo Molnar : Added APIC timers, based on code + * from Jose Renau + * Ingo Molnar : various cleanups and rewrites + * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. + * Maciej W. Rozycki : Bits for genuine 82489DX APICs + * Martin J. Bligh : Added support for multi-quad systems + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DEBUG_SMP +#ifdef DEBUG_SMP +#define Dprintk(x...) printk(x) +#else +#define Dprintk(x...) +#endif + +extern int cpu_idle(void); +extern cpumask_t cpu_initialized; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Data structures and variables */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/* Processor that is doing the boot up */ +static unsigned int bsp_phys_id = -1; + +/* Bitmask of physically existing CPUs */ +physid_mask_t phys_cpu_present_map; + +/* Bitmask of currently online CPUs */ +cpumask_t cpu_online_map; + +cpumask_t cpu_bootout_map; +cpumask_t cpu_bootin_map; +cpumask_t cpu_callout_map; +static cpumask_t cpu_callin_map; + +/* Per CPU bogomips and other parameters */ +struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned; + +/* Set when the idlers are all forked */ +int smp_threads_ready; + +static int cpucount; +static cpumask_t smp_commenced_mask; + +extern struct { + void * spi; + unsigned short ss; +} stack_start; + +/* which physical physical ID maps to which logical CPU number */ +static volatile int physid_2_cpu[NR_CPUS]; + +/* which logical CPU number maps to which physical ID */ +volatile int cpu_2_physid[NR_CPUS]; + +DEFINE_PER_CPU(int, prof_multiplier) = 1; +DEFINE_PER_CPU(int, prof_old_multiplier) = 1; +DEFINE_PER_CPU(int, prof_counter) = 1; + +spinlock_t ipi_lock[NR_IPIS]; + +static unsigned int calibration_result; + +unsigned long cache_decay_ticks = HZ / 100; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Function Prototypes */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +void smp_prepare_boot_cpu(void); +void smp_prepare_cpus(unsigned int); +static void smp_tune_scheduling(void); +static void init_ipi_lock(void); +static void do_boot_cpu(int); +int __cpu_up(unsigned int); +void smp_cpus_done(unsigned int); + +int start_secondary(void *); +static void smp_callin(void); +static void smp_online(void); + +static void show_mp_info(int); +static void smp_store_cpu_info(int); +static void show_cpu_info(int); +int setup_profiling_timer(unsigned int); +static void init_cpu_to_physid(void); +static void map_cpu_to_physid(int, int); +static void unmap_cpu_to_physid(int, int); + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Boot up APs Routins : BSP */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +void __devinit smp_prepare_boot_cpu(void) +{ + bsp_phys_id = hard_smp_processor_id(); + physid_set(bsp_phys_id, phys_cpu_present_map); + cpu_set(0, cpu_online_map); /* BSP's cpu_id == 0 */ + cpu_set(0, cpu_callout_map); + cpu_set(0, cpu_callin_map); + + /* + * Initialize the logical to physical CPU number mapping + */ + init_cpu_to_physid(); + map_cpu_to_physid(0, bsp_phys_id); + current_thread_info()->cpu = 0; +} + +/*==========================================================================* + * Name: smp_prepare_cpus (old smp_boot_cpus) + * + * Description: This routine boot up APs. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + int phys_id; + unsigned long nr_cpu; + + nr_cpu = inl(M32R_FPGA_NUM_OF_CPUS_PORTL); + if (nr_cpu > NR_CPUS) { + printk(KERN_INFO "NUM_OF_CPUS reg. value [%ld] > NR_CPU [%d]", + nr_cpu, NR_CPUS); + goto smp_done; + } + for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++) + physid_set(phys_id, phys_cpu_present_map); + + show_mp_info(nr_cpu); + + init_ipi_lock(); + + /* + * Setup boot CPU information + */ + smp_store_cpu_info(0); /* Final full version of the data */ + smp_tune_scheduling(); + + /* + * If SMP should be disabled, then really disable it! + */ + if (!max_cpus) { + printk(KERN_INFO "SMP mode deactivated by commandline.\n"); + goto smp_done; + } + + /* + * Now scan the CPU present map and fire up the other CPUs. + */ + Dprintk("CPU present map : %lx\n", physids_coerce(phys_cpu_present_map)); + + for (phys_id = 0 ; phys_id < NR_CPUS ; phys_id++) { + /* + * Don't even attempt to start the boot CPU! + */ + if (phys_id == bsp_phys_id) + continue; + + if (!physid_isset(phys_id, phys_cpu_present_map)) + continue; + + if ((max_cpus >= 0) && (max_cpus <= cpucount + 1)) + continue; + + do_boot_cpu(phys_id); + + /* + * Make sure we unmap all failed CPUs + */ + if (physid_to_cpu(phys_id) == -1) { + physid_clear(phys_id, phys_cpu_present_map); + printk("phys CPU#%d not responding - " \ + "cannot use it.\n", phys_id); + } + } + +smp_done: + Dprintk("Boot done.\n"); +} + +static void __init smp_tune_scheduling(void) +{ + /* Nothing to do. */ +} + +/* + * init_ipi_lock : Initialize IPI locks. + */ +static void __init init_ipi_lock(void) +{ + int ipi; + + for (ipi = 0 ; ipi < NR_IPIS ; ipi++) + ipi_lock[ipi] = SPIN_LOCK_UNLOCKED; +} + +/*==========================================================================* + * Name: do_boot_cpu + * + * Description: This routine boot up one AP. + * + * Born on Date: 2002.02.05 + * + * Arguments: phys_id - Target CPU physical ID + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +static void __init do_boot_cpu(int phys_id) +{ + struct task_struct *idle; + unsigned long send_status, boot_status; + int timeout, cpu_id; + + cpu_id = ++cpucount; + + /* + * We can't use kernel_thread since we must avoid to + * reschedule the child. + */ + idle = fork_idle(cpu_id); + if (IS_ERR(idle)) + panic("failed fork for CPU#%d.", cpu_id); + + idle->thread.lr = (unsigned long)start_secondary; + + map_cpu_to_physid(cpu_id, phys_id); + + /* So we see what's up */ + printk("Booting processor %d/%d\n", phys_id, cpu_id); + stack_start.spi = (void *)idle->thread.sp; + idle->thread_info->cpu = cpu_id; + + /* + * Send Startup IPI + * 1.IPI received by CPU#(phys_id). + * 2.CPU#(phys_id) enter startup_AP (arch/m32r/kernel/head.S) + * 3.CPU#(phys_id) enter start_secondary() + */ + send_status = 0; + boot_status = 0; + + cpu_set(phys_id, cpu_bootout_map); + + /* Send Startup IPI */ + send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0); + + Dprintk("Waiting for send to finish...\n"); + timeout = 0; + + /* Wait 100[ms] */ + do { + Dprintk("+"); + udelay(1000); + send_status = !cpu_isset(phys_id, cpu_bootin_map); + } while (send_status && (timeout++ < 100)); + + Dprintk("After Startup.\n"); + + if (!send_status) { + /* + * allow APs to start initializing. + */ + Dprintk("Before Callout %d.\n", cpu_id); + cpu_set(cpu_id, cpu_callout_map); + Dprintk("After Callout %d.\n", cpu_id); + + /* + * Wait 5s total for a response + */ + for (timeout = 0; timeout < 5000; timeout++) { + if (cpu_isset(cpu_id, cpu_callin_map)) + break; /* It has booted */ + udelay(1000); + } + + if (cpu_isset(cpu_id, cpu_callin_map)) { + /* number CPUs logically, starting from 1 (BSP is 0) */ + Dprintk("OK.\n"); + } else { + boot_status = 1; + printk("Not responding.\n"); + } + } else + printk("IPI never delivered???\n"); + + if (send_status || boot_status) { + unmap_cpu_to_physid(cpu_id, phys_id); + cpu_clear(cpu_id, cpu_callout_map); + cpu_clear(cpu_id, cpu_callin_map); + cpu_clear(cpu_id, cpu_initialized); + cpucount--; + } +} + +int __devinit __cpu_up(unsigned int cpu_id) +{ + int timeout; + + cpu_set(cpu_id, smp_commenced_mask); + + /* + * Wait 5s total for a response + */ + for (timeout = 0; timeout < 5000; timeout++) { + if (cpu_isset(cpu_id, cpu_online_map)) + break; + udelay(1000); + } + if (!cpu_isset(cpu_id, cpu_online_map)) + BUG(); + + return 0; +} + +void __init smp_cpus_done(unsigned int max_cpus) +{ + int cpu_id, timeout; + unsigned long bogosum = 0; + + for (timeout = 0; timeout < 5000; timeout++) { + if (cpus_equal(cpu_callin_map, cpu_online_map)) + break; + udelay(1000); + } + if (!cpus_equal(cpu_callin_map, cpu_online_map)) + BUG(); + + for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++) + show_cpu_info(cpu_id); + + /* + * Allow the user to impress friends. + */ + Dprintk("Before bogomips.\n"); + if (cpucount) { + for_each_cpu_mask(cpu_id, cpu_online_map) + bogosum += cpu_data[cpu_id].loops_per_jiffy; + + printk(KERN_INFO "Total of %d processors activated " \ + "(%lu.%02lu BogoMIPS).\n", cpucount + 1, + bogosum / (500000 / HZ), + (bogosum / (5000 / HZ)) % 100); + Dprintk("Before bogocount - setting activated=1.\n"); + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Activate a secondary processor Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*==========================================================================* + * Name: start_secondary + * + * Description: This routine activate a secondary processor. + * + * Born on Date: 2002.02.05 + * + * Arguments: *unused - currently unused. + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +int __init start_secondary(void *unused) +{ + cpu_init(); + smp_callin(); + while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) + rep_nop(); + + smp_online(); + + /* + * low-memory mappings have been cleared, flush them from + * the local TLBs too. + */ + local_flush_tlb_all(); + + return cpu_idle(); +} + +/*==========================================================================* + * Name: smp_callin + * + * Description: This routine activate a secondary processor. + * + * Born on Date: 2002.02.05 + * + * Arguments: NONE + * + * Returns: void (cannot fail) + * + * Modification log: + * Date Who Description + * ---------- --- -------------------------------------------------------- + * 2003-06-24 hy modify for linux-2.5.69 + * + *==========================================================================*/ +static void __init smp_callin(void) +{ + int phys_id = hard_smp_processor_id(); + int cpu_id = smp_processor_id(); + unsigned long timeout; + + if (cpu_isset(cpu_id, cpu_callin_map)) { + printk("huh, phys CPU#%d, CPU#%d already present??\n", + phys_id, cpu_id); + BUG(); + } + Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpu_id, phys_id); + + /* Waiting 2s total for startup (udelay is not yet working) */ + timeout = jiffies + (2 * HZ); + while (time_before(jiffies, timeout)) { + /* Has the boot CPU finished it's STARTUP sequence ? */ + if (cpu_isset(cpu_id, cpu_callout_map)) + break; + rep_nop(); + } + + if (!time_before(jiffies, timeout)) { + printk("BUG: CPU#%d started up but did not get a callout!\n", + cpu_id); + BUG(); + } + + /* Allow the master to continue. */ + cpu_set(cpu_id, cpu_callin_map); +} + +static void __init smp_online(void) +{ + int cpu_id = smp_processor_id(); + + local_irq_enable(); + + /* Get our bogomips. */ + calibrate_delay(); + + /* Save our processor parameters */ + smp_store_cpu_info(cpu_id); + + cpu_set(cpu_id, cpu_online_map); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* Boot up CPUs common Routins */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +static void __init show_mp_info(int nr_cpu) +{ + int i; + char cpu_model0[17], cpu_model1[17], cpu_ver[9]; + + strncpy(cpu_model0, (char *)M32R_FPGA_CPU_NAME_ADDR, 16); + strncpy(cpu_model1, (char *)M32R_FPGA_MODEL_ID_ADDR, 16); + strncpy(cpu_ver, (char *)M32R_FPGA_VERSION_ADDR, 8); + + cpu_model0[16] = '\0'; + for (i = 15 ; i >= 0 ; i--) { + if (cpu_model0[i] != ' ') + break; + cpu_model0[i] = '\0'; + } + cpu_model1[16] = '\0'; + for (i = 15 ; i >= 0 ; i--) { + if (cpu_model1[i] != ' ') + break; + cpu_model1[i] = '\0'; + } + cpu_ver[8] = '\0'; + for (i = 7 ; i >= 0 ; i--) { + if (cpu_ver[i] != ' ') + break; + cpu_ver[i] = '\0'; + } + + printk(KERN_INFO "M32R-mp information\n"); + printk(KERN_INFO " On-chip CPUs : %d\n", nr_cpu); + printk(KERN_INFO " CPU model : %s/%s(%s)\n", cpu_model0, + cpu_model1, cpu_ver); +} + +/* + * The bootstrap kernel entry code has set these up. Save them for + * a given CPU + */ +static void __init smp_store_cpu_info(int cpu_id) +{ + struct cpuinfo_m32r *ci = cpu_data + cpu_id; + + *ci = boot_cpu_data; + ci->loops_per_jiffy = loops_per_jiffy; +} + +static void __init show_cpu_info(int cpu_id) +{ + struct cpuinfo_m32r *ci = &cpu_data[cpu_id]; + + printk("CPU#%d : ", cpu_id); + +#define PRINT_CLOCK(name, value) \ + printk(name " clock %d.%02dMHz", \ + ((value) / 1000000), ((value) % 1000000) / 10000) + + PRINT_CLOCK("CPU", (int)ci->cpu_clock); + PRINT_CLOCK(", Bus", (int)ci->bus_clock); + printk(", loops_per_jiffy[%ld]\n", ci->loops_per_jiffy); +} + +/* + * the frequency of the profiling timer can be changed + * by writing a multiplier value into /proc/profile. + */ +int setup_profiling_timer(unsigned int multiplier) +{ + int i; + + /* + * Sanity check. [at least 500 APIC cycles should be + * between APIC interrupts as a rule of thumb, to avoid + * irqs flooding us] + */ + if ( (!multiplier) || (calibration_result / multiplier < 500)) + return -EINVAL; + + /* + * Set the new multiplier for each CPU. CPUs don't start using the + * new values until the next timer interrupt in which they do process + * accounting. At that time they also adjust their APIC timers + * accordingly. + */ + for (i = 0; i < NR_CPUS; ++i) + per_cpu(prof_multiplier, i) = multiplier; + + return 0; +} + +/* Initialize all maps between cpu number and apicids */ +static void __init init_cpu_to_physid(void) +{ + int i; + + for (i = 0 ; i < NR_CPUS ; i++) { + cpu_2_physid[i] = -1; + physid_2_cpu[i] = -1; + } +} + +/* + * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, + * else physical apic ids + */ +static void __init map_cpu_to_physid(int cpu_id, int phys_id) +{ + physid_2_cpu[phys_id] = cpu_id; + cpu_2_physid[cpu_id] = phys_id; +} + +/* + * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, + * else physical apic ids + */ +static void __init unmap_cpu_to_physid(int cpu_id, int phys_id) +{ + physid_2_cpu[phys_id] = -1; + cpu_2_physid[cpu_id] = -1; +} + diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c new file mode 100644 index 000000000..f34fa19ac --- /dev/null +++ b/arch/m32r/kernel/sys_m32r.c @@ -0,0 +1,217 @@ +/* + * linux/arch/m32r/kernel/sys_m32r.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/M32R platform. + * + * Taken from i386 version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * sys_tas() - test-and-set + * linuxthreads testing version + */ +#ifndef CONFIG_SMP +asmlinkage int sys_tas(int *addr) +{ + int oldval; + unsigned long flags; + + if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) + return -EFAULT; + local_irq_save(flags); + oldval = *addr; + *addr = 1; + local_irq_restore(flags); + return oldval; +} +#else /* CONFIG_SMP */ +#include + +static spinlock_t tas_lock = SPIN_LOCK_UNLOCKED; + +asmlinkage int sys_tas(int *addr) +{ + int oldval; + + if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) + return -EFAULT; + + spin_lock(&tas_lock); + oldval = *addr; + *addr = 1; + spin_unlock(&tas_lock); + + return oldval; +} +#endif /* CONFIG_SMP */ + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +asmlinkage int +sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, struct pt_regs regs) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file *file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc(uint call, int first, int second, + int third, void __user *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, (const struct timespec __user *)fifth); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void __user * __user *) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf __user *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge __user *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf __user *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds __user *) ptr); + case SHMAT: { + ulong raddr; + + if ((ret = verify_area(VERIFY_WRITE, (ulong __user *) third, + sizeof(ulong)))) + return ret; + ret = do_shmat (first, (char __user *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong __user *) third); + } + case SHMDT: + return sys_shmdt ((char __user *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds __user *) ptr); + default: + return -ENOSYS; + } +} + +asmlinkage int sys_uname(struct old_utsname * name) +{ + int err; + if (!name) + return -EFAULT; + down_read(&uts_sem); + err=copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + return err?-EFAULT:0; +} + +asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) +{ + /* This should flush more selectivly ... */ + _flush_cache_all(); + return 0; +} + +asmlinkage int sys_cachectl(char *addr, int nbytes, int op) +{ + /* Not implemented yet. */ + return -ENOSYS; +} + diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c new file mode 100644 index 000000000..25a31668f --- /dev/null +++ b/arch/m32r/kernel/time.c @@ -0,0 +1,317 @@ +/* + * linux/arch/m32r/kernel/time.c + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto + * Taken from i386 version. + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1996, 1997, 1998 Ralf Baechle + * + * This file contains the time handling details for PC-style clocks as + * found in some MIPS systems. + * + * Some code taken from sh version. + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + * Copyright (C) 2000 Philipp Rumpf + */ + +#undef DEBUG_TIMER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef CONFIG_SMP +extern void send_IPI_allbutself(int, int); +extern void smp_local_timer_interrupt(struct pt_regs *); +#endif + +u64 jiffies_64 = INITIAL_JIFFIES; + +EXPORT_SYMBOL(jiffies_64); + +extern unsigned long wall_jiffies; +#define TICK_SIZE (tick_nsec / 1000) + +/* + * Change this if you have some constant time drift + */ + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +static unsigned long latch; + +static unsigned long do_gettimeoffset(void) +{ + unsigned long elapsed_time = 0; /* [us] */ + +#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ + || defined(CONFIG_CHIP_OPSP) +#ifndef CONFIG_SMP + + unsigned long count; + + /* timer count may underflow right here */ + count = inl(M32R_MFT2CUT_PORTL); + + if (inl(M32R_ICU_CR18_PORTL) & 0x00000100) /* underflow check */ + count = 0; + + count = (latch - count) * TICK_SIZE; + elapsed_time = (count + latch / 2) / latch; + /* NOTE: LATCH is equal to the "interval" value (= reload count). */ + +#else /* CONFIG_SMP */ + unsigned long count; + static unsigned long p_jiffies = -1; + static unsigned long p_count = 0; + + /* timer count may underflow right here */ + count = inl(M32R_MFT2CUT_PORTL); + + if (jiffies == p_jiffies && count > p_count) + count = 0; + + p_jiffies = jiffies; + p_count = count; + + count = (latch - count) * TICK_SIZE; + elapsed_time = (count + latch / 2) / latch; + /* NOTE: LATCH is equal to the "interval" value (= reload count). */ +#endif /* CONFIG_SMP */ +#elif defined(CONFIG_CHIP_M32310) +#warning do_gettimeoffse not implemented +#else +#error no chip configuration +#endif + + return elapsed_time; +} + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long seq; + unsigned long usec, sec; + unsigned long max_ntp_tick = tick_usec - tickadj; + + do { + unsigned long lost; + + seq = read_seqbegin(&xtime_lock); + + usec = do_gettimeoffset(); + lost = jiffies - wall_jiffies; + + /* + * If time_adjust is negative then NTP is slowing the clock + * so make sure not to go into next possible interval. + * Better to lose some accuracy than have time go backwards.. + */ + if (unlikely(time_adjust < 0)) { + usec = min(usec, max_ntp_tick); + if (lost) + usec += lost * max_ntp_tick; + } else if (unlikely(lost)) + usec += lost * tick_usec; + + sec = xtime.tv_sec; + usec += (xtime.tv_nsec / 1000); + } while (read_seqretry(&xtime_lock, seq)); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +EXPORT_SYMBOL(do_gettimeofday); + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set "xtime" correctly. However, the + * value in this location is the value at the most recent update of + * wall time. Discover what correction gettimeofday() would have + * made, and then undo it! + */ + nsec -= do_gettimeoffset() * NSEC_PER_USEC; + nsec -= (jiffies - wall_jiffies) * TICK_NSEC; + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + + return 0; +} + +EXPORT_SYMBOL(do_settimeofday); + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static __inline__ int set_rtc_mmss(unsigned long nowtime) +{ + return 0; +} + +/* last time the cmos clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static __inline__ void do_timer_interrupt(int irq, void *dev_id, + struct pt_regs * regs) +{ + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2 + && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2) + { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + } + /* As we return to user mode fire off the other CPU schedulers.. + this is basically because we don't yet share IRQ's around. + This message is rigged to be safe on the 386 - basically it's + a hack, so don't look closely for now.. */ + +#ifdef CONFIG_SMP + smp_local_timer_interrupt(regs); +#endif +} + +irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + write_seqlock(&xtime_lock); + do_timer_interrupt(irq, NULL, regs); + write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + profile_tick(CPU_PROFILING, regs); +#endif + + return IRQ_HANDLED; +} + +struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, + "MFT2", NULL, NULL }; + +void __init time_init(void) +{ + unsigned int epoch, year, mon, day, hour, min, sec; + + sec = min = hour = day = mon = year = 0; + epoch = 0; + + year = 23; + mon = 4; + day = 17; + + /* Attempt to guess the epoch. This is the same heuristic as in rtc.c + so no stupid things will happen to timekeeping. Who knows, maybe + Ultrix also uses 1952 as epoch ... */ + if (year > 10 && year < 44) + epoch = 1980; + else if (year < 96) + epoch = 1952; + year += epoch; + + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); + wall_to_monotonic.tv_sec = -xtime.tv_sec; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; + +#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ + || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ + || defined(CONFIG_CHIP_OPSP) + + /* M32102 MFT setup */ + setup_irq(M32R_IRQ_MFT2, &irq0); + { + unsigned long bus_clock; + unsigned short divide; + + bus_clock = boot_cpu_data.bus_clock; + divide = boot_cpu_data.timer_divide; + latch = (bus_clock/divide + HZ / 2) / HZ; + + printk("Timer start : latch = %ld\n", latch); + + outl((M32R_MFTMOD_CC_MASK | M32R_MFTMOD_TCCR \ + |M32R_MFTMOD_CSSEL011), M32R_MFT2MOD_PORTL); + outl(latch, M32R_MFT2RLD_PORTL); + outl(latch, M32R_MFT2CUT_PORTL); + outl(0, M32R_MFT2CMPRLD_PORTL); + outl((M32R_MFTCR_MFT2MSK|M32R_MFTCR_MFT2EN), M32R_MFTCR_PORTL); + } + +#elif defined(CONFIG_CHIP_M32310) +#warning time_init not implemented +#else +#error no chip configuration +#endif +} + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies * (1000000000 / HZ); +} + diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c new file mode 100644 index 000000000..87fdc4ddc --- /dev/null +++ b/arch/m32r/kernel/traps.c @@ -0,0 +1,330 @@ +/* + * linux/arch/m32r/kernel/traps.c + * + * Copyright (C) 2001, 2002 Hirokazu Takata, Hiroyuki Kondo, + * Hitoshi Yamamoto + */ + +/* $Id$ */ + +/* + * 'traps.c' handles hardware traps and faults after we have saved some + * state in 'entry.S'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +asmlinkage void alignment_check(void); +asmlinkage void ei_handler(void); +asmlinkage void rie_handler(void); +asmlinkage void debug_trap(void); +asmlinkage void cache_flushing_handler(void); + +#ifdef CONFIG_SMP +extern void smp_reschedule_interrupt(void); +extern void smp_invalidate_interrupt(void); +extern void smp_call_function_interrupt(void); +extern void smp_ipi_timer_interrupt(void); +extern void smp_flush_cache_all_interrupt(void); + +/* + * for Boot AP function + */ +asm ( + " .section .eit_vector4,\"ax\" \n" + " .global _AP_RE \n" + " .global startup_AP \n" + "_AP_RE: \n" + " .fill 32, 4, 0 \n" + "_AP_EI: bra startup_AP \n" + " .previous \n" +); +#endif /* CONFIG_SMP */ + +extern unsigned long eit_vector[]; +#define BRA_INSN(func, entry) \ + ((unsigned long)func - (unsigned long)eit_vector - entry*4)/4 \ + + 0xff000000UL + +void set_eit_vector_entries(void) +{ + extern void default_eit_handler(void); + extern void system_call(void); + extern void pie_handler(void); + extern void ace_handler(void); + extern void tme_handler(void); + extern void _flush_cache_copyback_all(void); + + eit_vector[0] = 0xd0c00001; /* seth r0, 0x01 */ + eit_vector[1] = BRA_INSN(default_eit_handler, 1); + eit_vector[4] = 0xd0c00010; /* seth r0, 0x10 */ + eit_vector[5] = BRA_INSN(default_eit_handler, 5); + eit_vector[8] = BRA_INSN(rie_handler, 8); + eit_vector[12] = BRA_INSN(alignment_check, 12); + eit_vector[16] = 0xff000000UL; + eit_vector[17] = BRA_INSN(debug_trap, 17); + eit_vector[18] = BRA_INSN(system_call, 18); + eit_vector[19] = 0xff000000UL; + eit_vector[20] = 0xff000000UL; + eit_vector[21] = 0xff000000UL; + eit_vector[22] = 0xff000000UL; + eit_vector[23] = 0xff000000UL; + eit_vector[24] = 0xff000000UL; + eit_vector[25] = 0xff000000UL; + eit_vector[26] = 0xff000000UL; + eit_vector[27] = 0xff000000UL; + eit_vector[28] = BRA_INSN(cache_flushing_handler, 28); + eit_vector[29] = 0xff000000UL; + eit_vector[30] = 0xff000000UL; + eit_vector[31] = 0xff000000UL; + eit_vector[32] = BRA_INSN(ei_handler, 32); + eit_vector[64] = BRA_INSN(pie_handler, 64); + eit_vector[68] = BRA_INSN(ace_handler, 68); + eit_vector[72] = BRA_INSN(tme_handler, 72); +#ifdef CONFIG_SMP + eit_vector[184] = (unsigned long)smp_reschedule_interrupt; + eit_vector[185] = (unsigned long)smp_invalidate_interrupt; + eit_vector[186] = (unsigned long)smp_call_function_interrupt; + eit_vector[187] = (unsigned long)smp_ipi_timer_interrupt; + eit_vector[188] = (unsigned long)smp_flush_cache_all_interrupt; + eit_vector[189] = 0; + eit_vector[190] = 0; + eit_vector[191] = 0; +#endif + _flush_cache_copyback_all(); +} + +void __init trap_init(void) +{ + set_eit_vector_entries(); + + /* + * Should be a barrier for any external CPU state. + */ + cpu_init(); +} + +int kstack_depth_to_print = 24; + +void show_trace(struct task_struct *task, unsigned long *stack) +{ + unsigned long addr; + + if (!stack) + stack = (unsigned long*)&stack; + + printk("Call Trace: "); + while (!kstack_end(stack)) { + addr = *stack++; + if (__kernel_text_address(addr)) { + printk("[<%08lx>] ", addr); + print_symbol("%s\n", addr); + } + } + printk("\n"); +} + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + unsigned long *stack; + int i; + + /* + * debugging aid: "show_stack(NULL);" prints the + * back trace for this cpu. + */ + + if(sp==NULL) { + if (task) + sp = (unsigned long *)task->thread.sp; + else + sp=(unsigned long*)&sp; + } + + stack = sp; + for(i=0; i < kstack_depth_to_print; i++) { + if (kstack_end(stack)) + break; + if (i && ((i % 4) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + printk("\n"); + show_trace(task, sp); +} + +void dump_stack(void) +{ + unsigned long stack; + + show_trace(current, &stack); +} + +EXPORT_SYMBOL(dump_stack); + +static void show_registers(struct pt_regs *regs) +{ + int i = 0; + int in_kernel = 1; + unsigned long sp; + + printk("CPU: %d\n", smp_processor_id()); + show_regs(regs); + + sp = (unsigned long) (1+regs); + if (user_mode(regs)) { + in_kernel = 0; + sp = regs->spu; + printk("SPU: %08lx\n", sp); + } else { + printk("SPI: %08lx\n", sp); + } + printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)", + current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current); + + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + printk("\nStack: "); + show_stack(current, (unsigned long*) sp); + + printk("\nCode: "); + if (regs->bpc < PAGE_OFFSET) + goto bad; + + for(i=0;i<20;i++) { + unsigned char c; + if (__get_user(c, &((unsigned char*)regs->bpc)[i])) { +bad: + printk(" Bad PC value."); + break; + } + printk("%02x ", c); + } + } + printk("\n"); +} + +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; + +void die(const char * str, struct pt_regs * regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + bust_spinlocks(1); + printk("%s: %04lx\n", str, err & 0xffff); + show_registers(regs); + bust_spinlocks(0); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +static __inline__ void die_if_kernel(const char * str, + struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +static __inline__ void do_trap(int trapnr, int signr, const char * str, + struct pt_regs * regs, long error_code, siginfo_t *info) +{ + if (user_mode(regs)) { + /* trap_signal */ + struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); + return; + } else { + /* kernel_trap */ + if (!fixup_exception(regs)) + die(str, regs, error_code); + return; + } +} + +#define DO_ERROR(trapnr, signr, str, name) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + do_trap(trapnr, signr, 0, regs, error_code, NULL); \ +} + +#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ + do_trap(trapnr, signr, str, regs, error_code, &info); \ +} + +DO_ERROR( 1, SIGTRAP, "debug trap", debug_trap) +DO_ERROR_INFO(0x20, SIGILL, "reserved instruction ", rie_handler, ILL_ILLOPC, regs->bpc) +DO_ERROR_INFO(0x100, SIGILL, "privilege instruction", pie_handler, ILL_PRVOPC, regs->bpc) + +extern int handle_unaligned_access(unsigned long, struct pt_regs *); + +/* This code taken from arch/sh/kernel/traps.c */ +asmlinkage void do_alignment_check(struct pt_regs *regs, long error_code) +{ + mm_segment_t oldfs; + unsigned long insn; + int tmp; + + oldfs = get_fs(); + + if (user_mode(regs)) { + local_irq_enable(); + current->thread.error_code = error_code; + current->thread.trap_no = 0x17; + + set_fs(USER_DS); + if (copy_from_user(&insn, (void *)regs->bpc, 4)) { + set_fs(oldfs); + goto uspace_segv; + } + tmp = handle_unaligned_access(insn, regs); + set_fs(oldfs); + + if (!tmp) + return; + + uspace_segv: + printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " + "access\n", current->comm); + force_sig(SIGSEGV, current); + } else { + set_fs(KERNEL_DS); + if (copy_from_user(&insn, (void *)regs->bpc, 4)) { + set_fs(oldfs); + die("insn faulting in do_address_error", regs, 0); + } + handle_unaligned_access(insn, regs); + set_fs(oldfs); + } +} + diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S new file mode 100644 index 000000000..729a2645a --- /dev/null +++ b/arch/m32r/kernel/vmlinux.lds.S @@ -0,0 +1,143 @@ +/* ld script to make M32R Linux kernel + */ + +#include +#include +#include +#include + +OUTPUT_ARCH(m32r) +ENTRY(startup_32) +#if defined(__LITTLE_ENDIAN__) + jiffies = jiffies_64; +#else + jiffies = jiffies_64 + 4; +#endif +SECTIONS +{ + . = CONFIG_MEMORY_START + __PAGE_OFFSET; + eit_vector = .; + + . = . + 0x1000; + .empty_zero_page : { *(.empty_zero_page) } = 0 + + /* read-only */ + _text = .; /* Text and read-only data */ + .boot : { *(.boot) } = 0 + .text : { + *(.text) + SCHED_TEXT + LOCK_TEXT + *(.fixup) + *(.gnu.warning) + } = 0x9090 +#ifdef CONFIG_SMP + . = ALIGN(65536); + .eit_vector4 : { *(.eit_vector4) } +#endif + _etext = .; /* End of text section */ + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + RODATA + + /* writeable */ + .data : { /* Data */ + *(.spu) + *(.spi) + *(.data) + CONSTRUCTORS + } + + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + /* will be freed after init */ + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + .init.data : { *(.init.data) } + . = ALIGN(16); + __setup_start = .; + .init.setup : { *(.init.setup) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + } + __initcall_end = .; + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; + SECURITY_INIT + . = 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) } + . = ALIGN(4096); + __initramfs_start = .; + .init.ramfs : { *(.init.ramfs) } + __initramfs_end = .; + . = ALIGN(32); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + . = ALIGN(4096); + __init_end = .; + /* freed after init ends here */ + + __bss_start = .; /* BSS */ + .bss : { *(.bss) } + . = ALIGN(4); + __bss_stop = .; + + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/arch/m32r/lib/Makefile b/arch/m32r/lib/Makefile new file mode 100644 index 000000000..e632d10c7 --- /dev/null +++ b/arch/m32r/lib/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for M32R-specific library files.. +# + +lib-y := checksum.o ashxdi3.o memset.o memcpy.o getuser.o \ + putuser.o delay.o strlen.o usercopy.o csum_partial_copy.o + diff --git a/arch/m32r/lib/ashxdi3.S b/arch/m32r/lib/ashxdi3.S new file mode 100644 index 000000000..78effca9d --- /dev/null +++ b/arch/m32r/lib/ashxdi3.S @@ -0,0 +1,297 @@ +/* + * linux/arch/m32r/lib/ashxdi3.S + * + * Copyright (C) 2001,2002 Hiroyuki Kondo, and Hirokazu Takata + * + */ +/* $Id$ */ + +#include + +; +; input (r0,r1) src +; input r2 shift val +; r3 scratch +; output (r0,r1) +; + +#ifdef CONFIG_ISA_DUAL_ISSUE + +#ifndef __LITTLE_ENDIAN__ + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r1, r0 || srai r0, #31 + addi r2, #-32 + sra r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 || srl r1, r2 + sra r0, r2 || neg r2, r2 + sll r3, r2 + or r1, r3 || jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r0, r1 || addi r2, #-32 + sll r0, r2 || ldi r1, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 || sll r0, r2 + sll r1, r2 || neg r2, r2 + srl r3, r2 + or r0, r3 || jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r1, r0 || addi r2, #-32 + ldi r0, #0 || srl r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 || srl r1, r2 + srl r0, r2 || neg r2, r2 + sll r3, r2 + or r1, r3 || jmp r14 + +#else /* LITTLE_ENDIAN */ + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r0, r1 || srai r1, #31 + addi r2, #-32 + sra r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 || srl r0, r2 + sra r1, r2 || neg r2, r2 + sll r3, r2 + or r0, r3 || jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r1, r0 || addi r2, #-32 + sll r1, r2 || ldi r0, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 || sll r1, r2 + sll r0, r2 || neg r2, r2 + srl r3, r2 + or r1, r3 || jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + cmpz r2 || ldi r3, #32 + jc r14 || cmpu r2, r3 + bc 1f + ; case 32 =< shift + mv r0, r1 || addi r2, #-32 + ldi r1, #0 || srl r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 || srl r0, r2 + srl r1, r2 || neg r2, r2 + sll r3, r2 + or r0, r3 || jmp r14 + +#endif + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +#ifndef __LITTLE_ENDIAN__ + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r1, r0 + srai r0, #31 + addi r2, #-32 + sra r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 + srl r1, r2 + sra r0, r2 + neg r2, r2 + sll r3, r2 + or r1, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r0, r1 + addi r2, #-32 + sll r0, r2 + ldi r1, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 + sll r0, r2 + sll r1, r2 + neg r2, r2 + srl r3, r2 + or r0, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r1, r0 + ldi r0, #0 + addi r2, #-32 + srl r1, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 + srl r1, r2 + srl r0, r2 + neg r2, r2 + sll r3, r2 + or r1, r3 + .fillinsn +2: + jmp r14 + +#else + + .text + .align 4 + .globl __ashrdi3 +__ashrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r0, r1 + srai r1, #31 + addi r2, #-32 + sra r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 + srl r0, r2 + sra r1, r2 + neg r2, r2 + sll r3, r2 + or r0, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __ashldi3 + .globl __lshldi3 +__ashldi3: +__lshldi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r1, r0 + addi r2, #-32 + sll r1, r2 + ldi r0, #0 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r0 + sll r1, r2 + sll r0, r2 + neg r2, r2 + srl r3, r2 + or r1, r3 + .fillinsn +2: + jmp r14 + + .align 4 + .globl __lshrdi3 +__lshrdi3: + beqz r2, 2f + cmpui r2, #32 + bc 1f + ; case 32 =< shift + mv r0, r1 + ldi r1, #0 + addi r2, #-32 + srl r0, r2 + jmp r14 + .fillinsn +1: ; case shift <32 + mv r3, r1 + srl r0, r2 + srl r1, r2 + neg r2, r2 + sll r3, r2 + or r0, r3 + .fillinsn +2: + jmp r14 + +#endif + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end + diff --git a/arch/m32r/lib/checksum.S b/arch/m32r/lib/checksum.S new file mode 100644 index 000000000..f6fc1bdb8 --- /dev/null +++ b/arch/m32r/lib/checksum.S @@ -0,0 +1,322 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Pentium Pro/II routines: + * Alexander Kjeldaas + * Finn Arne Gangstad + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * Andi Kleen, add zeroing on error + * converted to pure assembler + * Hirokazu Takata,Hiroyuki Kondo rewrite for the m32r architecture. + * + * 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. + */ +/* $Id$ */ + + +#include +#include +#include +#include + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ + + +#ifdef CONFIG_ISA_DUAL_ISSUE + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ + + .text +ENTRY(csum_partial) + ; Function args + ; r0: unsigned char *buff + ; r1: int len + ; r2: unsigned int sum + + push r2 || ldi r2, #0 + and3 r7, r0, #1 ; Check alignment. + beqz r7, 1f ; Jump if alignment is ok. + ; 1-byte mis aligned + ldub r4, @r0 || addi r0, #1 + ; clear c-bit || Alignment uses up bytes. + cmp r0, r0 || addi r1, #-1 + ldi r3, #0 || addx r2, r4 + addx r2, r3 + .fillinsn +1: + and3 r4, r0, #2 ; Check alignment. + beqz r4, 2f ; Jump if alignment is ok. + ; clear c-bit || Alignment uses up two bytes. + cmp r0, r0 || addi r1, #-2 + bgtz r1, 1f ; Jump if we had at least two bytes. + bra 4f || addi r1, #2 + .fillinsn ; len(r1) was < 2. Deal with it. +1: + ; 2-byte aligned + lduh r4, @r0 || ldi r3, #0 + addx r2, r4 || addi r0, #2 + addx r2, r3 + .fillinsn +2: + ; 4-byte aligned + cmp r0, r0 ; clear c-bit + srl3 r6, r1, #5 + beqz r6, 2f + .fillinsn + +1: ld r3, @r0+ + ld r4, @r0+ ; +4 + ld r5, @r0+ ; +8 + ld r3, @r0+ || addx r2, r3 ; +12 + ld r4, @r0+ || addx r2, r4 ; +16 + ld r5, @r0+ || addx r2, r5 ; +20 + ld r3, @r0+ || addx r2, r3 ; +24 + ld r4, @r0+ || addx r2, r4 ; +28 + addx r2, r5 || addi r6, #-1 + addx r2, r3 + addx r2, r4 + bnez r6, 1b + + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn +2: and3 r6, r1, #0x1c ; withdraw len + beqz r6, 4f + srli r6, #2 + .fillinsn + +3: ld r4, @r0+ || addi r6, #-1 + addx r2, r4 + bnez r6, 3b + + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn +4: and3 r1, r1, #3 + beqz r1, 7f ; if len == 0 goto end + and3 r6, r1, #2 + beqz r6, 5f ; if len < 2 goto 5f(1byte) + lduh r4, @r0 || addi r0, #2 + addi r1, #-2 || slli r4, #16 + addx r2, r4 + beqz r1, 6f + .fillinsn +5: ldub r4, @r0 || ldi r1, #0 +#ifndef __LITTLE_ENDIAN__ + slli r4, #8 +#endif + addx r2, r4 + .fillinsn +6: addx r2, r1 + .fillinsn +7: + and3 r0, r2, #0xffff + srli r2, #16 + add r0, r2 + srl3 r2, r0, #16 + beqz r2, 1f + addi r0, #1 + and3 r0, r0, #0xffff + .fillinsn +1: + beqz r7, 1f ; swap the upper byte for the lower + and3 r2, r0, #0xff + srl3 r0, r0, #8 + slli r2, #8 + or r0, r2 + .fillinsn +1: + pop r2 || cmp r0, r0 + addx r0, r2 || ldi r2, #0 + addx r0, r2 + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ + + .text +ENTRY(csum_partial) + ; Function args + ; r0: unsigned char *buff + ; r1: int len + ; r2: unsigned int sum + + push r2 + ldi r2, #0 + and3 r7, r0, #1 ; Check alignment. + beqz r7, 1f ; Jump if alignment is ok. + ; 1-byte mis aligned + ldub r4, @r0 + addi r0, #1 + addi r1, #-1 ; Alignment uses up bytes. + cmp r0, r0 ; clear c-bit + ldi r3, #0 + addx r2, r4 + addx r2, r3 + .fillinsn +1: + and3 r4, r0, #2 ; Check alignment. + beqz r4, 2f ; Jump if alignment is ok. + addi r1, #-2 ; Alignment uses up two bytes. + cmp r0, r0 ; clear c-bit + bgtz r1, 1f ; Jump if we had at least two bytes. + addi r1, #2 ; len(r1) was < 2. Deal with it. + bra 4f + .fillinsn +1: + ; 2-byte aligned + lduh r4, @r0 + addi r0, #2 + ldi r3, #0 + addx r2, r4 + addx r2, r3 + .fillinsn +2: + ; 4-byte aligned + cmp r0, r0 ; clear c-bit + srl3 r6, r1, #5 + beqz r6, 2f + .fillinsn + +1: ld r3, @r0+ + ld r4, @r0+ ; +4 + ld r5, @r0+ ; +8 + addx r2, r3 + addx r2, r4 + addx r2, r5 + ld r3, @r0+ ; +12 + ld r4, @r0+ ; +16 + ld r5, @r0+ ; +20 + addx r2, r3 + addx r2, r4 + addx r2, r5 + ld r3, @r0+ ; +24 + ld r4, @r0+ ; +28 + addi r6, #-1 + addx r2, r3 + addx r2, r4 + bnez r6, 1b + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn + +2: and3 r6, r1, #0x1c ; withdraw len + beqz r6, 4f + srli r6, #2 + .fillinsn + +3: ld r4, @r0+ + addi r6, #-1 + addx r2, r4 + bnez r6, 3b + addx r2, r6 ; r6=0 + cmp r0, r0 ; This clears c-bit + .fillinsn + +4: and3 r1, r1, #3 + beqz r1, 7f ; if len == 0 goto end + and3 r6, r1, #2 + beqz r6, 5f ; if len < 2 goto 5f(1byte) + + lduh r4, @r0 + addi r0, #2 + addi r1, #-2 + slli r4, #16 + addx r2, r4 + beqz r1, 6f + .fillinsn +5: ldub r4, @r0 +#ifndef __LITTLE_ENDIAN__ + slli r4, #8 +#endif + addx r2, r4 + .fillinsn +6: ldi r5, #0 + addx r2, r5 + .fillinsn +7: + and3 r0, r2, #0xffff + srli r2, #16 + add r0, r2 + srl3 r2, r0, #16 + beqz r2, 1f + addi r0, #1 + and3 r0, r0, #0xffff + .fillinsn +1: + beqz r7, 1f + mv r2, r0 + srl3 r0, r2, #8 + and3 r2, r2, #0xff + slli r2, #8 + or r0, r2 + .fillinsn +1: + pop r2 + cmp r0, r0 + addx r0, r2 + ldi r2, #0 + addx r0, r2 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +/* +unsigned int csum_partial_copy_generic (const char *src, char *dst, + int len, int sum, int *src_err_ptr, int *dst_err_ptr) + */ + +/* + * Copy from ds while checksumming, otherwise like csum_partial + * + * The macros SRC and DST specify the type of access for the instruction. + * thus we can call a custom exception handler for all access types. + * + * FIXME: could someone double-check whether I haven't mixed up some SRC and + * DST definitions? It's damn hard to trigger all cases. I hope I got + * them all but there's no guarantee. + */ + +ENTRY(csum_partial_copy_generic) + nop + nop + nop + nop + jmp r14 + nop + nop + nop + diff --git a/arch/m32r/lib/csum_partial_copy.c b/arch/m32r/lib/csum_partial_copy.c new file mode 100644 index 000000000..22600fc08 --- /dev/null +++ b/arch/m32r/lib/csum_partial_copy.c @@ -0,0 +1,58 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * MIPS specific IP/TCP/UDP checksumming routines + * + * Authors: Ralf Baechle, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 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 +#include + +#include +#include +#include +#include + +/* + * Copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy_nocheck (const char *src, char *dst, + int len, unsigned int sum) +{ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} +EXPORT_SYMBOL(csum_partial_copy_nocheck); + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char __user *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len-missing, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); diff --git a/arch/m32r/lib/delay.c b/arch/m32r/lib/delay.c new file mode 100644 index 000000000..7afe66e9d --- /dev/null +++ b/arch/m32r/lib/delay.c @@ -0,0 +1,126 @@ +/* + * linux/arch/m32r/lib/delay.c + * + * Copyright (c) 2002 Hitoshi Yamamoto, Hirokazu Takata + * Copyright (c) 2004 Hirokazu Takata + */ + +/* $Id$ */ + +#include +#include +#ifdef CONFIG_SMP +#include +#include +#include +#endif /* CONFIG_SMP */ +#include + +void __delay(unsigned long loops) +{ +#ifdef CONFIG_ISA_DUAL_ISSUE + __asm__ __volatile__ ( + "beqz %0, 2f \n\t" + "addi %0, #-1 \n\t" + + " .fillinsn \n\t" + "1: \n\t" + "cmpz %0 || addi %0, #-1 \n\t" + "bc 2f || cmpz %0 \n\t" + "bc 2f || addi %0, #-1 \n\t" + "cmpz %0 || addi %0, #-1 \n\t" + "bc 2f || cmpz %0 \n\t" + "bnc 1b || addi %0, #-1 \n\t" + " .fillinsn \n\t" + "2: \n\t" + : "+r" (loops) + : "r" (0) + : "cbit" + ); +#else + __asm__ __volatile__ ( + "beqz %0, 2f \n\t" + " .fillinsn \n\t" + "1: \n\t" + "addi %0, #-1 \n\t" + "blez %0, 2f \n\t" + "addi %0, #-1 \n\t" + "blez %0, 2f \n\t" + "addi %0, #-1 \n\t" + "blez %0, 2f \n\t" + "addi %0, #-1 \n\t" + "bgtz %0, 1b \n\t" + " .fillinsn \n\t" + "2:i \n\t" + : "+r" (loops) + : "r" (0) + ); +#endif +} + +void __const_udelay(unsigned long xloops) +{ +#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) + /* + * loops [1] = (xloops >> 32) [sec] * loops_per_jiffy [1/jiffy] + * * HZ [jiffy/sec] + * = (xloops >> 32) [sec] * (loops_per_jiffy * HZ) [1/sec] + * = (((xloops * loops_per_jiffy) >> 32) * HZ) [1] + * + * NOTE: + * - '[]' depicts variable's dimension in the above equation. + * - "rac" instruction rounds the accumulator in word size. + */ + __asm__ __volatile__ ( + "srli %0, #1 \n\t" + "mulwhi %0, %1 ; a0 \n\t" + "mulwu1 %0, %1 ; a1 \n\t" + "sadd ; a0 += (a1 >> 16) \n\t" + "rac a0, a0, #1 \n\t" + "mvfacmi %0, a0 \n\t" + : "+r" (xloops) + : "r" (current_cpu_data.loops_per_jiffy) + : "a0", "a1" + ); +#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) + /* + * u64 ull; + * ull = (u64)xloops * (u64)current_cpu_data.loops_per_jiffy; + * xloops = (ull >> 32); + */ + __asm__ __volatile__ ( + "and3 r4, %0, #0xffff \n\t" + "and3 r5, %1, #0xffff \n\t" + "mul r4, r5 \n\t" + "srl3 r6, %0, #16 \n\t" + "srli r4, #16 \n\t" + "mul r5, r6 \n\t" + "add r4, r5 \n\t" + "and3 r5, %0, #0xffff \n\t" + "srl3 r6, %1, #16 \n\t" + "mul r5, r6 \n\t" + "add r4, r5 \n\t" + "srl3 r5, %0, #16 \n\t" + "srli r4, #16 \n\t" + "mul r5, r6 \n\t" + "add r4, r5 \n\t" + "mv %0, r4 \n\t" + : "+r" (xloops) + : "r" (current_cpu_data.loops_per_jiffy) + : "r4", "r5", "r6" + ); +#else +#error unknown isa configuration +#endif + __delay(xloops * HZ); +} + +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ +} + +void __ndelay(unsigned long nsecs) +{ + __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ +} diff --git a/arch/m32r/lib/getuser.S b/arch/m32r/lib/getuser.S new file mode 100644 index 000000000..58a0db055 --- /dev/null +++ b/arch/m32r/lib/getuser.S @@ -0,0 +1,88 @@ +/* + * __get_user functions. + * + * (C) Copyright 2001 Hirokazu Takata + * + * These functions have a non-standard call interface + * to make them more efficient, especially as they + * return an error value in addition to the "real" + * return value. + */ + +#include + +/* + * __get_user_X + * + * Inputs: r0 contains the address + * + * Outputs: r0 is error code (0 or -EFAULT) + * r1 contains zero-extended value + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text + .balign 4 + .globl __get_user_1 +__get_user_1: +1: ldub r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_2 +__get_user_2: +2: lduh r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_4 +__get_user_4: +3: ld r1, @r0 || ldi r0, #0 + jmp r14 + +bad_get_user: + ldi r1, #0 || ldi r0, #-14 + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text + .balign 4 + .globl __get_user_1 +__get_user_1: +1: ldub r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_2 +__get_user_2: +2: lduh r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __get_user_4 +__get_user_4: +3: ld r1, @r0 + ldi r0, #0 + jmp r14 + +bad_get_user: + ldi r1, #0 + ldi r0, #-14 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +.section __ex_table,"a" + .long 1b,bad_get_user + .long 2b,bad_get_user + .long 3b,bad_get_user +.previous + + .end diff --git a/arch/m32r/lib/memcpy.S b/arch/m32r/lib/memcpy.S new file mode 100644 index 000000000..800898a2d --- /dev/null +++ b/arch/m32r/lib/memcpy.S @@ -0,0 +1,95 @@ +/* + * linux/arch/m32r/lib/memcpy.S + * + * Copyright (C) 2001 Hiroyuki Kondo, and Hirokazu Takata + * Copyright (C) 2004 Hirokazu Takata + * + * void *memcopy(void *dst, const void *src, int n); + * + * dst: r0 + * src: r1 + * n : r2 + */ +/* $Id$ */ + + + .text +#include +#include +#include + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text +ENTRY(memcpy) +memcopy: + mv r4, r0 || mv r7, r0 + or r7, r1 || cmpz r2 + jc r14 || cmpeq r0, r1 ; return if r2=0 + jc r14 ; return if r0=r1 + + and3 r7, r7, #3 + bnez r7, byte_copy + srl3 r3, r2, #2 + and3 r2, r2, #3 + beqz r3, byte_copy + addi r4, #-4 +word_copy: + ld r7, @r1+ || addi r3, #-1 + st r7, @+r4 || cmpz r2 + bnez r3, word_copy + addi r4, #4 || jc r14 ; return if r2=0 +#if defined(CONFIG_ISA_M32R2) +byte_copy: + ldb r7, @r1 || addi r1, #1 + addi r2, #-1 || stb r7, @r4+ + bnez r2, byte_copy +#elif defined(CONFIG_ISA_M32R) +byte_copy: + ldb r7, @r1 || addi r1, #1 + addi r2, #-1 || stb r7, @r4 + addi r4, #1 + bnez r2, byte_copy +#else +#error unknown isa configuration +#endif +end_memcopy: + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text +ENTRY(memcpy) +memcopy: + mv r4, r0 + mv r7, r0 + or r7, r1 + beq r0, r1, end_memcopy + beqz r2, end_memcopy + + and3 r7, r7, #3 + bnez r7, byte_copy + srl3 r3, r2, #2 + and3 r2, r2, #3 + beqz r3, byte_copy + addi r4, #-4 +word_copy: + ld r7, @r1+ + addi r3, #-1 + st r7, @+r4 + bnez r3, word_copy + beqz r2, end_memcopy + addi r4, #4 +byte_copy: + ldb r7, @r1 + addi r1, #1 + addi r2, #-1 + stb r7, @r4 + addi r4, #1 + bnez r2, byte_copy +end_memcopy: + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end diff --git a/arch/m32r/lib/memset.S b/arch/m32r/lib/memset.S new file mode 100644 index 000000000..7fe94b6c6 --- /dev/null +++ b/arch/m32r/lib/memset.S @@ -0,0 +1,178 @@ +/* + * linux/arch/m32r/lib/memset.S + * + * Copyright (C) 2001,2002 Hiroyuki Kondo, and Hirokazu Takata + * Copyright (C) 2004 Hirokazu Takata + * + * void *memset(void *dst, int val, int len); + * + * dst: r0 + * val: r1 + * len: r2 + * ret: r0 + * + */ +/* $Id$ */ + +#include + + .text + .global memset + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .align 4 +memset: + mv r4, r0 || cmpz r2 + jc r14 + cmpui r2, #16 + bnc qword_align_check + cmpui r2, #4 + bc byte_set +word_align_check: /* len >= 4 */ + and3 r3, r4, #3 + beqz r3, word_set + addi r3, #-4 + neg r3, r3 /* r3 = -(r3 - 4) */ +align_word: + stb r1, @r4 || addi r4, #1 + addi r2, #-1 || addi r3, #-1 + bnez r3, align_word + cmpui r2, #4 + bc byte_set +word_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 || addi r4, #-4 + sll3 r3, r1, #16 + or r1, r3 || addi r2, #-4 +word_set_loop: + st r1, @+r4 || addi r2, #-4 + bgtz r2, word_set_loop + bnez r2, byte_set_wrap + st r1, @+r4 + jmp r14 + +qword_align_check: /* len >= 16 */ + and3 r3, r4, #15 + bnez r3, word_align_check +qword_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 || addi r4, #-4 + sll3 r3, r1, #16 + or r1, r3 || ldi r5, #16 +qword_set_loop: + ld r3, @(4,r4) /* cache line allocate */ + st r1, @+r4 || addi r2, #-16 + st r1, @+r4 || cmpu r2, r5 + st r1, @+r4 + st r1, @+r4 + bnc qword_set_loop || cmpz r2 + jc r14 +word_set_wrap: + cmpui r2, #4 + bc byte_set + addi r2, #-4 + bra word_set_loop + +byte_set_wrap: + addi r2, #4 + addi r4, #4 || cmpz r2 + jc r14 +#if defined(CONFIG_ISA_M32R2) +byte_set: + addi r2, #-1 || stb r1, @r4+ + bnez r2, byte_set +#elif defined(CONFIG_ISA_M32R) +byte_set: + addi r2, #-1 || stb r1, @r4 + addi r4, #1 + bnez r2, byte_set +#else +#error unknown isa configuration +#endif +end_memset: + jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .align 4 +memset: + mv r4, r0 + beqz r2, end_memset + cmpui r2, #16 + bnc qword_align_check + cmpui r2, #4 + bc byte_set +word_align_check: /* len >= 4 */ + and3 r3, r4, #3 + beqz r3, word_set + addi r3, #-4 + neg r3, r3 /* r3 = -(r3 - 4) */ +align_word: + stb r1, @r4 + addi r4, #1 + addi r2, #-1 + addi r3, #-1 + bnez r3, align_word + cmpui r2, #4 + bc byte_set +word_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 + sll3 r3, r1, #16 + or r1, r3 + addi r2, #-4 + addi r4, #-4 +word_set_loop: + st r1, @+r4 + addi r2, #-4 + bgtz r2, word_set_loop + bnez r2, byte_set_wrap + st r1, @+r4 + jmp r14 + +qword_align_check: /* len >= 16 */ + and3 r3, r4, #15 + bnez r3, word_align_check +qword_set: + and3 r1, r1, #0x00ff /* r1: abababab <-- ??????ab */ + sll3 r3, r1, #8 + or r1, r3 + sll3 r3, r1, #16 + or r1, r3 + addi r4, #-4 +qword_set_loop: + ld r3, @(4,r4) /* cache line allocate */ + addi r2, #-16 + st r1, @+r4 + st r1, @+r4 + cmpui r2, #16 + st r1, @+r4 + st r1, @+r4 + bnc qword_set_loop + bnez r2, word_set_wrap + jmp r14 +word_set_wrap: + cmpui r2, #4 + bc byte_set + addi r2, #-4 + bra word_set_loop + +byte_set_wrap: + addi r2, #4 + addi r4, #4 + beqz r2, end_memset +byte_set: + addi r2, #-1 + stb r1, @r4 + addi r4, #1 + bnez r2, byte_set +end_memset: + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end diff --git a/arch/m32r/lib/putuser.S b/arch/m32r/lib/putuser.S new file mode 100644 index 000000000..218154cc3 --- /dev/null +++ b/arch/m32r/lib/putuser.S @@ -0,0 +1,84 @@ +/* + * __put_user functions. + * + * (C) Copyright 1998 Linus Torvalds + * (C) Copyright 2001 Hirokazu Takata + * + * These functions have a non-standard call interface + * to make them more efficient. + */ + +#include + +/* + * __put_user_X + * + * Inputs: r0 contains the address + * r1 contains the value + * + * Outputs: r0 is error code (0 or -EFAULT) + * r1 is corrupted (will contain "current_task"). + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text + .balign 4 + .globl __put_user_1 +__put_user_1: +1: stb r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_2 +__put_user_2: +2: sth r1, @r0 || ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_4 +__put_user_4: +3: st r1, @r0 || ldi r0, #0 + jmp r14 + +bad_put_user: + ldi r0, #-14 || jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text + .balign 4 + .globl __put_user_1 +__put_user_1: +1: stb r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_2 +__put_user_2: +2: sth r1, @r0 + ldi r0, #0 + jmp r14 + + .balign 4 + .globl __put_user_4 +__put_user_4: +3: st r1, @r0 + ldi r0, #0 + jmp r14 + +bad_put_user: + ldi r0, #-14 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +.section __ex_table,"a" + .long 1b,bad_put_user + .long 2b,bad_put_user + .long 3b,bad_put_user +.previous diff --git a/arch/m32r/lib/strlen.S b/arch/m32r/lib/strlen.S new file mode 100644 index 000000000..8d23cfbd6 --- /dev/null +++ b/arch/m32r/lib/strlen.S @@ -0,0 +1,120 @@ +/* + * linux/arch/m32r/strlen.S -- strlen code. + * + * Copyright (C) 2001 Hirokazu Takata + * + * size_t strlen(const char *s); + * + */ +/* $Id$ */ + + +#include +#include +#include + +#ifdef CONFIG_ISA_DUAL_ISSUE + + .text +ENTRY(strlen) + mv r6, r0 || ldi r2, #0 + and3 r0, r0, #3 + bnez r0, strlen_byte +; +strlen_word: + ld r0, @r6+ +; + seth r5, #high(0x01010101) + or3 r5, r5, #low(0x01010101) + sll3 r7, r5, #7 +strlen_word_loop: + ld r1, @r6+ || not r4, r0 + sub r0, r5 || and r4, r7 + and r4, r0 + bnez r4, strlen_last_bytes + ld r0, @r6+ || not r4, r1 + sub r1, r5 || and r4, r7 + and r4, r1 || addi r2, #4 + bnez r4, strlen_last_bytes + addi r2, #4 || bra.s strlen_word_loop + + ; NOTE: If a null char. exists, return 0. + ; if ((x - 0x01010101) & ~x & 0x80808080) + ; return 0; +; +strlen_byte: + ldb r1, @r6 || addi r6, #1 + beqz r1, strlen_exit + addi r2, #1 || bra.s strlen_byte +; +strlen_last_bytes: + ldi r0, #4 || addi r6, #-8 +; +strlen_byte_loop: + ldb r1, @r6 || addi r6, #1 + addi r0, #-1 || cmpz r1 + bc.s strlen_exit || cmpz r0 + addi r2, #1 || bnc.s strlen_byte_loop +; +strlen_exit: + mv r0, r2 || jmp r14 + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + + .text +ENTRY(strlen) + mv r6, r0 + ldi r2, #0 + and3 r0, r0, #3 + bnez r0, strlen_byte +; +strlen_word: + ld r0, @r6+ +; + seth r5, #high(0x01010101) + or3 r5, r5, #low(0x01010101) + sll3 r7, r5, #7 +strlen_word_loop: + ld r1, @r6+ + not r4, r0 ; NOTE: If a null char. exists, return 0. + sub r0, r5 ; if ((x - 0x01010101) & ~x & 0x80808080) + and r4, r7 ; return 0; + and r4, r0 + bnez r4, strlen_last_bytes + addi r2, #4 +; + ld r0, @r6+ + not r4, r1 ; NOTE: If a null char. exists, return 0. + sub r1, r5 ; if ((x - 0x01010101) & ~x & 0x80808080) + and r4, r7 ; return 0; + and r4, r1 + bnez r4, strlen_last_bytes + addi r2, #4 + bra strlen_word_loop +; +strlen_byte: + ldb r1, @r6 + addi r6, #1 + beqz r1, strlen_exit + addi r2, #1 + bra strlen_byte +; +strlen_last_bytes: + ldi r0, #4 + addi r6, #-8 +; +strlen_byte_loop: + ldb r1, @r6 + addi r6, #1 + addi r0, #-1 + beqz r1, strlen_exit + addi r2, #1 + bnez r0, strlen_byte_loop +; +strlen_exit: + mv r0, r2 + jmp r14 + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + + .end diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c new file mode 100644 index 000000000..6c6855f1a --- /dev/null +++ b/arch/m32r/lib/usercopy.c @@ -0,0 +1,391 @@ +/* + * User address space access functions. + * The non inlined parts of asm-m32r/uaccess.h are here. + * + * Copyright 1997 Andi Kleen + * Copyright 1997 Linus Torvalds + * Copyright 2001, 2002, 2004 Hirokazu Takata + */ +#include +#include +#include +#include +#include + +unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + prefetch(from); + if (access_ok(VERIFY_WRITE, to, n)) + __copy_user(to,from,n); + return n; +} + +unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + prefetchw(to); + if (access_ok(VERIFY_READ, from, n)) + __copy_user_zeroing(to,from,n); + else + memset(to, 0, n); + return n; +} + + +/* + * Copy a null terminated string from userspace. + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + int __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " beqz %1, 2f\n" \ + " .fillinsn\n" \ + "0: ldb r14, @%3 || addi %3, #1\n" \ + " stb r14, @%4 || addi %4, #1\n" \ + " beqz r14, 1f\n" \ + " addi %1, #-1\n" \ + " bnez %1, 0b\n" \ + " .fillinsn\n" \ + "1: sub %0, %1\n" \ + " .fillinsn\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "3: seth r14, #high(2b)\n" \ + " or3 r14, r14, #low(2b)\n" \ + " jmp r14 || ldi %0, #%5\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ + "=&r" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ + "4"(dst) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + int __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " beqz %1, 2f\n" \ + " .fillinsn\n" \ + "0: ldb r14, @%3\n" \ + " stb r14, @%4\n" \ + " addi %3, #1\n" \ + " addi %4, #1\n" \ + " beqz r14, 1f\n" \ + " addi %1, #-1\n" \ + " bnez %1, 0b\n" \ + " .fillinsn\n" \ + "1: sub %0, %1\n" \ + " .fillinsn\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "3: ldi %0, #%5\n" \ + " seth r14, #high(2b)\n" \ + " or3 r14, r14, #low(2b)\n" \ + " jmp r14\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ + "=&r" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ + "4"(dst) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#endif /* CONFIG_ISA_DUAL_ISSUE */ + +long +__strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + + +/* + * Zero Userspace + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +#define __do_clear_user(addr,size) \ +do { \ + int __dst, __c; \ + __asm__ __volatile__( \ + " beqz %1, 9f\n" \ + " and3 r14, %0, #3\n" \ + " bnez r14, 2f\n" \ + " and3 r14, %1, #3\n" \ + " bnez r14, 2f\n" \ + " and3 %1, %1, #3\n" \ + " beqz %2, 2f\n" \ + " addi %0, #-4\n" \ + " .fillinsn\n" \ + "0: ; word clear \n" \ + " st %6, @+%0 || addi %2, #-1\n" \ + " bnez %2, 0b\n" \ + " beqz %1, 9f\n" \ + " .fillinsn\n" \ + "2: ; byte clear \n" \ + " stb %6, @%0 || addi %1, #-1\n" \ + " addi %0, #1\n" \ + " bnez %1, 2b\n" \ + " .fillinsn\n" \ + "9:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "4: slli %2, #2\n" \ + " seth r14, #high(9b)\n" \ + " or3 r14, r14, #low(9b)\n" \ + " jmp r14 || add %1, %2\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,4b\n" \ + " .long 2b,9b\n" \ + ".previous\n" \ + : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ + : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +#define __do_clear_user(addr,size) \ +do { \ + int __dst, __c; \ + __asm__ __volatile__( \ + " beqz %1, 9f\n" \ + " and3 r14, %0, #3\n" \ + " bnez r14, 2f\n" \ + " and3 r14, %1, #3\n" \ + " bnez r14, 2f\n" \ + " and3 %1, %1, #3\n" \ + " beqz %2, 2f\n" \ + " addi %0, #-4\n" \ + " .fillinsn\n" \ + "0: st %6, @+%0 ; word clear \n" \ + " addi %2, #-1\n" \ + " bnez %2, 0b\n" \ + " beqz %1, 9f\n" \ + " .fillinsn\n" \ + "2: stb %6, @%0 ; byte clear \n" \ + " addi %1, #-1\n" \ + " addi %0, #1\n" \ + " bnez %1, 2b\n" \ + " .fillinsn\n" \ + "9:\n" \ + ".section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "4: slli %2, #2\n" \ + " add %1, %2\n" \ + " seth r14, #high(9b)\n" \ + " or3 r14, r14, #low(9b)\n" \ + " jmp r14\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .balign 4\n" \ + " .long 0b,4b\n" \ + " .long 2b,9b\n" \ + ".previous\n" \ + : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ + : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ + : "r14", "cbit", "memory"); \ +} while (0) + +#endif /* not CONFIG_ISA_DUAL_ISSUE */ + +unsigned long +clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __do_clear_user(to, n); + return n; +} + +unsigned long +__clear_user(void *to, unsigned long n) +{ + __do_clear_user(to, n); + return n; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ + +#ifdef CONFIG_ISA_DUAL_ISSUE + +long strnlen_user(const char *s, long n) +{ + unsigned long mask = -__addr_ok(s); + unsigned long res; + + __asm__ __volatile__( + " and %0, %5 || mv r1, %1\n" + " beqz %0, strnlen_exit\n" + " and3 r0, %1, #3\n" + " bnez r0, strnlen_byte_loop\n" + " cmpui %0, #4\n" + " bc strnlen_byte_loop\n" + "strnlen_word_loop:\n" + "0: ld r0, @%1+\n" + " pcmpbz r0\n" + " bc strnlen_last_bytes_fixup\n" + " addi %0, #-4\n" + " beqz %0, strnlen_exit\n" + " bgtz %0, strnlen_word_loop\n" + "strnlen_last_bytes:\n" + " mv %0, %4\n" + "strnlen_last_bytes_fixup:\n" + " addi %1, #-4\n" + "strnlen_byte_loop:\n" + "1: ldb r0, @%1 || addi %0, #-1\n" + " beqz r0, strnlen_exit\n" + " addi %1, #1\n" + " bnez %0, strnlen_byte_loop\n" + "strnlen_exit:\n" + " sub %1, r1\n" + " add3 %0, %1, #1\n" + " .fillinsn\n" + "9:\n" + ".section .fixup,\"ax\"\n" + " .balign 4\n" + "4: addi %1, #-4\n" + " .fillinsn\n" + "5: seth r1, #high(9b)\n" + " or3 r1, r1, #low(9b)\n" + " jmp r1 || ldi %0, #0\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .balign 4\n" + " .long 0b,4b\n" + " .long 1b,5b\n" + ".previous" + : "=&r" (res), "=r" (s) + : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) + : "r0", "r1", "cbit"); + + /* NOTE: strnlen_user() algorism: + * { + * char *p; + * for (p = s; n-- && *p != '\0'; ++p) + * ; + * return p - s + 1; + * } + */ + + /* NOTE: If a null char. exists, return 0. + * if ((x - 0x01010101) & ~x & 0x80808080)\n" + * return 0;\n" + */ + + return res & mask; +} + +#else /* not CONFIG_ISA_DUAL_ISSUE */ + +long strnlen_user(const char *s, long n) +{ + unsigned long mask = -__addr_ok(s); + unsigned long res; + + __asm__ __volatile__( + " and %0, %5\n" + " mv r1, %1\n" + " beqz %0, strnlen_exit\n" + " and3 r0, %1, #3\n" + " bnez r0, strnlen_byte_loop\n" + " cmpui %0, #4\n" + " bc strnlen_byte_loop\n" + " sll3 r3, %6, #7\n" + "strnlen_word_loop:\n" + "0: ld r0, @%1+\n" + " not r2, r0\n" + " sub r0, %6\n" + " and r2, r3\n" + " and r2, r0\n" + " bnez r2, strnlen_last_bytes_fixup\n" + " addi %0, #-4\n" + " beqz %0, strnlen_exit\n" + " bgtz %0, strnlen_word_loop\n" + "strnlen_last_bytes:\n" + " mv %0, %4\n" + "strnlen_last_bytes_fixup:\n" + " addi %1, #-4\n" + "strnlen_byte_loop:\n" + "1: ldb r0, @%1\n" + " addi %0, #-1\n" + " beqz r0, strnlen_exit\n" + " addi %1, #1\n" + " bnez %0, strnlen_byte_loop\n" + "strnlen_exit:\n" + " sub %1, r1\n" + " add3 %0, %1, #1\n" + " .fillinsn\n" + "9:\n" + ".section .fixup,\"ax\"\n" + " .balign 4\n" + "4: addi %1, #-4\n" + " .fillinsn\n" + "5: ldi %0, #0\n" + " seth r1, #high(9b)\n" + " or3 r1, r1, #low(9b)\n" + " jmp r1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .balign 4\n" + " .long 0b,4b\n" + " .long 1b,5b\n" + ".previous" + : "=&r" (res), "=r" (s) + : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) + : "r0", "r1", "r2", "r3", "cbit"); + + /* NOTE: strnlen_user() algorism: + * { + * char *p; + * for (p = s; n-- && *p != '\0'; ++p) + * ; + * return p - s + 1; + * } + */ + + /* NOTE: If a null char. exists, return 0. + * if ((x - 0x01010101) & ~x & 0x80808080)\n" + * return 0;\n" + */ + + return res & mask; +} + +#endif /* CONFIG_ISA_DUAL_ISSUE */ + diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.smp b/arch/m32r/m32700ut/defconfig.m32700ut.smp new file mode 100644 index 000000000..df7f9d01b --- /dev/null +++ b/arch/m32r/m32700ut/defconfig.m32700ut.smp @@ -0,0 +1,662 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=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=15 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +CONFIG_SMP=y +CONFIG_CHIP_M32700_TS1=y +CONFIG_NR_CPUS=2 +# CONFIG_NUMA is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_CFC=y +CONFIG_M32700UT_CFC=y +CONFIG_CFC_NUM=1 +# CONFIG_MTD_M32R is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +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_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# 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_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 device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# 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=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +CONFIG_M32R_AR=y +CONFIG_M32R_AR_VGA=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_EPSON_S1D13806=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_M32R_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# 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 is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.up b/arch/m32r/m32700ut/defconfig.m32700ut.up new file mode 100644 index 000000000..5a9da73fb --- /dev/null +++ b/arch/m32r/m32700ut/defconfig.m32700ut.up @@ -0,0 +1,659 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=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=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_CFC=y +CONFIG_M32700UT_CFC=y +CONFIG_CFC_NUM=1 +# CONFIG_MTD_M32R is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +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_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# 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_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 device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# 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=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +CONFIG_M32R_AR=y +CONFIG_M32R_AR_VGA=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_EPSON_S1D13806=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_M32R_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# 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 is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB b/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB new file mode 100644 index 000000000..fa79cd9fb --- /dev/null +++ b/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB @@ -0,0 +1,249 @@ +# .gdbinit file +# $Id: dot.gdbinit_200MHz_16MB,v 1.1 2004/08/17 02:58:11 takata Exp $ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $ +#----- +# target platform: m32700ut + +# setting +set width 0d70 +set radix 0d16 + +debug_chaos + +# clk xin:cpu:bif:bus=25:200:50:50 +define clock_init + set *(unsigned long *)0x00ef4008 = 0x00000000 + set *(unsigned long *)0x00ef4004 = 0 + shell sleep 0.1 + # NOTE: Please change the master clock source from PLL-clock to Xin-clock + # and switch off PLL, before resetting the clock gear ratio. + + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00041302 + # Ch0-ADR (size:16MB) + set *(unsigned long *)0x00ef6020 = 0x08000002 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010517 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x08ffffff (16MB) +end + +# Initialize BSEL3 for UT-CFC +define cfc_init + set $sfrbase = 0xa0ef0000 +# too fast +# set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000 +# set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f +end +document cfc_init + CF controller initialization +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Initialize TLB entries +define init_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set *(unsigned long *)($addr + 0x4) = 0 + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define tlb_init + set $itlb=0xfe000000 + init_tlb_entries $itlb 0d32 + set $dtlb=0xfe000800 + init_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + # SDRAM: 16MB + set *(unsigned long *)0x00ef6020 = 0x08000002 + cfc_init + # USB + set *(unsigned short *)0xb0301000 = 0x100 + + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d200000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x console=tty1 video=s1d13xxxfb:mode:240x320-16 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=16M \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc = 0x08001000 + set *(unsigned char *)0xffffffff = 0x03 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + set $pc = 0 + b *0x04001000 + b *0x08001000 + b *0x08002000 + si + c + tlb_init + del + setup + load_modules + boot +end + +define si + stepi + x/i $pc + show_reg +end + +sdireset +sdireset +file vmlinux +target m32rsdi +set $pc = 0 +b *0x04001000 +b *0x08001000 +b *0x08002000 +c +tlb_init +del +setup +load_modules +boot + diff --git a/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB b/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB new file mode 100644 index 000000000..4df06e1d9 --- /dev/null +++ b/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB @@ -0,0 +1,249 @@ +# .gdbinit file +# $Id: dot.gdbinit_300MHz_32MB,v 1.1 2004/08/17 02:58:11 takata Exp $ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $ +#----- +# target platform: m32700ut + +# setting +set width 0d70 +set radix 0d16 + +debug_chaos + +# clk xin:cpu:bif:bus=25:300:75:75 +define clock_init + set *(unsigned long *)0x00ef4008 = 0x00000000 + set *(unsigned long *)0x00ef4004 = 0 + shell sleep 0.1 + # NOTE: Please change the master clock source from PLL-clock to Xin-clock + # and switch off PLL, before resetting the clock gear ratio. + + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 5 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + # Ch0-ADR (size:16MB) + set *(unsigned long *)0x00ef6020 = 0x08000002 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010e24 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x08ffffff (16MB) +end + +# Initialize BSEL3 for UT-CFC +define cfc_init + set $sfrbase = 0xa0ef0000 +# too fast +# set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000 +# set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000 +# set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f +# set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f +end +document cfc_init + CF controller initialization +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Initialize TLB entries +define init_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set *(unsigned long *)($addr + 0x4) = 0 + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define tlb_init + set $itlb=0xfe000000 + init_tlb_entries $itlb 0d32 + set $dtlb=0xfe000800 + init_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + # SDRAM: 16MB + set *(unsigned long *)0x00ef6020 = 0x08000002 + cfc_init + # USB + set *(unsigned short *)0xb0301000 = 0x100 + + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d300000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d75000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x console=tty1 video=s1d13xxxfb:mode:240x320-16 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=16M \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc = 0x08001000 + set *(unsigned char *)0xffffffff = 0x03 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + set $pc = 0 + b *0x04001000 + b *0x08001000 + b *0x08002000 + si + c + tlb_init + del + setup + load_modules + boot +end + +define si + stepi + x/i $pc + show_reg +end + +sdireset +sdireset +file vmlinux +target m32rsdi +set $pc = 0 +b *0x04001000 +b *0x08001000 +b *0x08002000 +c +tlb_init +del +setup +load_modules +boot + diff --git a/arch/m32r/mappi/defconfig.nommu b/arch/m32r/mappi/defconfig.nommu new file mode 100644 index 000000000..cae54bf18 --- /dev/null +++ b/arch/m32r/mappi/defconfig.nommu @@ -0,0 +1,529 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +# 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=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_PLAT_MAPPI=y +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +# CONFIG_MMU is not set +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x00000000 +CONFIG_MEMORY_SIZE=0x00E00000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32RPCC is not set +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# 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=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# 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=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +# CONFIG_TMPFS is not set +# 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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/mappi/defconfig.smp b/arch/m32r/mappi/defconfig.smp new file mode 100644 index 000000000..b0fe57100 --- /dev/null +++ b/arch/m32r/mappi/defconfig.smp @@ -0,0 +1,646 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=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=15 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_PLAT_MAPPI=y +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=10000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_NOHIGHMEM=y +CONFIG_DISCONTIGMEM=y +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +CONFIG_SMP=y +CONFIG_CHIP_M32700_TS1=y +CONFIG_NR_CPUS=2 +# CONFIG_NUMA is not set + +# +# M32R drivers +# +CONFIG_M32RPCC=y +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +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 is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# 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 device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +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=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# 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=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_HUGETLBFS is not set +# 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_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/m32r/mappi/defconfig.up b/arch/m32r/mappi/defconfig.up new file mode 100644 index 000000000..b4ab5ff29 --- /dev/null +++ b/arch/m32r/mappi/defconfig.up @@ -0,0 +1,642 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=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=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_PLAT_MAPPI=y +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=10000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_NOHIGHMEM=y +CONFIG_DISCONTIGMEM=y +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +CONFIG_M32RPCC=y +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +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 is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# 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 device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +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=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# 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=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_HUGETLBFS is not set +# 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_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/m32r/mappi/dot.gdbinit b/arch/m32r/mappi/dot.gdbinit new file mode 100644 index 000000000..ea566b691 --- /dev/null +++ b/arch/m32r/mappi/dot.gdbinit @@ -0,0 +1,242 @@ +# .gdbinit file +# $Id$ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.8 2004/02/27 07:08:32 takata Exp $ +#----- +# target platform: mappi + +# setting +set width 0d70 +set radix 0d16 +debug_chaos + +# clk xin:cpu:bif:bus=30:360:180:90 +define clock_init + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 5 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize programmable ports +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 + # LED ON + set *(unsigned char *)($sfrbase + 0x1015) = 0xff + set *(unsigned char *)($sfrbase + 0x1085) = 0xff + shell sleep 0.1 + # LED OFF + set *(unsigned char *)($sfrbase + 0x1085) = 0x00 +end +document port_init + P5=LED(output), P6.b4=LAN_RESET(output) +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + # Ch0-ADR (size:64MB) + set *(unsigned long *)0x00ef6020 = 0x08000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010e2b + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x0bffffff (64MB) +end + +# Initialize LAN controller +define lanc_init + set $sfrbase = 0x00ef0000 + # Set BSEL3 (BSEL3 for the Chaos's bselc) + set *(unsigned long *)($sfrbase + 0x5300) = 0x0a0a8040 + set *(unsigned long *)($sfrbase + 0x5304) = 0x01120203 + set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001 + # Reset (P5=LED,P6.b4=LAN_RESET) + set *(unsigned short *)($sfrbase + 0x106c) = 0x0000 + set *(unsigned char *)($sfrbase + 0x1016) = 0xff + set *(unsigned char *)($sfrbase + 0x1086) = 0xff + shell sleep 0.1 + # swivel: 0=normal, 4=reverse +# set *(unsigned char *)($sfrbase + 0x1086) = 0x00 + set *(unsigned char *)($sfrbase + 0x1086) = 0x04 + set *(unsigned long *)(0x0c000330) = 0xffffffff + # Set mac address + set $lanc = (void*)0x0c000300 + set *(unsigned long *)($lanc + 0x0000) = 0x00610010 + set *(unsigned long *)($lanc + 0x0004) = 0x00200030 + set *(unsigned long *)($lanc + 0x0008) = 0x00400050 + set *(unsigned long *)($lanc + 0x000c) = 0x00600007 +end +document lanc_init + LAN controller initialization + ex.) MAC address: 10 20 30 40 50 60 +end + +# LCD & CRT dual-head setting (8bpp) +define dispc_init + set $sfrbase = 0x00ef0000 + # BSEL4 Dispc + set *(unsigned long *)($sfrbase + 0x5400) = 0x0e0e8000 + set *(unsigned long *)($sfrbase + 0x5404) = 0x0012220a +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + port_init + sdram_init + lanc_init + dispc_init + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d360000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d90000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc=0x08001000 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup +#load_module +#set_breakpoints +#boot + diff --git a/arch/m32r/mappi/dot.gdbinit.nommu b/arch/m32r/mappi/dot.gdbinit.nommu new file mode 100644 index 000000000..1ca03f872 --- /dev/null +++ b/arch/m32r/mappi/dot.gdbinit.nommu @@ -0,0 +1,245 @@ +# .gdbinit file +# $Id$ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.5 2004/01/23 08:23:25 takata Exp $ +#----- +# target platform: mappi + +# setting +set width 0d70 +set radix 0d16 +debug_chaos + +# clk xin:cpu:bif:bus=25:200:50:50 +define clock_init + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x00000200 +end + +# Initialize programmable ports +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 + # LED ON + set *(unsigned char *)($sfrbase + 0x1015) = 0xff + set *(unsigned char *)($sfrbase + 0x1085) = 0xff + shell sleep 0.1 + # LED OFF + set *(unsigned char *)($sfrbase + 0x1085) = 0x00 +end +document port_init + P5=LED(output), P6.b4=LAN_RESET(output) +end + +# Initialize SDRAM controller +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + # Ch0-ADR (size:64MB) + set *(unsigned long *)0x00ef6020 = 0x00000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010f05 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x08000000 - 0x0bffffff (64MB) +end + +# Initialize LAN controller +define lanc_init + set $sfrbase = 0x00ef0000 + # Set BSEL3 (BSEL3 for the Chaos's bselc) + set *(unsigned long *)($sfrbase + 0x5300) = 0x07078040 + set *(unsigned long *)($sfrbase + 0x5304) = 0x01110102 + set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001 + # Reset (P5=LED,P6.b4=LAN_RESET) + set *(unsigned short *)($sfrbase + 0x106c) = 0x0000 + set *(unsigned char *)($sfrbase + 0x1016) = 0xff + set *(unsigned char *)($sfrbase + 0x1086) = 0xff + shell sleep 0.1 + # swivel: 0=normal, 4=reverse +# set *(unsigned char *)($sfrbase + 0x1086) = 0x00 + set *(unsigned char *)($sfrbase + 0x1086) = 0x04 + set *(unsigned long *)(0x0c000330) = 0xffffffff + # Set mac address + set $lanc = (void*)0x0c000300 + set *(unsigned long *)($lanc + 0x0000) = 0x00610010 + set *(unsigned long *)($lanc + 0x0004) = 0x00200030 + set *(unsigned long *)($lanc + 0x0008) = 0x00400050 + set *(unsigned long *)($lanc + 0x000c) = 0x00600007 +end +document lanc_init + LAN controller initialization + ex.) MAC address: 10 20 30 40 50 60 +end + +# LCD & CRT dual-head setting (8bpp) +define dispc_init + set $sfrbase = 0x00ef0000 + # BSEL4 Dispc + set *(unsigned long *)($sfrbase + 0x5400) = 0x06078000 + set *(unsigned long *)($sfrbase + 0x5404) = 0x00101101 +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + set $nr_entries = $arg1 + use_mon_code + while ($i < $nr_entries) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb 0d32 +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb 0d32 +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + port_init + sdram_init + lanc_init + dispc_init + set $evb=0x00000000 +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x00002000 + # INITRD_START + #set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + #set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d200000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.bbox-httpd nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc=0x00001000 + set *(long *)0xfffffff4=0x8080 +# b load_flat_binary +# set *(unsigned char *)0x08001003=0x63 +# set *(unsigned char *)0x08001003=0x02 + si +# c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup +load_modules +boot + diff --git a/arch/m32r/mappi/dot.gdbinit.smp b/arch/m32r/mappi/dot.gdbinit.smp new file mode 100644 index 000000000..db0274fef --- /dev/null +++ b/arch/m32r/mappi/dot.gdbinit.smp @@ -0,0 +1,344 @@ +# .gdbinit file +# $Id$ + +# setting +set width 0d70 +set radix 0d16 +debug_chaos + +# clk xin:cpu:bif:bus=1:4:2:1 +define clock_init_on + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +# set *(unsigned long *)0x00ef4008 = 0x0201 +end + +# clk xin:cpu:bif:bus=1:4:1:1 +define clock_init_on_1411 + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:4:2:1 +define clock_init_on_1421 + set *(unsigned long *)0x00ef4024 = 2 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:8:2:1 +define clock_init_on_1821 + set *(unsigned long *)0x00ef4024 = 3 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:8:4:1 +define clock_init_on_1841 + set *(unsigned long *)0x00ef4024 = 3 + set *(unsigned long *)0x00ef4020 = 1 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x3 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:16:8:1 +define clock_init_on_11681 + set *(unsigned long *)0x00ef4024 = 4 + set *(unsigned long *)0x00ef4020 = 2 + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + set *(unsigned long *)0x00ef4004 = 0x7 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +# clk xin:cpu:bif:bus=1:1:1:1 +define clock_init_off + # CPU + set *(unsigned long *)0x00ef4010 = 0 + set *(unsigned long *)0x00ef4014 = 0 + # BIF + set *(unsigned long *)0x00ef4020 = 0 + # BUS + set *(unsigned long *)0x00ef4024 = 0 + # PLL + set *(unsigned long *)0x00ef4008 = 0x0000 +end + +# Initialize programmable ports +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 + # LED ON + set *(unsigned char *)($sfrbase + 0x1015) = 0xff + set *(unsigned char *)($sfrbase + 0x1085) = 0xff + shell sleep 0.1 + # LED OFF + set *(unsigned char *)($sfrbase + 0x1085) = 0x00 +end +document port_init + P5=LED(output), P6.b4=LAN_RESET(output) +end + +# Initialize SDRAM controller for Mappi +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # Ch0-MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + # Ch0-TR + set *(unsigned long *)0x00ef6028 = 0x00010002 + # Ch0-ADR + set *(unsigned long *)0x00ef6020 = 0x08000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010107 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + Mappi SDRAM controller initialization + 0x08000000 - 0x0bffffff (64MB) +end + +# Initialize LAN controller for Mappi +define lanc_init + set $sfrbase = 0x00ef0000 + # Set BSEL3 (BSEL3 for the Chaos's bselc) +# set *(unsigned long *)($sfrbase + 0x5300) = 0x01018040 +# set *(unsigned long *)($sfrbase + 0x5304) = 0x01011101 + set *(unsigned long *)($sfrbase + 0x5300) = 0x04048000 + set *(unsigned long *)($sfrbase + 0x5304) = 0x01011103 + set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001 + # Reset (P5=LED,P6.b4=LAN_RESET) + set *(unsigned short *)($sfrbase + 0x106c) = 0x0000 + set *(unsigned char *)($sfrbase + 0x1016) = 0xff + set *(unsigned char *)($sfrbase + 0x1086) = 0xff + shell sleep 0.1 +# set *(unsigned char *)($sfrbase + 0x1086) = 0x00 + set *(unsigned char *)($sfrbase + 0x1086) = 0x04 + set *(unsigned long *)(0x0c000330) = 0xffffffff + # Set mac address + set $lanc = (void*)0x0c000300 + set *(unsigned long *)($lanc + 0x0000) = 0x00610010 + set *(unsigned long *)($lanc + 0x0004) = 0x00200030 + set *(unsigned long *)($lanc + 0x0008) = 0x00400050 + set *(unsigned long *)($lanc + 0x000c) = 0x00600007 +end +document lanc_init + Mappi LAN controller initialization + ex.) MAC address: 10 20 30 40 50 60 +end + +# LCD & CRT dual-head setting (8bpp) +define dispc_init + set $sfrbase = 0x00ef0000 + # BSEL4 Dispc + # 20MHz +# set *(unsigned long *)($sfrbase + 0x5400) = 0x02028282 +# set *(unsigned long *)($sfrbase + 0x5404) = 0x00122202 + # 40MHz + set *(unsigned long *)($sfrbase + 0x5400) = 0x04048000 + set *(unsigned long *)($sfrbase + 0x5404) = 0x00101103 +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + use_mon_code + while ($i < 0d32 ) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end + use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb +end + + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set $task = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$fp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb +end + + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 +# clock_init_on_1411 + clock_init_on_1421 +# clock_init_on_1821 +# clock_init_on_1841 +# clock_init_on_11681 +# clock_init_off + shell sleep 0.1 + port_init + sdram_init + lanc_init + dispc_init + set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +# load ramdisk_082a0000.mot +# load romfs_082a0000.mot +# use_mon_code +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08002000 + # INITRD_START +# set *(unsigned long *)($param + 0x0010) = 0x082a0000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d160000000 +# set *(unsigned long *)($param + 0x0018) = 0d80000000 +# set *(unsigned long *)($param + 0x0018) = 0d40000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d40000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=tty1 console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +# set {char[0x200]}($param + 0x100) = "console=tty1 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $pc=0x08001000 + set *(unsigned char *)0x08001003=0x03 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x08000030 +end + +## Boot MP +define boot_mp + set_kernel_parameters + set *(unsigned long *)0x00f00000 = boot - 0x80000000 + set *(unsigned long *)0x00eff2f8 = 0x2 + x 0x00eff2f8 + + set $pc=0x08001000 + si + c +end +document boot_mp + Boot BSP +end + +## Boot UP +define boot_up + set_kernel_parameters + set $pc=0x08001000 + si + c +end +document boot_up + Boot BSP +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot_mp +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup diff --git a/arch/m32r/mm/Makefile b/arch/m32r/mm/Makefile new file mode 100644 index 000000000..c51c1c3b4 --- /dev/null +++ b/arch/m32r/mm/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the Linux M32R-specific parts of the memory manager. +# + +ifdef CONFIG_MMU +obj-y := init.o fault.o mmu.o extable.o ioremap.o cache.o page.o +else +obj-y := init.o fault-nommu.o mmu.o extable.o ioremap-nommu.o cache.o page.o +endif + +obj-$(CONFIG_DISCONTIGMEM) += discontig.o + diff --git a/arch/m32r/mm/cache.c b/arch/m32r/mm/cache.c new file mode 100644 index 000000000..e2dd92d69 --- /dev/null +++ b/arch/m32r/mm/cache.c @@ -0,0 +1,68 @@ +/* + * linux/arch/m32r/mm/cache.c + * + * Copyright (C) 2002 Hirokazu Takata + */ + +/* $Id$ */ + +#include +#include + +#undef MCCR + +#if defined(CONFIG_CHIP_XNUX2) || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_OPSP) +/* Cache Control Register */ +#define MCCR ((volatile unsigned long*)0xfffffffc) +#define MCCR_CC (1UL << 7) /* Cache mode modify bit */ +#define MCCR_IIV (1UL << 6) /* I-cache invalidate */ +#define MCCR_DIV (1UL << 5) /* D-cache invalidate */ +#define MCCR_DCB (1UL << 4) /* D-cache copy back */ +#define MCCR_ICM (1UL << 1) /* I-cache mode [0:off,1:on] */ +#define MCCR_DCM (1UL << 0) /* D-cache mode [0:off,1:on] */ +#define MCCR_ICACHE_INV (MCCR_CC|MCCR_IIV) +#define MCCR_DCACHE_CB (MCCR_CC|MCCR_DCB) +#define MCCR_DCACHE_CBINV (MCCR_CC|MCCR_DIV|MCCR_DCB) +#define CHECK_MCCR(mccr) (mccr = *MCCR) +#elif defined(CONFIG_CHIP_M32102) +#define MCCR ((volatile unsigned long*)0xfffffffc) +#define MCCR_IIV (1UL << 8) /* I-cache invalidate */ +#define MCCR_ICACHE_INV MCCR_IIV +#endif /* CONFIG_CHIP_XNUX2 || CONFIG_CHIP_M32700 */ + +#ifndef MCCR +#error Unknown cache type. +#endif + + +/* Copy back and invalidate D-cache and invalidate I-cache all */ +void _flush_cache_all(void) +{ +#if defined(CONFIG_CHIP_M32102) + *MCCR = MCCR_ICACHE_INV; +#else + unsigned long mccr; + + /* Copyback and invalidate D-cache */ + /* Invalidate I-cache */ + *MCCR = MCCR_ICACHE_INV | MCCR_DCACHE_CBINV; + while ((mccr = *MCCR) & MCCR_IIV); /* loop while invalidating... */ +#endif +} + +/* Copy back D-cache and invalidate I-cache all */ +void _flush_cache_copyback_all(void) +{ +#if defined(CONFIG_CHIP_M32102) + *MCCR = MCCR_ICACHE_INV; +#else + unsigned long mccr; + + /* Copyback D-cache */ + /* Invalidate I-cache */ + *MCCR = MCCR_ICACHE_INV | MCCR_DCACHE_CB; + while ((mccr = *MCCR) & MCCR_IIV); /* loop while invalidating... */ + +#endif +} + diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c new file mode 100644 index 000000000..3e49ff64b --- /dev/null +++ b/arch/m32r/mm/discontig.c @@ -0,0 +1,170 @@ +/* + * linux/arch/m32r/mm/discontig.c + * + * Discontig memory support + * + * Copyright (c) 2003 Hitoshi Yamamoto + */ + +#include +#include +#include +#include +#include + +#include + +extern char _end[]; + +struct pglist_data *node_data[MAX_NUMNODES]; +static bootmem_data_t node_bdata[MAX_NUMNODES] __initdata; + +pg_data_t m32r_node_data[MAX_NUMNODES]; + +/* Memory profile */ +typedef struct { + unsigned long start_pfn; + unsigned long pages; + unsigned long holes; + unsigned long free_pfn; +} mem_prof_t; +static mem_prof_t mem_prof[MAX_NUMNODES]; + +static void __init mem_prof_init(void) +{ + unsigned long start_pfn, holes, free_pfn; + const unsigned long zone_alignment = 1UL << (MAX_ORDER - 1); + unsigned long ul; + mem_prof_t *mp; + + /* Node#0 SDRAM */ + mp = &mem_prof[0]; + mp->start_pfn = PFN_UP(CONFIG_MEMORY_START); + mp->pages = PFN_DOWN(CONFIG_MEMORY_SIZE); + mp->holes = 0; + mp->free_pfn = PFN_UP(__pa(_end)); + + /* Node#1 internal SRAM */ + mp = &mem_prof[1]; + start_pfn = free_pfn = PFN_UP(CONFIG_IRAM_START); + holes = 0; + if (start_pfn & (zone_alignment - 1)) { + ul = zone_alignment; + while (start_pfn >= ul) + ul += zone_alignment; + + start_pfn = ul - zone_alignment; + holes = free_pfn - start_pfn; + } + + mp->start_pfn = start_pfn; + mp->pages = PFN_DOWN(CONFIG_IRAM_SIZE) + holes; + mp->holes = holes; + mp->free_pfn = PFN_UP(CONFIG_IRAM_START); +} + +unsigned long __init setup_memory(void) +{ + unsigned long bootmap_size; + unsigned long min_pfn; + int nid; + mem_prof_t *mp; + + max_low_pfn = 0; + min_low_pfn = -1; + + mem_prof_init(); + + for (nid = 0 ; nid < numnodes ; nid++) { + mp = &mem_prof[nid]; + NODE_DATA(nid)=(pg_data_t *)&m32r_node_data[nid]; + NODE_DATA(nid)->bdata = &node_bdata[nid]; + min_pfn = mp->start_pfn; + max_pfn = mp->start_pfn + mp->pages; + bootmap_size = init_bootmem_node(NODE_DATA(nid), mp->free_pfn, + mp->start_pfn, max_pfn); + + free_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn), + PFN_PHYS(mp->pages)); + + reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn), + PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size); + + if (max_low_pfn < max_pfn) + max_low_pfn = max_pfn; + + if (min_low_pfn > min_pfn) + min_low_pfn = min_pfn; + } + +#ifdef CONFIG_BLK_DEV_INITRD + if (LOADER_TYPE && INITRD_START) { + if (INITRD_START + INITRD_SIZE <= PFN_PHYS(max_low_pfn)) { + reserve_bootmem_node(NODE_DATA(0), INITRD_START, + INITRD_SIZE); + initrd_start = INITRD_START ? + INITRD_START + PAGE_OFFSET : 0; + + initrd_end = initrd_start + INITRD_SIZE; + printk("initrd:start[%08lx],size[%08lx]\n", + initrd_start, INITRD_SIZE); + } else { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + INITRD_START + INITRD_SIZE, + PFN_PHYS(max_low_pfn)); + + initrd_start = 0; + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + return max_low_pfn; +} + +#define START_PFN(nid) \ + (NODE_DATA(nid)->bdata->node_boot_start >> PAGE_SHIFT) +#define MAX_LOW_PFN(nid) (NODE_DATA(nid)->bdata->node_low_pfn) + +unsigned long __init zone_sizes_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES], zholes_size[MAX_NR_ZONES]; + unsigned long low, start_pfn; + unsigned long holes = 0; + int nid, i; + mem_prof_t *mp; + + pgdat_list = NULL; + for (nid = numnodes - 1 ; nid >= 0 ; nid--) { + NODE_DATA(nid)->pgdat_next = pgdat_list; + pgdat_list = NODE_DATA(nid); + } + + for (nid = 0 ; nid < numnodes ; nid++) { + mp = &mem_prof[nid]; + for (i = 0 ; i < MAX_NR_ZONES ; i++) { + zones_size[i] = 0; + zholes_size[i] = 0; + } + start_pfn = START_PFN(nid); + low = MAX_LOW_PFN(nid); + zones_size[ZONE_DMA] = low - start_pfn; + zholes_size[ZONE_DMA] = mp->holes; + holes += zholes_size[ZONE_DMA]; + + free_area_init_node(nid, NODE_DATA(nid), zones_size, + start_pfn, zholes_size); + } + + /* + * For test + * Use all area of internal RAM. + * see __alloc_pages() + */ + NODE_DATA(1)->node_zones->pages_min = 0; + NODE_DATA(1)->node_zones->pages_low = 0; + NODE_DATA(1)->node_zones->pages_high = 0; + + return holes; +} + diff --git a/arch/m32r/mm/extable.c b/arch/m32r/mm/extable.c new file mode 100644 index 000000000..9a97363b6 --- /dev/null +++ b/arch/m32r/mm/extable.c @@ -0,0 +1,22 @@ +/* + * linux/arch/i386/mm/extable.c + */ + +#include +#include +#include +#include + +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(regs->bpc); + if (fixup) { + regs->bpc = fixup->fixup; + return 1; + } + + return 0; +} + diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c new file mode 100644 index 000000000..da267d843 --- /dev/null +++ b/arch/m32r/mm/fault-nommu.c @@ -0,0 +1,164 @@ +/* + * linux/arch/m32r/mm/fault.c + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto, and H. Kondo + * + * Some code taken from i386 version. + * Copyright (C) 1995 Linus Torvalds + */ + +/* $Id: fault-nommu.c,v 1.1 2004/03/30 06:40:59 sakugawa Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern void die(const char *, struct pt_regs *, long); + +#ifndef CONFIG_SMP +asmlinkage unsigned int tlb_entry_i_dat; +asmlinkage unsigned int tlb_entry_d_dat; +#define tlb_entry_i tlb_entry_i_dat +#define tlb_entry_d tlb_entry_d_dat +#else +unsigned int tlb_entry_i_dat[NR_CPUS]; +unsigned int tlb_entry_d_dat[NR_CPUS]; +#define tlb_entry_i tlb_entry_i_dat[smp_processor_id()] +#define tlb_entry_d tlb_entry_d_dat[smp_processor_id()] +#endif + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + int loglevel_save = console_loglevel; + + if (yes) { + oops_in_progress = 1; + return; + } +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; +} + +void do_BUG(const char *file, int line) +{ + bust_spinlocks(1); + printk("kernel BUG at %s:%d!\n", file, line); +} + +/*======================================================================* + * do_page_fault() + *======================================================================* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * ARGUMENT: + * regs : M32R SP reg. + * error_code : See below + * address : M32R MMU MDEVA reg. (Operand ACE) + * : M32R BPC reg. (Instruction ACE) + * + * error_code : + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * bit 2 == 0 means kernel, 1 means user-mode + *======================================================================*/ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, + unsigned long address) +{ + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk(" printing bpc:\n"); + printk(KERN_ALERT "bpc = %08lx\n", regs->bpc); + + die("Oops", regs, error_code); + bust_spinlocks(0); + do_exit(SIGKILL); +} + +/*======================================================================* + * update_mmu_cache() + *======================================================================*/ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, + pte_t pte) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_page() : flushes one page + *======================================================================*/ +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_range() : flushes a range of pages + *======================================================================*/ +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_mm() : flushes the specified mm context TLB's + *======================================================================*/ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + BUG(); +} + +/*======================================================================* + * flush_tlb_all() : flushes all processes TLBs + *======================================================================*/ +void local_flush_tlb_all(void) +{ + BUG(); +} + diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c new file mode 100644 index 000000000..393ff03ae --- /dev/null +++ b/arch/m32r/mm/fault.c @@ -0,0 +1,572 @@ +/* + * linux/arch/m32r/mm/fault.c + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto, and H. Kondo + * + * Some code taken from i386 version. + * Copyright (C) 1995 Linus Torvalds + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For unblank_screen() */ +#include +#include + +#include +#include +#include +#include +#include +#include + +extern void die(const char *, struct pt_regs *, long); + +#ifndef CONFIG_SMP +asmlinkage unsigned int tlb_entry_i_dat; +asmlinkage unsigned int tlb_entry_d_dat; +#define tlb_entry_i tlb_entry_i_dat +#define tlb_entry_d tlb_entry_d_dat +#else +unsigned int tlb_entry_i_dat[NR_CPUS]; +unsigned int tlb_entry_d_dat[NR_CPUS]; +#define tlb_entry_i tlb_entry_i_dat[smp_processor_id()] +#define tlb_entry_d tlb_entry_d_dat[smp_processor_id()] +#endif + +extern void init_tlb(void); + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + int loglevel_save = console_loglevel; + + if (yes) { + oops_in_progress = 1; + return; + } +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; +} + +/*======================================================================* + * do_page_fault() + *======================================================================* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * ARGUMENT: + * regs : M32R SP reg. + * error_code : See below + * address : M32R MMU MDEVA reg. (Operand ACE) + * : M32R BPC reg. (Instruction ACE) + * + * error_code : + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * bit 2 == 0 means kernel, 1 means user-mode + * bit 3 == 0 means data, 1 means instruction + *======================================================================*/ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, + unsigned long address) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + unsigned long page, addr; + int write; + siginfo_t info; + + /* + * If BPSW IE bit enable --> set PSW IE bit + */ + if (regs->psw & M32R_PSW_BIE) + local_irq_enable(); + + tsk = current; + + info.si_code = SEGV_MAPERR; + + /* + * 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 (address >= TASK_SIZE && !(error_code & 4)) + goto vmalloc_fault; + + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user context or are running in an + * atomic region then we must not take the fault.. + */ + if (in_atomic() || !mm) + goto bad_area_nosemaphore; + + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the + * kernel and should generate an OOPS. Unfortunatly, in the case of an + * erroneous fault occuring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user + * space from well defined areas of code, which are listed in the + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform + * the source reference check when there is a possibilty of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. + */ + if (!down_read_trylock(&mm->mmap_sem)) { + if ((error_code & 4) == 0 && + !search_exception_tables(regs->psw)) + goto bad_area_nosemaphore; + down_read(&mm->mmap_sem); + } + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +#if 0 + if (error_code & 4) { + /* + * accessing the stack below "spu" is always a bug. + * The "+ 4" is there due to the push instruction + * doing pre-decrement on the stack and that + * doesn't show up until later.. + */ + if (address + 4 < regs->spu) + goto bad_area; + } +#endif + if (expand_stack(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + info.si_code = SEGV_ACCERR; + write = 0; + switch (error_code & 3) { + default: /* 3: write, present */ + /* fall through */ + case 2: /* write, not present */ + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + write++; + break; + case 1: /* read, present */ + case 0: /* read, not present */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + +survive: + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + addr = (address & PAGE_MASK) | (error_code & 8); + switch (handle_mm_fault(mm, vma, addr, write)) { + case VM_FAULT_MINOR: + tsk->min_flt++; + break; + case VM_FAULT_MAJOR: + tsk->maj_flt++; + break; + case VM_FAULT_SIGBUS: + goto do_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); + } + + up_read(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up_read(&mm->mmap_sem); + +bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ + if (error_code & 4) { + tsk->thread.address = address; + tsk->thread.error_code = error_code | (address >= TASK_SIZE); + tsk->thread.trap_no = 14; + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void __user *)address; + force_sig_info(SIGSEGV, &info, tsk); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + if (fixup_exception(regs)) + return; + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT " printing bpc:\n"); + printk("%08lx\n", regs->bpc); + page = *(unsigned long *)MPTB; + page = ((unsigned long *) page)[address >> PGDIR_SHIFT]; + printk(KERN_ALERT "*pde = %08lx\n", page); + if (page & _PAGE_PRESENT) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); + } + die("Oops", regs, error_code); + bust_spinlocks(0); + do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up_read(&mm->mmap_sem); + if (tsk->pid == 1) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up_read(&mm->mmap_sem); + + /* Kernel mode? Handle exception or die */ + if (!(error_code & 4)) + goto no_context; + + tsk->thread.address = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, tsk); + return; + +vmalloc_fault: + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + pte_t *pte_k; + + pgd = (pgd_t *)*(unsigned long *)MPTB; + pgd = offset + (pgd_t *)pgd; + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd_k)) + goto no_context; + + /* + * set_pgd(pgd, *pgd_k); here would be useless on PAE + * and redundant with the set_pmd() on non-PAE. + */ + + pmd = pmd_offset(pgd, address); + pmd_k = pmd_offset(pgd_k, address); + if (!pmd_present(*pmd_k)) + goto no_context; + set_pmd(pmd, *pmd_k); + + pte_k = pte_offset_kernel(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; + + addr = (address & PAGE_MASK) | (error_code & 8); + update_mmu_cache(NULL, addr, *pte_k); + return; + } +} + +/*======================================================================* + * update_mmu_cache() + *======================================================================*/ +#define TLB_MASK (NR_TLB_ENTRIES - 1) +#define ITLB_END (unsigned long *)(ITLB_BASE + (NR_TLB_ENTRIES * 8)) +#define DTLB_END (unsigned long *)(DTLB_BASE + (NR_TLB_ENTRIES * 8)) +void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr, + pte_t pte) +{ + unsigned long *entry1, *entry2; + unsigned long pte_data, flags; + unsigned int *entry_dat; + int inst = vaddr & 8; + int i; + + /* Ptrace may call this routine. */ + if (vma && current->active_mm != vma->vm_mm) + return; + + local_irq_save(flags); + + vaddr = (vaddr & PAGE_MASK) | get_asid(); + +#ifdef CONFIG_CHIP_OPSP + entry1 = (unsigned long *)ITLB_BASE; + for(i = 0 ; i < NR_TLB_ENTRIES; i++) { + if(*entry1++ == vaddr) { + pte_data = pte_val(pte); + set_tlb_data(entry1, pte_data); + break; + } + entry1++; + } + entry2 = (unsigned long *)DTLB_BASE; + for(i = 0 ; i < NR_TLB_ENTRIES ; i++) { + if(*entry2++ == vaddr) { + pte_data = pte_val(pte); + set_tlb_data(entry2, pte_data); + break; + } + entry2++; + } + local_irq_restore(flags); + return; +#else + pte_data = pte_val(pte); + + /* + * Update TLB entries + * entry1: ITLB entry address + * entry2: DTLB entry address + */ + __asm__ __volatile__ ( + "seth %0, #high(%4) \n\t" + "st %2, @(%5, %0) \n\t" + "ldi %1, #1 \n\t" + "st %1, @(%6, %0) \n\t" + "add3 r4, %0, %7 \n\t" + ".fillinsn \n" + "1: \n\t" + "ld %1, @(%6, %0) \n\t" + "bnez %1, 1b \n\t" + "ld %0, @r4+ \n\t" + "ld %1, @r4 \n\t" + "st %3, @+%0 \n\t" + "st %3, @+%1 \n\t" + : "=&r" (entry1), "=&r" (entry2) + : "r" (vaddr), "r" (pte_data), "i" (MMU_REG_BASE), + "i" (MSVA_offset), "i" (MTOP_offset), "i" (MIDXI_offset) + : "r4", "memory" + ); + + if ((!inst && entry2 >= DTLB_END) || (inst && entry1 >= ITLB_END)) + goto notfound; + +found: + local_irq_restore(flags); + + return; + + /* Valid entry not found */ +notfound: + /* + * Update ITLB or DTLB entry + * entry1: TLB entry address + * entry2: TLB base address + */ + if (!inst) { + entry2 = (unsigned long *)DTLB_BASE; + entry_dat = &tlb_entry_d; + } else { + entry2 = (unsigned long *)ITLB_BASE; + entry_dat = &tlb_entry_i; + } + entry1 = entry2 + (((*entry_dat - 1) & TLB_MASK) << 1); + + for (i = 0 ; i < NR_TLB_ENTRIES ; i++) { + if (!(entry1[1] & 2)) /* Valid bit check */ + break; + + if (entry1 != entry2) + entry1 -= 2; + else + entry1 += TLB_MASK << 1; + } + + if (i >= NR_TLB_ENTRIES) { /* Empty entry not found */ + entry1 = entry2 + (*entry_dat << 1); + *entry_dat = (*entry_dat + 1) & TLB_MASK; + } + *entry1++ = vaddr; /* Set TLB tag */ + set_tlb_data(entry1, pte_data); + + goto found; +#endif +} + +/*======================================================================* + * flush_tlb_page() : flushes one page + *======================================================================*/ +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_mm && mm_context(vma->vm_mm) != NO_CONTEXT) { + unsigned long flags; + + local_irq_save(flags); + page &= PAGE_MASK; + page |= (mm_context(vma->vm_mm) & MMU_CONTEXT_ASID_MASK); + __flush_tlb_page(page); + local_irq_restore(flags); + } +} + +/*======================================================================* + * flush_tlb_range() : flushes a range of pages + *======================================================================*/ +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct mm_struct *mm; + + mm = vma->vm_mm; + if (mm_context(mm) != NO_CONTEXT) { + unsigned long flags; + int size; + + local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (NR_TLB_ENTRIES / 4)) { /* Too many TLB to flush */ + mm_context(mm) = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + } else { + unsigned long asid; + + asid = mm_context(mm) & MMU_CONTEXT_ASID_MASK; + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + + start |= asid; + end |= asid; + while (start < end) { + __flush_tlb_page(start); + start += PAGE_SIZE; + } + } + local_irq_restore(flags); + } +} + +/*======================================================================* + * flush_tlb_mm() : flushes the specified mm context TLB's + *======================================================================*/ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + /* Invalidate all TLB of this process. */ + /* Instead of invalidating each TLB, we get new MMU context. */ + if (mm_context(mm) != NO_CONTEXT) { + unsigned long flags; + + local_irq_save(flags); + mm_context(mm) = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + local_irq_restore(flags); + } +} + +/*======================================================================* + * flush_tlb_all() : flushes all processes TLBs + *======================================================================*/ +void local_flush_tlb_all(void) +{ + unsigned long flags; + + local_irq_save(flags); + __flush_tlb_all(); + local_irq_restore(flags); +} + +/*======================================================================* + * init_mmu() + *======================================================================*/ +void __init init_mmu(void) +{ + tlb_entry_i = 0; + tlb_entry_d = 0; + mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; + set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); + *(volatile unsigned long *)MPTB = (unsigned long)swapper_pg_dir; +} diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c new file mode 100644 index 000000000..a290e3793 --- /dev/null +++ b/arch/m32r/mm/init.c @@ -0,0 +1,250 @@ +/* + * linux/arch/m32r/mm/init.c + * + * Copyright (c) 2001, 2002 Hitoshi Yamamoto + * + * Some code taken from sh version. + * Copyright (C) 1999 Niibe Yutaka + * Based on linux/arch/i386/mm/init.c: + * Copyright (C) 1995 Linus Torvalds + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* References to section boundaries */ +extern char _text, _etext, _edata; +extern char __init_begin, __init_end; + +pgd_t swapper_pg_dir[1024]; + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +void show_mem(void) +{ + int total = 0, reserved = 0; + int shared = 0, cached = 0; + int highmem = 0; + struct page *page; + pg_data_t *pgdat; + unsigned long i; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; ++i) { + page = pgdat->node_mem_map + i; + total++; + if (PageHighMem(page)) + highmem++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } + } + printk("%d pages of RAM\n", total); + printk("%d pages of HIGHMEM\n",highmem); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); +} + +/* + * Cache of MMU context last used. + */ +#ifndef CONFIG_SMP +unsigned long mmu_context_cache_dat; +#else +unsigned long mmu_context_cache_dat[NR_CPUS]; +#endif +static unsigned long hole_pages; + +/* + * function prototype + */ +void __init paging_init(void); +void __init mem_init(void); +void free_initmem(void); +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long, unsigned long); +#endif + +/* It'd be good if these lines were in the standard header file. */ +#define START_PFN(nid) \ + (NODE_DATA(nid)->bdata->node_boot_start >> PAGE_SHIFT) +#define MAX_LOW_PFN(nid) (NODE_DATA(nid)->bdata->node_low_pfn) + +#ifndef CONFIG_DISCONTIGMEM +unsigned long __init zone_sizes_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long max_dma; + unsigned long low; + unsigned long start_pfn; + +#ifdef CONFIG_MMU + start_pfn = START_PFN(0); + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = MAX_LOW_PFN(0); + + if (low < max_dma){ + zones_size[ZONE_DMA] = low - start_pfn; + zones_size[ZONE_NORMAL] = 0; + } else { + zones_size[ZONE_DMA] = low - start_pfn; + zones_size[ZONE_NORMAL] = low - max_dma; + } +#else + zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT; + zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT; + start_pfn = __MEMORY_START >> PAGE_SHIFT; +#endif /* CONFIG_MMU */ + + free_area_init_node(0, NODE_DATA(0), zones_size, start_pfn, 0); + + mem_map = contig_page_data.node_mem_map; + + return 0; +} +#else /* CONFIG_DISCONTIGMEM */ +extern unsigned long zone_sizes_init(void); +#endif /* CONFIG_DISCONTIGMEM */ + +/*======================================================================* + * paging_init() : sets up the page tables + *======================================================================*/ +void __init paging_init(void) +{ +#ifdef CONFIG_MMU + int i; + pgd_t *pg_dir; + + /* We don't need kernel mapping as hardware support that. */ + pg_dir = swapper_pg_dir; + + for (i = 0 ; i < USER_PTRS_PER_PGD * 2 ; i++) + pgd_val(pg_dir[i]) = 0; +#endif /* CONFIG_MMU */ + hole_pages = zone_sizes_init(); +} + +int __init reservedpages_count(void) +{ + int reservedpages, nid, i; + + reservedpages = 0; + for (nid = 0 ; nid < numnodes ; nid++) + for (i = 0 ; i < MAX_LOW_PFN(nid) - START_PFN(nid) ; i++) + if (PageReserved(NODE_DATA(nid)->node_mem_map + i)) + reservedpages++; + + return reservedpages; +} + +/*======================================================================* + * mem_init() : + * orig : arch/sh/mm/init.c + *======================================================================*/ +void __init mem_init(void) +{ + int codesize, reservedpages, datasize, initsize; + int nid; +#ifndef CONFIG_MMU + extern unsigned long memory_end; +#endif + + num_physpages = 0; + for (nid = 0 ; nid < numnodes ; nid++) + num_physpages += MAX_LOW_PFN(nid) - START_PFN(nid) + 1; + + num_physpages -= hole_pages; + +#ifndef CONFIG_DISCONTIGMEM + max_mapnr = num_physpages; +#endif /* CONFIG_DISCONTIGMEM */ + +#ifdef CONFIG_MMU + high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0))); +#else + high_memory = (void *)(memory_end & PAGE_MASK); +#endif /* CONFIG_MMU */ + + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); + + /* this will put all low memory onto the freelists */ + for (nid = 0 ; nid < numnodes ; nid++) + totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); + + reservedpages = reservedpages_count() - hole_pages; + codesize = (unsigned long) &_etext - (unsigned long)&_text; + datasize = (unsigned long) &_edata - (unsigned long)&_etext; + initsize = (unsigned long) &__init_end - (unsigned long)&__init_begin; + + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " + "%dk reserved, %dk data, %dk init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} + +/*======================================================================* + * free_initmem() : + * orig : arch/sh/mm/init.c + *======================================================================*/ +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", \ + (int)(&__init_end - &__init_begin) >> 10); +} + +#ifdef CONFIG_BLK_DEV_INITRD +/*======================================================================* + * free_initrd_mem() : + * orig : arch/sh/mm/init.c + *======================================================================*/ +void free_initrd_mem(unsigned long start, unsigned long end) +{ + unsigned long p; + for (p = start; p < end; p += PAGE_SIZE) { + ClearPageReserved(virt_to_page(p)); + set_page_count(virt_to_page(p), 1); + free_page(p); + totalram_pages++; + } + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif + diff --git a/arch/m32r/mm/ioremap-nommu.c b/arch/m32r/mm/ioremap-nommu.c new file mode 100644 index 000000000..2759f2d48 --- /dev/null +++ b/arch/m32r/mm/ioremap-nommu.c @@ -0,0 +1,52 @@ +/* + * linux/arch/m32r/mm/ioremap-nommu.c + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo + * + * Taken from mips version. + * (C) Copyright 1995 1996 Linus Torvalds + * (C) Copyright 2001 Ralf Baechle + */ + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ + +#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL)) + +void __iomem * +__ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + return (void *)phys_addr; +} + +#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1) + +void iounmap(volatile void __iomem *addr) +{ +} + diff --git a/arch/m32r/mm/ioremap.c b/arch/m32r/mm/ioremap.c new file mode 100644 index 000000000..70c59055c --- /dev/null +++ b/arch/m32r/mm/ioremap.c @@ -0,0 +1,192 @@ +/* + * linux/arch/m32r/mm/ioremap.c + * + * Copyright (c) 2001, 2002 Hiroyuki Kondo + * + * Taken from mips version. + * (C) Copyright 1995 1996 Linus Torvalds + * (C) Copyright 2001 Ralf Baechle + */ + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +static inline void +remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + unsigned long pfn; + pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ + | _PAGE_WRITE | flags); + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + if (address >= end) + BUG(); + pfn = phys_addr >> PAGE_SHIFT; + do { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, pfn_pte(pfn, pgprot)); + address += PAGE_SIZE; + pfn++; + pte++; + } while (address && (address < end)); +} + +static inline int +remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + if (address >= end) + BUG(); + do { + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int +remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + int error; + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; + if (!pmd) + break; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + break; + error = 0; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); + flush_tlb_all(); + return error; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ + +#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL)) + +void __iomem * +__ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void __iomem * addr; + struct vm_struct * area; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Map objects in the low 512mb of address space using KSEG1, otherwise + * map using page tables. + */ + if (IS_LOW512(phys_addr) && IS_LOW512(phys_addr + size - 1)) + return (void *) KSEG1ADDR(phys_addr); + + /* + * Don't allow anybody to remap normal RAM that we're using.. + */ + if (phys_addr < virt_to_phys(high_memory)) { + char *t_addr, *t_end; + struct page *page; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + + for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) + if(!PageReserved(page)) + return NULL; + } + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + area->phys_addr = phys_addr; + addr = (void __iomem *) area->addr; + if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) { + vunmap((void __force *) addr); + return NULL; + } + + return (void __iomem *) (offset + (char __iomem *)addr); +} + +#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1) + +void iounmap(volatile void __iomem *addr) +{ + if (!IS_KSEG1(addr)) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} + diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S new file mode 100644 index 000000000..0c28f11d6 --- /dev/null +++ b/arch/m32r/mm/mmu.S @@ -0,0 +1,350 @@ +/* + * linux/arch/m32r/mm/mmu.S + * + * Copyright (C) 2001 by Hiroyuki Kondo + */ + +/* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */ + +#include /* CONFIG_MMU */ +#include +#include +#include + + .text +#ifdef CONFIG_MMU + +#include +#include +#include +#include + +/* + * TLB Miss Exception handler + */ + .balign 16 +ENTRY(tme_handler) + .global tlb_entry_i_dat + .global tlb_entry_d_dat + + SWITCH_TO_KERNEL_STACK + +#if defined(CONFIG_ISA_M32R2) + st r0, @-sp + st r1, @-sp + st r2, @-sp + st r3, @-sp + + seth r3, #high(MMU_REG_BASE) + ld r1, @(MESTS_offset, r3) ; r1: status (MESTS reg.) + ld r0, @(MDEVP_offset, r3) ; r0: PFN + ASID (MDEVP reg.) + st r1, @(MESTS_offset, r3) ; clear status (MESTS reg.) + and3 r1, r1, #(MESTS_IT) + bnez r1, 1f ; instruction TLB miss? + +;; data TLB miss +;; input +;; r0: PFN + ASID (MDEVP reg.) +;; r1 - r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry base address +;; r2: &tlb_entry_{i|d}_dat +;; r3: free + +#ifndef CONFIG_SMP + seth r2, #high(tlb_entry_d_dat) + or3 r2, r2, #low(tlb_entry_d_dat) +#else /* CONFIG_SMP */ + ldi r1, #-8192 + seth r2, #high(tlb_entry_d_dat) + or3 r2, r2, #low(tlb_entry_d_dat) + and r1, sp + ld r1, @(16, r1) ; current_thread_info->cpu + slli r1, #2 + add r2, r1 +#endif /* !CONFIG_SMP */ + seth r1, #high(DTLB_BASE) + or3 r1, r1, #low(DTLB_BASE) + bra 2f + + .balign 16 + .fillinsn +1: +;; instrucntion TLB miss +;; input +;; r0: MDEVP reg. (included ASID) +;; r1 - r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry base address +;; r2: &tlb_entry_{i|d}_dat +;; r3: free + ldi r3, #-4096 + and3 r0, r0, #(MMU_CONTEXT_ASID_MASK) + mvfc r1, bpc + and r1, r3 + or r0, r1 ; r0: PFN + ASID +#ifndef CONFIG_SMP + seth r2, #high(tlb_entry_i_dat) + or3 r2, r2, #low(tlb_entry_i_dat) +#else /* CONFIG_SMP */ + ldi r1, #-8192 + seth r2, #high(tlb_entry_i_dat) + or3 r2, r2, #low(tlb_entry_i_dat) + and r1, sp + ld r1, @(16, r1) ; current_thread_info->cpu + slli r1, #2 + add r2, r1 +#endif /* !CONFIG_SMP */ + seth r1, #high(ITLB_BASE) + or3 r1, r1, #low(ITLB_BASE) + + .fillinsn +2: +;; select TLB entry +;; input +;; r0: PFN + ASID +;; r1: TLB entry base address +;; r2: &tlb_entry_{i|d}_dat +;; r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2, r3: free +#ifdef CONFIG_ISA_DUAL_ISSUE + ld r3, @r2 || srli r1, #3 +#else + ld r3, @r2 + srli r1, #3 +#endif + add r1, r3 + ; tlb_entry_{d|i}_dat++; + addi r3, #1 + and3 r3, r3, #(NR_TLB_ENTRIES - 1) +#ifdef CONFIG_ISA_DUAL_ISSUE + st r3, @r2 || slli r1, #3 +#else + st r3, @r2 + slli r1, #3 +#endif + +;; load pte +;; input +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2, r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2: pte_data +;; r3: free + ; pgd = *(unsigned long *)MPTB; + ld24 r2, #(-MPTB - 1) + srl3 r3, r0, #22 +#ifdef CONFIG_ISA_DUAL_ISSUE + not r2, r2 || slli r3, #2 ; r3: pgd offset +#else + not r2, r2 + slli r3, #2 +#endif + ld r2, @r2 ; r2: pgd base addr (MPTB reg.) + or r3, r2 ; r3: pmd addr + + ; pmd = pmd_offset(pgd, address); + ld r3, @r3 ; r3: pmd data + ldi r2, #-4096 + beqz r3, 3f ; pmd_none(*pmd) ? + + ; pte = pte_offset(pmd, address); + and r2, r3 ; r2: pte base addr + srl3 r3, r0, #10 + and3 r3, r3, #0xffc ; r3: pte offset + or r3, r2 + seth r2, #0x8000 + or r3, r2 ; r3: pte addr + + ; pte_data = (unsigned long)pte_val(*pte); + ld r2, @r3 ; r2: pte data + or3 r2, r2, #2 ; _PAGE_PRESENT(=2) + + .fillinsn +5: +;; set tlb +;; input +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2: pte_data +;; r3: free + st r0, @r1 ; set_tlb_tag(entry++, address); + st r2, @+r1 ; set_tlb_data(entry, pte_data); + + .fillinsn +6: + ld r3, @sp+ + ld r2, @sp+ + ld r1, @sp+ + ld r0, @sp+ + rte + + .fillinsn +3: +;; error +;; input +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2, r3: free +;; output +;; r0: PFN + ASID +;; r1: TLB entry address +;; r2: pte_data +;; r3: free +#ifdef CONFIG_ISA_DUAL_ISSUE + bra 5b || ldi r2, #2 +#else + ldi r2, #2 ; r2: pte_data = 0 | _PAGE_PRESENT(=2) + bra 5b +#endif + +#elif defined (CONFIG_ISA_M32R) + + st sp, @-sp + st r0, @-sp + st r1, @-sp + st r2, @-sp + st r3, @-sp + st r4, @-sp + + seth r3, #high(MMU_REG_BASE) + ld r0, @(MDEVA_offset,r3) ; r0: address (MDEVA reg.) + mvfc r2, bpc ; r2: bpc + ld r1, @(MESTS_offset,r3) ; r1: status (MESTS reg.) + st r1, @(MESTS_offset,r3) ; clear status (MESTS reg.) + and3 r1, r1, #(MESTS_IT) + beqz r1, 1f ; data TLB miss? + +;; instrucntion TLB miss + mv r0, r2 ; address = bpc; + ; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2; + seth r3, #shigh(tlb_entry_i_dat) + ld r4, @(low(tlb_entry_i_dat),r3) + sll3 r2, r4, #3 + seth r1, #high(ITLB_BASE) + or3 r1, r1, #low(ITLB_BASE) + add r2, r1 ; r2: entry + addi r4, #1 ; tlb_entry_i++; + and3 r4, r4, #(NR_TLB_ENTRIES-1) + st r4, @(low(tlb_entry_i_dat),r3) + bra 2f + .fillinsn +1: +;; data TLB miss + ; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2; + seth r3, #shigh(tlb_entry_d_dat) + ld r4, @(low(tlb_entry_d_dat),r3) + sll3 r2, r4, #3 + seth r1, #high(DTLB_BASE) + or3 r1, r1, #low(DTLB_BASE) + add r2, r1 ; r2: entry + addi r4, #1 ; tlb_entry_d++; + and3 r4, r4, #(NR_TLB_ENTRIES-1) + st r4, @(low(tlb_entry_d_dat),r3) + .fillinsn +2: +;; load pte +; r0: address, r2: entry +; r1,r3,r4: (free) + ; pgd = *(unsigned long *)MPTB; + ld24 r1, #(-MPTB-1) + not r1, r1 + ld r1, @r1 + srl3 r4, r0, #22 + sll3 r3, r4, #2 + add r3, r1 ; r3: pgd + ; pmd = pmd_offset(pgd, address); + ld r1, @r3 ; r1: pmd + beqz r1, 3f ; pmd_none(*pmd) ? +; + and3 r1, r1, #0xeff + ldi r4, #611 ; _KERNPG_TABLE(=611) + beq r1, r4, 4f ; !pmd_bad(*pmd) ? + .fillinsn +3: + ldi r1, #0 ; r1: pte_data = 0 + bra 5f + .fillinsn +4: + ; pte = pte_offset(pmd, address); + ld r4, @r3 ; r4: pte + ldi r3, #-4096 + and r4, r3 + srl3 r3, r0, #10 + and3 r3, r3, #0xffc + add r4, r3 + seth r3, #0x8000 + add r4, r3 ; r4: pte + ; pte_data = (unsigned long)pte_val(*pte); + ld r1, @r4 ; r1: pte_data + .fillinsn + +;; set tlb +; r0: address, r1: pte_data, r2: entry +; r3,r4: (free) +5: + ldi r3, #-4096 ; set_tlb_tag(entry++, address); + and r3, r0 + seth r4, #shigh(MASID) + ld r4, @(low(MASID),r4) ; r4: MASID + and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) + or r3, r4 + st r3, @r2 + or3 r4, r1, #2 ; _PAGE_PRESENT(=2) + st r4, @(4,r2) ; set_tlb_data(entry, pte_data); + + ld r4, @sp+ + ld r3, @sp+ + ld r2, @sp+ + ld r1, @sp+ + ld r0, @sp+ + ld sp, @sp+ + rte + +#else +#error unknown isa configuration +#endif + +ENTRY(init_tlb) +;; Set MMU Register + seth r0, #high(MMU_REG_BASE) ; Set MMU_REG_BASE higher + or3 r0, r0, #low(MMU_REG_BASE) ; Set MMU_REG_BASE lower + ldi r1, #0 + st r1, @(MPSZ_offset,r0) ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2) + ldi r1, #0 + st r1, @(MASID_offset,r0) ; Set ASID Zero + +;; Set TLB + seth r0, #high(ITLB_BASE) ; Set ITLB_BASE higher + or3 r0, r0, #low(ITLB_BASE) ; Set ITLB_BASE lower + seth r1, #high(DTLB_BASE) ; Set DTLB_BASE higher + or3 r1, r1, #low(DTLB_BASE) ; Set DTLB_BASE lower + ldi r2, #0 + ldi r3, #NR_TLB_ENTRIES + addi r0, #-4 + addi r1, #-4 +clear_tlb: + st r2, @+r0 ; VPA <- 0 + st r2, @+r0 ; PPA <- 0 + st r2, @+r1 ; VPA <- 0 + st r2, @+r1 ; PPA <- 0 + addi r3, #-1 + bnez r3, clear_tlb +;; + jmp r14 + +ENTRY(m32r_itlb_entrys) +ENTRY(m32r_otlb_entrys) + +#endif /* CONFIG_MMU */ + +.end + diff --git a/arch/m32r/mm/page.S b/arch/m32r/mm/page.S new file mode 100644 index 000000000..a2e9367db --- /dev/null +++ b/arch/m32r/mm/page.S @@ -0,0 +1,82 @@ +/* + * linux/arch/m32r/mm/page.S + * + * Clear/Copy page with CPU + * + * Copyright (C) 2004 The Free Software Initiative of Japan + * + * Written by Niibe Yutaka + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + .text + .global copy_page + /* + * copy_page (to, from) + * + * PAGE_SIZE = 4096-byte + * Cache line = 16-byte + * 16 * 256 + */ + .align 4 +copy_page: + ldi r2, #255 + ld r3, @r0 /* cache line allocate */ + ld r4, @r1+ + ld r5, @r1+ + ld r6, @r1+ + ld r7, @r1+ + .fillinsn +0: + st r4, @r0 + st r5, @+r0 + st r6, @+r0 + st r7, @+r0 + ld r4, @r1+ + addi r0, #4 + ld r5, @r1+ + ld r6, @r1+ + ld r7, @r1+ + ld r3, @r0 /* cache line allocate */ + addi r2, #-1 + bnez r2, 0b + + st r4, @r0 + st r5, @+r0 + st r6, @+r0 + st r7, @+r0 + jmp r14 + + .text + .global clear_page + /* + * clear_page (to) + * + * PAGE_SIZE = 4096-byte + * Cache line = 16-byte + * 16 * 256 + */ + .align 4 +clear_page: + ldi r2, #255 + ldi r4, #0 + ld r3, @r0 /* cache line allocate */ + .fillinsn +0: + st r4, @r0 + st r4, @+r0 + st r4, @+r0 + st r4, @+r0 + addi r0, #4 + ld r3, @r0 /* cache line allocate */ + addi r2, #-1 + bnez r2, 0b + + st r4, @r0 + st r4, @+r0 + st r4, @+r0 + st r4, @+r0 + jmp r14 diff --git a/arch/m32r/oaks32r/defconfig.nommu b/arch/m32r/oaks32r/defconfig.nommu new file mode 100644 index 000000000..816b53ee7 --- /dev/null +++ b/arch/m32r/oaks32r/defconfig.nommu @@ -0,0 +1,521 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +# 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=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +CONFIG_PLAT_OAKS32R=y +# CONFIG_PLAT_MAPPI2 is not set +# CONFIG_CHIP_M32700 is not set +CONFIG_CHIP_M32102=y +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_ISA_M32R=y +CONFIG_BUS_CLOCK=33333333 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x01000000 +CONFIG_MEMORY_SIZE=0x00800000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +CONFIG_M32R_NE2000=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# 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=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET 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_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# 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_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +# CONFIG_TMPFS is not set +# 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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/oaks32r/dot.gdbinit.nommu b/arch/m32r/oaks32r/dot.gdbinit.nommu new file mode 100644 index 000000000..48420f7e8 --- /dev/null +++ b/arch/m32r/oaks32r/dot.gdbinit.nommu @@ -0,0 +1,155 @@ +# .gdbinit file +# $Id: dot.gdbinit.oaks32r,v 1.2 2004/04/15 02:33:14 takata Exp $ +#----- +# NOTE: this file is generated by a script, "gen_gdbinit.pl". +# (Please type "gen_gdbinit.pl --help" and check the help message). +# $ Id: gen_gdbinit.pl,v 1.10 2004/04/15 02:10:45 takata Exp $ +#----- +# target platform: oaks32r + +# setting +set width 0d70 +set radix 0d16 + +# clk xin:cpu:bus=16:66:33 +define clock_init + set *(unsigned long *)0x00ef4008 = 1 + shell sleep 0.1 + set *(unsigned long *)0x00ef4000 = 0x00020100 +end + +# Initialize programmable ports +define port_init + set *(unsigned long *)0x00ef1000 = 0x1 + set *(unsigned long *)0x00ef1060 = 0x01400001 + set *(unsigned long *)0x00ef1064 = 0x00015555 + set *(unsigned long *)0x00ef1068 = 0x55555050 + set *(unsigned long *)0x00ef106c = 0x05150040 +end + +# Initialize SDRAM controller +define sdram_init + set *(unsigned long *)0x00ef6008 = 0x00000182 + set *(unsigned long *)0x00ef600c = 0x00000001 + shell sleep 0.1 + set *(unsigned long *)0x00ef602c = 0x00000010 + set *(unsigned long *)0x00ef6028 = 0x00000300 + set *(unsigned long *)0x00ef6048 = 0x00000001 + set *(unsigned long *)0x00ef6020 = 0x01000041 + set *(unsigned long *)0x00ef6004 = 0x00010117 + set *(unsigned long *)0x00ef6010 = 0x00000001 + set *(unsigned long *)0x00ef6024 = 0x00000001 +end +document sdram_init + SDRAM controller initialization + 0x01000000 - 0x017fffff (8MB) +end + +# Initialize LAN controller +define lanc_init + set *(unsigned long *)0x00ef5008 = 0x03031303 + #RST DRV (P64) + set *(unsigned char *)0x00ef1046 = 0x08 + set *(unsigned char *)0x00ef1026 = 0xff + set *(unsigned char *)0x00ef1026 = 0x00 + set *(unsigned short *)0x02000630 = 0xffff +end + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch +end + +# Setup all +define setup + use_mon_code + set *(unsigned int)0xfffffffc=0x60 + shell sleep 0.1 + clock_init + shell sleep 0.1 + port_init + sdram_init + lanc_init +end + +# Load modules +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x01002000 + # INITRD_START + set *(unsigned long *)($param + 0x0010) = 0x00000000 + # INITRD_SIZE + set *(unsigned long *)($param + 0x0014) = 0x00000000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d66666667 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d33333333 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + +# set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.busybox.flat nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0" +end + +# Boot +define boot + set_kernel_parameters + set $fp = 0 + set $pc = 0x01001000 + si + c +end + +# Set breakpoints +define set_breakpoints + b *0x00000020 + b *0x00000030 +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi +setup +#load_modules +#set_breakpoints +#boot + diff --git a/arch/m32r/oprofile/Kconfig b/arch/m32r/oprofile/Kconfig new file mode 100644 index 000000000..19d37730b --- /dev/null +++ b/arch/m32r/oprofile/Kconfig @@ -0,0 +1,23 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff --git a/arch/m32r/oprofile/Makefile b/arch/m32r/oprofile/Makefile new file mode 100644 index 000000000..06e7c81ea --- /dev/null +++ b/arch/m32r/oprofile/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) init.o diff --git a/arch/m32r/oprofile/init.c b/arch/m32r/oprofile/init.c new file mode 100644 index 000000000..f5843c8cc --- /dev/null +++ b/arch/m32r/oprofile/init.c @@ -0,0 +1,25 @@ +/** + * @file init.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include + +extern void timer_init(struct oprofile_operations ** ops); + +int __init oprofile_arch_init(struct oprofile_operations ** ops) +{ + return -ENODEV; +} + + +void oprofile_arch_exit(void) +{ +} diff --git a/arch/m32r/opsput/defconfig.opsput b/arch/m32r/opsput/defconfig.opsput new file mode 100644 index 000000000..07eae9601 --- /dev/null +++ b/arch/m32r/opsput/defconfig.opsput @@ -0,0 +1,598 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_M32R=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=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=y +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +CONFIG_PLAT_OPSPUT=y +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +# CONFIG_CHIP_M32700 is not set +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +CONFIG_CHIP_OPSP=y +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_PREEMPT is not set +# CONFIG_SMP is not set + +# +# M32R drivers +# +# CONFIG_M32R_CFC is not set +CONFIG_M32R_SMC91111=y +CONFIG_M32700UT_DS1302=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD 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 +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET 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 +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# 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 is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# 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=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO is not set +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# 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 is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +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_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_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=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 +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# 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 +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/opsput/dot.gdbinit b/arch/m32r/opsput/dot.gdbinit new file mode 100644 index 000000000..9883f001d --- /dev/null +++ b/arch/m32r/opsput/dot.gdbinit @@ -0,0 +1,180 @@ +# .gdbinit file +# $Id: dot.gdbinit,v 1.1 2004/07/27 06:54:20 sakugawa Exp $ + +# setting +set width 0d70 +set radix 0d16 +set height 0 +debug_chaos + +define tlb_init + set $tlbbase = 0xfe000000 + set *(unsigned long *)($tlbbase + 0x04) = 0x0 + set *(unsigned long *)($tlbbase + 0x0c) = 0x0 + set *(unsigned long *)($tlbbase + 0x14) = 0x0 + set *(unsigned long *)($tlbbase + 0x1c) = 0x0 + set *(unsigned long *)($tlbbase + 0x24) = 0x0 + set *(unsigned long *)($tlbbase + 0x2c) = 0x0 + set *(unsigned long *)($tlbbase + 0x34) = 0x0 + set *(unsigned long *)($tlbbase + 0x3c) = 0x0 + set *(unsigned long *)($tlbbase + 0x44) = 0x0 + set *(unsigned long *)($tlbbase + 0x4c) = 0x0 + set *(unsigned long *)($tlbbase + 0x54) = 0x0 + set *(unsigned long *)($tlbbase + 0x5c) = 0x0 + set *(unsigned long *)($tlbbase + 0x64) = 0x0 + set *(unsigned long *)($tlbbase + 0x6c) = 0x0 + set *(unsigned long *)($tlbbase + 0x74) = 0x0 + set *(unsigned long *)($tlbbase + 0x7c) = 0x0 + set *(unsigned long *)($tlbbase + 0x84) = 0x0 + set *(unsigned long *)($tlbbase + 0x8c) = 0x0 + set *(unsigned long *)($tlbbase + 0x94) = 0x0 + set *(unsigned long *)($tlbbase + 0x9c) = 0x0 + set *(unsigned long *)($tlbbase + 0xa4) = 0x0 + set *(unsigned long *)($tlbbase + 0xac) = 0x0 + set *(unsigned long *)($tlbbase + 0xb4) = 0x0 + set *(unsigned long *)($tlbbase + 0xbc) = 0x0 + set *(unsigned long *)($tlbbase + 0xc4) = 0x0 + set *(unsigned long *)($tlbbase + 0xcc) = 0x0 + set *(unsigned long *)($tlbbase + 0xd4) = 0x0 + set *(unsigned long *)($tlbbase + 0xdc) = 0x0 + set *(unsigned long *)($tlbbase + 0xe4) = 0x0 + set *(unsigned long *)($tlbbase + 0xec) = 0x0 + set *(unsigned long *)($tlbbase + 0xf4) = 0x0 + set *(unsigned long *)($tlbbase + 0xfc) = 0x0 + set $tlbbase = 0xfe000800 + set *(unsigned long *)($tlbbase + 0x04) = 0x0 + set *(unsigned long *)($tlbbase + 0x0c) = 0x0 + set *(unsigned long *)($tlbbase + 0x14) = 0x0 + set *(unsigned long *)($tlbbase + 0x1c) = 0x0 + set *(unsigned long *)($tlbbase + 0x24) = 0x0 + set *(unsigned long *)($tlbbase + 0x2c) = 0x0 + set *(unsigned long *)($tlbbase + 0x34) = 0x0 + set *(unsigned long *)($tlbbase + 0x3c) = 0x0 + set *(unsigned long *)($tlbbase + 0x44) = 0x0 + set *(unsigned long *)($tlbbase + 0x4c) = 0x0 + set *(unsigned long *)($tlbbase + 0x54) = 0x0 + set *(unsigned long *)($tlbbase + 0x5c) = 0x0 + set *(unsigned long *)($tlbbase + 0x64) = 0x0 + set *(unsigned long *)($tlbbase + 0x6c) = 0x0 + set *(unsigned long *)($tlbbase + 0x74) = 0x0 + set *(unsigned long *)($tlbbase + 0x7c) = 0x0 + set *(unsigned long *)($tlbbase + 0x84) = 0x0 + set *(unsigned long *)($tlbbase + 0x8c) = 0x0 + set *(unsigned long *)($tlbbase + 0x94) = 0x0 + set *(unsigned long *)($tlbbase + 0x9c) = 0x0 + set *(unsigned long *)($tlbbase + 0xa4) = 0x0 + set *(unsigned long *)($tlbbase + 0xac) = 0x0 + set *(unsigned long *)($tlbbase + 0xb4) = 0x0 + set *(unsigned long *)($tlbbase + 0xbc) = 0x0 + set *(unsigned long *)($tlbbase + 0xc4) = 0x0 + set *(unsigned long *)($tlbbase + 0xcc) = 0x0 + set *(unsigned long *)($tlbbase + 0xd4) = 0x0 + set *(unsigned long *)($tlbbase + 0xdc) = 0x0 + set *(unsigned long *)($tlbbase + 0xe4) = 0x0 + set *(unsigned long *)($tlbbase + 0xec) = 0x0 + set *(unsigned long *)($tlbbase + 0xf4) = 0x0 + set *(unsigned long *)($tlbbase + 0xfc) = 0x0 +end + +define load_modules + use_debug_dma + load +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x88002000 + # INITRD_START +# set *(unsigned long *)($param + 0x0010) = 0x08300000 + # INITRD_SIZE +# set *(unsigned long *)($param + 0x0014) = 0x00400000 + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d200000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 +# set *(unsigned long *)($param + 0x001c) = 0d25000000 + + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x\ + root=/dev/nfsroot \ + nfsroot=192.168.0.1:/project/m32r-linux/export/root.2.6 \ + nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \ + mem=16m \0" +end + +define boot + set_kernel_parameters + set $pc=0x88001000 + set $fp=0 + set $evb=0x88000000 + # I/D-Cache ON + +# IPI +# set *(long *)0x00eff2f8 = 0x2 + set $fp=0 +# set *(unsigned long *)0xa0ef4000 = 0x100 + si +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + use_mon_code + while ($i < 0d32 ) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end +# use_debug_dma +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb +end + +define show_regs + printf " R0[%08lx] R1[%08lx] R2[%08lx] R3[%08lx]\n",$r0,$r1,$r2,$r3 + printf " R4[%08lx] R5[%08lx] R6[%08lx] R7[%08lx]\n",$r4,$r5,$r6,$r7 + printf " R8[%08lx] R9[%08lx] R10[%08lx] R11[%08lx]\n",$r8,$r9,$r10,$r11 + printf "R12[%08lx] FP[%08lx] LR[%08lx] SP[%08lx]\n",$r12,$fp,$lr,$sp + printf "PSW[%08lx] CBR[%08lx] SPI[%08lx] SPU[%08lx]\n",$psw,$cbr,$spi,$spu + printf "BPC[%08lx] PC[%08lx] ACCL[%08lx] ACCH[%08lx]\n",$bpc,$pc,$accl,$acch + printf "EVB[%08lx]\n",$evb +end + +define setup + debug_chaos + set *(unsigned long *)0xa0ef6004 = 0x0001053f + set *(unsigned long *)0xa0ef6028 = 0x00031102 +# set *(unsigned long *)0xa0ef400c = 0x2 +end + +sdireset +sdireset +file vmlinux +target m32rsdi +set $pc=0x0 +b *0x30000 +c +setup +tlb_init +load_modules +#set *(long *)0xa0ef4000=0x101 +#set *(long *)0xa0ef400c=0x002 + +boot +#b tme_handler +b *0x88000020 + + + + diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 1fa88d5f3..b3ab305ba 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -21,12 +21,10 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool - mainmenu "Linux/68k Kernel Configuration" source "init/Kconfig" - menu "Platform dependent setup" config EISA @@ -355,7 +353,6 @@ config 060_WRITETHROUGH endmenu - menu "General setup" source "fs/Kconfig.binfmt" @@ -447,7 +444,6 @@ endmenu source "drivers/Kconfig" - menu "Character devices" config ATARI_MFPSER @@ -652,47 +648,10 @@ endmenu source "fs/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting" - depends on DEBUG_KERNEL - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -endmenu +source "arch/m68k/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/m68k/Kconfig.debug b/arch/m68k/Kconfig.debug new file mode 100644 index 000000000..f53b6d530 --- /dev/null +++ b/arch/m68k/Kconfig.debug @@ -0,0 +1,5 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +endmenu diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index bc79771e8..59c25bc9d 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -28,7 +28,7 @@ ifdef CONFIG_SUN3 LDFLAGS_vmlinux = -N endif -CHECK := $(CHECK) -D__mc68000__=1 -I$(shell $(CC) -print-file-name=include) +CHECKFLAGS += -D__mc68000__ -I$(shell $(CC) -print-file-name=include) # without -fno-strength-reduce the 53c7xx.c driver fails ;-( CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 081a6747c..458925c47 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -7,7 +7,7 @@ ifndef CONFIG_SUN3 else extra-y := sun3-head.o endif -extra-y += vmlinux.lds.s +extra-y += vmlinux.lds obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c index be2f7e616..738531ca2 100644 --- a/arch/m68k/kernel/bios32.c +++ b/arch/m68k/kernel/bios32.c @@ -77,11 +77,6 @@ static int disable_pci_burst; /* If set do not allow PCI bursts. */ static unsigned int io_base; static unsigned int mem_base; -struct pci_fixup pcibios_fixups[] = -{ - { 0 } -}; - /* * static void disable_dev(struct pci_dev *dev) * diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index b069b0c84..fe837e31a 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -16,7 +16,6 @@ #include #include #include -#include asmlinkage long long __ashldi3 (long long, int); asmlinkage long long __ashrdi3 (long long, int); @@ -72,18 +71,18 @@ EXPORT_SYMBOL(vme_brdtype); explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(__muldi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(get_wchan); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index b426ab55a..93b043e2a 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/ptrace.c b/arch/m68k/kernel/ptrace.c index 12e4acdfd..b043a7f94 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -379,11 +379,8 @@ asmlinkage void syscall_trace(void) if (!current->thread.work.delayed_trace && !current->thread.work.syscall_trace) return; - 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 * for normal use. strace only continues with a signal if the diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index c37c4dbb8..4a319bdef 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/time.c b/arch/m68k/kernel/time.c index d85616f14..11d122980 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -38,24 +38,6 @@ static inline int set_rtc_mmss(unsigned long nowtime) return -1; } -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -63,9 +45,7 @@ static inline void do_profile (unsigned long pc) static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) { do_timer(regs); - - if (!user_mode(regs)) - do_profile(regs->pc); + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_HEARTBEAT /* use power LED as a heartbeat instead -- much more useful diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index b0a5cd53d..42aeea9fc 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 12931b324..7a18ed062 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/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 541897351..1215b5bea 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -19,12 +19,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index f11317725..d8769bc86 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -5,6 +5,10 @@ mainmenu "uClinux/68k (w/o MMU) Kernel Configuration" +config M68KNOMMU + bool + default y + config MMU bool default n @@ -25,7 +29,6 @@ config RWSEM_XCHGADD_ALGORITHM bool default n - source "init/Kconfig" menu "Processor type and features" @@ -388,7 +391,7 @@ config LARGE_ALLOCS a lot of RAM, and you need to able to allocate very large contiguous chunks. If unsure, say N. -choice +choice prompt "RAM size" default AUTO @@ -421,7 +424,7 @@ config RAM32MB endchoice -choice +choice prompt "RAM bus width" default RAMAUTOBIT @@ -472,7 +475,6 @@ endchoice endmenu - menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" config PCI @@ -511,64 +513,10 @@ source "drivers/Kconfig" source "fs/Kconfig" -menu "Kernel hacking" - -config FULLDEBUG - bool "Full Symbolic/Source Debugging support" - help - Enable debuging symbols on kernel build. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - help - Enables console device to interpret special characters as - commands to dump state information. - -config HIGHPROFILE - bool "Use fast second timer for profiling" - depends on COLDFIRE - help - Use a fast secondary clock to produce profiling information. - -config BOOTPARAM - bool 'Compiled-in Kernel Boot Parameter' - -config BOOTPARAM_STRING - string 'Kernel Boot Parameter' - default 'console=ttyS0,19200' - depends on BOOTPARAM - -config DUMPTOFLASH - bool "Panic/Dump to FLASH" - depends on COLDFIRE - help - Dump any panic of trap output into a flash memory segment - for later analysis. - -config NO_KERNEL_MSG - bool "Suppress Kernel BUG Messages" - help - Do not output any debug BUG messages within the kernel. - -config BDM_DISABLE - bool "Disable BDM signals" - depends on (EXPERIMENTAL && COLDFIRE) - help - Disable the ColdFire CPU's BDM signals. - -endmenu +source "arch/m68knommu/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug new file mode 100644 index 000000000..763c9aa0b --- /dev/null +++ b/arch/m68knommu/Kconfig.debug @@ -0,0 +1,42 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debuging symbols on kernel build. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + depends on COLDFIRE + help + Use a fast secondary clock to produce profiling information. + +config BOOTPARAM + bool 'Compiled-in Kernel Boot Parameter' + +config BOOTPARAM_STRING + string 'Kernel Boot Parameter' + default 'console=ttyS0,19200' + depends on BOOTPARAM + +config DUMPTOFLASH + bool "Panic/Dump to FLASH" + depends on COLDFIRE + help + Dump any panic of trap output into a flash memory segment + for later analysis. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config BDM_DISABLE + bool "Disable BDM signals" + depends on (EXPERIMENTAL && COLDFIRE) + help + Disable the ColdFire CPU's BDM signals. + +endmenu diff --git a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile index 1a6a3600e..1c6cd1ab5 100644 --- a/arch/m68knommu/kernel/Makefile +++ b/arch/m68knommu/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for arch/m68knommu/kernel. # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds obj-y += dma.o entry.o init_task.o m68k_ksyms.o process.o ptrace.o semaphore.o \ setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c index c803fe64e..02c56f538 100644 --- a/arch/m68knommu/kernel/asm-offsets.c +++ b/arch/m68knommu/kernel/asm-offsets.c @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) diff --git a/arch/m68knommu/kernel/comempci.c b/arch/m68knommu/kernel/comempci.c index ce5dafa69..8670938f1 100644 --- a/arch/m68knommu/kernel/comempci.c +++ b/arch/m68knommu/kernel/comempci.c @@ -351,8 +351,6 @@ char *pcibios_setup(char *option) } /*****************************************************************************/ -struct pci_fixup pcibios_fixups[] = { { 0 } }; - void pcibios_fixup_bus(struct pci_bus *b) { } diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c index 33e084146..e93a5ad56 100644 --- a/arch/m68knommu/kernel/m68k_ksyms.c +++ b/arch/m68knommu/kernel/m68k_ksyms.c @@ -16,7 +16,6 @@ #include #include #include -#include #include extern void dump_thread(struct pt_regs *, struct user *); @@ -50,16 +49,16 @@ EXPORT_SYMBOL(csum_partial_copy); explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(get_wchan); @@ -79,27 +78,27 @@ extern void __udivsi3(void); extern void __umodsi3(void); /* gcc lib functions */ -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__divsi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(__modsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__mulsi3); -EXPORT_SYMBOL_NOVERS(__udivsi3); -EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); -EXPORT_SYMBOL_NOVERS(is_in_rom); +EXPORT_SYMBOL(is_in_rom); #ifdef CONFIG_COLDFIRE extern unsigned int *dma_device_address; extern unsigned long dma_base_addr, _ramend; -EXPORT_SYMBOL_NOVERS(dma_base_addr); -EXPORT_SYMBOL_NOVERS(dma_device_address); -EXPORT_SYMBOL_NOVERS(_ramend); +EXPORT_SYMBOL(dma_base_addr); +EXPORT_SYMBOL(dma_device_address); +EXPORT_SYMBOL(_ramend); extern asmlinkage void trap(void); extern void *_ramvec; -EXPORT_SYMBOL_NOVERS(trap); -EXPORT_SYMBOL_NOVERS(_ramvec); +EXPORT_SYMBOL(trap); +EXPORT_SYMBOL(_ramvec); #endif /* CONFIG_COLDFIRE */ diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 581eef2b7..b0901d817 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/ptrace.c b/arch/m68knommu/kernel/ptrace.c index 4f3df6d67..773dc91e4 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68knommu/kernel/ptrace.c @@ -133,13 +133,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; @@ -376,10 +369,8 @@ asmlinkage void syscall_trace(void) return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; - 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 * for normal use. strace only continues with a signal if the diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c index 3fb0d78f4..0d5891567 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/time.c b/arch/m68knommu/kernel/time.c index 74308a533..e328f2810 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c @@ -41,24 +41,6 @@ static inline int set_rtc_mmss(unsigned long nowtime) return -1; } -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -75,9 +57,8 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) write_seqlock(&xtime_lock); do_timer(regs); - - if (!user_mode(regs)) - do_profile(regs->pc); + if (current->pid) + profile_tick(CPU_PROFILING, regs); /* * If we have an externally synchronized Linux clock, then update diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S index 4d8f716d7..87f3bc407 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/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c index 99c7d9935..ef49596aa 100644 --- a/arch/m68knommu/platform/5307/timers.c +++ b/arch/m68knommu/platform/5307/timers.c @@ -110,17 +110,8 @@ void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs) { /* Reset ColdFire timer2 */ mcf_proftp->ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; - - if (!user_mode(regs)) { - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long ip = instruction_pointer(regs); - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - if (ip < prof_len) - prof_buffer[ip]++; - } - } + if (current->pid) + profile_tick(CPU_PROFILING, regs); } /***************************************************************************/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6ab62cb4d..ecad69906 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -381,7 +381,7 @@ config DDB5476 evaluation board. Features : kernel debugging, serial terminal, NFS root fs, on-board - ether port USB, AC97, PCI, PCI VGA card & framebuffer console, + ether port USB, AC97, PCI, PCI VGA card & framebuffer console, IDE controller, PS2 keyboard, PS2 mouse, etc. config DDB5477 @@ -400,7 +400,7 @@ config DDB5477_BUS_FREQUENCY int "bus frequency (in kHZ, 0 for auto-detect)" depends on DDB5477 default 0 - + config NEC_OSPREY bool "Support for NEC Osprey board" select DMA_NONCOHERENT @@ -513,15 +513,15 @@ config SOC_AU1550 endchoice -choice +choice prompt "AMD/Alchemy Au1x00 board support" depends on SOC_AU1X00 help These are evaluation boards built by AMD/Alchemy to showcase their Au1X00 Internet Edge Processors. The SOC design - is based on the MIPS32 architecture running at 266/400/500MHz - with many integrated peripherals. Further information can be - found at their website, . Say Y here if you + is based on the MIPS32 architecture running at 266/400/500MHz + with many integrated peripherals. Further information can be + found at their website, . Say Y here if you wish to build a kernel for this platform. config MIPS_PB1000 @@ -1091,7 +1091,6 @@ config TANBAC_TB0219 endmenu - menu "CPU selection" choice @@ -1194,7 +1193,7 @@ config PAGE_SIZE_4KB This option select the standard 4kB Linux page size. On some R3000-family processors this is the only available page size. Using 4kB page size will minimize memory consumption and is therefore - recommended for low memory systems. + recommended for low memory systems. config PAGE_SIZE_8KB bool "8kB" @@ -1382,21 +1381,6 @@ config PREEMPT This allows applications to run more reliably even when the system is under load. -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - config RTC_DS1742 bool "DS1742 BRAM/RTC support" depends on TOSHIBA_JMR3927 || TOSHIBA_RBTX4927 @@ -1562,7 +1546,7 @@ config EMBEDDED_RAMDISK_IMAGE default "ramdisk.gz" help This is the filename of the ramdisk image to be built into the - kernel. Relative pathnames are relative to arch/mips/ramdisk/. + kernel. Relative pathnames are relative to arch/mips/ramdisk/. The ramdisk image is not part of the kernel distribution; you must provide one yourself. @@ -1572,119 +1556,7 @@ source "drivers/Kconfig" source "fs/Kconfig" -menu "Kernel hacking" - -config CROSSCOMPILE - bool "Are you using a crosscompiler" - help - Say Y here if you are compiling the kernel on a different - architecture than the one it is intended to run on. - -config CMDLINE - string "Default kernel command string" - default "" - help - On some platforms, there is currently no way for the boot loader to - pass arguments to the kernel. For these platforms, you can supply - some command-line options at build time by entering them here. In - other cases you can specify kernel args so that you don't have - to set them up in board prom initialization routines. - -config DEBUG_KERNEL - bool "Kernel debugging" - -config DEBUG_STACK_USAGE - bool "Enable stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config KGDB - bool "Remote GDB kernel debugging" - depends on DEBUG_KERNEL - select DEBUG_INFO - help - If you say Y here, it will be possible to remotely debug the MIPS - kernel using gdb. This enlarges your kernel image disk size by - several megabytes and requires a machine with more than 16 MB, - better 32 MB RAM to avoid excessive linking time. This is only - useful for kernel hackers. If unsure, say N. - -config GDB_CONSOLE - bool "Console output to GDB" - depends on KGDB - help - If you are using GDB for remote debugging over a serial port and - would like kernel messages to be formatted into GDB $O packets so - that GDB prints them as program output, say 'Y'. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config SB1XXX_CORELIS - bool "Corelis Debugger" - depends on SIBYTE_SB1xxx_SOC - select DEBUG_INFO - help - Select compile flags that produce code that can be processed by the - Corelis mksym utility and UDB Emulator. - -config RUNTIME_DEBUG - bool "Enable run-time debugging" - depends on DEBUG_KERNEL - help - If you say Y here, some debugging macros will do run-time checking. - If you say N here, those macros will mostly turn to no-ops. See - include/asm-mips/debug.h for debuging macros. - If unsure, say N. - - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config MIPS_UNCACHED - bool "Run uncached" - depends on DEBUG_KERNEL && !SMP && !SGI_IP27 - help - If you say Y here there kernel will disable all CPU caches. This will - reduce the system's performance dramatically but can help finding - otherwise hard to track bugs. It can also useful if you're doing - hardware debugging with a logic analyzer and need to see all traffic - on the bus. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - -endmenu +source "arch/mips/Kconfig.debug" source "security/Kconfig" diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug new file mode 100644 index 000000000..d3c5cc3b9 --- /dev/null +++ b/arch/mips/Kconfig.debug @@ -0,0 +1,76 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config CROSSCOMPILE + bool "Are you using a crosscompiler" + help + Say Y here if you are compiling the kernel on a different + architecture than the one it is intended to run on. + +config CMDLINE + string "Default kernel command string" + default "" + help + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + other cases you can specify kernel args so that you don't have + to set them up in board prom initialization routines. + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config KGDB + bool "Remote GDB kernel debugging" + depends on DEBUG_KERNEL + select DEBUG_INFO + help + If you say Y here, it will be possible to remotely debug the MIPS + kernel using gdb. This enlarges your kernel image disk size by + several megabytes and requires a machine with more than 16 MB, + better 32 MB RAM to avoid excessive linking time. This is only + useful for kernel hackers. If unsure, say N. + +config GDB_CONSOLE + bool "Console output to GDB" + depends on KGDB + help + If you are using GDB for remote debugging over a serial port and + would like kernel messages to be formatted into GDB $O packets so + that GDB prints them as program output, say 'Y'. + +config SB1XXX_CORELIS + bool "Corelis Debugger" + depends on SIBYTE_SB1xxx_SOC + select DEBUG_INFO + help + Select compile flags that produce code that can be processed by the + Corelis mksym utility and UDB Emulator. + +config RUNTIME_DEBUG + bool "Enable run-time debugging" + depends on DEBUG_KERNEL + help + If you say Y here, some debugging macros will do run-time checking. + If you say N here, those macros will mostly turn to no-ops. See + include/asm-mips/debug.h for debuging macros. + If unsure, say N. + +config MIPS_UNCACHED + bool "Run uncached" + depends on DEBUG_KERNEL && !SMP && !SGI_IP27 + help + If you say Y here there kernel will disable all CPU caches. This will + reduce the system's performance dramatically but can help finding + otherwise hard to track bugs. It can also useful if you're doing + hardware debugging with a logic analyzer and need to see all traffic + on the bus. + +endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 371558708..5025c01b9 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -56,14 +56,12 @@ endif # cflags-y := -I $(TOPDIR)/include/asm/gcc cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -cflags-y += $(call check_gcc, -finline-limit=100000,) +cflags-y += $(call cc-option, -finline-limit=100000) LDFLAGS_vmlinux += -G 0 -static -n MODFLAGS += -mlong-calls cflags-$(CONFIG_SB1XXX_CORELIS) += -mno-sched-prolog -fno-omit-frame-pointer -check_warning = $(shell if $(CC) $(1) -c -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) - # # Use: $(call set_gccflags,,,,,) # @@ -162,7 +160,7 @@ cflags-$(CONFIG_CPU_R5432) += \ cflags-$(CONFIG_CPU_NEVADA) += \ $(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \ -Wa,--trap -# $(call check_gcc,-mmad,) +# $(call cc-option,-mmad) cflags-$(CONFIG_CPU_RM7000) += \ $(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \ @@ -643,7 +641,7 @@ endif # none has been choosen above. # -AFLAGS_vmlinux.lds.o := \ +CPPFLAGS_vmlinux.lds := \ -D"LOADADDR=$(load-y)" \ -D"JIFFIES=$(JIFFIES)" \ -imacros $(srctree)/include/asm-$(ARCH)/sn/mapped_kernel.h diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index f58f454cd..a72de9727 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -38,11 +38,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/arch/mips/baget/irq.c b/arch/mips/baget/irq.c index d2067c037..3dcc16efd 100644 --- a/arch/mips/baget/irq.c +++ b/arch/mips/baget/irq.c @@ -180,7 +180,7 @@ skip: static void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction *action; - int do_random, cpu; + int ret, do_random, cpu; cpu = smp_processor_id(); irq_enter(); @@ -194,8 +194,9 @@ static void do_IRQ(int irq, struct pt_regs * regs) action = *(irq + irq_action); do_random = 0; do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + do_random |= action->flags; action = action->next; } while (action); if (do_random & SA_SAMPLE_RANDOM) diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig index b6f70da71..141dc6da4 100644 --- a/arch/mips/configs/jaguar-atx_defconfig +++ b/arch/mips/configs/jaguar-atx_defconfig @@ -306,10 +306,10 @@ CONFIG_EEPRO100=y # CONFIG_R8169 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set -CONFIG_MV64340_ETH=y -CONFIG_MV64340_ETH_0=y -CONFIG_MV64340_ETH_1=y -CONFIG_MV64340_ETH_2=y +CONFIG_MV643XX_ETH=y +CONFIG_MV643XX_ETH_0=y +CONFIG_MV643XX_ETH_1=y +CONFIG_MV643XX_ETH_2=y # # Ethernet (10000 Mbit) diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig index 3eafe9ae7..c7eb418e3 100644 --- a/arch/mips/configs/ocelot_c_defconfig +++ b/arch/mips/configs/ocelot_c_defconfig @@ -303,7 +303,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_R8169 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set -# CONFIG_MV64340_ETH is not set +# CONFIG_MV643XX_ETH is not set # # Ethernet (10000 Mbit) diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index d942862ad..9933eede8 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -272,7 +272,6 @@ CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_NAT=y CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_TOS=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y # CONFIG_IP_PNP_DHCP is not set diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig index cd08e3c03..5be7f568f 100644 --- a/arch/mips/configs/tb0229_defconfig +++ b/arch/mips/configs/tb0229_defconfig @@ -229,7 +229,6 @@ CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_NAT=y CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_TOS=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y # CONFIG_IP_PNP_DHCP is not set diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 3fd457737..86783790d 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the Linux/MIPS kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \ diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index b15f3b0de..15ae6af5a 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/irq.c b/arch/mips/kernel/irq.c index 13acf876b..7c1dae720 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -144,14 +144,16 @@ inline void synchronize_irq(unsigned int irq) int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -872,30 +874,6 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, #endif -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data, new_value; - unsigned long full_count = count, err; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -931,26 +909,15 @@ static void register_irq_proc (unsigned int irq) #endif } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 2b2265ada..169393cc9 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -26,36 +26,36 @@ extern long __strnlen_user_asm(const char *s); /* * String functions */ -EXPORT_SYMBOL_NOVERS(memchr); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(strcat); -EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); #ifdef CONFIG_MIPS64 -EXPORT_SYMBOL_NOVERS(strncmp); +EXPORT_SYMBOL(strncmp); #endif -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strstr); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(kernel_thread); /* * Userspace access stuff. */ -EXPORT_SYMBOL_NOVERS(__copy_user); -EXPORT_SYMBOL_NOVERS(__bzero); -EXPORT_SYMBOL_NOVERS(__strncpy_from_user_nocheck_asm); -EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); -EXPORT_SYMBOL_NOVERS(__strlen_user_nocheck_asm); -EXPORT_SYMBOL_NOVERS(__strlen_user_asm); -EXPORT_SYMBOL_NOVERS(__strnlen_user_nocheck_asm); -EXPORT_SYMBOL_NOVERS(__strnlen_user_asm); +EXPORT_SYMBOL(__copy_user); +EXPORT_SYMBOL(__bzero); +EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); +EXPORT_SYMBOL(__strncpy_from_user_asm); +EXPORT_SYMBOL(__strlen_user_nocheck_asm); +EXPORT_SYMBOL(__strlen_user_asm); +EXPORT_SYMBOL(__strnlen_user_nocheck_asm); +EXPORT_SYMBOL(__strnlen_user_asm); EXPORT_SYMBOL(csum_partial); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index a820be85e..325705fcc 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,19 +473,15 @@ 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, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); static inline void handle_signal(unsigned long sig, siginfo_t *info, - sigset_t *oldset, struct pt_regs *regs) + struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - switch(regs->regs[0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: @@ -539,6 +533,7 @@ extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs); asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) { + struct k_sigaction ka; siginfo_t info; int signr; @@ -564,9 +559,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) if (!oldset) oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - handle_signal(signr, &info, oldset, regs); + handle_signal(signr, &info, &ka, oldset, regs); return 1; } diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 407beff81..a449a5651 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 d262fbdc9..d2f8b8cf6 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 1f917fe93..6d1c473f6 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -254,16 +253,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, ®s, 0, NULL, NULL); -} - /* * Startup the CPU with this logical number */ @@ -275,20 +264,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 16519f7e8..51f467685 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, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 494d1872d..392c73853 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -810,8 +810,8 @@ asmlinkage int irix_times(struct tms * tbuf) return err; err |= __put_user(current->utime, &tbuf->tms_utime); err |= __put_user(current->stime, &tbuf->tms_stime); - err |= __put_user(current->cutime, &tbuf->tms_cutime); - err |= __put_user(current->cstime, &tbuf->tms_cstime); + err |= __put_user(current->signal->cutime, &tbuf->tms_cutime); + err |= __put_user(current->signal->cstime, &tbuf->tms_cstime); } return err; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 0199485a4..915e5539e 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -417,23 +416,8 @@ static long last_rtc_update; */ void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - if (!user_mode(regs)) { - if (prof_buffer && current->pid) { - unsigned long pc = regs->cp0_epc; - - pc -= (unsigned long) _stext; - pc >>= prof_shift; - /* - * Dont ignore out-of-bounds pc values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } - } - + if (current->pid) + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_SMP /* in UP mode, update_process_times() is invoked by do_timer() */ update_process_times(user_mode(regs)); diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 098cfaa23..e70684ee0 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -29,6 +29,7 @@ SECTIONS .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } =0 @@ -96,9 +97,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/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 9348cd3e6..fe7fc1730 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 820c3af08..ec8077c74 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c index df52d2adf..fa5982ac0 100644 --- a/arch/mips/momentum/jaguar_atx/prom.c +++ b/arch/mips/momentum/jaguar_atx/prom.c @@ -40,7 +40,7 @@ const char *get_system_type(void) return "Momentum Jaguar-ATX"; } -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH extern unsigned char prom_mac_addr_base[6]; static void burn_clocks(void) @@ -230,7 +230,7 @@ void __init prom_init(void) mips_machgroup = MACH_GROUP_MOMENCO; mips_machtype = MACH_MOMENCO_JAGUAR_ATX; -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH /* get the base MAC address for on-board ethernet ports */ get_mac(prom_mac_addr_base); #endif diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c index 762112965..49ac302d8 100644 --- a/arch/mips/momentum/ocelot_c/prom.c +++ b/arch/mips/momentum/ocelot_c/prom.c @@ -32,7 +32,7 @@ struct callvectors* debug_vectors; extern unsigned long marvell_base; extern unsigned long cpu_clock; -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH extern unsigned char prom_mac_addr_base[6]; #endif @@ -45,7 +45,7 @@ const char *get_system_type(void) #endif } -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH static void burn_clocks(void) { int i; @@ -227,7 +227,7 @@ void __init prom_init(void) mips_machgroup = MACH_GROUP_MOMENCO; mips_machtype = MACH_MOMENCO_OCELOT_C; -#ifdef CONFIG_MV64340_ETH +#ifdef CONFIG_MV643XX_ETH /* get the base MAC address for on-board ethernet ports */ get_mac(prom_mac_addr_base); #endif diff --git a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c index 4cbef3431..ae1930e67 100644 --- a/arch/mips/pci/fixup-atlas.c +++ b/arch/mips/pci/fixup-atlas.c @@ -60,13 +60,7 @@ static void atlas_saa9730_base_fixup (struct pci_dev *pdev) printk ("saa9730_base = %x\n", saa9730_base); } -#endif - +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, + atlas_saa9730_base_fixup); -struct pci_fixup pcibios_fixups[] __initdata = { -#ifdef CONFIG_KGDB - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, - atlas_saa9730_base_fixup}, #endif - { 0 } -}; diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c index 7bbe12336..2d42f9aa9 100644 --- a/arch/mips/pci/fixup-au1000.c +++ b/arch/mips/pci/fixup-au1000.c @@ -102,7 +102,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { return irq_tab_alchemy[slot][pin]; } - -struct pci_fixup pcibios_fixups[] __initdata = { -{ 0 } -}; diff --git a/arch/mips/pci/fixup-capcella.c b/arch/mips/pci/fixup-capcella.c index 9a0d68ed6..458270a02 100644 --- a/arch/mips/pci/fixup-capcella.c +++ b/arch/mips/pci/fixup-capcella.c @@ -42,7 +42,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { return irq_tab_capcella[slot][pin]; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index f72022a08..84c7e98de 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -41,6 +41,9 @@ static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, + qube_raq_via_bmIDE_fixup); + static void qube_raq_galileo_fixup(struct pci_dev *dev) { unsigned short galileo_id; @@ -73,13 +76,8 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev) } } -struct pci_fixup pcibios_fixups[] __initdata = { - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, - qube_raq_via_bmIDE_fixup}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_GALILEO, PCI_ANY_ID, - qube_raq_galileo_fixup}, - 0 -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_GALILEO, PCI_ANY_ID, + qube_raq_galileo_fixup); static char irq_tab_cobalt[] __initdata = { [COBALT_PCICONF_CPU] = 0, diff --git a/arch/mips/pci/fixup-ddb5074.c b/arch/mips/pci/fixup-ddb5074.c index 025285f9a..785bc03f8 100644 --- a/arch/mips/pci/fixup-ddb5074.c +++ b/arch/mips/pci/fixup-ddb5074.c @@ -17,8 +17,5 @@ static void ddb5074_fixup(struct pci_dev *dev) pci_write_config_byte(dev, 0x7e, t8); } -struct pci_fixup pcibios_fixups[] __initdata = { - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, - ddb5074_fixup }, - {0} -}; +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + ddb5074_fixup); diff --git a/arch/mips/pci/fixup-ddb5477.c b/arch/mips/pci/fixup-ddb5477.c index 985441343..25bf49307 100644 --- a/arch/mips/pci/fixup-ddb5477.c +++ b/arch/mips/pci/fixup-ddb5477.c @@ -41,6 +41,11 @@ static void ddb5477_fixup(struct pci_dev *dev) pci_write_config_byte(dev, 0x41, old | 0xd0); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + ddb5477_fixup); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1535, + ddb5477_fixup); + /* * Fixup baseboard AMD chip so that tx does not underflow. * bcr_18 |= 0x0800 @@ -69,12 +74,5 @@ static void ddb5477_amd_lance_fixup(struct pci_dev *dev) outw(temp, ioaddr + PCNET32_WIO_BDP); } -struct pci_fixup pcibios_fixups[] __initdata = { - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, - ddb5477_fixup }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1535, - ddb5477_fixup }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, - ddb5477_amd_lance_fixup }, - {0} -}; +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, + ddb5477_amd_lance_fixup); diff --git a/arch/mips/pci/fixup-ip32.c b/arch/mips/pci/fixup-ip32.c index 90c67c35f..f64529b7b 100644 --- a/arch/mips/pci/fixup-ip32.c +++ b/arch/mips/pci/fixup-ip32.c @@ -44,7 +44,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { return irq_tab_mace[slot][pin]; } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pci/fixup-jaguar.c b/arch/mips/pci/fixup-jaguar.c index fa78b9b1f..29b6a4615 100644 --- a/arch/mips/pci/fixup-jaguar.c +++ b/arch/mips/pci/fixup-jaguar.c @@ -36,7 +36,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return 0; panic("Whooops in pcibios_map_irq"); } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pci/fixup-lasat.c b/arch/mips/pci/fixup-lasat.c index 49d33ff56..e2ab64ab8 100644 --- a/arch/mips/pci/fixup-lasat.c +++ b/arch/mips/pci/fixup-lasat.c @@ -4,7 +4,3 @@ void __init pcibios_fixup_irqs(void) { } - -struct pci_fixup pcibios_fixups[] __initdata = { - { 0 } -}; diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index 3345e1952..bcde09eea 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c @@ -79,6 +79,8 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev) } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, + malta_piix_func0_fixup); static void __init malta_piix_func1_fixup(struct pci_dev *pdev) { @@ -96,10 +98,5 @@ static void __init malta_piix_func1_fixup(struct pci_dev *pdev) } } -struct pci_fixup pcibios_fixups[] __initdata = { - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - malta_piix_func0_fixup}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, - malta_piix_func1_fixup}, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, + malta_piix_func1_fixup); diff --git a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c index 1320c42af..8e5db12a4 100644 --- a/arch/mips/pci/fixup-mpc30x.c +++ b/arch/mips/pci/fixup-mpc30x.c @@ -42,7 +42,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return irq_tab_mpc30x[slot]; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff --git a/arch/mips/pci/fixup-ocelot-c.c b/arch/mips/pci/fixup-ocelot-c.c index 0cc86eceb..9edc05950 100644 --- a/arch/mips/pci/fixup-ocelot-c.c +++ b/arch/mips/pci/fixup-ocelot-c.c @@ -33,7 +33,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return 0; panic("Whooops in pcibios_map_irq"); } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pci/fixup-ocelot-g.c b/arch/mips/pci/fixup-ocelot-g.c index 9a2cc8505..a79fc4a08 100644 --- a/arch/mips/pci/fixup-ocelot-g.c +++ b/arch/mips/pci/fixup-ocelot-g.c @@ -29,7 +29,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return -1; } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c index 99067c76b..563fb2c89 100644 --- a/arch/mips/pci/fixup-sni.c +++ b/arch/mips/pci/fixup-sni.c @@ -82,7 +82,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return irq_tab_rm200[slot][pin]; } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pci/fixup-tb0219.c b/arch/mips/pci/fixup-tb0219.c index ca4d99fbe..4d62bce5b 100644 --- a/arch/mips/pci/fixup-tb0219.c +++ b/arch/mips/pci/fixup-tb0219.c @@ -58,7 +58,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return irq; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff --git a/arch/mips/pci/fixup-tb0226.c b/arch/mips/pci/fixup-tb0226.c index 50e639e04..6643462f7 100644 --- a/arch/mips/pci/fixup-tb0226.c +++ b/arch/mips/pci/fixup-tb0226.c @@ -77,7 +77,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return irq; } - -struct pci_fixup pcibios_fixups[] __initdata = { - { .pass = 0, }, -}; diff --git a/arch/mips/pci/fixup-yosemite.c b/arch/mips/pci/fixup-yosemite.c index 92e40b091..e39ba2c54 100644 --- a/arch/mips/pci/fixup-yosemite.c +++ b/arch/mips/pci/fixup-yosemite.c @@ -33,7 +33,3 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return 3; /* Everything goes to one irq bit */ } - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c index 3c4183d45..b996766a2 100644 --- a/arch/mips/pci/pci-ip27.c +++ b/arch/mips/pci/pci-ip27.c @@ -329,6 +329,9 @@ static void __init pci_fixup_ioc3(struct pci_dev *d) pci_disable_swapping(d); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, + pci_fixup_ioc3); + static void __init pci_fixup_isp1020(struct pci_dev *d) { struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus); @@ -353,6 +356,9 @@ static void __init pci_fixup_isp1020(struct pci_dev *d) pci_enable_swapping(d); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, + pci_fixup_isp1020); + static void __init pci_fixup_isp2x00(struct pci_dev *d) { struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus); @@ -427,14 +433,7 @@ static void __init pci_fixup_isp2x00(struct pci_dev *d) /*d->resource[1].flags |= 1; */ } -struct pci_fixup pcibios_fixups[] = { - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - pci_fixup_ioc3}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, - pci_fixup_isp1020}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, - pci_fixup_isp2x00}, - {PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200, - pci_fixup_isp2x00}, - {0} -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, + pci_fixup_isp2x00); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200, + pci_fixup_isp2x00); diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c index 18e06ecd4..8c7c385e4 100644 --- a/arch/mips/pci/pci-sb1250.c +++ b/arch/mips/pci/pci-sb1250.c @@ -279,7 +279,3 @@ static int __init sb1250_pcibios_init(void) return 0; } arch_initcall(sb1250_pcibios_init); - -struct pci_fixup pcibios_fixups[] = { - {0} -}; diff --git a/arch/mips/pmc-sierra/yosemite/ht.c b/arch/mips/pmc-sierra/yosemite/ht.c index b9a12e90a..95bbfd013 100644 --- a/arch/mips/pmc-sierra/yosemite/ht.c +++ b/arch/mips/pmc-sierra/yosemite/ht.c @@ -414,11 +414,6 @@ struct pci_ops titan_pci_ops = { titan_ht_config_write_dword }; - -struct pci_fixup pcibios_fixups[] = { - {0} -}; - void __init pcibios_fixup_bus(struct pci_bus *c) { titan_ht_pcibios_fixup_bus(c); diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index 6c6df7b5b..e3cdb9582 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/mips/vr41xx/common/giu.c b/arch/mips/vr41xx/common/giu.c index bd2978fd5..fa93b0331 100644 --- a/arch/mips/vr41xx/common/giu.c +++ b/arch/mips/vr41xx/common/giu.c @@ -63,6 +63,12 @@ static uint32_t giu_base; +static struct irqaction giu_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + #define read_giuint(offset) readw(giu_base + (offset)) #define write_giuint(val, offset) writew((val), giu_base + (offset)) @@ -303,7 +309,6 @@ struct vr41xx_giuint_cascade { }; static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS]; -static struct irqaction giu_cascade = {no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL}; static int no_irq_number(int irq) { diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index 4fd195bc9..19ccb3b56 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -51,6 +51,12 @@ extern void giuint_irq_dispatch(struct pt_regs *regs); static uint32_t icu1_base; static uint32_t icu2_base; +static struct irqaction icu_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + static unsigned char sysint1_assign[16] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char sysint2_assign[16] = { @@ -159,218 +165,268 @@ void vr41xx_enable_piuint(uint16_t mask) { irq_desc_t *desc = irq_desc + PIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MPIUINTREG); - val |= mask; - write_icu1(val, MPIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_piuint); + void vr41xx_disable_piuint(uint16_t mask) { irq_desc_t *desc = irq_desc + PIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MPIUINTREG); - val &= ~mask; - write_icu1(val, MPIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_piuint); + void vr41xx_enable_aiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + AIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MAIUINTREG); - val |= mask; - write_icu1(val, MAIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_aiuint); + void vr41xx_disable_aiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + AIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MAIUINTREG); - val &= ~mask; - write_icu1(val, MAIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_aiuint); + void vr41xx_enable_kiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + KIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MKIUINTREG); - val |= mask; - write_icu1(val, MKIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_kiuint); + void vr41xx_disable_kiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + KIU_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MKIUINTREG); - val &= ~mask; - write_icu1(val, MKIUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_kiuint); + void vr41xx_enable_dsiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + DSIU_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MDSIUINTREG); - val |= mask; - write_icu1(val, MDSIUINTREG); + set_icu1(MDSIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_enable_dsiuint); + void vr41xx_disable_dsiuint(uint16_t mask) { irq_desc_t *desc = irq_desc + DSIU_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu1(MDSIUINTREG); - val &= ~mask; - write_icu1(val, MDSIUINTREG); + clear_icu1(MDSIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_disable_dsiuint); + void vr41xx_enable_firint(uint16_t mask) { irq_desc_t *desc = irq_desc + FIR_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MFIRINTREG); - val |= mask; - write_icu2(val, MFIRINTREG); + set_icu2(MFIRINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_enable_firint); + void vr41xx_disable_firint(uint16_t mask) { irq_desc_t *desc = irq_desc + FIR_IRQ; unsigned long flags; - uint16_t val; spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MFIRINTREG); - val &= ~mask; - write_icu2(val, MFIRINTREG); + clear_icu2(MFIRINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); } +EXPORT_SYMBOL(vr41xx_disable_firint); + void vr41xx_enable_pciint(void) { irq_desc_t *desc = irq_desc + PCI_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(PCIINT0, MPCIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(PCIINT0, MPCIINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_pciint); + void vr41xx_disable_pciint(void) { irq_desc_t *desc = irq_desc + PCI_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(0, MPCIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MPCIINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_pciint); + void vr41xx_enable_scuint(void) { irq_desc_t *desc = irq_desc + SCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(SCUINT0, MSCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(SCUINT0, MSCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_scuint); + void vr41xx_disable_scuint(void) { irq_desc_t *desc = irq_desc + SCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(0, MSCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MSCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_scuint); + void vr41xx_enable_csiint(uint16_t mask) { irq_desc_t *desc = irq_desc + CSI_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MCSIINTREG); - val |= mask; - write_icu2(val, MCSIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + set_icu2(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_csiint); + void vr41xx_disable_csiint(uint16_t mask) { irq_desc_t *desc = irq_desc + CSI_IRQ; unsigned long flags; - uint16_t val; - spin_lock_irqsave(&desc->lock, flags); - val = read_icu2(MCSIINTREG); - val &= ~mask; - write_icu2(val, MCSIINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu2(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_csiint); + void vr41xx_enable_bcuint(void) { irq_desc_t *desc = irq_desc + BCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(BCUINTR, MBCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(BCUINTR, MBCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_enable_bcuint); + void vr41xx_disable_bcuint(void) { irq_desc_t *desc = irq_desc + BCU_IRQ; unsigned long flags; - spin_lock_irqsave(&desc->lock, flags); - write_icu2(0, MBCUINTREG); - spin_unlock_irqrestore(&desc->lock, flags); + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MBCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } } +EXPORT_SYMBOL(vr41xx_disable_bcuint); + /*=======================================================================*/ static unsigned int startup_sysint1_irq(unsigned int irq) @@ -674,8 +730,6 @@ early_initcall(vr41xx_icu_init); /*=======================================================================*/ -static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL}; - static inline void init_vr41xx_icu_irq(void) { int i; diff --git a/arch/mips/vr41xx/common/serial.c b/arch/mips/vr41xx/common/serial.c index cc445eeff..939ac827e 100644 --- a/arch/mips/vr41xx/common/serial.c +++ b/arch/mips/vr41xx/common/serial.c @@ -115,7 +115,7 @@ void __init vr41xx_siu_init(void) port.line = vr41xx_serial_ports; port.uartclk = SIU_BASE_BAUD * 16; port.irq = SIU_IRQ; - port.flags = UPF_RESOURCES | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; switch (current_cpu_data.cputype) { case CPU_VR4111: case CPU_VR4121: @@ -160,7 +160,7 @@ void __init vr41xx_dsiu_init(void) port.line = vr41xx_serial_ports; port.uartclk = DSIU_BASE_BAUD * 16; port.irq = DSIU_IRQ; - port.flags = UPF_RESOURCES | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.mapbase = DSIU_BASE; port.regshift = 0; port.iotype = UPIO_MEM; diff --git a/arch/mips/vr41xx/common/vrc4173.c b/arch/mips/vr41xx/common/vrc4173.c index 3b006358c..0bbad1e8c 100644 --- a/arch/mips/vr41xx/common/vrc4173.c +++ b/arch/mips/vr41xx/common/vrc4173.c @@ -316,6 +316,96 @@ static inline void vrc4173_giu_init(void) spin_lock_init(&vrc4173_giu_lock); } +void vrc4173_enable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MPIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MPIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_eanble_piuint); + +void vrc4173_disable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MPIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MPIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_piuint); + +void vrc4173_enable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MAIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MAIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_aiuint); + +void vrc4173_disable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MAIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MAIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_aiuint); + +void vrc4173_enable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MKIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MKIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_kiuint); + +void vrc4173_disable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MKIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MKIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_kiuint); + static void enable_vrc4173_irq(unsigned int irq) { uint16_t val; diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 9e37d3dfe..4bdec1e0f 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -106,7 +106,7 @@ config PARISC64 depends on PA8X00 help Enable this if you want to support 64bit kernel on PA-RISC platform. - + At the moment, only people willing to use more than 2GB of RAM, or having a 64bit-only capable PA-RISC machine should say Y here. @@ -188,76 +188,10 @@ source "fs/Kconfig" source "arch/parisc/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_RWLOCK - bool "Read-write spinlock debugging" - depends on DEBUG_KERNEL && SMP - help - If you say Y here then read-write lock processing will count how many - times it has tried to get the lock and issue an error message after - too many attempts. If you suspect a rwlock problem or a kernel - hacker asks for this option then say Y. Otherwise say N. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -endmenu +source "arch/parisc/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug new file mode 100644 index 000000000..8caaed187 --- /dev/null +++ b/arch/parisc/Kconfig.debug @@ -0,0 +1,14 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_RWLOCK + bool "Read-write spinlock debugging" + depends on DEBUG_KERNEL && SMP + help + If you say Y here then read-write lock processing will count how many + times it has tried to get the lock and issue an error message after + too many attempts. If you suspect a rwlock problem or a kernel + hacker asks for this option then say Y. Otherwise say N. + +endmenu diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index b032c6b79..adffb0504 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -4,7 +4,7 @@ head-y := head.o head-$(CONFIG_PARISC64) := head64.o -extra-y := init_task.o $(head-y) vmlinux.lds.s +extra-y := init_task.o $(head-y) vmlinux.lds AFLAGS_entry.o := -traditional AFLAGS_pacache.o := -traditional diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c index 64d49cb2d..cf8a8583f 100644 --- a/arch/parisc/kernel/asm-offsets.c +++ b/arch/parisc/kernel/asm-offsets.c @@ -32,11 +32,11 @@ #include #include #include -#include +#include +#include #include #include -#include #include #define DEFINE(sym, val) \ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index eadc88c5a..0703ab036 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -245,7 +245,7 @@ void disable_sr_hashing(void) void flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); - struct vm_area_struct *mpnt = NULL; + struct vm_area_struct *mpnt; struct prio_tree_iter iter; unsigned long offset; unsigned long addr; @@ -272,8 +272,7 @@ void flush_dcache_page(struct page *page) * to flush one address here for them all to become coherent */ flush_dcache_mmap_lock(mapping); - while ((mpnt = vma_prio_tree_next(mpnt, &mapping->i_mmap, - &iter, pgoff, pgoff)) != NULL) { + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c index 6b65bf468..4abd43910 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 + * Copyright 1999 by Alex deVries * 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/pci.c b/arch/parisc/kernel/pci.c index 937ab23ca..3cb08a4a5 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -146,15 +146,6 @@ char *pcibios_setup(char *str) return str; } -/* Used in drivers/pci/quirks.c */ -struct pci_fixup pcibios_fixups[] = { -#ifdef CONFIG_SUPERIO - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci }, -#endif - { 0 } -}; - - /* * Called by pci_set_master() - a driver interface. * diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index dd938ef77..d7365b958 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/ptrace.c b/arch/parisc/kernel/ptrace.c index 514e8b5f8..598aadd36 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -404,11 +404,8 @@ void syscall_trace(void) return; if (!(current->ptrace & PT_PTRACED)) return; - 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 * for normal use. strace only continues with a signal if the diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 0f1daa584..9def95a43 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -485,24 +485,6 @@ void __init smp_callin(void) panic("smp_callin() AAAAaaaaahhhh....\n"); } -/* - * 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, ®s, 0, NULL, NULL); -} - - /* * Bring one cpu online. */ @@ -521,13 +503,10 @@ int __init smp_boot_one_cpu(int cpuid) * Sheesh . . . */ - idle = fork_by_hand(); + idle = fork_idle(cpuid); 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->thread_info->cpu = cpuid; /* Let _start know what logical CPU we're booting diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 949998ffb..8f4ad0cf2 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -47,44 +47,6 @@ static long halftick; extern void smp_do_timer(struct pt_regs *regs); #endif -static inline void -parisc_do_profile(struct pt_regs *regs) -{ - unsigned long pc = regs->iaoq[0]; -#if 0 - extern unsigned long prof_cpu_mask; -#endif - extern char _stext; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - -#if 0 - /* FIXME: when we have irq affinity to cpu, we need to - * only look at the cpus specified in this mask - */ - - if (!((1 << smp_processor_id()) & prof_cpu_mask)) - return; -#endif - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { long now; @@ -92,7 +54,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) int nticks; int cpu = smp_processor_id(); - parisc_do_profile(regs); + profile_tick(CPU_PROFILING, regs); now = mfctl(16); /* initialize next_tick to time at last clocktick */ diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 7da318ed0..e011bc856 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -52,6 +52,7 @@ SECTIONS .text ALIGN(16) : { *(.text) SCHED_TEXT + LOCK_TEXT *(.text.do_softirq) *(.text.sys_exit) *(.text.do_sigaltstack) @@ -130,9 +131,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/lib/debuglocks.c b/arch/parisc/lib/debuglocks.c index 7e79f1bad..5166a9378 100644 --- a/arch/parisc/lib/debuglocks.c +++ b/arch/parisc/lib/debuglocks.c @@ -25,8 +25,8 @@ #include #include #include +#include /* in_interrupt() */ #include -#include /* in_interrupt() */ #undef INIT_STUCK #define INIT_STUCK 1L << 30 diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 871d7df27..065da5807 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/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index d56a031e6..41ca12432 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -1986,9 +1986,9 @@ fcc_restart(struct net_device *dev, int duplex) fccp = fcp->fccp; if (duplex) - fccp->fcc_fpsmr |= FCC_PSMR_FDE; + fccp->fcc_fpsmr |= FCC_PSMR_FDE | FCC_PSMR_LPB; else - fccp->fcc_fpsmr &= ~FCC_PSMR_FDE; + fccp->fcc_fpsmr &= ~(FCC_PSMR_FDE | FCC_PSMR_LPB); /* Enable transmit/receive */ fccp->fcc_gfmr |= FCC_GFMR_ENR | FCC_GFMR_ENT; diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 171e5e900..34a463a94 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 cc4e6b9db..46139ac97 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -49,7 +49,7 @@ config 6xx There are four types of PowerPC chips supported. The more common types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions (821, 823, 850, 855, 860, 52xx, 8260), the IBM embedded - versions (403 and 405) and the high end 64 bit Power processors + versions (403 and 405) and the high end 64 bit Power processors (POWER 3, POWER4, and IBM 970 also known as G5) Unless you are building a kernel for one of the embedded processor systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx. @@ -626,7 +626,7 @@ config EMBEDDEDBOOT bool depends on 8xx || 8260 default y - + config PPC_MPC52xx bool @@ -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" @@ -1043,13 +1041,13 @@ config PCI_8260 bool depends on PCI && 8260 && !8272 default y - + config 8260_PCI9 bool " Enable workaround for MPC826x erratum PCI 9" depends on PCI_8260 default y -choice +choice prompt " IDMA channel for PCI 9 workaround" depends on 8260_PCI9 @@ -1228,128 +1226,7 @@ source "lib/Kconfig" source "arch/ppc/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and to CONFIG_SMP to include code to check for missing - spinlock initialization and some other common spinlock errors. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This options enables additional error checking for high memory - systems. Disable for production systems. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - depends on DEBUG_KERNEL - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -config KGDB - bool "Include kgdb kernel debugger" - depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) - select DEBUG_INFO - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -choice - prompt "Serial Port" - depends on KGDB - default KGDB_TTYS1 - -config KGDB_TTYS0 - bool "ttyS0" - -config KGDB_TTYS1 - bool "ttyS1" - -config KGDB_TTYS2 - bool "ttyS2" - -config KGDB_TTYS3 - bool "ttyS3" - -endchoice - -config KGDB_CONSOLE - bool "Enable serial console thru kgdb port" - depends on KGDB && 8xx || CPM2 - help - If you enable this, all serial console messages will be sent - over the gdb stub. - If unsure, say N. - -config XMON - bool "Include xmon kernel debugger" - depends on DEBUG_KERNEL - help - Include in-kernel hooks for the xmon kernel monitor/debugger. - Unless you are intending to debug the kernel, say N here. - -config BDI_SWITCH - bool "Include BDI-2000 user context switcher" - depends on DEBUG_KERNEL - help - Include in-kernel support for the Abatron BDI2000 debugger. - Unless you are intending to debug the kernel with one of these - machines, say N here. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use some sort of debugger to - debug the kernel. - If you don't debug the kernel, you can say N. - -config BOOTX_TEXT - bool "Support for early boot text console (BootX or OpenFirmware only)" - depends PPC_OF - help - Say Y here to see progress messages from the boot firmware in text - mode. Requires either BootX or Open Firmware. - -config SERIAL_TEXT_DEBUG - bool "Support for early boot texts over serial port" - depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx - -config PPC_OCP - bool - depends on IBM_OCP || FSL_OCP - default y - -endmenu +source "arch/ppc/Kconfig.debug" source "security/Kconfig" diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug new file mode 100644 index 000000000..0df281455 --- /dev/null +++ b/arch/ppc/Kconfig.debug @@ -0,0 +1,84 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) + select DEBUG_INFO + help + Include in-kernel hooks for kgdb, the Linux kernel source level + debugger. See for more information. + Unless you are intending to debug the kernel, say N here. + +choice + prompt "Serial Port" + depends on KGDB + default KGDB_TTYS1 + +config KGDB_TTYS0 + bool "ttyS0" + +config KGDB_TTYS1 + bool "ttyS1" + +config KGDB_TTYS2 + bool "ttyS2" + +config KGDB_TTYS3 + bool "ttyS3" + +endchoice + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB && 8xx || CPM2 + help + If you enable this, all serial console messages will be sent + over the gdb stub. + If unsure, say N. + +config XMON + bool "Include xmon kernel debugger" + depends on DEBUG_KERNEL + help + Include in-kernel hooks for the xmon kernel monitor/debugger. + Unless you are intending to debug the kernel, say N here. + +config BDI_SWITCH + bool "Include BDI-2000 user context switcher" + depends on DEBUG_KERNEL + help + Include in-kernel support for the Abatron BDI2000 debugger. + 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 + help + Say Y here to see progress messages from the boot firmware in text + mode. Requires either BootX or Open Firmware. + +config SERIAL_TEXT_DEBUG + bool "Support for early boot texts over serial port" + depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx + +config PPC_OCP + bool + depends on IBM_OCP || FSL_OCP + default y + +endmenu diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index e15c6919a..53dd5640d 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -13,7 +13,7 @@ # This must match PAGE_OFFSET in include/asm-ppc/page.h. KERNELLOAD := $(CONFIG_KERNEL_START) -HAS_BIARCH := $(shell if $(CC) -m32 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;) +HAS_BIARCH := $(call cc-option-yn, -m32) ifeq ($(HAS_BIARCH),y) AS := $(AS) -a32 LD := $(LD) -m elf32ppc @@ -24,10 +24,10 @@ LDFLAGS_vmlinux := -Ttext $(KERNELLOAD) -Bstatic CPPFLAGS += -Iarch/$(ARCH) AFLAGS += -Iarch/$(ARCH) CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe \ - -ffixed-r2 -Wno-uninitialized -mmultiple + -ffixed-r2 -mmultiple CPP = $(CC) -E $(CFLAGS) -CHECK := $(CHECK) -D__powerpc__=1 +CHECKFLAGS += -D__powerpc__ ifndef CONFIG_E500 CFLAGS += -mstring @@ -70,7 +70,7 @@ BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm all: zImage -AFLAGS_vmlinux.lds.o := -Upowerpc +CPPFLAGS_vmlinux.lds := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage @@ -104,16 +104,15 @@ arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s $(call filechk,gen-asm-offsets) -ifdef CONFIG_6xx -# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later -NEW_AS := $(shell echo dssall | $(AS) -many -o /dev/null >/dev/null 2>&1 ; echo $$?) -GOODVER := 2.12.1 -else -NEW_AS := 0 -endif +# Use the file '.tmp_gas_check' for binutils tests, as gas won't output +# to stdout and these checks are run even on install targets. +TOUT := .tmp_gas_check +# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec +# instructions. +AS_ALTIVEC := $(shell echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; echo $$?) # gcc-3.4 and binutils-2.14 are a fatal combination. -GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) -BAD_GCC_AS := $(shell echo mftb 5 | $(AS) -mppc -many -o /dev/null >/dev/null 2>&1 && echo 0 || echo 1) +GCC_VERSION := $(call cc-version) +BAD_GCC_AS := $(shell echo mftb 5 | $(AS) -mppc -many -o $(TOUT) >/dev/null 2>&1 && echo 0 || echo 1) checkbin: ifeq ($(GCC_VERSION)$(BAD_GCC_AS),03041) @@ -122,13 +121,16 @@ ifeq ($(GCC_VERSION)$(BAD_GCC_AS),03041) @echo '*** Please upgrade your binutils or downgrade your gcc' @false endif -ifneq ($(NEW_AS),0) +ifneq ($(AS_ALTIVEC),0) + echo $(AS_ALTIVEC) @echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' @echo 'correctly with old versions of binutils.' - @echo '*** Please upgrade your binutils to ${GOODVER} or newer' + @echo '*** Please upgrade your binutils to 2.12.1 or newer' @false endif @true CLEAN_FILES += include/asm-$(ARCH)/offsets.h \ - arch/$(ARCH)/kernel/asm-offsets.s + arch/$(ARCH)/kernel/asm-offsets.s \ + $(TOUT) + diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c index cc93c9eb3..af881d745 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/Makefile b/arch/ppc/boot/Makefile index 8c1d7eb8b..995f89bb0 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -23,12 +23,12 @@ subdir-$(CONFIG_PPC_OF) += of1275 # for cleaning subdir- += simple openfirmware -host-progs := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree) +hostprogs-y := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree) .PHONY: $(BOOT_TARGETS) $(bootdir-y) $(BOOT_TARGETS): $(bootdir-y) $(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \ - $(addprefix $(obj)/,$(host-progs)) + $(addprefix $(obj)/,$(hostprogs-y)) $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS) diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c index 868fa81b7..7acd03b31 100644 --- a/arch/ppc/boot/common/misc-common.c +++ b/arch/ppc/boot/common/misc-common.c @@ -17,7 +17,7 @@ #include /* for va_ bits */ #include #include -#include "zlib.h" +#include #include "nonstdio.h" /* If we're on a PReP, assume we have a keyboard controller @@ -202,11 +202,10 @@ void error(char *x) while(1); /* Halt */ } -void *zalloc(void *x, unsigned items, unsigned size) +static void *zalloc(unsigned size) { void *p = avail_ram; - size *= items; size = (size + 7) & -8; avail_ram += size; if (avail_ram > end_avail) { @@ -216,18 +215,12 @@ void *zalloc(void *x, unsigned items, unsigned size) return p; } -void zfree(void *x, void *addr, unsigned nb) -{ -} - #define HEAD_CRC 2 #define EXTRA_FIELD 4 #define ORIG_NAME 8 #define COMMENT 0x10 #define RESERVED 0xe0 -#define DEFLATED 8 - void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) { z_stream s; @@ -236,7 +229,7 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) /* skip header */ i = 10; flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { puts("bad gzipped data\n"); exit(); } @@ -255,24 +248,24 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) exit(); } - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); + /* Initialize ourself. */ + s.workspace = zalloc(zlib_inflate_workspacesize()); + r = zlib_inflateInit2(&s, -MAX_WBITS); if (r != Z_OK) { - puts("inflateInit2 returned "); puthex(r); puts("\n"); + puts("zlib_inflateInit2 returned "); puthex(r); puts("\n"); exit(); } s.next_in = src + i; s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); + r = zlib_inflate(&s, Z_FINISH); if (r != Z_OK && r != Z_STREAM_END) { puts("inflate returned "); puthex(r); puts("\n"); exit(); } *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); + zlib_inflateEnd(&s); } void @@ -526,6 +519,11 @@ _dump_buf(unsigned char *p, int s) * on others it's an offset from a given location. -- Tom */ +void ISA_init(unsigned long base) +{ + ISA_io = (unsigned char *)base; +} + void outb(int port, unsigned char val) { diff --git a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c index 8eb07a63f..9017c547a 100644 --- a/arch/ppc/boot/common/ns16550.c +++ b/arch/ppc/boot/common/ns16550.c @@ -5,14 +5,14 @@ #include #include #include -#include #include #include +#include "nonstdio.h" +#include "serial.h" + #define SERIAL_BAUD 9600 -extern void outb(int port, unsigned char val); -extern unsigned char inb(int port); extern unsigned long ISA_io; static struct serial_state rs_table[RS_TABLE_SIZE] = { diff --git a/arch/ppc/boot/common/serial_stub.c b/arch/ppc/boot/common/serial_stub.c index 2dc176ed0..03dfaa01f 100644 --- a/arch/ppc/boot/common/serial_stub.c +++ b/arch/ppc/boot/common/serial_stub.c @@ -11,11 +11,6 @@ * is" without any warranty of any kind, whether express or implied. */ -void __attribute__ ((weak)) -serial_fixups(void) -{ -} - unsigned long __attribute__ ((weak)) serial_init(int chan, void *ignored) { diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S index 93771e298..7c4fb8f57 100644 --- a/arch/ppc/boot/common/util.S +++ b/arch/ppc/boot/common/util.S @@ -41,7 +41,7 @@ disable_6xx_mmu: /* Test for a 601 */ mfpvr r10 srwi r10,r10,16 - cmpi 0,r10,1 /* 601 ? */ + cmpwi 0,r10,1 /* 601 ? */ beq .clearbats_601 /* Clear BATs */ @@ -117,9 +117,9 @@ _setup_L2CR: /* Wait for the invalidation to complete */ mfspr r8,PVR srwi r8,r8,16 - cmpli cr0,r8,0x8000 /* 7450 */ - cmpli cr1,r8,0x8001 /* 7455 */ - cmpli cr2,r8,0x8002 /* 7457 */ + cmplwi cr0,r8,0x8000 /* 7450 */ + cmplwi cr1,r8,0x8001 /* 7455 */ + cmplwi cr2,r8,0x8002 /* 7457 */ cror 4*cr0+eq,4*cr0+eq,4*cr1+eq /* Now test if any are true. */ cror 4*cr0+eq,4*cr0+eq,4*cr2+eq bne 2f @@ -190,7 +190,7 @@ timebase_period_ns: udelay: mfspr r4,PVR srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ + cmpwi 0,r4,1 /* 601 ? */ bne .udelay_not_601 00: li r0,86 /* Instructions / microsecond? */ mtctr r0 @@ -213,16 +213,16 @@ udelay: 1: mftbu r5 mftb r6 mftbu r7 - cmp 0,r5,r7 + cmpw 0,r5,r7 bne 1b /* Get [synced] base time */ addc r9,r6,r4 /* Compute end time */ addze r8,r5 2: mftbu r5 - cmp 0,r5,r8 + cmpw 0,r5,r8 blt 2b bgt 3f mftb r6 - cmp 0,r6,r9 + cmpw 0,r6,r9 blt 2b 3: blr diff --git a/arch/ppc/boot/include/nonstdio.h b/arch/ppc/boot/include/nonstdio.h index 7a0f027f9..f2b5526fa 100644 --- a/arch/ppc/boot/include/nonstdio.h +++ b/arch/ppc/boot/include/nonstdio.h @@ -30,3 +30,5 @@ extern void puthex(unsigned long val); extern void puts(const char *); extern void udelay(long delay); extern unsigned char inb(int port); +extern void board_isa_init(void); +extern void ISA_init(unsigned long base); diff --git a/arch/ppc/boot/include/serial.h b/arch/ppc/boot/include/serial.h new file mode 100644 index 000000000..d710eabb4 --- /dev/null +++ b/arch/ppc/boot/include/serial.h @@ -0,0 +1,46 @@ +/* + * A really private header file for the (dumb) serial driver in arch/ppc/boot + * + * Shamelessly taken from include/linux/serialP.h: + * + * Copyright (C) 1997 by Theodore Ts'o. + * + * Redistribution of this file is permitted under the terms of the GNU + * Public License (GPL) + */ + +#ifndef _PPC_BOOT_SERIALP_H +#define _PPC_BOOT_SERIALP_H + +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * Given that this is how SERIAL_PORT_DFNS are done, and that we need + * to use a few of their fields, we need to have our own copy of it. + */ +struct serial_state { + int magic; + int baud_base; + unsigned long port; + int irq; + int flags; + int hub6; + int type; + int line; + int revision; /* Chip revision (950) */ + int xmit_fifo_size; + int custom_divisor; + int count; + u8 *iomem_base; + u16 iomem_reg_shift; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + unsigned long icount; + int io_type; + void *info; + void *dev; +}; +#endif /* _PPC_BOOT_SERIAL_H */ diff --git a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile index 97ef7d19e..9d088a566 100644 --- a/arch/ppc/boot/lib/Makefile +++ b/arch/ppc/boot/lib/Makefile @@ -4,5 +4,7 @@ CFLAGS_kbd.o += -Idrivers/char -lib-y := zlib.o div64.o +lib-y := $(addprefix ../../../../lib/zlib_inflate/, \ + infblock.o infcodes.o inffast.o inflate.o inftrees.o infutil.o) +lib-y += div64.o lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o diff --git a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c index 94c23c0c9..04ba9d57e 100644 --- a/arch/ppc/boot/openfirmware/coffmain.c +++ b/arch/ppc/boot/openfirmware/coffmain.c @@ -12,7 +12,6 @@ #include "nonstdio.h" #include "of1275.h" -#include "zlib.h" /* Passed from the linker */ extern char __image_begin, __image_end; diff --git a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c index 71195067c..9e6952781 100644 --- a/arch/ppc/boot/openfirmware/common.c +++ b/arch/ppc/boot/openfirmware/common.c @@ -7,10 +7,10 @@ * 2 of the License, or (at your option) any later version. */ -#include "zlib.h" #include "nonstdio.h" #include "of1275.h" #include +#include #include #include @@ -30,12 +30,11 @@ struct memchunk { static struct memchunk *freechunks; -static void *zalloc(void *x, unsigned items, unsigned size) +static void *zalloc(unsigned size) { void *p; struct memchunk **mpp, *mp; - size *= items; size = (size + 7) & -8; heap_use += size; if (heap_use > heap_max) @@ -57,74 +56,57 @@ static void *zalloc(void *x, unsigned items, unsigned size) return p; } -static void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = (nb + 7) & -8; - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - #define HEAD_CRC 2 #define EXTRA_FIELD 4 #define ORIG_NAME 8 #define COMMENT 0x10 #define RESERVED 0xe0 -#define DEFLATED 8 - void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) { - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n\r"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n\r"); - exit(); - } + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n\r", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); + /* Initialize ourself. */ + s.workspace = zalloc(zlib_inflate_workspacesize()); + r = zlib_inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("zlib_inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = zlib_inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + zlib_inflateEnd(&s); } /* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, diff --git a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S index 844c0bca2..ab9e897ca 100644 --- a/arch/ppc/boot/openfirmware/misc.S +++ b/arch/ppc/boot/openfirmware/misc.S @@ -16,7 +16,7 @@ setup_bats: mfpvr 5 rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,5,1 + cmpwi 0,5,1 li 0,0 bne 4f mtibatl 3,0 /* invalidate BAT first */ diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile index e31b7e499..895b55750 100644 --- a/arch/ppc/boot/simple/Makefile +++ b/arch/ppc/boot/simple/Makefile @@ -64,6 +64,7 @@ zimageinitrd-$(CONFIG_EBONY) := zImage.initrd-TREE zimageinitrd-$(CONFIG_OCOTEA) := zImage.initrd-TREE end-$(CONFIG_OCOTEA) := ocotea entrypoint-$(CONFIG_OCOTEA) := 0x01000000 + extra.o-$(CONFIG_OCOTEA) := pibs.o extra.o-$(CONFIG_EV64260) := direct.o misc-ev64260.o end-$(CONFIG_EV64260) := ev64260 @@ -73,7 +74,7 @@ zimageinitrd-$(CONFIG_OCOTEA) := zImage.initrd-TREE zimageinitrd-$(CONFIG_GEMINI) := zImage.initrd-STRIPELF end-$(CONFIG_GEMINI) := gemini - extra.o-$(CONFIG_K2) := legacy.o + extra.o-$(CONFIG_K2) := prepmap.o end-$(CONFIG_K2) := k2 cacheflag-$(CONFIG_K2) := -include $(clear_L2_L3) @@ -89,7 +90,7 @@ zimageinitrd-$(motorola) := zImage.initrd-PPLUS end-$(motorola) := pplus # Overrides previous assingment - extra.o-$(CONFIG_PPLUS) := legacy.o + extra.o-$(CONFIG_PPLUS) := prepmap.o extra.o-$(CONFIG_LOPEC) := mpc10x_memory.o zimage-$(pcore) := zImage-STRIPELF @@ -100,7 +101,7 @@ zimageinitrd-$(pcore) := zImage.initrd-STRIPELF zimage-$(CONFIG_PPC_PREP) := zImage-PPLUS zimageinitrd-$(CONFIG_PPC_PREP) := zImage.initrd-PPLUS - extra.o-$(CONFIG_PPC_PREP) := legacy.o + extra.o-$(CONFIG_PPC_PREP) := prepmap.o misc-$(CONFIG_PPC_PREP) += misc-prep.o mpc10x_memory.o end-$(CONFIG_PPC_PREP) := prep diff --git a/arch/ppc/boot/simple/chrpmap.c b/arch/ppc/boot/simple/chrpmap.c new file mode 100644 index 000000000..14d9e05d9 --- /dev/null +++ b/arch/ppc/boot/simple/chrpmap.c @@ -0,0 +1,12 @@ +/* + * 2004 (C) IBM. 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 + +void board_isa_init(void) +{ + ISA_init(0xFE000000); +} diff --git a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c index 58e2a92e8..8615d5f22 100644 --- a/arch/ppc/boot/simple/misc-embedded.c +++ b/arch/ppc/boot/simple/misc-embedded.c @@ -22,7 +22,6 @@ #endif #include "nonstdio.h" -#include "zlib.h" /* The linker tells us where the image is. */ extern char __image_begin, __image_end; @@ -72,6 +71,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/boot/simple/misc-prep.c b/arch/ppc/boot/simple/misc-prep.c index da29deca4..75380ac41 100644 --- a/arch/ppc/boot/simple/misc-prep.c +++ b/arch/ppc/boot/simple/misc-prep.c @@ -88,6 +88,7 @@ load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, ofinit(OFW_interface); } + board_isa_init(); #if defined(CONFIG_VGA_CONSOLE) vga_init((unsigned char *)0xC0000000); #endif /* CONFIG_VGA_CONSOLE */ diff --git a/arch/ppc/boot/simple/misc-spruce.c b/arch/ppc/boot/simple/misc-spruce.c index fa181ffb7..d012c3927 100644 --- a/arch/ppc/boot/simple/misc-spruce.c +++ b/arch/ppc/boot/simple/misc-spruce.c @@ -26,7 +26,6 @@ extern unsigned long decompress_kernel(unsigned long load_addr, int num_words, /* Define some important locations of the Spruce. */ #define SPRUCE_PCI_CONFIG_ADDR 0xfec00000 #define SPRUCE_PCI_CONFIG_DATA 0xfec00004 -#define SPRUCE_ISA_IO_BASE 0xf8000000 /* PCI configuration space access routines. */ unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR; @@ -86,8 +85,6 @@ void cpc700_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, out_le32((unsigned *)pci_config_data, val); } -unsigned long isa_io_base = SPRUCE_ISA_IO_BASE; - #define PCNET32_WIO_RDP 0x10 #define PCNET32_WIO_RAP 0x12 #define PCNET32_WIO_RESET 0x14 diff --git a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c index f09af4f28..1b2ae8d77 100644 --- a/arch/ppc/boot/simple/misc.c +++ b/arch/ppc/boot/simple/misc.c @@ -29,7 +29,6 @@ #include #include "nonstdio.h" -#include "zlib.h" /* Default cmdline */ #ifdef CONFIG_CMDLINE @@ -49,7 +48,9 @@ * Val Henson has requested that Gemini doesn't wait for the * user to edit the cmdline or not. */ -#if (defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \ +#if (defined(CONFIG_SERIAL_8250_CONSOLE) \ + || defined(CONFIG_VGA_CONSOLE) \ + || defined(CONFIG_SERIAL_MPC52xx_CONSOLE)) \ && !defined(CONFIG_GEMINI) #define INTERACTIVE_CONSOLE 1 #endif @@ -95,9 +96,8 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) #endif char *cp; struct bi_record *rec; - unsigned long initrd_loc, TotalMemory = 0; + unsigned long initrd_loc = 0, TotalMemory = 0; - serial_fixups(); #ifdef CONFIG_SERIAL_8250_CONSOLE com_port = serial_init(0, NULL); #endif @@ -221,7 +221,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) puts("\n"); puts("Uncompressing Linux..."); - gunzip(NULL, 0x400000, zimage_start, &zimage_size); + gunzip(0x0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); /* get the bi_rec address */ @@ -268,10 +268,16 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) return rec; } +void __attribute__ ((weak)) +board_isa_init(void) +{ +} + /* Allow decompress_kernel to be hooked into. This is the default. */ void * __attribute__ ((weak)) load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, void *ign1, void *ign2) { + board_isa_init(); return decompress_kernel(load_addr, num_words, cksum); } diff --git a/arch/ppc/boot/simple/pibs.c b/arch/ppc/boot/simple/pibs.c new file mode 100644 index 000000000..9ce8847d2 --- /dev/null +++ b/arch/ppc/boot/simple/pibs.c @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +extern unsigned long decompress_kernel(unsigned long load_addr, int num_words, + unsigned long cksum); + +/* We need to make sure that this is before the images to ensure + * that it's in a mapped location. - Tom */ +bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot"))); +bd_t *hold_residual = &hold_resid_buf; + +/* String functions lifted from lib/vsprintf.c and lib/ctype.c */ +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + +/** + * simple_strtoull - convert a string to an unsigned long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) +{ + unsigned long long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } else if (base == 16) { + if (cp[0] == '0' && toupper(cp[1]) == 'X') + cp += 2; + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +void * +load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, + void *ign1, void *ign2) +{ + unsigned long long mac64; + + decompress_kernel(load_addr, num_words, cksum); + + mac64 = simple_strtoull((char *)OCOTEA_PIBS_MAC_BASE, 0, 16); + memcpy(hold_residual->bi_enetaddr, (char *)&mac64+2, 6); + mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET), 0, 16); + memcpy(hold_residual->bi_enet1addr, (char *)&mac64+2, 6); + mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*2), 0, 16); + memcpy(hold_residual->bi_enet2addr, (char *)&mac64+2, 6); + mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*3), 0, 16); + memcpy(hold_residual->bi_enet3addr, (char *)&mac64+2, 6); + return (void *)hold_residual; +} diff --git a/arch/ppc/boot/simple/prepmap.c b/arch/ppc/boot/simple/prepmap.c new file mode 100644 index 000000000..c871a4db6 --- /dev/null +++ b/arch/ppc/boot/simple/prepmap.c @@ -0,0 +1,12 @@ +/* + * 2004 (C) IBM. 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 + +void board_isa_init(void) +{ + ISA_init(0x80000000); +} diff --git a/arch/ppc/boot/simple/relocate.S b/arch/ppc/boot/simple/relocate.S index e57d9673e..555a216cc 100644 --- a/arch/ppc/boot/simple/relocate.S +++ b/arch/ppc/boot/simple/relocate.S @@ -50,7 +50,7 @@ relocate: * Check if we need to relocate ourselves to the link addr or were * we loaded there to begin with. */ - cmp cr0,r3,r4 + cmpw cr0,r3,r4 beq start_ldr /* If 0, we don't need to relocate */ /* Move this code somewhere safe. This is max(load + size, end) @@ -122,7 +122,7 @@ do_relocate: GETSYM(r4, start) mr r3,r8 /* Get the load addr */ - cmp cr0,r4,r3 /* If we need to copy from the end, do so */ + cmpw cr0,r4,r3 /* If we need to copy from the end, do so */ bgt do_relocate_from_end do_relocate_from_start: @@ -165,7 +165,7 @@ start_ldr: subi r4,r4,4 li r0,0 50: stwu r0,4(r3) - cmp cr0,r3,r4 + cmpw cr0,r3,r4 bne 50b 90: mr r9,r1 /* Save old stack pointer (in case it matters) */ lis r1,.stack@h diff --git a/arch/ppc/boot/utils/mkbugboot.c b/arch/ppc/boot/utils/mkbugboot.c index 8158d8c6f..f6629a28e 100644 --- a/arch/ppc/boot/utils/mkbugboot.c +++ b/arch/ppc/boot/utils/mkbugboot.c @@ -1,5 +1,5 @@ /* - * arch/ppc/pp3boot/mkbugboot.c + * arch/ppc/boot/utils/mkbugboot.c * * Makes a Motorola PPCBUG ROM bootable image which can be flashed * into one of the FLASH banks on a Motorola PowerPlus board. @@ -21,6 +21,11 @@ #include #include #include +#ifdef __sun__ +#include +#else +#include +#endif #ifdef __i386__ #define cpu_to_be32(x) le32_to_cpu(x) @@ -49,11 +54,6 @@ unsigned short le16_to_cpu(unsigned short x) /* size of read buffer */ #define SIZE 0x1000 -/* typedef long int32_t; */ -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -typedef unsigned char uint8_t; - /* PPCBUG ROM boot header */ typedef struct bug_boot_header { uint8_t magic_word[4]; /* "BOOT" */ diff --git a/arch/ppc/boot/utils/mktree.c b/arch/ppc/boot/utils/mktree.c index 7ef98c077..2be22e28f 100644 --- a/arch/ppc/boot/utils/mktree.c +++ b/arch/ppc/boot/utils/mktree.c @@ -15,7 +15,11 @@ #include #include #include +#ifdef __sun__ +#include +#else #include +#endif /* This gets tacked on the front of the image. There are also a few * bytes allocated after the _start label used by the boot rom (see diff --git a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig index 6e1a38d72..46776b9c1 100644 --- a/arch/ppc/configs/mvme5100_defconfig +++ b/arch/ppc/configs/mvme5100_defconfig @@ -1,26 +1,48 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Wed Sep 22 09:53:26 2004 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_GENERIC_IOMAP=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y # # General setup # +CONFIG_LOCALVERSION="" 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_EMBEDDED is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +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 +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -33,24 +55,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 +90,30 @@ 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_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 @@ -109,15 +129,29 @@ CONFIG_KERNEL_START=0xc0000000 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 +163,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 +218,70 @@ 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_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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 @@ -250,6 +290,10 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # # CONFIG_I2O is not set +# +# Macintosh device drivers +# + # # Networking support # @@ -261,86 +305,90 @@ 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 +CONFIG_INET_TUNNEL=m + +# +# 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 +# CONFIG_IP_NF_CT_ACCT is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m -# CONFIG_IP_NF_TFTP is not set -# CONFIG_IP_NF_AMANDA is not set +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m # CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -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_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_LIMIT is not set +# CONFIG_IP_NF_MATCH_IPRANGE is not set +# CONFIG_IP_NF_MATCH_MAC is not set +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +# CONFIG_IP_NF_MATCH_MARK is not set +# CONFIG_IP_NF_MATCH_MULTIPORT is not set +# CONFIG_IP_NF_MATCH_TOS is not set +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +# CONFIG_IP_NF_MATCH_AH_ESP is not set +# CONFIG_IP_NF_MATCH_LENGTH is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_MATCH_TCPMSS is not set 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_NAT_LOCAL is not set -# CONFIG_IP_NF_NAT_SNMP_BASIC is not set -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_STATE is not set +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +# CONFIG_IP_NF_MATCH_SCTP is not set +# CONFIG_IP_NF_FILTER is not set # CONFIG_IP_NF_TARGET_LOG is not set -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_COMPAT_IPCHAINS=m +# CONFIG_IP_NF_TARGET_ULOG is not set +# CONFIG_IP_NF_TARGET_TCPMSS is not set +# CONFIG_IP_NF_NAT is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set # CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_XFRM_USER is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y # # 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 @@ -382,17 +434,26 @@ CONFIG_MII=y # # Tulip family network device support # -# CONFIG_NET_TULIP is not set +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # 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 +464,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,52 +483,39 @@ 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 +# CONFIG_ISDN is not set # -# Graphics support +# Telephony Support # -# CONFIG_FB is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set +# CONFIG_PHONE is not set # # Input device support @@ -483,18 +532,16 @@ CONFIG_EEPRO100=y # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y # CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set # # Input Device Drivers # -# -# Macintosh device drivers -# - # # Character devices # +# CONFIG_VT is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -502,6 +549,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,27 +558,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_QIC02_TAPE is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # # IPMI @@ -551,11 +580,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 @@ -567,6 +608,26 @@ CONFIG_GEN_RTC=y # # CONFIG_DVB is not set +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + # # File systems # @@ -592,17 +653,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 +675,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 +690,21 @@ 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_RPCSEC_GSS_SPKM3 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 +714,26 @@ CONFIG_SUNRPC=y CONFIG_MSDOS_PARTITION=y # -# Sound +# Native Language Support # -# CONFIG_SOUND is not set +# CONFIG_NLS is not set # -# USB support -# -# CONFIG_USB is not set -# CONFIG_USB_GADGET is not set - -# -# Bluetooth support +# Library routines # -# CONFIG_BT is not set +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# 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/Makefile b/arch/ppc/kernel/Makefile index 2531070a6..94e0b41d6 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -9,7 +9,7 @@ extra-$(CONFIG_E500) := head_e500.o extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_POWER4) += idle_power4.o -extra-y += vmlinux.lds.s +extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 39f51985e..c7d99f033 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -37,6 +37,7 @@ struct aligninfo { #define U 0x10 /* update index register */ #define M 0x20 /* multiple load/store */ #define S 0x40 /* single-precision fp, or byte-swap value */ +#define SX 0x40 /* byte count in XER */ #define HARD 0x80 /* string, stwcx. */ #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ @@ -88,10 +89,10 @@ static struct aligninfo aligninfo[128] = { INVALID, /* 01 0 0101: lwax */ INVALID, /* 01 0 0110 */ INVALID, /* 01 0 0111 */ - { 0, LD+HARD }, /* 01 0 1000: lswx */ - { 0, LD+HARD }, /* 01 0 1001: lswi */ - { 0, ST+HARD }, /* 01 0 1010: stswx */ - { 0, ST+HARD }, /* 01 0 1011: stswi */ + { 4, LD+M+HARD+SX }, /* 01 0 1000: lswx */ + { 4, LD+M+HARD }, /* 01 0 1001: lswi */ + { 4, ST+M+HARD+SX }, /* 01 0 1010: stswx */ + { 4, ST+M+HARD }, /* 01 0 1011: stswi */ INVALID, /* 01 0 1100 */ INVALID, /* 01 0 1101 */ INVALID, /* 01 0 1110 */ @@ -189,7 +190,9 @@ fix_alignment(struct pt_regs *regs) #endif int i, t; int reg, areg; + int offset, nb0; unsigned char __user *addr; + unsigned char *rptr; union { long l; float f; @@ -206,7 +209,8 @@ fix_alignment(struct pt_regs *regs) * an alignment fault. -- paulus */ - instr = *((unsigned int *)regs->nip); + if (__get_user(instr, (unsigned int __user *) regs->nip)) + return 0; opcode = OPCD(instr); reg = RS(instr); areg = RA(instr); @@ -230,7 +234,7 @@ fix_alignment(struct pt_regs *regs) nb = aligninfo[instr].len; if (nb == 0) { - long *p; + long __user *p; int i; if (instr != DCBZ) @@ -242,13 +246,19 @@ fix_alignment(struct pt_regs *regs) * case when we are running with the cache disabled * for debugging. */ - p = (long *) (regs->dar & -L1_CACHE_BYTES); + p = (long __user *) (regs->dar & -L1_CACHE_BYTES); + if (user_mode(regs) + && verify_area(VERIFY_WRITE, p, L1_CACHE_BYTES)) + return -EFAULT; for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i) - p[i] = 0; + if (__put_user(0, p+i)) + return -EFAULT; return 1; } flags = aligninfo[instr].flags; + if ((flags & (LD|ST)) == 0) + return 0; /* For the 4xx-family & Book-E processors, the 'dar' field of the * pt_regs structure is overloaded and is really from the DEAR. @@ -256,6 +266,66 @@ fix_alignment(struct pt_regs *regs) addr = (unsigned char __user *)regs->dar; + if (flags & M) { + /* lmw, stmw, lswi/x, stswi/x */ + nb0 = 0; + if (flags & HARD) { + if (flags & SX) { + nb = regs->xer & 127; + if (nb == 0) + return 1; + } else { + if (__get_user(instr, + (unsigned int __user *)regs->nip)) + return 0; + nb = (instr >> 11) & 0x1f; + if (nb == 0) + nb = 32; + } + if (nb + reg * 4 > 128) { + nb0 = nb + reg * 4 - 128; + nb = 128 - reg * 4; + } + } else { + /* lwm, stmw */ + nb = (32 - reg) * 4; + } + rptr = (unsigned char *) ®s->gpr[reg]; + if (flags & LD) { + for (i = 0; i < nb; ++i) + if (__get_user(rptr[i], addr+i)) + return -EFAULT; + if (nb0 > 0) { + rptr = (unsigned char *) ®s->gpr[0]; + addr += nb; + for (i = 0; i < nb0; ++i) + if (__get_user(rptr[i], addr+i)) + return -EFAULT; + } + for (; (i & 3) != 0; ++i) + rptr[i] = 0; + } else { + for (i = 0; i < nb; ++i) + if (__put_user(rptr[i], addr+i)) + return -EFAULT; + if (nb0 > 0) { + rptr = (unsigned char *) ®s->gpr[0]; + addr += nb; + for (i = 0; i < nb0; ++i) + if (__put_user(rptr[i], addr+i)) + return -EFAULT; + } + } + return 1; + } + + offset = 0; + if (nb < 4) { + /* read/write the least significant bits */ + data.l = 0; + offset = 4 - nb; + } + /* Verify the address of the operand */ if (user_mode(regs)) { if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb)) @@ -268,45 +338,26 @@ fix_alignment(struct pt_regs *regs) giveup_fpu(current); preempt_enable(); } - if (flags & M) - return 0; /* too hard for now */ - /* If we read the operand, copy it in */ + /* If we read the operand, copy it in, else get register values */ if (flags & LD) { - if (nb == 2) { - data.v[0] = data.v[1] = 0; - if (__get_user(data.v[2], addr) - || __get_user(data.v[3], addr+1)) + for (i = 0; i < nb; ++i) + if (__get_user(data.v[offset+i], addr+i)) return -EFAULT; - } else { - for (i = 0; i < nb; ++i) - if (__get_user(data.v[i], addr+i)) - return -EFAULT; - } + } else if (flags & F) { + data.d = current->thread.fpr[reg]; + } else { + data.l = regs->gpr[reg]; } switch (flags & ~U) { - case LD+SE: + case LD+SE: /* sign extend */ if (data.v[2] >= 0x80) data.v[0] = data.v[1] = -1; - /* fall through */ - case LD: - regs->gpr[reg] = data.l; - break; - case LD+S: - if (nb == 2) { - SWAP(data.v[2], data.v[3]); - } else { - SWAP(data.v[0], data.v[3]); - SWAP(data.v[1], data.v[2]); - } - regs->gpr[reg] = data.l; - break; - case ST: - data.l = regs->gpr[reg]; break; + + case LD+S: /* byte-swap */ case ST+S: - data.l = regs->gpr[reg]; if (nb == 2) { SWAP(data.v[2], data.v[3]); } else { @@ -314,50 +365,34 @@ fix_alignment(struct pt_regs *regs) SWAP(data.v[1], data.v[2]); } break; - case LD+F: - current->thread.fpr[reg] = data.d; - break; - case ST+F: - data.d = current->thread.fpr[reg]; - break; - /* these require some floating point conversions... */ - /* we'd like to use the assignment, but we have to compile - * the kernel with -msoft-float so it doesn't use the - * fp regs for copying 8-byte objects. */ + + /* Single-precision FP load and store require conversions... */ case LD+F+S: preempt_disable(); enable_kernel_fp(); - cvt_fd(&data.f, ¤t->thread.fpr[reg], ¤t->thread.fpscr); - /* current->thread.fpr[reg] = data.f; */ + cvt_fd(&data.f, &data.d, ¤t->thread.fpscr); preempt_enable(); break; case ST+F+S: preempt_disable(); enable_kernel_fp(); - cvt_df(¤t->thread.fpr[reg], &data.f, ¤t->thread.fpscr); - /* data.f = current->thread.fpr[reg]; */ + cvt_df(&data.d, &data.f, ¤t->thread.fpscr); preempt_enable(); break; - default: - printk("align: can't handle flags=%x\n", flags); - return 0; } if (flags & ST) { - if (nb == 2) { - if (__put_user(data.v[2], addr) - || __put_user(data.v[3], addr+1)) + for (i = 0; i < nb; ++i) + if (__put_user(data.v[offset+i], addr+i)) return -EFAULT; - } else { - for (i = 0; i < nb; ++i) - if (__put_user(data.v[i], addr+i)) - return -EFAULT; - } + } else if (flags & F) { + current->thread.fpr[reg] = data.d; + } else { + regs->gpr[reg] = data.l; } - if (flags & U) { + if (flags & U) regs->gpr[areg] = regs->dar; - } return 1; } diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index 1999a42d8..946ea9922 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c @@ -129,6 +129,13 @@ main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); + DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); return 0; } diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S index ee0705c6e..e42049f3e 100644 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ b/arch/ppc/kernel/cpu_setup_6xx.S @@ -172,9 +172,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) setup_750cx: mfspr r10, SPRN_HID1 rlwinm r10,r10,4,28,31 - cmpi cr0,r10,7 - cmpi cr1,r10,9 - cmpi cr2,r10,11 + cmpwi cr0,r10,7 + cmpwi cr1,r10,9 + cmpwi cr2,r10,11 cror 4*cr0+eq,4*cr0+eq,4*cr1+eq cror 4*cr0+eq,4*cr0+eq,4*cr2+eq bnelr @@ -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) @@ -287,12 +287,12 @@ _GLOBAL(__save_cpu_setup) /* Now deal with CPU type dependent registers */ mfspr r3,PVR srwi r3,r3,16 - cmpli cr0,r3,0x8000 /* 7450 */ - cmpli cr1,r3,0x000c /* 7400 */ - cmpli cr2,r3,0x800c /* 7410 */ - cmpli cr3,r3,0x8001 /* 7455 */ - cmpli cr4,r3,0x8002 /* 7457 */ - cmpli cr5,r3,0x7000 /* 750FX */ + cmplwi cr0,r3,0x8000 /* 7450 */ + cmplwi cr1,r3,0x000c /* 7400 */ + cmplwi cr2,r3,0x800c /* 7410 */ + cmplwi cr3,r3,0x8001 /* 7455 */ + cmplwi cr4,r3,0x8002 /* 7457 */ + cmplwi cr5,r3,0x7000 /* 750FX */ /* cr1 is 7400 || 7410 */ cror 4*cr1+eq,4*cr1+eq,4*cr2+eq /* cr0 is 74xx */ @@ -323,7 +323,7 @@ _GLOBAL(__save_cpu_setup) /* If rev 2.x, backup HID2 */ mfspr r3,PVR andi. r3,r3,0xff00 - cmpi cr0,r3,0x0200 + cmpwi cr0,r3,0x0200 bne 1f mfspr r4,SPRN_HID2 stw r4,CS_HID2(r5) @@ -354,12 +354,12 @@ _GLOBAL(__restore_cpu_setup) /* Now deal with CPU type dependent registers */ mfspr r3,PVR srwi r3,r3,16 - cmpli cr0,r3,0x8000 /* 7450 */ - cmpli cr1,r3,0x000c /* 7400 */ - cmpli cr2,r3,0x800c /* 7410 */ - cmpli cr3,r3,0x8001 /* 7455 */ - cmpli cr4,r3,0x8002 /* 7457 */ - cmpli cr5,r3,0x7000 /* 750FX */ + cmplwi cr0,r3,0x8000 /* 7450 */ + cmplwi cr1,r3,0x000c /* 7400 */ + cmplwi cr2,r3,0x800c /* 7410 */ + cmplwi cr3,r3,0x8001 /* 7455 */ + cmplwi cr4,r3,0x8002 /* 7457 */ + cmplwi cr5,r3,0x7000 /* 750FX */ /* cr1 is 7400 || 7410 */ cror 4*cr1+eq,4*cr1+eq,4*cr2+eq /* cr0 is 74xx */ @@ -412,7 +412,7 @@ _GLOBAL(__restore_cpu_setup) /* If rev 2.x, restore HID2 with low voltage bit cleared */ mfspr r3,PVR andi. r3,r3,0xff00 - cmpi cr0,r3,0x0200 + cmpwi cr0,r3,0x0200 bne 4f lwz r4,CS_HID2(r5) rlwinm r4,r4,0,19,17 @@ -426,7 +426,7 @@ _GLOBAL(__restore_cpu_setup) mftbl r5 3: mftbl r6 sub r6,r6,r5 - cmpli cr0,r6,10000 + cmplwi cr0,r6,10000 ble 3b /* Setup final PLL */ mtspr SPRN_HID1,r4 diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S index 6a6ee985c..f2ea1a990 100644 --- a/arch/ppc/kernel/cpu_setup_power4.S +++ b/arch/ppc/kernel/cpu_setup_power4.S @@ -112,7 +112,9 @@ _GLOBAL(__save_cpu_setup) /* We only deal with 970 for now */ mfspr r0,SPRN_PVR srwi r0,r0,16 - cmpwi r0,0x39 + cmpwi cr0,r0,0x39 + cmpwi cr1,r0,0x3c + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq bne 1f /* Save HID0,1,4 and 5 */ @@ -144,7 +146,9 @@ _GLOBAL(__restore_cpu_setup) /* We only deal with 970 for now */ mfspr r0,SPRN_PVR srwi r0,r0,16 - cmpwi r0,0x39 + cmpwi cr0,r0,0x39 + cmpwi cr1,r0,0x3c + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq bne 1f /* Clear interrupt prefix */ diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index b60fa998b..605afa6c6 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 @@ -63,6 +63,17 @@ extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spe #define CPU_FTR_COMMON 0 #endif +/* The powersave features NAP & DOZE seems to confuse BDI when + debugging. So if a BDI is used, disable theses + */ +#ifndef CONFIG_BDI_SWITCH +#define CPU_FTR_MAYBE_CAN_DOZE CPU_FTR_CAN_DOZE +#define CPU_FTR_MAYBE_CAN_NAP CPU_FTR_CAN_NAP +#else +#define CPU_FTR_MAYBE_CAN_DOZE 0 +#define CPU_FTR_MAYBE_CAN_NAP 0 +#endif + struct cpu_spec cpu_specs[] = { #if CLASSIC_PPC { /* 601 */ @@ -76,8 +87,8 @@ struct cpu_spec cpu_specs[] = { { /* 603 */ 0xffff0000, 0x00030000, "603", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -85,8 +96,8 @@ struct cpu_spec cpu_specs[] = { { /* 603e */ 0xffff0000, 0x00060000, "603e", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -94,8 +105,8 @@ struct cpu_spec cpu_specs[] = { { /* 603ev */ 0xffff0000, 0x00070000, "603ev", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -139,8 +150,8 @@ struct cpu_spec cpu_specs[] = { { /* 740/750 (0x4202, don't support TAU ?) */ 0xffffffff, 0x00084202, "740/750", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -148,8 +159,8 @@ struct cpu_spec cpu_specs[] = { { /* 745/755 */ 0xfffff000, 0x00083000, "745/755", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -157,8 +168,8 @@ struct cpu_spec cpu_specs[] = { { /* 750CX (80100 and 8010x?) */ 0xfffffff0, 0x00080100, "750CX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750cx @@ -166,8 +177,8 @@ struct cpu_spec cpu_specs[] = { { /* 750CX (82201 and 82202) */ 0xfffffff0, 0x00082200, "750CX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750cx @@ -175,8 +186,8 @@ struct cpu_spec cpu_specs[] = { { /* 750CXe (82214) */ 0xfffffff0, 0x00082210, "750CXe", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750cx @@ -184,8 +195,8 @@ struct cpu_spec cpu_specs[] = { { /* 750FX rev 1.x */ 0xffffff00, 0x70000100, "750FX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM, COMMON_PPC, 32, 32, @@ -194,8 +205,8 @@ struct cpu_spec cpu_specs[] = { { /* 750FX rev 2.0 must disable HID0[DPM] */ 0xffffffff, 0x70000200, "750FX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NO_DPM, COMMON_PPC, 32, 32, @@ -204,8 +215,8 @@ struct cpu_spec cpu_specs[] = { { /* 750FX (All revs except 2.0) */ 0xffff0000, 0x70000000, "750FX", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, 32, 32, @@ -213,8 +224,8 @@ struct cpu_spec cpu_specs[] = { }, { /* 750GX */ 0xffff0000, 0x70020000, "750GX", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, 32, 32, @@ -223,8 +234,8 @@ struct cpu_spec cpu_specs[] = { { /* 740/750 (L2CR bit need fixup for 740) */ 0xffff0000, 0x00080000, "740/750", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -232,9 +243,9 @@ struct cpu_spec cpu_specs[] = { { /* 7400 rev 1.1 ? (no TAU) */ 0xffffffff, 0x000c1101, "7400 (1.1)", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | - CPU_FTR_CAN_NAP, + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, 32, 32, __setup_cpu_7400 @@ -242,9 +253,9 @@ struct cpu_spec cpu_specs[] = { { /* 7400 */ 0xffff0000, 0x000c0000, "7400", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | - CPU_FTR_CAN_NAP, + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, 32, 32, __setup_cpu_7400 @@ -252,9 +263,9 @@ struct cpu_spec cpu_specs[] = { { /* 7410 */ 0xffff0000, 0x800c0000, "7410", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | - CPU_FTR_CAN_NAP, + CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, 32, 32, __setup_cpu_7410 @@ -272,7 +283,7 @@ struct cpu_spec cpu_specs[] = { { /* 7450 2.1 */ 0xffffffff, 0x80000201, "7450", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | CPU_FTR_NEED_COHERENT, @@ -283,7 +294,7 @@ struct cpu_spec cpu_specs[] = { { /* 7450 2.3 and newer */ 0xffff0000, 0x80000000, "7450", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT, @@ -305,7 +316,7 @@ struct cpu_spec cpu_specs[] = { { /* 7455 rev 2.0 */ 0xffffffff, 0x80010200, "7455", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS, @@ -316,7 +327,7 @@ struct cpu_spec cpu_specs[] = { { /* 7455 others */ 0xffff0000, 0x80010000, "7455", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, @@ -327,7 +338,7 @@ struct cpu_spec cpu_specs[] = { { /* 7447/7457 Rev 1.0 */ 0xffffffff, 0x80020100, "7447/7457", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC, @@ -338,7 +349,7 @@ struct cpu_spec cpu_specs[] = { { /* 7447/7457 Rev 1.1 */ 0xffffffff, 0x80020101, "7447/7457", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC, @@ -349,7 +360,7 @@ struct cpu_spec cpu_specs[] = { { /* 7447/7457 Rev 1.2 and later */ 0xffff0000, 0x80020000, "7447/7457", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, @@ -360,7 +371,7 @@ struct cpu_spec cpu_specs[] = { { /* 7447A */ 0xffff0000, 0x80030000, "7447A", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, @@ -371,15 +382,15 @@ struct cpu_spec cpu_specs[] = { { /* 82xx (8240, 8245, 8260 are all 603e cores) */ 0x7fff0000, 0x00810000, "82xx", CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB, COMMON_PPC, 32, 32, __setup_cpu_603 }, { /* All G2_LE (603e core, plus some) have the same pvr */ 0x7fff0000, 0x00820000, "G2_LE", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -440,7 +451,16 @@ struct cpu_spec cpu_specs[] = { 0xffff0000, 0x00390000, "PPC970", CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP, + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MAYBE_CAN_NAP, + COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_ALTIVEC_COMP, + 128, 128, + __setup_cpu_ppc970 + }, + { /* PPC970FX */ + 0xffff0000, 0x003c0000, "PPC970FX", + CPU_FTR_COMMON | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MAYBE_CAN_NAP, COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_ALTIVEC_COMP, 128, 128, __setup_cpu_ppc970 @@ -449,7 +469,8 @@ struct cpu_spec cpu_specs[] = { #ifdef CONFIG_8xx { /* 8xx */ 0xffff0000, 0x00500000, "8xx", - /* CPU_FTR_CAN_DOZE is possible, if the 8xx code is there.... */ + /* CPU_FTR_MAYBE_CAN_DOZE is possible, + * if the 8xx code is there.... */ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, 16, 16, @@ -590,7 +611,7 @@ struct cpu_spec cpu_specs[] = { #ifdef CONFIG_E500 { /* e500 */ 0xffff0000, 0x80200000, "e500", - /* xxx - galak: add CPU_FTR_CAN_DOZE */ + /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, 32, 32, diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c index 54f9a3e75..334b8bfdc 100644 --- a/arch/ppc/kernel/dma-mapping.c +++ b/arch/ppc/kernel/dma-mapping.c @@ -41,11 +41,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -381,6 +381,7 @@ void __dma_sync(void *vaddr, size_t size, int direction) break; } } +EXPORT_SYMBOL(__dma_sync); #ifdef CONFIG_HIGHMEM /* @@ -438,3 +439,4 @@ void __dma_sync_page(struct page *page, unsigned long offset, __dma_sync((void *)start, size, direction); #endif } +EXPORT_SYMBOL(__dma_sync_page); diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 4963b79c7..91318c15c 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -206,7 +206,7 @@ _GLOBAL(DoSyscall) andi. r11,r11,_TIF_SYSCALL_TRACE bne- syscall_dotrace syscall_dotrace_cont: - cmpli 0,r0,NR_syscalls + cmplwi 0,r0,NR_syscalls lis r10,sys_call_table@h ori r10,r10,sys_call_table@l slwi r0,r0,2 @@ -222,7 +222,7 @@ ret_from_syscall: #endif mr r6,r3 li r11,-_LAST_ERRNO - cmpl 0,r3,r11 + cmplw 0,r3,r11 rlwinm r12,r1,0,0,18 /* current_thread_info() */ blt+ 30f lwz r11,TI_LOCAL_FLAGS(r12) diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 121978c19..3a3e3c742 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -800,7 +800,7 @@ load_up_fpu: tophys(r6,0) /* get __pa constant */ addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f add r4,r4,r6 addi r4,r4,THREAD /* want last_task_used_math->thread */ @@ -927,7 +927,7 @@ load_up_altivec: tophys(r6,0) addis r3,r6,last_task_used_altivec@ha lwz r4,last_task_used_altivec@l(r3) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f add r4,r4,r6 addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ @@ -992,11 +992,11 @@ giveup_altivec: SYNC MTMSRD(r5) /* enable use of AltiVec now */ isync - cmpi 0,r3,0 + cmpwi 0,r3,0 beqlr- /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) - cmpi 0,r5,0 + cmpwi 0,r5,0 SAVE_32VR(0, r4, r3) mfvscr vr0 li r4,THREAD_VSCR @@ -1030,11 +1030,11 @@ giveup_fpu: MTMSRD(r5) /* enable use of fpu now */ SYNC_601 isync - cmpi 0,r3,0 + cmpwi 0,r3,0 beqlr- /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) - cmpi 0,r5,0 + cmpwi 0,r5,0 SAVE_32FPRS(0, r3) mffs fr0 stfd fr0,THREAD_FPSCR-4(r3) @@ -1539,7 +1539,7 @@ initial_bats: #ifndef CONFIG_PPC64BRIDGE mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 + cmpwi 0,r9,1 bne 4f ori r11,r11,4 /* set up BAT registers for 601 */ li r8,0x7f /* valid, block length = 8MB */ @@ -1591,7 +1591,7 @@ setup_disp_bat: lwz r8,4(r8) mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 + cmpwi 0,r9,1 beq 1f mtspr DBAT3L,r8 mtspr DBAT3U,r11 diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index f883dc239..73fd71105 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -41,16 +41,9 @@ #include #include #include +#include "head_booke.h" -/* - * Macros - */ -#define SET_IVOR(vector_number, vector_label) \ - li r26,vector_label@l; \ - mtspr SPRN_IVOR##vector_number,r26; \ - sync - /* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet * optional, information: @@ -302,234 +295,6 @@ skpinv: addi r4,r4,1 /* Increment */ * We align on a 32 byte cache line boundary for good measure. */ -#define NORMAL_EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ - mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG4W,r1; \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - beq 1f; \ - mfspr r1,SPRG3; /* if from user, start at top of */\ - lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ - addi r1,r1,THREAD_SIZE; \ -1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r1); \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r10,SPRG4R; \ - mfspr r12,SRR0; \ - stw r10,GPR1(r11); \ - mfspr r9,SRR1; \ - stw r10,0(r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. For Book E - * processors, we also have a reserved register (SPRG2) that is only used - * in critical exceptions so we can free up a GPR to use as the base for - * indirect access to the critical exception save area. This is necessary - * since the MMU is always on and the save area is offset from KERNELBASE. - */ -#define CRITICAL_EXCEPTION_PROLOG \ - mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ - lis r8,crit_save@ha; \ - stw r10,crit_r10@l(r8); \ - stw r11,crit_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,crit_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,crit_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,crit_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,crit_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,crit_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,crit_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,crit_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,crit_srr1@l(r8); \ - mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,critical_stack_top@h; \ - ori r11,r11,critical_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,CSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,CSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for machine check exceptions. This is similar to - * the critical exception prolog, except that machine check exceptions - * have their own save area. For Book E processors, we also have a - * reserved register (SPRG6) that is only used in machine check exceptions - * so we can free up a GPR to use as the base for indirect access to the - * machine check exception save area. This is necessary since the MMU - * is always on and the save area is offset from KERNELBASE. - */ -#define MCHECK_EXCEPTION_PROLOG \ - mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ - lis r8,mcheck_save@ha; \ - stw r10,mcheck_r10@l(r8); \ - stw r11,mcheck_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,mcheck_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,mcheck_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,mcheck_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,mcheck_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,mcheck_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,mcheck_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,mcheck_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,mcheck_srr1@l(r8); \ - mfspr r10,CSRR0; \ - stw r10,mcheck_csrr0@l(r8); \ - mfspr r10,CSRR1; \ - stw r10,mcheck_csrr1@l(r8); \ - mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,mcheck_stack_top@h; \ - ori r11,r11,mcheck_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,MCSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,MCSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception vectors. - */ -#define START_EXCEPTION(label) \ - .align 5; \ -label: - -#define FINISH_EXCEPTION(func) \ - bl transfer_to_handler_full; \ - .long func; \ - .long ret_from_except_full - -#define EXCEPTION(n, label, hdlr, xfer) \ - START_EXCEPTION(label); \ - NORMAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - CRITICAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define MCHECK_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - MCHECK_EXCEPTION_PROLOG; \ - lis r4,MCSR_MCS@h; \ - mtspr SPRN_MCSR,r4; \ - mfspr r5,SPRN_ESR; \ - stw r5,_ESR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, mcheck_transfer_to_handler, \ - ret_from_mcheck_exc) - -#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - lis r10,msr@h; \ - ori r10,r10,msr@l; \ - copyee(r10, r9); \ - bl tfer; \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ - ret_from_except) - interrupt_base: /* Critical Input Interrupt */ CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h new file mode 100644 index 000000000..6f54039c8 --- /dev/null +++ b/arch/ppc/kernel/head_booke.h @@ -0,0 +1,240 @@ +#ifndef __HEAD_BOOKE_H__ +#define __HEAD_BOOKE_H__ + +/* + * Macros used for common Book-e exception handling + */ + +#define SET_IVOR(vector_number, vector_label) \ + li r26,vector_label@l; \ + mtspr SPRN_IVOR##vector_number,r26; \ + sync + +#define NORMAL_EXCEPTION_PROLOG \ + mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ + mtspr SPRN_SPRG1,r11; \ + mtspr SPRN_SPRG4W,r1; \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + beq 1f; \ + mfspr r1,SPRG3; /* if from user, start at top of */\ + lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ + addi r1,r1,THREAD_SIZE; \ +1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ + tophys(r11,r1); \ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mfspr r10,SPRG0; \ + stw r10,GPR10(r11); \ + mfspr r12,SPRG1; \ + stw r12,GPR11(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r10,SPRG4R; \ + mfspr r12,SRR0; \ + stw r10,GPR1(r11); \ + mfspr r9,SRR1; \ + stw r10,0(r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for critical exceptions. This is a little different + * from the normal exception prolog above since a critical exception + * can potentially occur at any point during normal exception processing. + * Thus we cannot use the same SPRG registers as the normal prolog above. + * Instead we use a couple of words of memory at low physical addresses. + * This is OK since we don't support SMP on these processors. For Book E + * processors, we also have a reserved register (SPRG2) that is only used + * in critical exceptions so we can free up a GPR to use as the base for + * indirect access to the critical exception save area. This is necessary + * since the MMU is always on and the save area is offset from KERNELBASE. + */ +#define CRITICAL_EXCEPTION_PROLOG \ + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ + lis r8,crit_save@ha; \ + stw r10,crit_r10@l(r8); \ + stw r11,crit_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,crit_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,crit_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,crit_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,crit_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,crit_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,crit_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,crit_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,crit_srr1@l(r8); \ + mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,critical_stack_top@h; \ + ori r11,r11,critical_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,CSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,CSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for machine check exceptions. This is similar to + * the critical exception prolog, except that machine check exceptions + * have their own save area. For Book E processors, we also have a + * reserved register (SPRG6) that is only used in machine check exceptions + * so we can free up a GPR to use as the base for indirect access to the + * machine check exception save area. This is necessary since the MMU + * is always on and the save area is offset from KERNELBASE. + */ +#define MCHECK_EXCEPTION_PROLOG \ + mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ + lis r8,mcheck_save@ha; \ + stw r10,mcheck_r10@l(r8); \ + stw r11,mcheck_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,mcheck_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,mcheck_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,mcheck_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,mcheck_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,mcheck_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,mcheck_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,mcheck_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,mcheck_srr1@l(r8); \ + mfspr r10,CSRR0; \ + stw r10,mcheck_csrr0@l(r8); \ + mfspr r10,CSRR1; \ + stw r10,mcheck_csrr1@l(r8); \ + mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,mcheck_stack_top@h; \ + ori r11,r11,mcheck_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,MCSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,MCSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception vectors. + */ +#define START_EXCEPTION(label) \ + .align 5; \ +label: + +#define FINISH_EXCEPTION(func) \ + bl transfer_to_handler_full; \ + .long func; \ + .long ret_from_except_full + +#define EXCEPTION(n, label, hdlr, xfer) \ + START_EXCEPTION(label); \ + NORMAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + xfer(n, hdlr) + +#define CRITICAL_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + CRITICAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define MCHECK_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + MCHECK_EXCEPTION_PROLOG; \ + mfspr r5,SPRN_ESR; \ + stw r5,_ESR(r11); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, mcheck_transfer_to_handler, \ + ret_from_mcheck_exc) + +#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ + li r10,trap; \ + stw r10,TRAP(r11); \ + lis r10,msr@h; \ + ori r10,r10,msr@l; \ + copyee(r10, r9); \ + bl tfer; \ + .long hdlr; \ + .long ret + +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) + +#define EXC_XFER_STD(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ + ret_from_except) + +#define EXC_XFER_EE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_EE_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ + ret_from_except) + + +#endif /* __HEAD_BOOKE_H__ */ diff --git a/arch/ppc/kernel/head_e500.S b/arch/ppc/kernel/head_e500.S index ceb51d343..cf964198e 100644 --- a/arch/ppc/kernel/head_e500.S +++ b/arch/ppc/kernel/head_e500.S @@ -41,15 +41,7 @@ #include #include #include - -/* - * Macros - */ - -#define SET_IVOR(vector_number, vector_label) \ - li r26,vector_label@l; \ - mtspr SPRN_IVOR##vector_number,r26; \ - sync +#include "head_booke.h" /* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet @@ -371,232 +363,6 @@ skpinv: addi r6,r6,1 /* Increment */ * We align on a 32 byte cache line boundary for good measure. */ -#define NORMAL_EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ - mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG4W,r1; \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - beq 1f; \ - mfspr r1,SPRG3; /* if from user, start at top of */\ - lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ - addi r1,r1,THREAD_SIZE; \ -1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r1); \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r10,SPRG4R; \ - mfspr r12,SRR0; \ - stw r10,GPR1(r11); \ - mfspr r9,SRR1; \ - stw r10,0(r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. For Book E - * processors, we also have a reserved register (SPRG2) that is only used - * in critical exceptions so we can free up a GPR to use as the base for - * indirect access to the critical exception save area. This is necessary - * since the MMU is always on and the save area is offset from KERNELBASE. - */ -#define CRITICAL_EXCEPTION_PROLOG \ - mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ - lis r8,crit_save@ha; \ - stw r10,crit_r10@l(r8); \ - stw r11,crit_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,crit_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,crit_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,crit_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,crit_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,crit_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,crit_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,crit_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,crit_srr1@l(r8); \ - mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,critical_stack_top@h; \ - ori r11,r11,critical_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,CSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,CSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for machine check exceptions. This is similar to - * the critical exception prolog, except that machine check exceptions - * have their own save area. For Book E processors, we also have a - * reserved register (SPRG6) that is only used in machine check exceptions - * so we can free up a GPR to use as the base for indirect access to the - * machine check exception save area. This is necessary since the MMU - * is always on and the save area is offset from KERNELBASE. - */ -#define MCHECK_EXCEPTION_PROLOG \ - mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ - lis r8,mcheck_save@ha; \ - stw r10,mcheck_r10@l(r8); \ - stw r11,mcheck_r11@l(r8); \ - mfspr r10,SPRG0; \ - stw r10,mcheck_sprg0@l(r8); \ - mfspr r10,SPRG1; \ - stw r10,mcheck_sprg1@l(r8); \ - mfspr r10,SPRG4R; \ - stw r10,mcheck_sprg4@l(r8); \ - mfspr r10,SPRG5R; \ - stw r10,mcheck_sprg5@l(r8); \ - mfspr r10,SPRG7R; \ - stw r10,mcheck_sprg7@l(r8); \ - mfspr r10,SPRN_PID; \ - stw r10,mcheck_pid@l(r8); \ - mfspr r10,SRR0; \ - stw r10,mcheck_srr0@l(r8); \ - mfspr r10,SRR1; \ - stw r10,mcheck_srr1@l(r8); \ - mfspr r10,CSRR0; \ - stw r10,mcheck_csrr0@l(r8); \ - mfspr r10,CSRR1; \ - stw r10,mcheck_csrr1@l(r8); \ - mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,mcheck_stack_top@h; \ - ori r11,r11,mcheck_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,MCSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,MCSRR1; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception vectors. - */ -#define START_EXCEPTION(label) \ - .align 5; \ -label: - -#define FINISH_EXCEPTION(func) \ - bl transfer_to_handler_full; \ - .long func; \ - .long ret_from_except_full - -#define EXCEPTION(n, label, hdlr, xfer) \ - START_EXCEPTION(label); \ - NORMAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - CRITICAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define MCHECK_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - MCHECK_EXCEPTION_PROLOG; \ - mfspr r5,SPRN_ESR; \ - stw r5,_ESR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, mcheck_transfer_to_handler, \ - ret_from_mcheck_exc) - -#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - lis r10,msr@h; \ - ori r10,r10,msr@l; \ - copyee(r10, r9); \ - bl tfer; \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ - ret_from_except) - interrupt_base: /* Critical Input Interrupt */ CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 5adb6be19..6db80f60c 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -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/idle_6xx.S b/arch/ppc/kernel/idle_6xx.S index 608f71ccb..25d009c75 100644 --- a/arch/ppc/kernel/idle_6xx.S +++ b/arch/ppc/kernel/idle_6xx.S @@ -79,12 +79,12 @@ BEGIN_FTR_SECTION /* Now check if user or arch enabled NAP mode */ lis r4,powersave_nap@ha lwz r4,powersave_nap@l(r4) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f lis r3,HID0_NAP@h 1: END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) - cmpi 0,r3,0 + cmpwi 0,r3,0 beqlr /* Clear MSR:EE */ @@ -133,7 +133,7 @@ BEGIN_FTR_SECTION /* Go to low speed mode on some 750FX */ lis r4,powersave_lowspeed@ha lwz r4,powersave_lowspeed@l(r4) - cmpi 0,r4,0 + cmpwi 0,r4,0 beq 1f mfspr r4,SPRN_HID1 oris r4,r4,0x0001 diff --git a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S index 538a044f4..73a58ff03 100644 --- a/arch/ppc/kernel/idle_power4.S +++ b/arch/ppc/kernel/idle_power4.S @@ -56,7 +56,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) /* Now check if user or arch enabled NAP mode */ lis r4,powersave_nap@ha lwz r4,powersave_nap@l(r4) - cmpi 0,r4,0 + cmpwi 0,r4,0 beqlr /* Clear MSR:EE */ diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 2ac2e4b55..d4612e986 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -414,13 +415,15 @@ static inline void handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) { int status = 0; + int ret; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -620,32 +623,6 @@ static int irq_affinity_write_proc (struct file *file, const char __user *buffer return full_count; } -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - int err; - int full_count = count; - cpumask_t *mask = (cpumask_t *)data; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -673,23 +650,14 @@ static void register_irq_proc (unsigned int irq) smp_affinity_entry[irq] = entry; } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); - /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 873199e43..7141d7ecd 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -214,7 +214,7 @@ _GLOBAL(low_choose_750fx_pll) mtmsr r0 /* If switching to PLL1, disable HID0:BTIC */ - cmpli cr0,r3,0 + cmplwi cr0,r3,0 beq 1f mfspr r5,HID0 rlwinm r5,r5,0,27,25 @@ -239,7 +239,7 @@ _GLOBAL(low_choose_750fx_pll) stw r4,nap_save_hid1@l(r6) /* If switching to PLL0, enable HID0:BTIC */ - cmpli cr0,r3,0 + cmplwi cr0,r3,0 bne 1f mfspr r5,HID0 ori r5,r5,HID0_BTIC @@ -470,7 +470,7 @@ _GLOBAL(_tlbia) ori r9,r9,mmu_hash_lock@l tophys(r9,r9) 10: lwarx r7,0,r9 - cmpi 0,r7,0 + cmpwi 0,r7,0 bne- 10b stwcx. r8,0,r9 bne- 10b @@ -551,7 +551,7 @@ _GLOBAL(_tlbie) ori r9,r9,mmu_hash_lock@l tophys(r9,r9) 10: lwarx r7,0,r9 - cmpi 0,r7,0 + cmpwi 0,r7,0 bne- 10b stwcx. r8,0,r9 bne- 10b @@ -599,7 +599,7 @@ _GLOBAL(flush_instruction_cache) #else mfspr r3,PVR rlwinm r3,r3,16,16,31 - cmpi 0,r3,1 + cmpwi 0,r3,1 beqlr /* for 601, do nothing */ /* 603/604 processor - use invalidate-all bit in HID0 */ mfspr r3,HID0 @@ -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 @@ -1144,7 +1141,7 @@ _GLOBAL(kernel_thread) li r4,0 /* new sp (unused) */ li r0,__NR_clone sc - cmpi 0,r3,0 /* parent or child? */ + cmpwi 0,r3,0 /* parent or child? */ bne 1f /* return if parent */ li r0,0 /* make top-level stack frame */ stwu r0,-16(r1) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 4145ff7bf..08cdddee7 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -33,6 +33,7 @@ unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; +int pcibios_assign_bus_offset = 1; void pcibios_make_OF_bus_map(void); @@ -45,11 +46,6 @@ static void fixup_broken_pcnet32(struct pci_dev* dev); static int reparent_resources(struct resource *parent, struct resource *res); static void fixup_rev1_53c810(struct pci_dev* dev); static void fixup_cpc710_pci64(struct pci_dev* dev); -#ifdef CONFIG_PPC_PMAC -extern void pmac_pci_fixup_cardbus(struct pci_dev* dev); -extern void pmac_pci_fixup_pciata(struct pci_dev* dev); -extern void pmac_pci_fixup_k2_sata(struct pci_dev* dev); -#endif #ifdef CONFIG_PPC_OF static u8* pci_to_OF_bus_map; #endif @@ -64,20 +60,6 @@ struct pci_controller** hose_tail = &hose_head; static int pci_bus_count; -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64}, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, -#ifdef CONFIG_PPC_PMAC - /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus }, - { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata }, -#endif /* CONFIG_PPC_PMAC */ - { 0 } -}; - static void fixup_rev1_53c810(struct pci_dev* dev) { @@ -90,6 +72,7 @@ fixup_rev1_53c810(struct pci_dev* dev) dev->class = PCI_CLASS_STORAGE_SCSI; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); static void fixup_broken_pcnet32(struct pci_dev* dev) @@ -100,6 +83,7 @@ fixup_broken_pcnet32(struct pci_dev* dev) pci_name_device(dev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); static void fixup_cpc710_pci64(struct pci_dev* dev) @@ -112,6 +96,7 @@ fixup_cpc710_pci64(struct pci_dev* dev) dev->resource[1].start = dev->resource[1].end = 0; dev->resource[1].flags = 0; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); static void pcibios_fixup_resources(struct pci_dev *dev) @@ -158,9 +143,9 @@ pcibios_fixup_resources(struct pci_dev *dev) if (ppc_md.pcibios_fixup_resources) ppc_md.pcibios_fixup_resources(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; @@ -173,6 +158,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 @@ -187,8 +173,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; @@ -208,7 +193,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 @@ -427,7 +412,7 @@ probe_resource(struct pci_bus *parent, struct resource *pr, r = &dev->resource[i]; if (!r->flags || (r->flags & IORESOURCE_UNSET)) continue; - if (pci_find_parent_resource(bus->self, r) != pr) + if (pci_find_parent_resource(dev, r) != pr) continue; if (r->end >= res->start && res->end >= r->start) { *conflict = r; @@ -1279,7 +1264,7 @@ pcibios_init(void) bus = pci_scan_bus(hose->first_busno, hose->ops, hose); hose->last_busno = bus->subordinate; if (pci_assign_all_busses || next_busno <= hose->last_busno) - next_busno = hose->last_busno+1; + next_busno = hose->last_busno + pcibios_assign_bus_offset; } pci_bus_count = next_busno; @@ -1724,6 +1709,32 @@ pci_init_resource(struct resource *res, unsigned long start, unsigned long end, res->child = NULL; } +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len) + return NULL; + if (max && len > max) + len = max; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + return (void __iomem *) start; + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); + + /* * Null PCI config access functions, for the case when we can't * find a hose. diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 91592c03e..d8e027fd4 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -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/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 2d3e630a7..965a874a4 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -352,3 +352,7 @@ EXPORT_SYMBOL(cur_cpu_spec); extern unsigned long agp_special_page; EXPORT_SYMBOL(agp_special_page); #endif +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) +EXPORT_SYMBOL(__mtdcr); +EXPORT_SYMBOL(__mfdcr); +#endif diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 2ea505381..d9ab6a7de 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include extern unsigned long _get_SP(void); @@ -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, @@ -662,7 +661,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) ++count; sp = *(unsigned long *)sp; } -#if !CONFIG_KALLSYMS +#ifndef CONFIG_KALLSYMS if (count > 0) printk("\n"); #endif diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 376f7369c..57b70aec7 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -418,7 +418,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, * are used for initrd_start and initrd_size, * otherwise they contain 0xdeadbeef. */ - cmd_line[0] = 0; if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { strlcpy(cmd_line, (char *)r3 + KERNELBASE, sizeof(cmd_line)); @@ -484,6 +483,9 @@ static int __init set_preferred_console(void) char *name; int offset; + if (of_stdout_device == NULL) + return -ENODEV; + /* The user has requested a console so this is already set up. */ if (strstr(saved_command_line, "console=")) return -EBUSY; @@ -744,6 +746,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 20b6446c0..260716af5 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -270,7 +270,7 @@ save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, int sigret) static int restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig) { - unsigned long save_r2; + unsigned long save_r2 = 0; #if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE) unsigned long msr; #endif @@ -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: ¤t->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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked,¤t->blocked,&ka.sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index c28fbf398..dae491743 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -364,22 +363,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(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 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/time.c b/arch/ppc/kernel/time.c index cfeff0479..60e7ef5ad 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -108,41 +108,18 @@ static inline int tb_delta(unsigned *jiffy_stamp) { return delta; } -extern char _stext; - -static inline void ppc_do_profile (struct pt_regs *regs) +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) { - unsigned long nip; - extern unsigned long prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; + unsigned long pc = instruction_pointer(regs); - nip = instruction_pointer(regs); + if (in_lock_functions(pc)) + return regs->link; - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!((1<>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (nip > prof_len-1) - nip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[nip]); + return pc; } +EXPORT_SYMBOL(profile_pc); +#endif /* * timer_interrupt - gets called when the decrementer overflows, @@ -161,10 +138,10 @@ void timer_interrupt(struct pt_regs * regs) irq_enter(); - while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) { + while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { jiffy_stamp += tb_ticks_per_jiffy; - ppc_do_profile(regs); + profile_tick(CPU_PROFILING, regs); if (smp_processor_id()) continue; diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 544ea9fb5..7870bb680 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -357,7 +357,7 @@ void RunModeException(struct pt_regs *regs) /* Illegal instruction emulation support. Originally written to * provide the PVR to user applications using the mfspr rd, PVR. - * Return non-zero if we can't emulate, or EFAULT if the associated + * Return non-zero if we can't emulate, or -EFAULT if the associated * memory access caused an access fault. Return zero on success. * * There are a couple of ways to do this, either "decode" the instruction @@ -368,16 +368,19 @@ void RunModeException(struct pt_regs *regs) #define INST_MFSPR_PVR 0x7c1f42a6 #define INST_MFSPR_PVR_MASK 0xfc1fffff +#define INST_DCBA 0x7c0005ec +#define INST_DCBA_MASK 0x7c0007fe + +#define INST_MCRXR 0x7c000400 +#define INST_MCRXR_MASK 0x7c0007fe + static int emulate_instruction(struct pt_regs *regs) { u32 instword; u32 rd; - int retval; - - retval = -EINVAL; if (!user_mode(regs)) - return retval; + return -EINVAL; CHECK_FULL_REGS(regs); if (get_user(instword, (u32 __user *)(regs->nip))) @@ -388,10 +391,24 @@ static int emulate_instruction(struct pt_regs *regs) if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { rd = (instword >> 21) & 0x1f; regs->gpr[rd] = mfspr(PVR); - retval = 0; - regs->nip += 4; + return 0; } - return retval; + + /* Emulating the dcba insn is just a no-op. */ + if ((instword & INST_DCBA_MASK) == INST_DCBA) + return 0; + + /* Emulate the mcrxr insn. */ + if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { + int shift = (instword >> 21) & 0x1c; + unsigned long msk = 0xf0000000UL >> shift; + + regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); + regs->xer &= ~0xf0000000UL; + return 0; + } + + return -EINVAL; } /* @@ -528,17 +545,23 @@ void ProgramCheckException(struct pt_regs *regs) return; } - if (reason & REASON_PRIVILEGED) { - /* Try to emulate it if we should. */ - if (emulate_instruction(regs) == 0) { + /* Try to emulate it if we should. */ + if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { + switch (emulate_instruction(regs)) { + case 0: + regs->nip += 4; emulate_single_step(regs); return; + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; } - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - return; } - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + if (reason & REASON_PRIVILEGED) + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } void SingleStepException(struct pt_regs *regs) diff --git a/arch/ppc/kernel/vector.S b/arch/ppc/kernel/vector.S index d8fe6b5fb..82a21346b 100644 --- a/arch/ppc/kernel/vector.S +++ b/arch/ppc/kernel/vector.S @@ -106,7 +106,7 @@ vmaddfp: 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fmadds fr0,fr0,fr1,fr2 + fmadds fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b @@ -133,7 +133,7 @@ vnmsubfp: 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr1,fr2 + fnmsubs fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index 342848fe5..5d2cbc780 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S @@ -32,6 +32,7 @@ SECTIONS { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.got1) __got2_start = .; @@ -102,9 +103,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/lib/checksum.S b/arch/ppc/lib/checksum.S index 74928a7a2..7874e8a80 100644 --- a/arch/ppc/lib/checksum.S +++ b/arch/ppc/lib/checksum.S @@ -80,13 +80,13 @@ _GLOBAL(csum_partial) adde r0,r0,r5 /* be unnecessary to unroll this loop */ bdnz 2b andi. r4,r4,3 -3: cmpi 0,r4,2 +3: cmpwi 0,r4,2 blt+ 4f lhz r5,4(r3) addi r3,r3,2 subi r4,r4,2 adde r0,r0,r5 -4: cmpi 0,r4,1 +4: cmpwi 0,r4,1 bne+ 5f lbz r5,4(r3) slwi r5,r5,8 /* Upper byte of word */ @@ -143,7 +143,7 @@ _GLOBAL(csum_partial_copy_generic) adde r0,r0,r9 bdnz 82b 13: andi. r5,r5,3 -3: cmpi 0,r5,2 +3: cmpwi 0,r5,2 blt+ 4f 83: lhz r6,4(r3) addi r3,r3,2 @@ -151,7 +151,7 @@ _GLOBAL(csum_partial_copy_generic) 93: sth r6,4(r4) addi r4,r4,2 adde r0,r0,r6 -4: cmpi 0,r5,1 +4: cmpwi 0,r5,1 bne+ 5f 84: lbz r6,4(r3) 94: stb r6,4(r4) @@ -188,7 +188,7 @@ src_error_3: 97: stbu r6,1(r4) bdnz 97b src_error: - cmpi 0,r7,0 + cmpwi 0,r7,0 beq 1f li r6,-EFAULT stw r6,0(r7) @@ -196,7 +196,7 @@ src_error: blr dst_error: - cmpi 0,r8,0 + cmpwi 0,r8,0 beq 1f li r6,-EFAULT stw r6,0(r8) diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c index 103765660..9991c48f9 100644 --- a/arch/ppc/lib/rheap.c +++ b/arch/ppc/lib/rheap.c @@ -216,7 +216,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn) /* Grow the after block backwards */ if (before == NULL && after != NULL) { - (int8_t *) after->start -= size; + after->start = (int8_t *)after->start - size; after->size += size; return; } @@ -407,7 +407,7 @@ void *rh_detach_region(rh_info_t * info, void *start, int size) /* blk still in free list, with updated start and/or size */ if (bs == s || be == e) { if (bs == s) - (int8_t *) blk->start += size; + blk->start = (int8_t *)blk->start + size; blk->size -= size; } else { @@ -471,7 +471,7 @@ void *rh_alloc(rh_info_t * info, int size, const char *owner) newblk->owner = owner; /* blk still in free list, with updated start, size */ - (int8_t *) blk->start += size; + blk->start = (int8_t *)blk->start + size; blk->size -= size; start = newblk->start; @@ -535,7 +535,7 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner) /* blk still in free list, with updated start and/or size */ if (bs == s || be == e) { if (bs == s) - (int8_t *) blk->start += size; + blk->start = (int8_t *)blk->start + size; blk->size -= size; } else { diff --git a/arch/ppc/math-emu/op-common.h b/arch/ppc/math-emu/op-common.h index aeaa1cde5..afb82b649 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/mm/44x_mmu.c b/arch/ppc/mm/44x_mmu.c index 1d79838d9..a2ab8b053 100644 --- a/arch/ppc/mm/44x_mmu.c +++ b/arch/ppc/mm/44x_mmu.c @@ -72,7 +72,7 @@ unsigned int tlb_44x_hwater = 62; static void __init ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys) { - unsigned long attrib; + unsigned long attrib = 0; __asm__ __volatile__("\ clrrwi %2,%2,10\n\ diff --git a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c index 6066ff35c..a7f616140 100644 --- a/arch/ppc/mm/4xx_mmu.c +++ b/arch/ppc/mm/4xx_mmu.c @@ -52,6 +52,7 @@ #include #include "mmu_decl.h" +extern int __map_without_ltlbs; /* * MMU_init_hw does the chip-specific initialization of the MMU hardware. */ @@ -102,6 +103,10 @@ unsigned long __init mmu_mapin_ram(void) p = PPC_MEMSTART; s = 0; + if (__map_without_ltlbs) { + return s; + } + while (s <= (total_lowmem - LARGE_PAGE_SIZE_16M)) { pmd_t *pmdp; unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 448e80c11..cbed55208 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -104,6 +104,7 @@ extern unsigned long sysmap_size; * -- Cort */ int __map_without_bats; +int __map_without_ltlbs; /* max amount of RAM to use */ unsigned long __max_memory; @@ -204,6 +205,10 @@ void MMU_setup(void) __map_without_bats = 1; } + if (strstr(cmd_line, "noltlbs")) { + __map_without_ltlbs = 1; + } + /* Look for mem= option on command line */ if (strstr(cmd_line, "mem=")) { char *p, *q; diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index c16d4cce4..30482852c 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -271,6 +272,18 @@ void iounmap(void *addr) vunmap((void *) (PAGE_MASK & (unsigned long)addr)); } +void __iomem *ioport_map(unsigned long port, unsigned int len) +{ + return (void __iomem *) (port + _IO_BASE); +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + int map_page(unsigned long va, phys_addr_t pa, int flags) { diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c index 6c9bde473..118d8520e 100644 --- a/arch/ppc/platforms/4xx/ebony.c +++ b/arch/ppc/platforms/4xx/ebony.c @@ -4,9 +4,11 @@ * Ebony board specific routines * * Matt Porter - * * Copyright 2002 MontaVista Software Inc. * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * * 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 @@ -118,7 +120,7 @@ static u_char ebony_IRQ_initsenses[] __initdata = { (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 63: EMAC 1 WOL */ }; -extern void abort(void); +static struct ibm44x_clocks clocks __initdata; static void __init ebony_calibrate_decr(void) @@ -143,18 +145,7 @@ ebony_calibrate_decr(void) break; } - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - /* Set the time base to zero */ - mtspr(SPRN_TBWL, 0); - mtspr(SPRN_TBWU, 0); - - /* Clear any pending timer interrupts */ - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); - - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); + ibm44x_calibrate_decr(freq); } static int @@ -283,7 +274,7 @@ ebony_early_serial_map(void) memset(&port, 0, sizeof(port)); port.membase = ioremap64(PPC440GP_UART0_ADDR, 8); port.irq = 0; - port.uartclk = BASE_BAUD * 16; + port.uartclk = clocks.uart0; port.regshift = 0; port.iotype = SERIAL_IO_MEM; port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; @@ -306,7 +297,6 @@ static void __init ebony_setup_arch(void) { unsigned char * vpd_base; - struct ibm44x_clocks clocks; struct ocp_def *def; struct ocp_func_emac_data *emacdata; @@ -361,10 +351,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; @@ -374,152 +360,17 @@ ebony_setup_arch(void) printk("IBM Ebony port (MontaVista Software, Inc. (source@mvista.com))\n"); } -static void -ebony_restart(char *cmd) -{ - local_irq_disable(); - abort(); -} - -static void -ebony_power_off(void) -{ - local_irq_disable(); - for(;;); -} - -static void -ebony_halt(void) -{ - local_irq_disable(); - for(;;); -} - -/* - * Read the 440GP memory controller to get size of system memory. - */ -static unsigned long __init -ebony_find_end_of_memory(void) -{ - u32 i, bank_config; - u32 mem_size = 0; - - for (i=0; i<4; i++) - { - switch (i) - { - case 0: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR); - break; - case 1: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR); - break; - case 2: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR); - break; - case 3: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR); - break; - } - - bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); - - if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE)) - continue; - switch (SDRAM_CONFIG_BANK_SIZE(bank_config)) - { - case SDRAM_CONFIG_SIZE_8M: - mem_size += PPC44x_MEM_SIZE_8M; - break; - case SDRAM_CONFIG_SIZE_16M: - mem_size += PPC44x_MEM_SIZE_16M; - break; - case SDRAM_CONFIG_SIZE_32M: - mem_size += PPC44x_MEM_SIZE_32M; - break; - case SDRAM_CONFIG_SIZE_64M: - mem_size += PPC44x_MEM_SIZE_64M; - break; - case SDRAM_CONFIG_SIZE_128M: - mem_size += PPC44x_MEM_SIZE_128M; - break; - case SDRAM_CONFIG_SIZE_256M: - mem_size += PPC44x_MEM_SIZE_256M; - break; - case SDRAM_CONFIG_SIZE_512M: - mem_size += PPC44x_MEM_SIZE_512M; - break; - } - } - return mem_size; -} - -static void __init -ebony_init_irq(void) -{ - int i; - - ppc4xx_pic_init(); - - for (i = 0; i < NR_IRQS; i++) - irq_desc[i].handler = ppc4xx_pic; -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -static void -ebony_progress(char *s, unsigned short hex) -{ - volatile char c; - volatile unsigned long com_port; - u16 shift; - - com_port = (unsigned long)rs_table[0].iomem_base; - shift = rs_table[0].iomem_reg_shift; - - while ((c = *s++) != 0) { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = c; - - } - - /* Send LF/CR to pretty up output */ - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\r'; - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\n'; -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { parse_bootinfo((struct bi_record *) (r3 + KERNELBASE)); + ibm44x_platform_init(); + ppc_md.setup_arch = ebony_setup_arch; ppc_md.show_cpuinfo = ebony_show_cpuinfo; - ppc_md.init_IRQ = ebony_init_irq; ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ - ppc_md.find_end_of_memory = ebony_find_end_of_memory; - - ppc_md.restart = ebony_restart; - ppc_md.power_off = ebony_power_off; - ppc_md.halt = ebony_halt; - ppc_md.calibrate_decr = ebony_calibrate_decr; ppc_md.time_init = todc_time_init; ppc_md.set_rtc_time = todc_set_rtc_time; @@ -528,9 +379,6 @@ void __init platform_init(unsigned long r3, unsigned long r4, ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = ebony_progress; -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ #ifdef CONFIG_KGDB ppc_md.early_serial_map = ebony_early_serial_map; #endif diff --git a/arch/ppc/platforms/4xx/ebony.h b/arch/ppc/platforms/4xx/ebony.h index c4352e6bb..f90ddf309 100755 --- a/arch/ppc/platforms/4xx/ebony.h +++ b/arch/ppc/platforms/4xx/ebony.h @@ -40,21 +40,21 @@ #define EBONY_RTC_SIZE 0x2000 /* Flash */ -#define EBONY_FPGA_ADDR 0x0000000148300000 +#define EBONY_FPGA_ADDR 0x0000000148300000ULL #define EBONY_BOOT_SMALL_FLASH(x) (x & 0x20) #define EBONY_ONBRD_FLASH_EN(x) (x & 0x02) #define EBONY_FLASH_SEL(x) (x & 0x01) -#define EBONY_SMALL_FLASH_LOW1 0x00000001ff800000 -#define EBONY_SMALL_FLASH_LOW2 0x00000001ff880000 -#define EBONY_SMALL_FLASH_HIGH1 0x00000001fff00000 -#define EBONY_SMALL_FLASH_HIGH2 0x00000001fff80000 +#define EBONY_SMALL_FLASH_LOW1 0x00000001ff800000ULL +#define EBONY_SMALL_FLASH_LOW2 0x00000001ff880000ULL +#define EBONY_SMALL_FLASH_HIGH1 0x00000001fff00000ULL +#define EBONY_SMALL_FLASH_HIGH2 0x00000001fff80000ULL #define EBONY_SMALL_FLASH_SIZE 0x80000 -#define EBONY_LARGE_FLASH_LOW 0x00000001ff800000 -#define EBONY_LARGE_FLASH_HIGH 0x00000001ffc00000 +#define EBONY_LARGE_FLASH_LOW 0x00000001ff800000ULL +#define EBONY_LARGE_FLASH_HIGH 0x00000001ffc00000ULL #define EBONY_LARGE_FLASH_SIZE 0x400000 -#define EBONY_SMALL_FLASH_BASE 0x00000001fff80000 -#define EBONY_LARGE_FLASH_BASE 0x00000001ff800000 +#define EBONY_SMALL_FLASH_BASE 0x00000001fff80000ULL +#define EBONY_LARGE_FLASH_BASE 0x00000001ff800000ULL /* * Serial port defines diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c index 6376890e3..c981f70aa 100644 --- a/arch/ppc/platforms/4xx/ocotea.c +++ b/arch/ppc/platforms/4xx/ocotea.c @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -57,27 +58,21 @@ */ #include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h" -extern void abort(void); +bd_t __res; + +static struct ibm44x_clocks clocks __initdata; static void __init ocotea_calibrate_decr(void) { unsigned int freq; - freq = OCOTEA_SYSCLK; - - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - /* Set the time base to zero */ - mtspr(SPRN_TBWL, 0); - mtspr(SPRN_TBWU, 0); - - /* Clear any pending timer interrupts */ - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + if (mfspr(SPRN_CCR1) & CCR1_TCS) + freq = OCOTEA_TMR_CLK; + else + freq = clocks.cpu; - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); + ibm44x_calibrate_decr(freq); } static int @@ -88,6 +83,7 @@ ocotea_show_cpuinfo(struct seq_file *m) return 0; } + static inline int ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) { @@ -107,6 +103,46 @@ ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) return PCI_IRQ_TABLE_LOOKUP; } +static void __init ocotea_set_emacdata(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + int i; + + /* + * Note: Current rev. board only operates in Group 4a + * mode, so we always set EMAC0-1 for SMII and EMAC2-3 + * for RGMII (though these could run in RTBI just the same). + * + * The FPGA reg 3 information isn't even suitable for + * determining the phy_mode, so if the board becomes + * usable in !4a, it will be necessary to parse an environment + * variable from the firmware or similar to properly configure + * the phy_map/phy_mode. + */ + /* Set phy_map, phy_mode, and mac_addr for each EMAC */ + for (i=0; i<4; i++) { + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); + emacdata = def->additions; + if (i < 2) { + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_SMII; + } + else { + emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */ + emacdata->phy_mode = PHY_MODE_RGMII; + } + if (i == 0) + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); + else if (i == 1) + memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6); + else if (i == 2) + memcpy(emacdata->mac_addr, __res.bi_enet2addr, 6); + else if (i == 3) + memcpy(emacdata->mac_addr, __res.bi_enet3addr, 6); + } +} + #define PCIX_READW(offset) \ (readw((u32)pcix_reg_base+offset)) @@ -209,7 +245,7 @@ ocotea_setup_hose(void) TODC_ALLOC(); static void __init -ocotea_early_serial_map(const struct ibm44x_clocks *clks) +ocotea_early_serial_map(void) { struct uart_port port; @@ -217,7 +253,7 @@ ocotea_early_serial_map(const struct ibm44x_clocks *clks) memset(&port, 0, sizeof(port)); port.membase = ioremap64(PPC440GX_UART0_ADDR, 8); port.irq = UART0_INT; - port.uartclk = clks->uart0; + port.uartclk = clocks.uart0; port.regshift = 0; port.iotype = SERIAL_IO_MEM; port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; @@ -229,7 +265,7 @@ ocotea_early_serial_map(const struct ibm44x_clocks *clks) port.membase = ioremap64(PPC440GX_UART1_ADDR, 8); port.irq = UART1_INT; - port.uartclk = clks->uart1; + port.uartclk = clocks.uart1; port.line = 1; if (early_serial_setup(&port) != 0) { @@ -240,41 +276,7 @@ ocotea_early_serial_map(const struct ibm44x_clocks *clks) static void __init ocotea_setup_arch(void) { - unsigned char *addr; - unsigned long long mac64; - struct ocp_def *def; - struct ocp_func_emac_data *emacdata; - int i; - struct ibm44x_clocks clocks; - - /* - * Note: Current rev. board only operates in Group 4a - * mode, so we always set EMAC0-1 for SMII and EMAC2-3 - * for RGMII (though these could run in RTBI just the same). - * - * The FPGA reg 3 information isn't even suitable for - * determining the phy_mode, so if the board becomes - * usable in !4a, it will be necessary to parse an environment - * variable from the firmware or similar to properly configure - * the phy_map/phy_mode. - */ - /* Set phy_map, phy_mode, and mac_addr for each EMAC */ - addr = ioremap64(OCOTEA_MAC_BASE, OCOTEA_MAC_SIZE); - for (i=0; i<4; i++) { - mac64 = simple_strtoull(addr+OCOTEA_MAC_OFFSET*i, 0, 16); - def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); - emacdata = def->additions; - if (i < 2) { - emacdata->phy_map = 0x00000001; /* Skip 0x00 */ - emacdata->phy_mode = PHY_MODE_SMII; - } - else { - emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */ - emacdata->phy_mode = PHY_MODE_RGMII; - } - memcpy(emacdata->mac_addr, (char *)&mac64+2, 6); - } - iounmap(addr); + ocotea_set_emacdata(); ibm440gx_tah_enable(); @@ -319,173 +321,33 @@ ocotea_setup_arch(void) ROOT_DEV = Root_HDA1; #endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - ocotea_early_serial_map(&clocks); + ocotea_early_serial_map(); /* Identify the system */ printk("IBM Ocotea port (MontaVista Software, Inc. )\n"); } -static void -ocotea_restart(char *cmd) -{ - local_irq_disable(); - abort(); -} - -static void -ocotea_power_off(void) -{ - local_irq_disable(); - for(;;); -} - -static void -ocotea_halt(void) -{ - local_irq_disable(); - for(;;); -} - -/* - * Read the 440GX memory controller to get size of system memory. - */ -static unsigned long __init -ocotea_find_end_of_memory(void) -{ - u32 i, bank_config; - u32 mem_size = 0; - - for (i=0; i<4; i++) - { - switch (i) - { - case 0: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR); - break; - case 1: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR); - break; - case 2: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR); - break; - case 3: - mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR); - break; - } - - bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); - - if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE)) - continue; - switch (SDRAM_CONFIG_BANK_SIZE(bank_config)) - { - case SDRAM_CONFIG_SIZE_8M: - mem_size += PPC44x_MEM_SIZE_8M; - break; - case SDRAM_CONFIG_SIZE_16M: - mem_size += PPC44x_MEM_SIZE_16M; - break; - case SDRAM_CONFIG_SIZE_32M: - mem_size += PPC44x_MEM_SIZE_32M; - break; - case SDRAM_CONFIG_SIZE_64M: - mem_size += PPC44x_MEM_SIZE_64M; - break; - case SDRAM_CONFIG_SIZE_128M: - mem_size += PPC44x_MEM_SIZE_128M; - break; - case SDRAM_CONFIG_SIZE_256M: - mem_size += PPC44x_MEM_SIZE_256M; - break; - case SDRAM_CONFIG_SIZE_512M: - mem_size += PPC44x_MEM_SIZE_512M; - break; - } - } - return mem_size; -} - -static void __init -ocotea_init_irq(void) -{ - int i; - - ppc4xx_pic_init(); - - for (i = 0; i < NR_IRQS; i++) - irq_desc[i].handler = ppc4xx_pic; -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include -struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -static void -ocotea_progress(char *s, unsigned short hex) -{ - volatile char c; - volatile unsigned long com_port; - u16 shift; - - com_port = (unsigned long)rs_table[0].iomem_base; - shift = rs_table[0].iomem_reg_shift; - - while ((c = *s++) != 0) { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = c; - - } - - /* Send LF/CR to pretty up output */ - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\r'; - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\n'; -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - -#if 0 -static void __init -ocotea_map_io(void) -{ - io_block_mapping(0xe0000000, 0x0000000140000000, - 0x00001000, _PAGE_IO); -} -#endif - void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - parse_bootinfo((struct bi_record *) (r3 + KERNELBASE)); + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) + __res = *(bd_t *)(r3 + KERNELBASE); /* Disable L2-Cache due to hardware issues */ ibm440gx_l2c_disable(); + ibm44x_platform_init(); + ppc_md.setup_arch = ocotea_setup_arch; ppc_md.show_cpuinfo = ocotea_show_cpuinfo; - ppc_md.init_IRQ = ocotea_init_irq; ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ - ppc_md.find_end_of_memory = ocotea_find_end_of_memory; - - ppc_md.restart = ocotea_restart; - ppc_md.power_off = ocotea_power_off; - ppc_md.halt = ocotea_halt; - ppc_md.calibrate_decr = ocotea_calibrate_decr; ppc_md.time_init = todc_time_init; ppc_md.set_rtc_time = todc_set_rtc_time; @@ -494,9 +356,6 @@ void __init platform_init(unsigned long r3, unsigned long r4, ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = ocotea_progress; -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ #ifdef CONFIG_KGDB ppc_md.early_serial_map = ocotea_early_serial_map; #endif diff --git a/arch/ppc/platforms/4xx/ocotea.h b/arch/ppc/platforms/4xx/ocotea.h index 17fe8dada..90cd0afa1 100644 --- a/arch/ppc/platforms/4xx/ocotea.h +++ b/arch/ppc/platforms/4xx/ocotea.h @@ -24,13 +24,14 @@ /* F/W TLB mapping used in bootloader glue to reset EMAC */ #define PPC44x_EMAC0_MR0 0xE0000800 -/* Location of MAC addresses in firmware */ -#define OCOTEA_MAC_BASE (OCOTEA_SMALL_FLASH_HIGH+0xb0500) -#define OCOTEA_MAC_SIZE 0x200 -#define OCOTEA_MAC_OFFSET 0x100 - -/* Default clock rate */ -#define OCOTEA_SYSCLK 25000000 +/* Location of MAC addresses in PIBS image */ +#define OCOTEA_PIBS_FLASH 0xfff00000 +#define OCOTEA_PIBS_MAC_BASE (OCOTEA_PIBS_FLASH+0xb0500) +#define OCOTEA_PIBS_MAC_SIZE 0x200 +#define OCOTEA_PIBS_MAC_OFFSET 0x100 + +/* External timer clock frequency */ +#define OCOTEA_TMR_CLK 25000000 /* RTC/NVRAM location */ #define OCOTEA_RTC_ADDR 0x0000000148000000ULL diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index aada7e456..686dd6d9a 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 c7e53e39c..5eb6e4218 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -307,7 +307,7 @@ mpc85xx_exclude_device(u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; -#if CONFIG_85xx_PCI2 +#ifdef CONFIG_85xx_PCI2 /* With the current code we know PCI2 will be bus 2, however this may * not be guarnteed */ if (bus == 2 && PCI_SLOT(devfn) == 0) @@ -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 a4a91aa6a..50cc50a0c 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 c59d4871d..c393f58e5 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 56be78eb4..3514bb9ed 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 */ @@ -382,7 +375,7 @@ void __init chrp_init_IRQ(void) { struct device_node *np; int i; - unsigned long chrp_int_ack; + unsigned long chrp_int_ack = 0; unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c index 71f62a055..863d1e325 100644 --- a/arch/ppc/platforms/chrp_smp.c +++ b/arch/ppc/platforms/chrp_smp.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h index bc51f072a..adba68ecf 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/k2.c b/arch/ppc/platforms/k2.c index 4e2e18a52..8a602039f 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/lite5200.c b/arch/ppc/platforms/lite5200.c index 043040dc9..db6ea440c 100644 --- a/arch/ppc/platforms/lite5200.c +++ b/arch/ppc/platforms/lite5200.c @@ -36,6 +36,8 @@ #include +extern int powersave_nap; + /* Board data given by U-Boot */ bd_t __res; EXPORT_SYMBOL(__res); /* For modules */ @@ -64,25 +66,55 @@ struct ocp_def board_ocp[] = { .vendor = OCP_VENDOR_INVALID } }; - + /* ======================================================================== */ /* Platform specific code */ /* ======================================================================== */ static int -icecube_show_cpuinfo(struct seq_file *m) +lite5200_show_cpuinfo(struct seq_file *m) { seq_printf(m, "machine\t\t: Freescale LITE5200\n"); return 0; } static void __init -icecube_setup_arch(void) +lite5200_setup_cpu(void) { + struct mpc52xx_intr *intr; + + u32 intr_ctrl; + + /* Map zones */ + intr = (struct mpc52xx_intr *) + ioremap(MPC52xx_INTR,sizeof(struct mpc52xx_intr)); + + if (!intr) { + printk("lite5200.c: Error while mapping INTR during lite5200_setup_cpu\n"); + goto unmap_regs; + } + + /* IRQ[0-3] setup : IRQ0 - Level Active Low */ + /* IRQ[1-3] - Level Active High */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= ~0x00ff0000; + intr_ctrl |= 0x00c00000; + out_be32(&intr->ctrl, intr_ctrl); + + /* Unmap reg zone */ +unmap_regs: + if (intr) iounmap(intr); +} +static void __init +lite5200_setup_arch(void) +{ /* Add board OCP definitions */ mpc52xx_add_board_devices(board_ocp); + + /* CPU & Port mux setup */ + lite5200_setup_cpu(); } void __init @@ -110,7 +142,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, initrd_end = r5 + KERNELBASE; } #endif - + /* Load the command line */ if (r6) { *(char *)(r7+KERNELBASE) = 0; @@ -120,14 +152,17 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, /* BAT setup */ mpc52xx_set_bat(); - + /* No ISA bus AFAIK */ isa_io_base = 0; isa_mem_base = 0; + /* Powersave */ + powersave_nap = 1; /* We allow this platform to NAP */ + /* Setup the ppc_md struct */ - ppc_md.setup_arch = icecube_setup_arch; - ppc_md.show_cpuinfo = icecube_show_cpuinfo; + ppc_md.setup_arch = lite5200_setup_arch; + ppc_md.show_cpuinfo = lite5200_show_cpuinfo; ppc_md.show_percpuinfo = NULL; ppc_md.init_IRQ = mpc52xx_init_irq; ppc_md.get_irq = mpc52xx_get_irq; @@ -138,12 +173,12 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.restart = mpc52xx_restart; ppc_md.power_off = mpc52xx_power_off; ppc_md.halt = mpc52xx_halt; - - /* No time keeper on the IceCube */ + + /* No time keeper on the LITE5200 */ ppc_md.time_init = NULL; ppc_md.get_rtc_time = NULL; ppc_md.set_rtc_time = NULL; - + ppc_md.calibrate_decr = mpc52xx_calibrate_decr; #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = mpc52xx_progress; diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c new file mode 100644 index 000000000..0037f5ca4 --- /dev/null +++ b/arch/ppc/platforms/lopec.c @@ -0,0 +1,410 @@ +/* + * arch/ppc/platforms/lopec.c + * + * Setup routines for the Motorola LoPEC. + * + * Author: Dan Cox + * Maintainer: Tom Rini + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Define all of the IRQ senses and polarities. Taken from the + * LoPEC Programmer's Reference Guide. + */ +static u_char lopec_openpic_initsenses[16] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 5 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 6 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 7 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 8 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 9 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 10 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 11 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 12 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 13 */ + (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ 14 */ + (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) +{ + seq_printf(m, "machine\t\t: Motorola LoPEC\n"); + return 0; +} + +static u32 +lopec_irq_canonicalize(u32 irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static void +lopec_restart(char *cmd) +{ +#define LOPEC_SYSSTAT1 0xffe00000 + /* force a hard reset, if possible */ + unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1); + reg |= 0x80; + *((unsigned char *) LOPEC_SYSSTAT1) = reg; + + local_irq_disable(); + while(1); +#undef LOPEC_SYSSTAT1 +} + +static void +lopec_halt(void) +{ + local_irq_disable(); + while(1); +} + +static void +lopec_power_off(void) +{ + lopec_halt(); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +int lopec_ide_ports_known = 0; +static unsigned long lopec_ide_regbase[MAX_HWIFS]; +static unsigned long lopec_ide_ctl_regbase[MAX_HWIFS]; +static unsigned long lopec_idedma_regbase; + +static void +lopec_ide_probe(void) +{ + struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, + NULL); + lopec_ide_ports_known = 1; + + if (dev) { + lopec_ide_regbase[0] = dev->resource[0].start; + lopec_ide_regbase[1] = dev->resource[2].start; + lopec_ide_ctl_regbase[0] = dev->resource[1].start; + lopec_ide_ctl_regbase[1] = dev->resource[3].start; + lopec_idedma_regbase = dev->resource[4].start; + } +} + +static int +lopec_ide_default_irq(unsigned long base) +{ + if (lopec_ide_ports_known == 0) + lopec_ide_probe(); + + if (base == lopec_ide_regbase[0]) + return 14; + else if (base == lopec_ide_regbase[1]) + return 15; + else + return 0; +} + +static unsigned long +lopec_ide_default_io_base(int index) +{ + if (lopec_ide_ports_known == 0) + lopec_ide_probe(); + return lopec_ide_regbase[index]; +} + +static void __init +lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data, + unsigned long ctl, int *irq) +{ + unsigned long reg = data; + uint alt_status_base; + int 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]) { + alt_status_base = lopec_ide_ctl_regbase[1] + 2; + hw->irq = 15; + } else { + alt_status_base = 0; + hw->irq = 0; + } + + if (ctl) + hw->io_ports[IDE_CONTROL_OFFSET] = ctl; + else + hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; + + if (irq != NULL) + *irq = hw->irq; + +} +#endif /* BLK_DEV_IDE */ + +static void __init +lopec_init_IRQ(void) +{ + int i; + + /* + * Provide the open_pic code with the correct table of interrupts. + */ + OpenPIC_InitSenses = lopec_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses); + + mpc10x_set_openpic(); + + /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + &i8259_irq); + + /* Map i8259 interrupts */ + for(i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + /* + * The EPIC allows for a read in the range of 0xFEF00000 -> + * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. + */ + i8259_init(0xfef00000); +} + +static int __init +lopec_request_io(void) +{ + outb(0x00, 0x4d0); + outb(0xc0, 0x4d1); + + request_region(0x00, 0x20, "dma1"); + request_region(0x20, 0x20, "pic1"); + request_region(0x40, 0x20, "timer"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xa0, 0x20, "pic2"); + request_region(0xc0, 0x20, "dma2"); + + return 0; +} + +device_initcall(lopec_request_io); + +static void __init +lopec_map_io(void) +{ + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); + io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO); +} + +/* + * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. + */ +static __inline__ void +lopec_set_bat(void) +{ + mb(); + mtspr(DBAT1U, 0xf8000ffe); + mtspr(DBAT1L, 0xf800002a); + mb(); +} + +TODC_ALLOC(); + +static void __init +lopec_setup_arch(void) +{ + + TODC_INIT(TODC_TYPE_MK48T37, 0, 0, + ioremap(0xffe80000, 0x8000), 8); + + loops_per_jiffy = 100000000/HZ; + + lopec_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#elif defined(CONFIG_ROOT_NFS) + ROOT_DEV = Root_NFS; +#elif defined(CONFIG_BLK_DEV_IDEDISK) + ROOT_DEV = Root_HDA1; +#else + ROOT_DEV = Root_SDA1; +#endif + +#ifdef CONFIG_PPCBUG_NVRAM + /* Read in NVRAM data */ + init_prep_nvram(); + + /* if no bootargs, look in NVRAM */ + if ( cmd_line[0] == '\0' ) { + char *bootargs; + bootargs = prep_nvram_get_var("bootargs"); + if (bootargs != NULL) { + strcpy(cmd_line, bootargs); + /* again.. */ + strcpy(saved_command_line, cmd_line); + } + } +#endif +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + lopec_set_bat(); + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = lopec_setup_arch; + ppc_md.show_cpuinfo = lopec_show_cpuinfo; + ppc_md.irq_canonicalize = lopec_irq_canonicalize; + ppc_md.init_IRQ = lopec_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = lopec_restart; + ppc_md.power_off = lopec_power_off; + ppc_md.halt = lopec_halt; + + ppc_md.setup_io_mappings = lopec_map_io; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = lopec_ide_default_irq; + ppc_ide_md.default_io_base = lopec_ide_default_io_base; + ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports; +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +} diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h new file mode 100644 index 000000000..5490edb2d --- /dev/null +++ b/arch/ppc/platforms/lopec.h @@ -0,0 +1,39 @@ +/* + * include/asm-ppc/lopec_serial.h + * + * Definitions for Motorola LoPEC board. + * + * Author: Dan Cox + * danc@mvista.com (or, alternately, source@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 __H_LOPEC_SERIAL +#define __H_LOPEC_SERIAL + +#define RS_TABLE_SIZE 3 + +#define BASE_BAUD (1843200 / 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 + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, 0xffe10000, 29, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe10000, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, 0xffe11000, 20, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe11000, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, 0xffe12000, 21, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe12000, \ + io_type: SERIAL_IO_MEM } + +#endif diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c index 06ed9384f..348118b75 100644 --- a/arch/ppc/platforms/mcpn765.c +++ b/arch/ppc/platforms/mcpn765.c @@ -58,8 +58,6 @@ #include #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 872338317..4d35ecad0 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 /* 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 */ +/* 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/mpc5200.c b/arch/ppc/platforms/mpc5200.c index 30b6936c3..dce7225ad 100644 --- a/arch/ppc/platforms/mpc5200.c +++ b/arch/ppc/platforms/mpc5200.c @@ -16,6 +16,12 @@ #include #include + +struct ocp_fs_i2c_data mpc5200_i2c_def = { + .flags = FS_I2C_CLOCK_5200, +}; + + /* Here is the core_ocp struct. * With all the devices common to all board. Even if port multiplexing is * not setup for them (if the user don't want them, just don't select the @@ -23,6 +29,24 @@ * board specific file. */ struct ocp_def core_ocp[] = { + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = MPC52xx_I2C1, + .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C1 - Buggy */ + .pm = OCP_CPM_NA, + .additions = &mpc5200_i2c_def, + }, + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = MPC52xx_I2C2, + .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C2 - Buggy */ + .pm = OCP_CPM_NA, + .additions = &mpc5200_i2c_def, + }, { /* Terminating entry */ .vendor = OCP_VENDOR_INVALID } diff --git a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c new file mode 100644 index 000000000..b08be2458 --- /dev/null +++ b/arch/ppc/platforms/mvme5100.c @@ -0,0 +1,349 @@ +/* + * arch/ppc/platforms/mvme5100.c + * + * Board setup routines for the Motorola MVME5100. + * + * Author: Matt Porter + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; iresource[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) +{ + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: enter", 0); + + loops_per_jiffy = 50000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: find_bridges", 0); + + /* Setup PCI host bridge */ + mvme5100_setup_bridge(); + + /* Find and map our OpenPIC */ + hawk_mpic_init(MVME5100_PCI_MEM_OFFSET); + OpenPIC_InitSenses = mvme5100_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses); + + printk("MVME5100 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: exit", 0); + + return; +} + +static void __init +mvme5100_init2(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); +#endif + return; +} + +/* + * Interrupt setup and service. + * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC. + */ +static void __init +mvme5100_init_IRQ(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + int i; +#endif + + 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(NUM_8259_INTERRUPTS); + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + &i8259_irq); + + /* Map i8259 interrupts. */ + for (i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(NULL); +#else + openpic_init(0); +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: exit", 0); + + return; +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +mvme5100_set_bat(void) +{ + mb(); + mtspr(DBAT1U, 0xf0001ffe); + mtspr(DBAT1L, 0xf000002a); + mb(); +} + +static unsigned long __init +mvme5100_find_end_of_memory(void) +{ + return hawk_get_mem_size(MVME5100_HAWK_SMC_BASE); +} + +static void __init +mvme5100_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); + ioremap_base = 0xfe000000; +} + +static void +mvme5100_reset_board(void) +{ + local_irq_disable(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01); + + return; +} + +static void +mvme5100_restart(char *cmd) +{ + volatile ulong i = 10000000; + + mvme5100_reset_board(); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +mvme5100_halt(void) +{ + local_irq_disable(); + while (1); +} + +static void +mvme5100_power_off(void) +{ + mvme5100_halt(); +} + +static int +mvme5100_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola\n"); + seq_printf(m, "machine\t\t: MVME5100\n"); + + return 0; +} + +TODC_ALLOC(); + +void __init +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; + pci_dram_offset = MVME5100_PCI_DRAM_OFFSET; + + ppc_md.setup_arch = mvme5100_setup_arch; + ppc_md.show_cpuinfo = mvme5100_show_cpuinfo; + ppc_md.init_IRQ = mvme5100_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = mvme5100_init2; + + ppc_md.restart = mvme5100_restart; + ppc_md.power_off = mvme5100_power_off; + ppc_md.halt = mvme5100_halt; + + 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); + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; +} diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h index 5cc61d18b..edd479439 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/pcore.c b/arch/ppc/platforms/pcore.c index 9c428720d..da022ecd8 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_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index 5b2221a14..b51b37d16 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -24,10 +24,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -301,7 +301,6 @@ static int __pmac pmu_set_cpu_speed(int low_speed) static int __pmac do_set_cpu_speed(int speed_mode) { struct cpufreq_freqs freqs; - int rc; freqs.old = cur_freq; freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; @@ -315,7 +314,7 @@ static int __pmac do_set_cpu_speed(int speed_mode) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; - return rc; + return 0; } static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy) @@ -498,7 +497,7 @@ static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) - * - iBook2 500 (PMU based, 400Mhz & 500Mhz) + * - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz) * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) * - Recent MacRISC3 laptops * - iBook G4s and PowerBook G4s with 7447A CPUs @@ -533,11 +532,8 @@ static int __init pmac_cpufreq_setup(void) machine_is_compatible("PowerBook3,5") || machine_is_compatible("MacRISC3")) { pmac_cpufreq_init_MacRISC3(cpunode); - /* Else check for iBook2 500 */ + /* Else check for iBook2 500/600 */ } else if (machine_is_compatible("PowerBook4,1")) { - /* We only know about 500Mhz model */ - if (cur_freq < 450000 || cur_freq > 550000) - goto out; hi_freq = cur_freq; low_freq = 400000; set_speed_proc = pmu_set_cpu_speed; diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c index 35714de24..24b221450 100644 --- a/arch/ppc/platforms/pmac_feature.c +++ b/arch/ppc/platforms/pmac_feature.c @@ -2665,7 +2665,7 @@ set_initial_features(void) struct device_node *p = of_get_parent(ui2c); if (p && !strcmp(p->name, "uni-n")) break; - ui2c = of_find_node_by_type(np, "i2c"); + ui2c = of_find_node_by_type(ui2c, "i2c"); } if (ui2c == NULL) break; diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c index 9dcc4e2e5..4e53bea90 100644 --- a/arch/ppc/platforms/pmac_pci.c +++ b/arch/ppc/platforms/pmac_pci.c @@ -50,6 +50,7 @@ static struct pci_controller *u3_agp; #endif /* CONFIG_POWER4 */ extern u8 pci_cache_line_size; +extern int pcibios_assign_bus_offset; struct pci_dev *k2_skiplist[2]; @@ -315,6 +316,10 @@ u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, unsigned int addr; int i; + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + /* * When a device in K2 is powered down, we die on config * cycle accesses. Fix that here. @@ -362,6 +367,9 @@ u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, unsigned int addr; int i; + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; /* * When a device in K2 is powered down, we die on config * cycle accesses. Fix that here. @@ -565,6 +573,14 @@ pmac_find_bridges(void) init_p2pbridge(); fixup_nec_usb2(); + + /* We are still having some issues with the Xserve G4, enabling + * some offset between bus number and domains for now when we + * assign all busses should help for now + */ + if (pci_assign_all_busses) + pcibios_assign_bus_offset = 0x10; + #ifdef CONFIG_POWER4 /* There is something wrong with DMA on U3/HT. I haven't figured out * the details yet, but if I set the cache line size to 128 bytes like @@ -707,7 +723,7 @@ setup_u3_ht(struct pci_controller* hose, struct reg_property *addr) * properties or figuring out the U3 address space decoding logic and * then read its configuration register (if any). */ - hose->io_base_phys = 0xf4000000 + 0x00400000; + hose->io_base_phys = 0xf4000000; hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); isa_io_base = (unsigned long) hose->io_base_virt; hose->io_resource.name = np->full_name; @@ -1034,6 +1050,8 @@ void pmac_pci_fixup_cardbus(struct pci_dev* dev) } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus); + void pmac_pci_fixup_pciata(struct pci_dev* dev) { u8 progif = 0; @@ -1074,6 +1092,8 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev) printk(KERN_ERR "Rewrite of PROGIF failed !\n"); } } +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); + /* * Disable second function on K2-SATA, it's broken @@ -1104,3 +1124,4 @@ void __pmac pmac_pci_fixup_k2_sata(struct pci_dev* dev) } } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata); diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index b05cee1f7..79fc29514 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/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index 704742257..1a300ff40 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -32,13 +32,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c index cd8e3e7c4..09636546f 100644 --- a/arch/ppc/platforms/pmac_time.c +++ b/arch/ppc/platforms/pmac_time.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h index b834e1786..41a6dc881 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 * - * 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 - #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/pplus.c b/arch/ppc/platforms/pplus.c index 673641ff4..7922346f1 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 000000000..cecaba630 --- /dev/null +++ b/arch/ppc/platforms/pq2ads.c @@ -0,0 +1,26 @@ +/* + * arch/ppc/platforms/pq2ads.c + * + * PQ2ADS platform support + * + * Author: Kumar Gala + * 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 + +#include + +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 1bee6ca56..0c17a0cda 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/prep_pci.c b/arch/ppc/platforms/prep_pci.c index 58775fc7f..a528562cc 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 @@ -900,6 +907,17 @@ ibm43p_pci_map_non0(struct pci_dev *dev) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); } +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) { @@ -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 99acd5170..8051df176 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,17 +450,10 @@ 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) { @@ -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 e0ab8e301..a75553c9a 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 23ed94140..015b4f52c 100644 --- a/arch/ppc/platforms/prpmc750.h +++ b/arch/ppc/platforms/prpmc750.h @@ -5,20 +5,16 @@ * * Author: Matt Porter * - * 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 - /* * 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/prpmc800.c b/arch/ppc/platforms/prpmc800.c index 0ffcfdfb1..0e99f8bc3 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 4af2f2c9a..e53ec9b42 100644 --- a/arch/ppc/platforms/prpmc800.h +++ b/arch/ppc/platforms/prpmc800.h @@ -5,12 +5,10 @@ * * Author: Dale Farnsworth * - * 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/residual.c b/arch/ppc/platforms/residual.c index b094e2715..0f84ca603 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; iActualNumDevices; 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; iActualNumDevices; 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 system address */ + if (!((p.PPCData[0] == 3) && (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.h b/arch/ppc/platforms/rpx8260.h index 7d5cd8893..843494a50 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 fdcbcf240..d9307a261 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 28a77dba3..3a404a88c 100644 --- a/arch/ppc/platforms/sbc82xx.c +++ b/arch/ppc/platforms/sbc82xx.c @@ -16,10 +16,11 @@ */ #include -#include #include #include #include +#include +#include #include #include @@ -28,39 +29,12 @@ #include #include -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(); @@ -236,26 +210,36 @@ 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; + + if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(17, 0)) + return; + + printk(KERN_INFO "Setting up CardBus controller\n"); + + /* Set P2CCLK bit in System Control Register */ + pci_read_config_dword(pdev, 0x80, &ctrl); + ctrl |= (1<<27); + pci_write_config_dword(pdev, 0x80, ctrl); + /* Set MFUNC up for PCI IRQ routing via INTA and INTB, and LEDs. */ + pci_write_config_dword(pdev, 0x8c, 0x00c01d22); + +} +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; ppc_md.init_IRQ = sbc82xx_init_IRQ; ppc_md.pci_map_irq = sbc82xx_pci_map_irq; #ifdef CONFIG_GEN_RTC diff --git a/arch/ppc/platforms/sbc82xx.h b/arch/ppc/platforms/sbc82xx.h index adafd49be..e4042d499 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 ad671021e..74be32456 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 3366cbded..c7a78a646 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 1241ed5d4..a8880bfc0 100644 --- a/arch/ppc/platforms/tqm8260_setup.c +++ b/arch/ppc/platforms/tqm8260_setup.c @@ -14,33 +14,12 @@ * option) any later version. */ -#include -#include +#include #include #include #include -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 4de92f498..fe15101b2 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 43eac4135..bd8335b84 100644 --- a/arch/ppc/syslib/cpm2_pic.c +++ b/arch/ppc/syslib/cpm2_pic.c @@ -1,12 +1,3 @@ -#include -#include -#include -#include -#include -#include -#include -#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 +#include +#include +#include +#include + +#include +#include + +#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 a9da44168..d05003b09 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 - 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 9c2e1506a..a9911dc3a 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/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c index a0cefdc7c..76d18d337 100644 --- a/arch/ppc/syslib/ibm44x_common.c +++ b/arch/ppc/syslib/ibm44x_common.c @@ -6,6 +6,9 @@ * Matt Porter * Copyright 2002-2003 MontaVista Software Inc. * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * * 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 @@ -14,8 +17,14 @@ */ #include #include +#include + +#include #include #include +#include +#include +#include phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size) { @@ -35,3 +44,159 @@ phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size) return (page_4gb | addr); }; + +void __init ibm44x_calibrate_decr(unsigned int freq) +{ + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + /* Clear any pending timer interrupts */ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + + /* Enable decrementer interrupt */ + mtspr(SPRN_TCR, TCR_DIE); +} + +extern void abort(void); + +static void ibm44x_restart(char *cmd) +{ + local_irq_disable(); + abort(); +} + +static void ibm44x_power_off(void) +{ + local_irq_disable(); + for(;;); +} + +static void ibm44x_halt(void) +{ + local_irq_disable(); + for(;;); +} + +/* + * Read the 44x memory controller to get size of system memory. + */ +static unsigned long __init ibm44x_find_end_of_memory(void) +{ + u32 i, bank_config; + u32 mem_size = 0; + + for (i=0; i<4; i++) + { + switch (i) + { + case 0: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR); + break; + case 1: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR); + break; + case 2: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR); + break; + case 3: + mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR); + break; + } + + bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); + + if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE)) + continue; + switch (SDRAM_CONFIG_BANK_SIZE(bank_config)) + { + case SDRAM_CONFIG_SIZE_8M: + mem_size += PPC44x_MEM_SIZE_8M; + break; + case SDRAM_CONFIG_SIZE_16M: + mem_size += PPC44x_MEM_SIZE_16M; + break; + case SDRAM_CONFIG_SIZE_32M: + mem_size += PPC44x_MEM_SIZE_32M; + break; + case SDRAM_CONFIG_SIZE_64M: + mem_size += PPC44x_MEM_SIZE_64M; + break; + case SDRAM_CONFIG_SIZE_128M: + mem_size += PPC44x_MEM_SIZE_128M; + break; + case SDRAM_CONFIG_SIZE_256M: + mem_size += PPC44x_MEM_SIZE_256M; + break; + case SDRAM_CONFIG_SIZE_512M: + mem_size += PPC44x_MEM_SIZE_512M; + break; + } + } + return mem_size; +} + +static void __init ibm44x_init_irq(void) +{ + int i; + + ppc4xx_pic_init(); + + for (i = 0; i < NR_IRQS; i++) + irq_desc[i].handler = ppc4xx_pic; +} + +#ifdef CONFIG_SERIAL_TEXT_DEBUG +#include +#include +#include + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in */ +}; + +static void ibm44x_progress(char *s, unsigned short hex) +{ + volatile char c; + volatile unsigned long com_port; + u16 shift; + + com_port = (unsigned long)rs_table[0].iomem_base; + shift = rs_table[0].iomem_reg_shift; + + while ((c = *s++) != 0) { + while ((*((volatile unsigned char *)com_port + + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = c; + + } + + /* Send LF/CR to pretty up output */ + while ((*((volatile unsigned char *)com_port + + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = '\r'; + while ((*((volatile unsigned char *)com_port + + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = '\n'; +} +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ + +void __init ibm44x_platform_init(void) +{ + ppc_md.init_IRQ = ibm44x_init_irq; + ppc_md.find_end_of_memory = ibm44x_find_end_of_memory; + ppc_md.restart = ibm44x_restart; + ppc_md.power_off = ibm44x_power_off; + ppc_md.halt = ibm44x_halt; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = ibm44x_progress; +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +} + diff --git a/arch/ppc/syslib/ibm44x_common.h b/arch/ppc/syslib/ibm44x_common.h index ee1053ac2..b14eb603c 100644 --- a/arch/ppc/syslib/ibm44x_common.h +++ b/arch/ppc/syslib/ibm44x_common.h @@ -4,7 +4,7 @@ * PPC44x system library * * Eugene Surovegin or - * Copyright (c) 2003 Zultys Technologies + * Copyright (c) 2003, 2004 Zultys Technologies * * 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 @@ -31,6 +31,12 @@ struct ibm44x_clocks { unsigned int uart1; }; +/* common 44x platform init */ +void ibm44x_platform_init(void) __init; + +/* initialize decrementer and tick-related variables */ +void ibm44x_calibrate_decr(unsigned int freq) __init; + #endif /* __ASSEMBLY__ */ #endif /* __PPC_SYSLIB_IBM44x_COMMON_H */ #endif /* __KERNEL__ */ diff --git a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h index 4e2ce7f7c..d1352120a 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 24e1494c1..bfa66a235 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 -#include #include #include #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include #include +#include #include -#include #include #include -#include #include #include #include @@ -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 5ccf07149..0dc7889a8 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 000000000..7838a44bf --- /dev/null +++ b/arch/ppc/syslib/m8xx_wdt.c @@ -0,0 +1,99 @@ +/* + * m8xx_wdt.c - MPC8xx watchdog driver + * + * Author: Florian Schirmer + * + * 2002 (c) Florian Schirmer 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 +#include +#include +#include +#include +#include + +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 000000000..0d81a9f81 --- /dev/null +++ b/arch/ppc/syslib/m8xx_wdt.h @@ -0,0 +1,16 @@ +/* + * Author: Florian Schirmer + * + * 2002 (c) Florian Schirmer 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/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c index 0f88e63b0..4de79d3b9 100644 --- a/arch/ppc/syslib/mpc52xx_pic.c +++ b/arch/ppc/syslib/mpc52xx_pic.c @@ -114,7 +114,7 @@ mpc52xx_ic_ack(unsigned int irq) /* * Only some irqs are reset here, others in interrupting hardware. */ - + switch (irq) { case MPC52xx_IRQ0: val = in_be32(&intr->ctrl); @@ -180,13 +180,14 @@ void __init mpc52xx_init_irq(void) { int i; + u32 intr_ctrl; /* Remap the necessary zones */ intr = (struct mpc52xx_intr *) ioremap(MPC52xx_INTR, sizeof(struct mpc52xx_intr)); sdma = (struct mpc52xx_sdma *) ioremap(MPC52xx_SDMA, sizeof(struct mpc52xx_sdma)); - + if ((intr==NULL) || (sdma==NULL)) panic("Can't ioremap PIC/SDMA register for init_irq !"); @@ -195,12 +196,13 @@ mpc52xx_init_irq(void) out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ - out_be32(&intr->ctrl, - 0x0f000000 | /* clear IRQ 0-3 */ - 0x00c00000 | /* IRQ0: level-sensitive, active low */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ 0x00001000 | /* MEE master external enable */ 0x00000000 | /* 0 means disable IRQ 0-3 */ - 0x00000001); /* CEb route critical normally */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); /* Zero a bunch of the priority settings. */ out_be32(&intr->per_pri1, 0); @@ -214,6 +216,14 @@ mpc52xx_init_irq(void) irq_desc[i].handler = &mpc52xx_ic; irq_desc[i].status = IRQ_LEVEL; } + + #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i=0 ; i<4 ; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl,i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; + } } int diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c index 631cea34b..d73e6fea5 100644 --- a/arch/ppc/syslib/mpc52xx_setup.c +++ b/arch/ppc/syslib/mpc52xx_setup.c @@ -1,5 +1,5 @@ /* - * arch/ppc/syslib/mpc52xx_common.c + * arch/ppc/syslib/mpc52xx_setup.c * * Common code for the boards based on Freescale MPC52xx embedded CPU. * @@ -23,6 +23,7 @@ #include #include #include +#include #include extern bd_t __res; @@ -38,9 +39,9 @@ void mpc52xx_restart(char *cmd) { struct mpc52xx_gpt* gpt0 = (struct mpc52xx_gpt*) MPC52xx_GPTx(0); - + local_irq_disable(); - + /* Turn on the watchdog and wait for it to expire. It effectively does a reset */ if (gpt0 != NULL) { @@ -99,24 +100,28 @@ mpc52xx_map_io(void) #error "mpc52xx PSC for console not selected" #endif +static void +mpc52xx_psc_putc(struct mpc52xx_psc * psc, unsigned char c) +{ + while (!(in_be16(&psc->mpc52xx_psc_status) & + MPC52xx_PSC_SR_TXRDY)); + out_8(&psc->mpc52xx_psc_buffer_8, c); +} + void mpc52xx_progress(char *s, unsigned short hex) { struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE; char c; - /* Don't we need to disable serial interrupts ? */ - while ((c = *s++) != 0) { - if (c == '\n') { - while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXRDY)) ; - out_8(&psc->mpc52xx_psc_buffer_8, '\r'); - } - while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXRDY)) ; - out_8(&psc->mpc52xx_psc_buffer_8, c); + if (c == '\n') + mpc52xx_psc_putc(psc, '\r'); + mpc52xx_psc_putc(psc, c); } + + mpc52xx_psc_putc(psc, '\r'); + mpc52xx_psc_putc(psc, '\n'); } #endif /* CONFIG_SERIAL_TEXT_DEBUG */ @@ -137,7 +142,7 @@ mpc52xx_find_end_of_memory(void) /* Temp BAT2 mapping active when this is called ! */ mmap_ctl = (struct mpc52xx_mmap_ctl*) MPC52xx_MMAP_CTL; - + sdram_config_0 = in_be32(&mmap_ctl->sdram0); sdram_config_1 = in_be32(&mmap_ctl->sdram1); @@ -147,10 +152,8 @@ mpc52xx_find_end_of_memory(void) if (((sdram_config_1 & 0x1f) >= 0x13) && ((sdram_config_1 & 0xfff00000) == ramsize)) ramsize += 1 << ((sdram_config_1 & 0xf) + 17); - - iounmap(mmap_ctl); } - + return ramsize; } @@ -167,7 +170,7 @@ mpc52xx_calibrate_decr(void) /* Get RTC & Clock manager modules */ struct mpc52xx_rtc *rtc; struct mpc52xx_cdm *cdm; - + rtc = (struct mpc52xx_rtc*) ioremap(MPC52xx_RTC, sizeof(struct mpc52xx_rtc)); cdm = (struct mpc52xx_cdm*) @@ -206,7 +209,7 @@ mpc52xx_calibrate_decr(void) __res.bi_intfreq = cpufreq; __res.bi_ipbfreq = ipbfreq; __res.bi_pcifreq = pcifreq; - + /* Release mapping */ iounmap((void*)rtc); iounmap((void*)cdm); diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index a19f8c2d9..133797ab3 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include "open_pic_defs.h" @@ -412,7 +412,7 @@ void __init openpic_init(int offset) /* Initialize the spurious interrupt */ if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd); - openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); openpic_disable_8259_pass_through(); #ifdef CONFIG_EPIC_SERIAL_MODE openpic_eicr_set_clk(7); /* Slowest value until we know better */ @@ -865,7 +865,7 @@ openpic_get_irq(struct pt_regs *regs) irq = cirq; openpic_eoi(); } - } else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) + } else if (irq == OPENPIC_VEC_SPURIOUS) irq = -1; return irq; } @@ -988,9 +988,9 @@ int openpic_resume(struct sys_device *sysdev) /* OpenPIC sometimes seem to need some time to be fully back up... */ do { - openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); } while(openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK) - != (OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)); + != OPENPIC_VEC_SPURIOUS); openpic_disable_8259_pass_through(); diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index 52cb4a494..191e5af0e 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include "open_pic_defs.h" diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c index e6da0a20d..2dc63a58c 100644 --- a/arch/ppc/syslib/ppc4xx_pic.c +++ b/arch/ppc/syslib/ppc4xx_pic.c @@ -256,7 +256,7 @@ static void ppc4xx_uic_end(unsigned int irq) { int bit, word; - unsigned int tr_bits; + unsigned int tr_bits = 0; bit = irq & 0x1f; word = irq >> 5; diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c index f7458822f..735f3aec8 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/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index 6ceea97f4..d4e651534 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -277,7 +277,7 @@ mpc85xx_setup_hose(void) hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO; hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO; hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE; -#if CONFIG_85xx_PCI2 +#ifdef CONFIG_85xx_PCI2 isa_io_base = (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE, MPC85XX_PCI1_IO_SIZE + @@ -304,7 +304,7 @@ mpc85xx_setup_hose(void) hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); -#if CONFIG_85xx_PCI2 +#ifdef CONFIG_85xx_PCI2 hose_b = pcibios_alloc_controller(); if (!hose_b) diff --git a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c index c9701d5ba..ac4c8b158 100644 --- a/arch/ppc/syslib/prom_init.c +++ b/arch/ppc/syslib/prom_init.c @@ -115,11 +115,11 @@ prom_entry prom __initdata; ihandle prom_chosen __initdata; ihandle prom_stdout __initdata; -char *prom_display_paths[FB_MAX] __initdata; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays __initdata; -char *of_stdout_device __initdata; +static char *prom_display_paths[FB_MAX] __initdata; +static phandle prom_display_nodes[FB_MAX] __initdata; +static unsigned int prom_num_displays __initdata; static ihandle prom_disp_node __initdata; +char *of_stdout_device __initdata; unsigned int rtas_data; /* physical pointer */ unsigned int rtas_entry; /* physical pointer */ @@ -403,6 +403,7 @@ check_display(unsigned long mem) for (j=0; jcontrol_a); @@ -361,7 +361,7 @@ int todc_set_rtc_time(unsigned long nowtime) { struct rtc_time tm; - u_char save_control, save_freq_select; + u_char save_control, save_freq_select = 0; spin_lock(&rtc_lock); to_tm(nowtime, &tm); @@ -416,7 +416,7 @@ todc_set_rtc_time(unsigned long nowtime) */ static unsigned char __init todc_read_timereg(int addr) { - unsigned char save_control, val; + unsigned char save_control = 0, val; switch (todc_info->rtc_type) { case TODC_TYPE_DS1557: diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 5705ce63b..1a56c0d42 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -1,4 +1,4 @@ -# +# # For a description of the syntax of this configuration file, # see Documentation/kbuild/kconfig-language.txt. # @@ -58,16 +58,28 @@ menu "Platform support" choice prompt "Platform Type" - default PPC_PSERIES + default PPC_MULTIPLATFORM config PPC_ISERIES - bool "iSeries" + bool "IBM Legacy iSeries" -config PPC_PSERIES - bool "pSeries / PowerMac G5" +config PPC_MULTIPLATFORM + bool "Generic" endchoice +config PPC_PSERIES + depends on PPC_MULTIPLATFORM + bool " IBM pSeries & new iSeries" + default y + +config PPC_PMAC + depends on PPC_MULTIPLATFORM + bool " Apple G5 based machines" + default y + select ADB_PMU + select U3_DART + config PPC bool default y @@ -77,7 +89,7 @@ config PPC64 default y config PPC_OF - depends on PPC_PSERIES + depends on PPC_MULTIPLATFORM bool default y @@ -85,14 +97,9 @@ config PPC_OF # exception vectors for it config ALTIVEC bool "Support for VMX (Altivec) vector unit" - depends on PPC_PSERIES + depends on PPC_MULTIPLATFORM default y -config PPC_PMAC - depends on PPC_PSERIES - bool "Apple PowerMac G5 support" - select ADB_PMU - config PPC_SPLPAR depends on PPC_PSERIES bool "Support for shared-processor logical partitions" @@ -103,16 +110,10 @@ config PPC_SPLPAR processors, that is, which share physical processors between two or more partitions. -config PMAC_DART - bool "Enable DART/IOMMU on PowerMac (allow >2G of RAM)" - depends on PPC_PMAC - depends on EXPERIMENTAL +config U3_DART + bool + depends on PPC_MULTIPLATFORM default n - help - Enabling DART makes it possible to boot a PowerMac G5 with more - than 2GB of memory. Note that the code is very new and untested - at this time, so it has to be considered experimental. Enabling - this might result in data loss. config PPC_PMAC64 bool @@ -163,7 +164,7 @@ config SMP config IRQ_ALL_CPUS bool "Distribute interrupts on all CPUs by default" - depends on SMP && PPC_PSERIES + depends on SMP && PPC_MULTIPLATFORM help This option gives the kernel permission to distribute IRQs across multiple CPUs. Saying N here will route all IRQs to the first @@ -214,7 +215,7 @@ config MSCHUNKS config PPC_RTAS bool "Proc interface to RTAS" - depends on !PPC_ISERIES + depends on PPC_PSERIES config RTAS_FLASH tristate "Firmware flash interface" @@ -226,8 +227,9 @@ config SCANLOG config LPARCFG tristate "LPAR Configuration Data" + depends on PPC_PSERIES || PPC_ISERIES help - Provide system capacity information via human readable + Provide system capacity information via human readable = pairs through a /proc/ppc64/lparcfg interface. endmenu @@ -272,7 +274,7 @@ source "drivers/pci/Kconfig" config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" - depends on SMP && HOTPLUG && EXPERIMENTAL + depends on SMP && HOTPLUG && EXPERIMENTAL && PPC_PSERIES ---help--- Say Y here to be able to turn CPUs off and on. @@ -343,102 +345,10 @@ config VIOPATH source "arch/ppc64/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_STACKOVERFLOW - bool "Check for stack overflows" - depends on DEBUG_KERNEL - -config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUGGER - bool "Enable debugger hooks" - depends on DEBUG_KERNEL - help - Include in-kernel hooks for kernel debuggers. Unless you are - intending to debug the kernel, say N here. - -config XMON - bool "Include xmon kernel debugger" - depends on DEBUGGER - help - Include in-kernel hooks for the xmon kernel monitor/debugger. - Unless you are intending to debug the kernel, say N here. - -config XMON_DEFAULT - bool "Enable xmon by default" - depends on XMON - -config PPCDBG - bool "Include PPCDBG realtime debugging" - depends on DEBUG_KERNEL - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config IRQSTACKS - bool "Use separate kernel stacks when processing interrupts" - help - If you say Y here the kernel will use separate kernel stacks - for handling hard and soft interrupts. This can help avoid - overflowing the process kernel stacks. - -config SPINLINE - bool "Inline spinlock code at each call site" - depends on SMP && !PPC_SPLPAR && !PPC_ISERIES - help - Say Y if you want to have the code for acquiring spinlocks - and rwlocks inlined at each call site. This makes the kernel - somewhat bigger, but can be useful when profiling the kernel. - - If in doubt, say N. - -endmenu +source "arch/ppc64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug new file mode 100644 index 000000000..c3cd4c747 --- /dev/null +++ b/arch/ppc64/Kconfig.debug @@ -0,0 +1,59 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config DEBUGGER + bool "Enable debugger hooks" + depends on DEBUG_KERNEL + help + Include in-kernel hooks for kernel debuggers. Unless you are + intending to debug the kernel, say N here. + +config XMON + bool "Include xmon kernel debugger" + depends on DEBUGGER + help + Include in-kernel hooks for the xmon kernel monitor/debugger. + Unless you are intending to debug the kernel, say N here. + +config XMON_DEFAULT + bool "Enable xmon by default" + depends on XMON + +config PPCDBG + bool "Include PPCDBG realtime debugging" + depends on DEBUG_KERNEL + +config IRQSTACKS + bool "Use separate kernel stacks when processing interrupts" + help + If you say Y here the kernel will use separate kernel stacks + for handling hard and soft interrupts. This can help avoid + overflowing the process kernel stacks. + +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/Makefile b/arch/ppc64/Makefile index 10c1d6299..59fdc0e27 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -15,29 +15,34 @@ KERNELLOAD := 0xc000000000000000 -HAS_BIARCH := $(shell if $(CC) -m64 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;) +HAS_BIARCH := $(call cc-option-yn, -m64) ifeq ($(HAS_BIARCH),y) AS := $(AS) -a64 LD := $(LD) -m elf64ppc CC := $(CC) -m64 endif -CHECK := $(CHECK) -m64 -D__powerpc__=1 +new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) + +ifeq ($(new_nm),y) +NM := $(NM) --synthetic +endif + +CHECKFLAGS += -m64 -D__powerpc__ LDFLAGS := -m elf64ppc LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) -CFLAGS += -msoft-float -pipe -Wno-uninitialized -mminimal-toc \ - -mtraceback=none +CFLAGS += -msoft-float -pipe -mminimal-toc -mtraceback=none ifeq ($(CONFIG_POWER4_ONLY),y) - CFLAGS += $(call check_gcc,-mcpu=power4,) + CFLAGS += $(call cc-option,-mcpu=power4) else - CFLAGS += $(call check_gcc,-mtune=power4,) + CFLAGS += $(call cc-option,-mtune=power4) endif # Enable unit-at-a-time mode when possible. It shrinks the # kernel considerably. -CFLAGS += $(call check_gcc,-funit-at-a-time,) +CFLAGS += $(call cc-option,-funit-at-a-time) head-y := arch/ppc64/kernel/head.o diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index 9d6431dd6..8f99c9dbc 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -25,11 +25,11 @@ CROSS32_COMPILE ?= BOOTCC := $(CROSS32_COMPILE)gcc HOSTCC := gcc -BOOTCFLAGS := $(HOSTCFLAGS) -Iinclude -fno-builtin +BOOTCFLAGS := $(HOSTCFLAGS) $(LINUXINCLUDE) -fno-builtin BOOTAS := $(CROSS32_COMPILE)as BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional BOOTLD := $(CROSS32_COMPILE)ld -BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(obj)/zImage.lds +BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds BOOTOBJCOPY := $(CROSS32_COMPILE)objcopy OBJCOPYFLAGS := contents,alloc,load,readonly,data @@ -51,36 +51,31 @@ $(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S #----------------------------------------------------------- # ELF sections within the zImage bootloader/wrapper #----------------------------------------------------------- -required := vmlinux .config System.map +required := vmlinux.strip initrd := initrd obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section))) src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) -host-progs := piggy addnote addSystemMap addRamDisk +hostprogs-y := piggy addnote addRamDisk targets += zImage zImage.initrd imagesize.c \ $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ - vmlinux.sm vmlinux.initrd vmlinux.sminitrd -extra-y := sysmap.o initrd.o - -quiet_cmd_sysmap = SYSMAP $@ - cmd_sysmap = $(obj)/addSystemMap System.map $< $@ -$(obj)/vmlinux.sm: vmlinux $(obj)/addSystemMap System.map FORCE - $(call if_changed,sysmap) + vmlinux.initrd +extra-y := initrd.o quiet_cmd_ramdisk = RAMDISK $@ - cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz System.map $< $@ -$(obj)/vmlinux.initrd: vmlinux $(obj)/addRamDisk $(obj)/ramdisk.image.gz System.map FORCE - $(call if_changed,ramdisk) + cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@ -$(obj)/vmlinux.sminitrd: $(obj)/vmlinux.sm $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE - $(call if_changed,ramdisk) +quiet_cmd_stripvm = STRIP $@ + cmd_stripvm = $(STRIP) -s $< -o $@ -$(obj)/sysmap.o: System.map $(obj)/piggyback FORCE - $(call if_changed,piggy) +vmlinux.strip: vmlinux FORCE + $(call if_changed,stripvm) +$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE + $(call if_changed,ramdisk) addsection = $(BOOTOBJCOPY) $(1) \ --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \ @@ -113,9 +108,9 @@ $(obj)/zImage.initrd: obj-boot += $(call obj-sec, $(required) $(initrd)) $(obj)/zImage.initrd: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(obj)/addnote FORCE $(call if_changed,addnote) -$(obj)/imagesize.c: vmlinux +$(obj)/imagesize.c: vmlinux.strip @echo Generating $@ - ls -l vmlinux | \ + ls -l vmlinux.strip | \ awk '{printf "/* generated -- do not edit! */\n" \ "unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ @@ -123,6 +118,6 @@ $(obj)/imagesize.c: vmlinux >> $(obj)/imagesize.c install: $(CONFIGURE) $(obj)/$(BOOTIMAGE) - sh -x $(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(TOPDIR)/System.map" "$(INSTALL_PATH)" + sh -x $(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(INSTALL_PATH)" -clean-files := $(patsubst $(obj)/%,%, $(obj-boot)) +clean-files := $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip) diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index f5a9718ef..6cf78020a 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -31,13 +31,9 @@ unsigned long strlen(const char *s); void *memmove(void *dest, const void *src, unsigned long n); void *memcpy(void *dest, const void *src, unsigned long n); -static struct bi_record *make_bi_recs(unsigned long); - -#define RAM_START 0x00000000 -#define RAM_END (64<<20) - /* Value picked to match that used by yaboot */ #define PROG_START 0x01400000 +#define RAM_END (256<<20) // Fixme: use OF */ char *avail_ram; char *begin_avail, *end_avail; @@ -48,8 +44,6 @@ unsigned int heap_max; extern char _start[]; extern char _vmlinux_start[]; extern char _vmlinux_end[]; -extern char _sysmap_start[]; -extern char _sysmap_end[]; extern char _initrd_start[]; extern char _initrd_end[]; extern unsigned long vmlinux_filesize; @@ -62,7 +56,6 @@ struct addr_range { }; struct addr_range vmlinux = {0, 0, 0}; struct addr_range vmlinuz = {0, 0, 0}; -struct addr_range sysmap = {0, 0, 0}; struct addr_range initrd = {0, 0, 0}; static char scratch[128<<10]; /* 128kB of scratch space for gunzip */ @@ -70,7 +63,7 @@ static char scratch[128<<10]; /* 128kB of scratch space for gunzip */ typedef void (*kernel_entry_t)( unsigned long, unsigned long, void *, - struct bi_record *); + void *); int (*prom)(void *); @@ -80,12 +73,31 @@ void *stdin; void *stdout; void *stderr; +#define DEBUG + +static unsigned long claim_base = PROG_START; + +static unsigned long try_claim(unsigned long size) +{ + unsigned long addr = 0; + + for(; claim_base < RAM_END; claim_base += 0x100000) { +#ifdef DEBUG + printf(" trying: 0x%08lx\n\r", claim_base); +#endif + addr = (unsigned long)claim(claim_base, size, 0); + if ((void *)addr != (void *)-1) + break; + } + if (addr == 0) + return 0; + claim_base = PAGE_ALIGN(claim_base + size); + return addr; +} -void -start(unsigned long a1, unsigned long a2, void *promptr) +void start(unsigned long a1, unsigned long a2, void *promptr) { - unsigned long i, claim_addr, claim_size; - struct bi_record *bi_recs; + unsigned long i; kernel_entry_t kernel_entry; Elf64_Ehdr *elf64; Elf64_Phdr *elf64ph; @@ -102,61 +114,59 @@ start(unsigned long a1, unsigned long a2, void *promptr) printf("zImage starting: loaded at 0x%x\n\r", (unsigned)_start); -#if 0 - sysmap.size = (unsigned long)(_sysmap_end - _sysmap_start); - sysmap.memsize = sysmap.size; - if ( sysmap.size > 0 ) { - sysmap.addr = (RAM_END - sysmap.size) & ~0xFFF; - claim(sysmap.addr, RAM_END - sysmap.addr, 0); - printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", - sysmap.addr, (unsigned long)_sysmap_start, sysmap.size); - memcpy((void *)sysmap.addr, (void *)_sysmap_start, sysmap.size); + /* + * Now we try to claim some memory for the kernel itself + * our "vmlinux_memsize" is the memory footprint in RAM, _HOWEVER_, what + * our Makefile stuffs in is an image containing all sort of junk including + * an ELF header. We need to do some calculations here to find the right + * size... In practice we add 1Mb, that is enough, but we should really + * consider fixing the Makefile to put a _raw_ kernel in there ! + */ + vmlinux_memsize += 0x100000; + printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize); + vmlinux.addr = try_claim(vmlinux_memsize); + if (vmlinux.addr == 0) { + printf("Can't allocate memory for kernel image !\n\r"); + exit(); } -#endif + vmlinuz.addr = (unsigned long)_vmlinux_start; + vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); + vmlinux.size = PAGE_ALIGN(vmlinux_filesize); + vmlinux.memsize = vmlinux_memsize; + /* + * Now we try to claim memory for the initrd (and copy it there) + */ initrd.size = (unsigned long)(_initrd_end - _initrd_start); initrd.memsize = initrd.size; if ( initrd.size > 0 ) { - initrd.addr = (RAM_END - initrd.size) & ~0xFFF; - a1 = a2 = 0; - claim(initrd.addr, RAM_END - initrd.addr, 0); + printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size); + initrd.addr = try_claim(initrd.size); + if (initrd.addr == 0) { + printf("Can't allocate memory for initial ramdisk !\n\r"); + exit(); + } + a1 = initrd.addr; + a2 = initrd.size; printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", initrd.addr, (unsigned long)_initrd_start, initrd.size); - memcpy((void *)initrd.addr, (void *)_initrd_start, initrd.size); - } - - vmlinuz.addr = (unsigned long)_vmlinux_start; - vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); - vmlinux.addr = (unsigned long)(void *)-1; - vmlinux.size = PAGE_ALIGN(vmlinux_filesize); - vmlinux.memsize = vmlinux_memsize; - - claim_size = vmlinux.memsize /* PPPBBB: + fudge for bi_recs */; - for(claim_addr = PROG_START; - claim_addr <= PROG_START * 8; - claim_addr += 0x100000) { -#ifdef DEBUG - printf(" trying: 0x%08lx\n\r", claim_addr); -#endif - vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0); - if ((void *)vmlinux.addr != (void *)-1) break; - } - if ((void *)vmlinux.addr == (void *)-1) { - printf("claim error, can't allocate kernel memory\n\r"); - exit(); + memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size); + printf("initrd head: 0x%lx\n", *((u32 *)initrd.addr)); } - /* PPPBBB: should kernel always be gziped? */ + /* Eventually gunzip the kernel */ if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { + int len; avail_ram = scratch; begin_avail = avail_high = avail_ram; end_avail = scratch + sizeof(scratch); printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); + len = vmlinuz.size; gunzip((void *)vmlinux.addr, vmlinux.size, - (unsigned char *)vmlinuz.addr, (int *)&vmlinuz.size); - printf("done %lu bytes\n\r", vmlinuz.size); - printf("%u bytes of heap consumed, max in use %u\n\r", + (unsigned char *)vmlinuz.addr, &len); + printf("done 0x%lx bytes\n\r", len); + printf("0x%x bytes of heap consumed, max in use 0x%\n\r", (unsigned)(avail_high - begin_avail), heap_max); } else { memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size); @@ -192,7 +202,8 @@ start(unsigned long a1, unsigned long a2, void *promptr) flush_cache((void *)vmlinux.addr, vmlinux.memsize); - bi_recs = make_bi_recs(vmlinux.addr + vmlinux.memsize); + if (a1) + printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr)); kernel_entry = (kernel_entry_t)vmlinux.addr; #ifdef DEBUG @@ -203,65 +214,16 @@ start(unsigned long a1, unsigned long a2, void *promptr) " prom = 0x%lx,\n\r" " bi_recs = 0x%lx,\n\r", (unsigned long)kernel_entry, a1, a2, - (unsigned long)prom, (unsigned long)bi_recs); + (unsigned long)prom, NULL); #endif - kernel_entry( a1, a2, prom, bi_recs ); + kernel_entry( a1, a2, prom, NULL ); printf("Error: Linux kernel returned to zImage bootloader!\n\r"); exit(); } -static struct bi_record * -make_bi_recs(unsigned long addr) -{ - struct bi_record *bi_recs; - struct bi_record *rec; - - bi_recs = rec = bi_rec_init(addr); - - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_FIRST; - /* rec->data[0] = ...; # Written below before return */ - /* rec->data[1] = ...; # Written below before return */ - - rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1); - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "chrpboot"); - - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_MACHTYPE; - rec->data[0] = PLATFORM_PSERIES; - rec->data[1] = 1; - - if ( initrd.size > 0 ) { - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_INITRD; - rec->data[0] = initrd.addr; - rec->data[1] = initrd.size; - } - - if ( sysmap.size > 0 ) { - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap.addr; - rec->data[1] = (unsigned long)sysmap.size; - } - - rec = bi_rec_alloc(rec, 1); - rec->tag = BI_LAST; - rec->data[0] = (bi_rec_field)bi_recs; - - /* Save the _end_ address of the bi_rec's in the first bi_rec - * data field for easy access by the kernel. - */ - bi_recs->data[0] = (bi_rec_field)rec; - bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs; - - return bi_recs; -} - struct memchunk { unsigned int size; unsigned int pad; diff --git a/arch/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds index 7070cd2f7..941ade38f 100644 --- a/arch/ppc64/boot/zImage.lds +++ b/arch/ppc64/boot/zImage.lds @@ -61,19 +61,9 @@ SECTIONS . = ALIGN(4096); _vmlinux_start = .; - .kernel:vmlinux : { *(.kernel:vmlinux) } + .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) } _vmlinux_end = .; - . = ALIGN(4096); - _dotconfig_start = .; - .kernel:.config : { *(.kernel:.config) } - _dotconfig_end = .; - - . = ALIGN(4096); - _sysmap_start = .; - .kernel:System.map : { *(.kernel:System.map) } - _sysmap_end = .; - . = ALIGN(4096); _initrd_start = .; .kernel:initrd : { *(.kernel:initrd) } diff --git a/arch/ppc64/configs/g5_defconfig b/arch/ppc64/configs/g5_defconfig index 0485eed76..9cc01b5ba 100644 --- a/arch/ppc64/configs/g5_defconfig +++ b/arch/ppc64/configs/g5_defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3 +# Thu Oct 7 15:18:38 2004 # CONFIG_64BIT=y CONFIG_MMU=y @@ -16,11 +18,11 @@ CONFIG_FORCE_MAX_ZONEORDER=13 # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set @@ -32,6 +34,8 @@ CONFIG_HOTPLUG=y # 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_IOSCHED_NOOP=y @@ -39,6 +43,8 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -50,18 +56,20 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_KMOD is not set CONFIG_STOP_MACHINE=y +CONFIG_SYSVIPC_COMPAT=y # # Platform support # # CONFIG_PPC_ISERIES is not set -CONFIG_PPC_PSERIES=y +CONFIG_PPC_MULTIPLATFORM=y +# CONFIG_PPC_PSERIES is not set +CONFIG_PPC_PMAC=y CONFIG_PPC=y CONFIG_PPC64=y CONFIG_PPC_OF=y CONFIG_ALTIVEC=y -CONFIG_PPC_PMAC=y -CONFIG_PMAC_DART=y +CONFIG_U3_DART=y CONFIG_PPC_PMAC64=y CONFIG_BOOTX_TEXT=y CONFIG_POWER4_ONLY=y @@ -69,8 +77,8 @@ CONFIG_IOMMU_VMERGE=y CONFIG_SMP=y CONFIG_IRQ_ALL_CPUS=y CONFIG_NR_CPUS=2 -# CONFIG_HMT is not set -# CONFIG_DISCONTIGMEM is not set +# CONFIG_SCHED_SMT is not set +# CONFIG_PREEMPT is not set # CONFIG_PPC_RTAS is not set # CONFIG_LPARCFG is not set @@ -104,6 +112,8 @@ CONFIG_PROC_DEVICETREE=y # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set @@ -132,7 +142,8 @@ CONFIG_FW_LOADER=y CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_CARMEL is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_INITRD=y @@ -146,9 +157,9 @@ 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_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDETAPE=y CONFIG_BLK_DEV_IDEFLOPPY=y @@ -170,7 +181,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set @@ -196,6 +206,7 @@ CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y CONFIG_BLK_DEV_IDEDMA_PMAC=y # CONFIG_BLK_DEV_IDE_PMAC_BLINK is not set CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -221,7 +232,6 @@ CONFIG_CHR_DEV_SG=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -235,23 +245,25 @@ CONFIG_SCSI_SPI_ATTRS=y # 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_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA_SVW=y # CONFIG_SCSI_ATA_PIIX is not set +# 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 # CONFIG_SCSI_SATA_SIS is not set # CONFIG_SCSI_SATA_VIA is not set # 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 @@ -264,6 +276,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # 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 @@ -277,7 +290,6 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set # CONFIG_SCSI_MAC53C94 is not set # @@ -288,11 +300,15 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=y # CONFIG_MD_RAID6 is not set # CONFIG_MD_MULTIPATH is not set CONFIG_BLK_DEV_DM=y # CONFIG_DM_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set # # Fusion MPT device support @@ -332,6 +348,7 @@ CONFIG_IEEE1394_RAWIO=y # # I2O device support # +# CONFIG_I2O is not set # # Macintosh device drivers @@ -340,7 +357,6 @@ CONFIG_ADB=y CONFIG_ADB_PMU=y # CONFIG_PMAC_PBOOK is not set # CONFIG_PMAC_BACKLIGHT is not set -# CONFIG_MAC_SERIAL is not set # CONFIG_INPUT_ADBHID is not set CONFIG_THERM_PM72=y @@ -369,14 +385,13 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -384,6 +399,8 @@ CONFIG_NETFILTER=y # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=y +# CONFIG_IP_NF_CT_ACCT is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set # CONFIG_IP_NF_FTP is not set # CONFIG_IP_NF_IRC is not set # CONFIG_IP_NF_TFTP is not set @@ -408,8 +425,15 @@ CONFIG_IP_NF_MATCH_HELPER=y CONFIG_IP_NF_MATCH_STATE=y CONFIG_IP_NF_MATCH_CONNTRACK=y CONFIG_IP_NF_MATCH_OWNER=y +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +# CONFIG_IP_NF_MATCH_SCTP is not set +# CONFIG_IP_NF_MATCH_COMMENT is not set CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_IP_NF_TARGET_ULOG=y +CONFIG_IP_NF_TARGET_TCPMSS=y CONFIG_IP_NF_NAT=y CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y @@ -424,9 +448,7 @@ CONFIG_IP_NF_TARGET_ECN=y CONFIG_IP_NF_TARGET_DSCP=y CONFIG_IP_NF_TARGET_MARK=y CONFIG_IP_NF_TARGET_CLASSIFY=y -CONFIG_IP_NF_TARGET_LOG=y -CONFIG_IP_NF_TARGET_ULOG=y -CONFIG_IP_NF_TARGET_TCPMSS=y +# CONFIG_IP_NF_RAW is not set CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y @@ -438,7 +460,9 @@ CONFIG_XFRM=y # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_IPX is not set @@ -454,30 +478,33 @@ CONFIG_LLC=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=m +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m # # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=m -CONFIG_BONDING=m -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_OAKNET is not set # CONFIG_HAPPYMEAL is not set CONFIG_SUNGEM=y # CONFIG_NET_VENDOR_3COM is not set @@ -509,57 +536,38 @@ CONFIG_TIGON3=m # # CONFIG_IXGB is not set # CONFIG_S2IO is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_IBMVETH is not set -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set # # Token Ring devices # CONFIG_TR=y CONFIG_IBMOL=y -# CONFIG_IBMLS is not set # CONFIG_3C359 is not set # CONFIG_TMS380TR is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set # -# IrDA (infrared) support +# Wireless LAN (non-hamradio) # -# CONFIG_IRDA is not set +# CONFIG_NET_RADIO is not set # -# Bluetooth support +# Wan interfaces # -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # ISDN subsystem @@ -598,6 +606,7 @@ CONFIG_SERIO=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -636,8 +645,6 @@ CONFIG_HW_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -CONFIG_HVC_CONSOLE=y -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -673,6 +680,7 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set # # I2C Hardware Bus support @@ -697,23 +705,29 @@ CONFIG_I2C_KEYWEST=y # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set # # Hardware Sensors Chip support # # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set # CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set @@ -725,11 +739,17 @@ CONFIG_I2C_KEYWEST=y # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + # # Misc devices # @@ -748,6 +768,8 @@ CONFIG_I2C_KEYWEST=y # Graphics support # CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y @@ -755,10 +777,12 @@ CONFIG_FB_OF=y # CONFIG_FB_PLATINUM is not set # CONFIG_FB_VALKYRIE is not set # CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set -# CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_RIVA=y +# CONFIG_FB_RIVA_I2C is not set +# CONFIG_FB_RIVA_DEBUG is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_RADEON_OLD is not set CONFIG_FB_RADEON=y @@ -778,10 +802,8 @@ CONFIG_FB_RADEON_I2C=y # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -811,6 +833,7 @@ CONFIG_USB=y CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -829,6 +852,7 @@ CONFIG_USB_ACM=m CONFIG_USB_PRINTER=y CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set CONFIG_USB_STORAGE_DATAFAB=y CONFIG_USB_STORAGE_FREECOM=y CONFIG_USB_STORAGE_ISD200=y @@ -853,6 +877,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -959,6 +984,7 @@ CONFIG_USB_EZUSB=y # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_TEST is not set # @@ -997,6 +1023,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -1004,6 +1031,8 @@ CONFIG_UDF_FS=m 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 # @@ -1016,8 +1045,8 @@ CONFIG_SYSFS=y CONFIG_DEVPTS_FS_XATTR=y # CONFIG_DEVPTS_FS_SECURITY is not set CONFIG_TMPFS=y -# CONFIG_HUGETLBFS is not set -# CONFIG_HUGETLB_PAGE is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y # @@ -1030,7 +1059,7 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set +CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -1054,11 +1083,14 @@ CONFIG_EXPORTFS=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_POSIX 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 # @@ -1076,7 +1108,6 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_LDM_PARTITION is not set -# CONFIG_NEC98_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set @@ -1110,6 +1141,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 @@ -1135,13 +1167,16 @@ CONFIG_OPROFILE=y # Kernel hacking # CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_STACKOVERFLOW is not set # CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_SLAB is not set -CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUGGER is not set # CONFIG_PPCDBG is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_IRQSTACKS=y +# CONFIG_SCHEDSTATS is not set # # Security options @@ -1159,6 +1194,7 @@ CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m +# CONFIG_CRYPTO_WP512 is not set CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m @@ -1166,14 +1202,19 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_TEA is not set CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_KHAZAD is not set CONFIG_CRYPTO_DEFLATE=m CONFIG_CRYPTO_MICHAEL_MIC=m +# CONFIG_CRYPTO_CRC32C is not set CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y -CONFIG_ZLIB_INFLATE=m +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff --git a/arch/ppc64/configs/iSeries_defconfig b/arch/ppc64/configs/iSeries_defconfig index 63ec73f75..84ae55bcc 100644 --- a/arch/ppc64/configs/iSeries_defconfig +++ b/arch/ppc64/configs/iSeries_defconfig @@ -16,17 +16,17 @@ CONFIG_FORCE_MAX_ZONEORDER=13 # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y @@ -34,6 +34,7 @@ CONFIG_IKCONFIG_PROC=y # 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_IOSCHED_NOOP=y @@ -41,6 +42,8 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -62,10 +65,11 @@ CONFIG_PPC_ISERIES=y CONFIG_PPC=y CONFIG_PPC64=y # CONFIG_POWER4_ONLY is not set -# CONFIG_IOMMU_VMERGE is not set +CONFIG_IOMMU_VMERGE=y CONFIG_SMP=y CONFIG_NR_CPUS=32 # CONFIG_SCHED_SMT is not set +# CONFIG_PREEMPT is not set CONFIG_MSCHUNKS=y CONFIG_LPARCFG=y @@ -97,6 +101,8 @@ CONFIG_PCI_NAMES=y # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set @@ -125,7 +131,7 @@ CONFIG_FW_LOADER=m CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m -# 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 @@ -168,22 +174,23 @@ CONFIG_SCSI_FC_ATTRS=y # 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_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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_IPS is not set +CONFIG_SCSI_IBMVSCSI=m # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set @@ -209,11 +216,15 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m CONFIG_MD_RAID5=y -CONFIG_MD_RAID6=y -# CONFIG_MD_MULTIPATH is not set +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m # # Fusion MPT device support @@ -259,6 +270,7 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration @@ -324,7 +336,13 @@ CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_COMPAT_IPFWADM=m -# CONFIG_IP_NF_RAW is not set +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 is not set +CONFIG_IP_NF_MATCH_SCTP=m +CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_XFRM=y CONFIG_XFRM_USER=m @@ -351,6 +369,7 @@ CONFIG_LLC=y # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +CONFIG_NET_CLS_ROUTE=y # # Network testing @@ -379,7 +398,6 @@ CONFIG_TUN=m # 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 @@ -408,18 +426,32 @@ CONFIG_E100=y # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set # -# Gigabit Ethernet (1000/10000 Mbit) +# Ethernet (1000 Mbit) # -# CONFIG_NET_GIGE is not set +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set # # Token Ring devices # CONFIG_TR=y CONFIG_IBMOL=y -# CONFIG_IBMLS is not set # CONFIG_3C359 is not set # CONFIG_TMS380TR is not set @@ -508,10 +540,11 @@ CONFIG_SERIO_SERPORT=y # # Non-8250 serial port support # +CONFIG_SERIAL_CORE=m +CONFIG_SERIAL_ICOM=m CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -541,6 +574,11 @@ CONFIG_MAX_RAW_DEVS=256 # # CONFIG_I2C is not set +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + # # Misc devices # @@ -592,8 +630,10 @@ CONFIG_FS_MBCACHE=y 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=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set @@ -616,6 +656,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -623,6 +664,8 @@ CONFIG_UDF_FS=m 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 # @@ -663,19 +706,22 @@ CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set -CONFIG_NFSD=y +CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y +CONFIG_RPCSEC_GSS_SPKM3=m # CONFIG_SMB_FS is not set CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -691,7 +737,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -714,7 +760,8 @@ 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_ISO8859_1 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -748,14 +795,16 @@ CONFIG_OPROFILE=y # Kernel hacking # CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_DEBUG_SLAB is not set -CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUGGER is not set # CONFIG_PPCDBG is not set -# CONFIG_DEBUG_INFO is not set # CONFIG_IRQSTACKS is not set +# CONFIG_SCHEDSTATS is not set # # Security options @@ -773,6 +822,7 @@ CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WHIRLPOOL=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m @@ -780,16 +830,19 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_DEFLATE=m -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set +CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff --git a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig index f5503873a..73981148d 100644 --- a/arch/ppc64/configs/pSeries_defconfig +++ b/arch/ppc64/configs/pSeries_defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2 +# Thu Sep 23 16:45:05 2004 # CONFIG_64BIT=y CONFIG_MMU=y @@ -16,27 +18,35 @@ CONFIG_FORCE_MAX_ZONEORDER=13 # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y CONFIG_LOG_BUF_SHIFT=17 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 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 +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -48,25 +58,31 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_KMOD is not set CONFIG_STOP_MACHINE=y +CONFIG_SYSVIPC_COMPAT=y # # Platform support # # CONFIG_PPC_ISERIES is not set +CONFIG_PPC_MULTIPLATFORM=y CONFIG_PPC_PSERIES=y +# CONFIG_PPC_PMAC is not set CONFIG_PPC=y CONFIG_PPC64=y CONFIG_PPC_OF=y CONFIG_ALTIVEC=y -# CONFIG_PPC_PMAC is not set +CONFIG_PPC_SPLPAR=y # CONFIG_BOOTX_TEXT is not set # CONFIG_POWER4_ONLY is not set -# CONFIG_IOMMU_VMERGE is not set +CONFIG_IOMMU_VMERGE=y CONFIG_SMP=y CONFIG_IRQ_ALL_CPUS=y -CONFIG_NR_CPUS=32 +CONFIG_NR_CPUS=128 # CONFIG_HMT is not set -# CONFIG_DISCONTIGMEM is not set +CONFIG_DISCONTIGMEM=y +CONFIG_NUMA=y +CONFIG_SCHED_SMT=y +# CONFIG_PREEMPT is not set CONFIG_PPC_RTAS=y CONFIG_RTAS_FLASH=m CONFIG_SCANLOG=m @@ -81,6 +97,7 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG_CPU=y # # PCMCIA/CardBus support @@ -107,7 +124,9 @@ CONFIG_PROC_DEVICETREE=y # # Generic Driver Options # -CONFIG_FW_LOADER=m +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set # @@ -127,7 +146,7 @@ CONFIG_FW_LOADER=m # # Block devices # -CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_FD=m # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -135,7 +154,8 @@ CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_CARMEL is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -149,9 +169,9 @@ 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_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# 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 @@ -173,7 +193,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set CONFIG_BLK_DEV_AMD74XX=y @@ -194,6 +213,7 @@ CONFIG_BLK_DEV_AMD74XX=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -219,7 +239,6 @@ CONFIG_CHR_DEV_SG=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -233,28 +252,32 @@ CONFIG_SCSI_FC_ATTRS=y # 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_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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_IPS is not set +CONFIG_SCSI_IBMVSCSI=m # CONFIG_SCSI_INIA100 is not set CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +CONFIG_SCSI_IPR=y +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set @@ -277,11 +300,15 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m CONFIG_MD_RAID5=y -CONFIG_MD_RAID6=y -# CONFIG_MD_MULTIPATH is not set +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m # # Fusion MPT device support @@ -296,6 +323,7 @@ CONFIG_DM_CRYPT=m # # I2O device support # +# CONFIG_I2O is not set # # Macintosh device drivers @@ -322,19 +350,17 @@ CONFIG_NET_IPIP=y # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set -CONFIG_INET_ECN=y CONFIG_SYN_COOKIES=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=y # # IP: Virtual Server Configuration # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -342,6 +368,8 @@ CONFIG_NETFILTER=y # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m CONFIG_IP_NF_TFTP=m @@ -366,8 +394,14 @@ CONFIG_IP_NF_MATCH_HELPER=m CONFIG_IP_NF_MATCH_STATE=m CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_REALM=m +CONFIG_IP_NF_MATCH_SCTP=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m @@ -386,9 +420,8 @@ CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_CLASSIFY=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m @@ -400,10 +433,11 @@ CONFIG_XFRM_USER=m # # 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_DECNET is not set CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_IPX is not set @@ -419,28 +453,35 @@ CONFIG_LLC=y # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +CONFIG_NET_CLS_ROUTE=y # # Network testing # # CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +CONFIG_NETPOLL_RX=y +CONFIG_NETPOLL_TRAP=y +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m # # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=m -CONFIG_BONDING=m -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m # # 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=y @@ -452,6 +493,7 @@ CONFIG_VORTEX=y # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set +CONFIG_IBMVETH=m CONFIG_NET_PCI=y CONFIG_PCNET32=y # CONFIG_AMD8111_ETH is not set @@ -471,6 +513,7 @@ CONFIG_E100=y # 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) @@ -484,7 +527,6 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set CONFIG_TIGON3=y @@ -493,59 +535,40 @@ CONFIG_TIGON3=y # CONFIG_IXGB=m # CONFIG_IXGB_NAPI is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -CONFIG_IBMVETH=m -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set # # Token Ring devices # CONFIG_TR=y CONFIG_IBMOL=y -# CONFIG_IBMLS is not set # CONFIG_3C359 is not set # CONFIG_TMS380TR is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set -CONFIG_NETCONSOLE=y # -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support +# Wireless LAN (non-hamradio) # -# CONFIG_IRDA is not set +# CONFIG_NET_RADIO is not set # -# Bluetooth support +# Wan interfaces # -# CONFIG_BT is not set -CONFIG_NETPOLL=y -CONFIG_NETPOLL_RX=y -CONFIG_NETPOLL_TRAP=y -CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=y # # ISDN subsystem @@ -584,6 +607,7 @@ CONFIG_SERIO_I8042=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -591,15 +615,17 @@ CONFIG_SERIO_I8042=y 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=y -CONFIG_INPUT_PCSPKR=y +# CONFIG_INPUT_PCSPKR is not set # CONFIG_INPUT_UINPUT is not set # @@ -624,16 +650,12 @@ CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_PMACZILOG is not set +CONFIG_SERIAL_ICOM=m CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 CONFIG_HVC_CONSOLE=y - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set +CONFIG_HVCS=m # # IPMI @@ -656,7 +678,7 @@ CONFIG_HVC_CONSOLE=y # CONFIG_AGP is not set # CONFIG_DRM is not set CONFIG_RAW_DRIVER=y -CONFIG_MAX_RAW_DEVS=256 +CONFIG_MAX_RAW_DEVS=1024 # # I2C support @@ -669,11 +691,13 @@ CONFIG_I2C=y # CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set # # I2C Hardware Bus support # # CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set # CONFIG_I2C_ALI15X3 is not set # CONFIG_I2C_AMD756 is not set # CONFIG_I2C_AMD8111 is not set @@ -691,29 +715,51 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set # -# I2C Hardware Sensors Chip support +# Hardware Sensors Chip support # # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + # # Misc devices # @@ -732,12 +778,14 @@ CONFIG_I2C_ALGOBIT=y # Graphics support # CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y # CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set -# CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set # CONFIG_FB_RIVA is not set CONFIG_FB_MATROX=y @@ -765,10 +813,8 @@ CONFIG_FB_RADEON_I2C=y # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -798,11 +844,14 @@ CONFIG_USB=y CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers # CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set CONFIG_USB_OHCI_HCD=y # CONFIG_USB_UHCI_HCD is not set @@ -814,6 +863,7 @@ CONFIG_USB_OHCI_HCD=y # CONFIG_USB_PRINTER is not set CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set @@ -834,7 +884,10 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_WACOM is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set # CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set # # USB Imaging devices @@ -881,6 +934,8 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_TEST is not set # @@ -905,7 +960,10 @@ CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set -CONFIG_JFS_FS=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set @@ -928,6 +986,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -935,6 +994,8 @@ CONFIG_UDF_FS=m 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 # @@ -942,6 +1003,7 @@ CONFIG_VFAT_FS=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS_XATTR=y # CONFIG_DEVPTS_FS_SECURITY is not set @@ -974,18 +1036,22 @@ CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set -CONFIG_NFSD=y +CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_SUNRPC=y -CONFIG_SUNRPC_GSS=m -CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +CONFIG_RPCSEC_GSS_SPKM3=m # CONFIG_SMB_FS is not set CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -1001,7 +1067,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -1024,7 +1090,8 @@ 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_ISO8859_1 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -1049,15 +1116,18 @@ CONFIG_OPROFILE=y # Kernel hacking # CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_DEBUG_SLAB is not set -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUGGER=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y # CONFIG_PPCDBG is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_IRQSTACKS=y +# CONFIG_SCHEDSTATS is not set # # Security options @@ -1071,24 +1141,31 @@ CONFIG_CRYPTO=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_WHIRLPOOL=m +CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y +CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff --git a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c index 6f21bde21..c923a8157 100644 --- a/arch/ppc64/kernel/ItLpQueue.c +++ b/arch/ppc64/kernel/ItLpQueue.c @@ -25,7 +25,7 @@ static __inline__ int set_inUse( struct ItLpQueue * lpQueue ) __asm__ __volatile__("\n\ 1: lwarx %0,0,%2 \n\ - cmpi 0,%0,0 \n\ + cmpwi 0,%0,0 \n\ li %0,0 \n\ bne- 2f \n\ addi %0,%0,1 \n\ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index c5dd7e13b..020b64fac 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -3,11 +3,11 @@ # EXTRA_CFLAGS += -mno-minimal-toc -extra-y := head.o vmlinux.lds.s +extra-y := head.o vmlinux.lds obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ - align.o semaphore.o bitops.o stab.o pacaData.o \ + align.o semaphore.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ @@ -17,9 +17,9 @@ obj-$(CONFIG_PPC_OF) += of_device.o pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_pci_reset.o \ iSeries_IoMmTable.o -pci-obj-$(CONFIG_PPC_PSERIES) += pci_dn.o pci_dma_direct.o +pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_dma_direct.o -obj-$(CONFIG_PCI) += pci.o pci_iommu.o $(pci-obj-y) +obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ iSeries_VpdInfo.o XmPciLpEvent.o \ @@ -28,10 +28,11 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o open_pic.o i8259.o prom_init.o prom.o + obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ - eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \ - open_pic.o xics.o pSeries_htab.o rtas.o \ - chrp_setup.o i8259.o prom.o pSeries_iommu.o + eeh.o pSeries_nvram.o rtasd.o ras.o \ + xics.o rtas.o pSeries_setup.o pSeries_iommu.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o @@ -48,7 +49,7 @@ obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ pmac_time.o pmac_nvram.o pmac_low_i2c.o \ open_pic_u3.o -obj-$(CONFIG_PMAC_DART) += pmac_iommu.o +obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index f19f76379..618592161 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -22,18 +22,17 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include #include #include -#include #include #include @@ -58,6 +57,7 @@ int main(void) DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); DEFINE(KSP, offsetof(struct thread_struct, ksp)); + DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); #ifdef CONFIG_ALTIVEC DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); @@ -93,16 +93,10 @@ int main(void) DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); - DEFINE(PACASLBR3, offsetof(struct paca_struct, slb_r3)); #ifdef CONFIG_HUGETLB_PAGE DEFINE(PACAHTLBSEGS, offsetof(struct paca_struct, context.htlb_segs)); #endif /* CONFIG_HUGETLB_PAGE */ DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); - DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled)); - DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len)); - DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift)); - DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer)); - DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext)); DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); @@ -113,15 +107,10 @@ int main(void) DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt)); - DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr)); - DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending)); - DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags)); - DEFINE(PROMENTRY, offsetof(struct prom_t, entry)); /* RTAS */ DEFINE(RTASBASE, offsetof(struct rtas_t, base)); DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); - DEFINE(RTASSIZE, offsetof(struct rtas_t, size)); /* Interrupt register frame */ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); @@ -148,10 +137,6 @@ int main(void) DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); - DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); - DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); - DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); - DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); /* * Note: these symbols include _ because they overlap with special * register names diff --git a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c index 33e10865d..c53f079e9 100644 --- a/arch/ppc64/kernel/btext.c +++ b/arch/ppc64/kernel/btext.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -36,6 +36,11 @@ static int g_loc_Y; static int g_max_loc_X; static int g_max_loc_Y; +static int dispDeviceRowBytes; +static int dispDeviceDepth; +static int dispDeviceRect[4]; +static unsigned char *dispDeviceBase, *logicalDisplayBase; + unsigned long disp_BAT[2] __initdata = {0, 0}; #define cmapsz (16*256) @@ -45,30 +50,6 @@ static unsigned char vga_font[cmapsz]; int boot_text_mapped; int force_printk_to_btext = 0; -boot_infos_t disp_bi; - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -void __init btext_setup_display(int width, int height, int depth, int pitch, - unsigned long address) -{ - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; - bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = (unsigned char *)address; - bi->dispDeviceRowBytes = pitch; - bi->dispDeviceDepth = depth; - bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; - RELOC(boot_text_mapped) = 1; -} /* Here's a small text engine to use during early boot * or for debugging purposes @@ -84,34 +65,84 @@ void __init btext_setup_display(int width, int height, int depth, int pitch, void map_boot_text(void) { unsigned long base, offset, size; - boot_infos_t *bi = &disp_bi; unsigned char *vbase; /* By default, we are no longer mapped */ boot_text_mapped = 0; - if (bi->dispDeviceBase == 0) + if (dispDeviceBase == 0) return; - base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL; - offset = ((unsigned long) bi->dispDeviceBase) - base; - size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset - + bi->dispDeviceRect[0]; + base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) dispDeviceBase) - base; + size = dispDeviceRowBytes * dispDeviceRect[3] + offset + + dispDeviceRect[0]; vbase = __ioremap(base, size, _PAGE_NO_CACHE); if (vbase == 0) return; - bi->logicalDisplayBase = vbase + offset; + logicalDisplayBase = vbase + offset; boot_text_mapped = 1; } +int btext_initialize(struct device_node *np) +{ + unsigned int width, height, depth, pitch; + unsigned long address = 0; + u32 *prop; + + prop = (u32 *)get_property(np, "width", NULL); + if (prop == NULL) + return -EINVAL; + width = *prop; + prop = (u32 *)get_property(np, "height", NULL); + if (prop == NULL) + return -EINVAL; + height = *prop; + prop = (u32 *)get_property(np, "depth", NULL); + if (prop == NULL) + return -EINVAL; + depth = *prop; + pitch = width * ((depth + 7) / 8); + prop = (u32 *)get_property(np, "linebytes", NULL); + if (prop) + pitch = *prop; + if (pitch == 1) + pitch = 0x1000; + prop = (u32 *)get_property(np, "address", NULL); + if (prop) + address = *prop; + + /* FIXME: Add support for PCI reg properties */ + + if (address == 0) + return -EINVAL; + + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; + logicalDisplayBase = (unsigned char *)address; + dispDeviceBase = (unsigned char *)address; + dispDeviceRowBytes = pitch; + dispDeviceDepth = depth; + dispDeviceRect[0] = dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + + map_boot_text(); + + return 0; +} + + /* Calc the base address of a given point (x,y) */ -static unsigned char * calc_base(boot_infos_t *bi, int x, int y) +static unsigned char * calc_base(int x, int y) { unsigned char *base; - base = bi->logicalDisplayBase; + base = logicalDisplayBase; if (base == 0) - base = bi->dispDeviceBase; - base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3); - base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes; + base = dispDeviceBase; + base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3); + base += (y + dispDeviceRect[1]) * dispDeviceRowBytes; return base; } @@ -119,24 +150,22 @@ static unsigned char * calc_base(boot_infos_t *bi, int x, int y) void btext_update_display(unsigned long phys, int width, int height, int depth, int pitch) { - boot_infos_t *bi = &disp_bi; - - if (bi->dispDeviceBase == 0) + if (dispDeviceBase == 0) return; /* check it's the same frame buffer (within 256MB) */ - if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000) + if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000) return; - bi->dispDeviceBase = (__u8 *) phys; - bi->dispDeviceRect[0] = 0; - bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; - bi->dispDeviceDepth = depth; - bi->dispDeviceRowBytes = pitch; + dispDeviceBase = (__u8 *) phys; + dispDeviceRect[0] = 0; + dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + dispDeviceDepth = depth; + dispDeviceRowBytes = pitch; if (boot_text_mapped) { - iounmap(bi->logicalDisplayBase); + iounmap(logicalDisplayBase); boot_text_mapped = 0; } map_boot_text(); @@ -148,108 +177,101 @@ void btext_update_display(unsigned long phys, int width, int height, void btext_clearscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); - unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 3; + unsigned long *base = (unsigned long *)calc_base(0, 0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 3; int i,j; - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) + for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) { unsigned long *ptr = base; for(j=width; j; --j) *(ptr++) = 0; - base += (bi->dispDeviceRowBytes >> 3); + base += (dispDeviceRowBytes >> 3); } } #ifndef NO_SCROLL static void scrollscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - unsigned long *src = (unsigned long *)calc_base(bi,0,16); - unsigned long *dst = (unsigned long *)calc_base(bi,0,0); - unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 3; + unsigned long *src = (unsigned long *)calc_base(0,16); + unsigned long *dst = (unsigned long *)calc_base(0,0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 3; int i,j; - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) + for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; unsigned long *dst_ptr = dst; for(j=width; j; --j) *(dst_ptr++) = *(src_ptr++); - src += (bi->dispDeviceRowBytes >> 3); - dst += (bi->dispDeviceRowBytes >> 3); + src += (dispDeviceRowBytes >> 3); + dst += (dispDeviceRowBytes >> 3); } for (i=0; i<16; i++) { unsigned long *dst_ptr = dst; for(j=width; j; --j) *(dst_ptr++) = 0; - dst += (bi->dispDeviceRowBytes >> 3); + dst += (dispDeviceRowBytes >> 3); } } #endif /* ndef NO_SCROLL */ void btext_drawchar(char c) { - unsigned long offset = reloc_offset(); int cline = 0; #ifdef NO_SCROLL int x; #endif - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; switch (c) { case '\b': - if (RELOC(g_loc_X) > 0) - --RELOC(g_loc_X); + if (g_loc_X > 0) + --g_loc_X; break; case '\t': - RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8; + g_loc_X = (g_loc_X & -8) + 8; break; case '\r': - RELOC(g_loc_X) = 0; + g_loc_X = 0; break; case '\n': - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + g_loc_X = 0; + g_loc_Y++; cline = 1; break; default: - draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + draw_byte(c, g_loc_X++, g_loc_Y); } - if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + if (g_loc_X >= g_max_loc_X) { + g_loc_X = 0; + g_loc_Y++; cline = 1; } #ifndef NO_SCROLL - while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) { + while (g_loc_Y >= g_max_loc_Y) { scrollscreen(); - RELOC(g_loc_Y)--; + g_loc_Y--; } #else /* wrap around from bottom to top of screen so we don't waste time scrolling each line. -- paulus. */ - if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) - RELOC(g_loc_Y) = 0; + if (g_loc_Y >= g_max_loc_Y) + g_loc_Y = 0; if (cline) { - for (x = 0; x < RELOC(g_max_loc_X); ++x) - draw_byte(' ', x, RELOC(g_loc_Y)); + for (x = 0; x < g_max_loc_X; ++x) + draw_byte(' ', x, g_loc_Y); } #endif } void btext_drawstring(const char *c) { - unsigned long offset = reloc_offset(); - - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; while (*c) btext_drawchar(*c++); @@ -257,10 +279,9 @@ void btext_drawstring(const char *c) void btext_drawhex(unsigned long v) { - unsigned long offset = reloc_offset(); - char *hex_table = RELOC("0123456789abcdef"); + char *hex_table = "0123456789abcdef"; - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]); btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]); @@ -283,14 +304,11 @@ void btext_drawhex(unsigned long v) static void draw_byte(unsigned char c, long locX, long locY) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); - unsigned char *base = calc_base(bi, locX << 3, locY << 4); - unsigned char *font = PTRRELOC(&vga_font[((unsigned int)c) * 16]); - int rb = bi->dispDeviceRowBytes; - -#if 0 - switch(bi->dispDeviceDepth) { + unsigned char *base = calc_base(locX << 3, locY << 4); + unsigned char *font = &vga_font[((unsigned int)c) * 16]; + int rb = dispDeviceRowBytes; + + switch(dispDeviceDepth) { case 24: case 32: draw_byte_32(font, (unsigned int *)base, rb); @@ -303,17 +321,6 @@ static void draw_byte(unsigned char c, long locX, long locY) draw_byte_8(font, (unsigned int *)base, rb); break; } -#else - if(bi->dispDeviceDepth == 24 || - bi->dispDeviceDepth == 32) { - draw_byte_32(font, (unsigned int *)base, rb); - } else if(bi->dispDeviceDepth == 15 || - bi->dispDeviceDepth == 16) { - draw_byte_16(font, (unsigned int *)base, rb); - } else if(bi->dispDeviceDepth == 8) { - draw_byte_8(font, (unsigned int *)base, rb); - } -#endif } static unsigned int expand_bits_8[16] = { @@ -369,8 +376,7 @@ static void draw_byte_16(unsigned char *font, unsigned int *base, int rb) int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned int *eb = PTRRELOC((int *)expand_bits_16); + unsigned int *eb = (int *)expand_bits_16; for (l = 0; l < 16; ++l) { @@ -388,8 +394,7 @@ static void draw_byte_8(unsigned char *font, unsigned int *base, int rb) int l, bits; int fg = 0x0F0F0F0FUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned int *eb = PTRRELOC((int *)expand_bits_8); + unsigned int *eb = (int *)expand_bits_8; for (l = 0; l < 16; ++l) { diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c index 5fdcce2db..6e87e5631 100644 --- a/arch/ppc64/kernel/eeh.c +++ b/arch/ppc64/kernel/eeh.c @@ -48,9 +48,6 @@ static int ibm_read_slot_reset_state; static int ibm_slot_error_detail; static int eeh_subsystem_enabled; -#define EEH_MAX_OPTS 4096 -static char *eeh_opts; -static int eeh_opts_last; /* Buffer for reporting slot-error-detail rtas calls */ static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; @@ -62,10 +59,6 @@ static DEFINE_PER_CPU(unsigned long, total_mmio_ffs); static DEFINE_PER_CPU(unsigned long, false_positives); static DEFINE_PER_CPU(unsigned long, ignored_failures); -static int eeh_check_opts_config(struct device_node *dn, int class_code, - int vendor_id, int device_id, - int default_state); - /** * The pci address cache subsystem. This subsystem places * PCI device address resources into a red-black tree, sorted @@ -209,6 +202,7 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) { struct device_node *dn; int i; + int inserted = 0; dn = pci_device_to_OF_node(dev); if (!dn) { @@ -242,7 +236,12 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) if (start == 0 || ~start == 0 || end == 0 || ~end == 0) continue; pci_addr_cache_insert(dev, start, end, flags); + inserted = 1; } + + /* If there was nothing to add, the cache has no reference... */ + if (!inserted) + pci_dev_put(dev); } /** @@ -265,6 +264,7 @@ void pci_addr_cache_insert_device(struct pci_dev *dev) static inline void __pci_addr_cache_remove_device(struct pci_dev *dev) { struct rb_node *n; + int removed = 0; restart: n = rb_first(&pci_io_addr_cache_root.rb_root); @@ -274,6 +274,7 @@ restart: if (piar->pcidev == dev) { rb_erase(n, &pci_io_addr_cache_root.rb_root); + removed = 1; kfree(piar); goto restart; } @@ -281,7 +282,8 @@ restart: } /* The cache no longer holds its reference to this device... */ - pci_dev_put(dev); + if (removed) + pci_dev_put(dev); } /** @@ -333,47 +335,38 @@ void __init pci_addr_cache_build(void) /** * eeh_token_to_phys - convert EEH address token to phys address - * @token i/o token, should be address in the form 0xA.... - * - * Converts EEH address tokens into physical addresses. Note that - * ths routine does *not* convert I/O BAR addresses (which start - * with 0xE...) to phys addresses! + * @token i/o token, should be address in the form 0xE.... */ -static unsigned long eeh_token_to_phys(unsigned long token) +static inline unsigned long eeh_token_to_phys(unsigned long token) { pte_t *ptep; - unsigned long pa, vaddr; + unsigned long pa; - if (REGION_ID(token) == EEH_REGION_ID) - vaddr = IO_TOKEN_TO_ADDR(token); - else + ptep = find_linux_pte(ioremap_mm.pgd, token); + if (!ptep) return token; - - ptep = find_linux_pte(ioremap_mm.pgd, vaddr); pa = pte_pfn(*ptep) << PAGE_SHIFT; - return pa | (vaddr & (PAGE_SIZE-1)); + return pa | (token & (PAGE_SIZE-1)); } /** - * eeh_check_failure - check if all 1's data is due to EEH slot freeze - * @token i/o token, should be address in the form 0xA.... - * @val value, should be all 1's (XXX why do we need this arg??) + * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze + * @dn device node + * @dev pci device, if known * - * Check for an eeh failure at the given token address. - * The given value has been read and it should be 1's (0xff, 0xffff or - * 0xffffffff). + * Check for an EEH failure for the given device node. Call this + * routine if the result of a read was all 0xff's and you want to + * find out if this is due to an EEH slot freeze event. This routine + * will query firmware for the EEH status. * - * Probe to determine if an error actually occurred. If not return val. - * Otherwise panic. + * Returns 0 if there has not been an EEH error; otherwise returns + * an error code. * - * Note this routine might be called in an interrupt context ... + * It is safe to call this routine in an interrupt context. */ -unsigned long eeh_check_failure(void *token, unsigned long val) +int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) { - unsigned long addr; - struct pci_dev *dev; - struct device_node *dn; int ret; int rets[2]; unsigned long flags; @@ -381,30 +374,19 @@ unsigned long eeh_check_failure(void *token, unsigned long val) __get_cpu_var(total_mmio_ffs)++; if (!eeh_subsystem_enabled) - return val; + return 0; - /* Finding the phys addr + pci device; this is pretty quick. */ - addr = eeh_token_to_phys((unsigned long)token); - dev = pci_get_device_by_addr(addr); - if (!dev) - return val; - - dn = pci_device_to_OF_node(dev); - if (!dn) { - pci_dev_put(dev); - return val; - } + if (!dn) + return 0; /* Access to IO BARs might get this far and still not want checking. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) { - pci_dev_put(dev); - return val; + return 0; } if (!dn->eeh_config_addr) { - pci_dev_put(dev); - return val; + return 0; } /* @@ -418,7 +400,7 @@ unsigned long eeh_check_failure(void *token, unsigned long val) dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid)); - if (ret == 0 && rets[1] == 1 && rets[0] >= 2) { + if (ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4)) { int log_event; spin_lock_irqsave(&slot_errbuf_lock, flags); @@ -430,7 +412,7 @@ unsigned long eeh_check_failure(void *token, unsigned long val) BUID_LO(dn->phb->buid), NULL, 0, virt_to_phys(slot_errbuf), eeh_error_buf_size, - 2 /* Permanent Error */); + 1 /* Temporary Error */); if (log_event == 0) log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, @@ -438,6 +420,10 @@ unsigned long eeh_check_failure(void *token, unsigned long val) spin_unlock_irqrestore(&slot_errbuf_lock, flags); + printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n", + rets[0], dn->name, dn->full_name); + WARN_ON(1); + /* * XXX We should create a separate sysctl for this. * @@ -446,26 +432,57 @@ unsigned long eeh_check_failure(void *token, unsigned long val) * can use it here. */ if (panic_on_oops) { - panic("EEH: MMIO failure (%d) on device:%s %s\n", - rets[0], pci_name(dev), pci_pretty_name(dev)); + panic("EEH: MMIO failure (%d) on device: %s %s\n", + rets[0], dn->name, dn->full_name); } else { __get_cpu_var(ignored_failures)++; - printk(KERN_INFO "EEH: MMIO failure (%d) on device:%s %s\n", - rets[0], pci_name(dev), pci_pretty_name(dev)); } } else { __get_cpu_var(false_positives)++; } + return 0; +} + +EXPORT_SYMBOL(eeh_dn_check_failure); + +/** + * eeh_check_failure - check if all 1's data is due to EEH slot freeze + * @token i/o token, should be address in the form 0xA.... + * @val value, should be all 1's (XXX why do we need this arg??) + * + * Check for an eeh failure at the given token address. + * Check for an EEH failure at the given token address. Call this + * routine if the result of a read was all 0xff's and you want to + * find out if this is due to an EEH slot freeze event. This routine + * will query firmware for the EEH status. + * + * Note this routine is safe to call in an interrupt context. + */ +unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) +{ + unsigned long addr; + struct pci_dev *dev; + struct device_node *dn; + + /* Finding the phys addr + pci device; this is pretty quick. */ + addr = eeh_token_to_phys((unsigned long __force) token); + dev = pci_get_device_by_addr(addr); + if (!dev) + return val; + + dn = pci_device_to_OF_node(dev); + eeh_dn_check_failure (dn, dev); + pci_dev_put(dev); return val; } + EXPORT_SYMBOL(eeh_check_failure); struct eeh_early_enable_info { unsigned int buid_hi; unsigned int buid_lo; - int force_off; }; /* Enable eeh for the given device node. */ @@ -507,18 +524,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data) if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) enable = 0; - if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, - enable)) { - if (enable) { - printk(KERN_WARNING "EEH: %s user requested to run " - "without EEH checking.\n", dn->full_name); - enable = 0; - } - } - - if (!enable || info->force_off) { + if (!enable) dn->eeh_mode |= EEH_MODE_NOCHECK; - } /* Ok... see if this device supports EEH. Some do, some don't, * and the only way to find out is to check each and every one. */ @@ -572,15 +579,12 @@ void __init eeh_init(void) { struct device_node *phb, *np; struct eeh_early_enable_info info; - char *eeh_force_off = strstr(saved_command_line, "eeh-force-off"); init_pci_config_tokens(); np = of_find_node_by_path("/rtas"); - if (np == NULL) { - printk(KERN_WARNING "EEH: RTAS not found !\n"); + if (np == NULL) return; - } ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); @@ -600,13 +604,6 @@ void __init eeh_init(void) eeh_error_buf_size = RTAS_ERROR_LOG_MAX; } - info.force_off = 0; - if (eeh_force_off) { - printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error " - "Handling is user disabled\n"); - info.force_off = 1; - } - /* Enable EEH for all adapters. Note that eeh requires buid's */ for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) { @@ -621,11 +618,10 @@ void __init eeh_init(void) traverse_pci_devices(phb, early_enable_eeh, &info); } - if (eeh_subsystem_enabled) { + if (eeh_subsystem_enabled) printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n"); - } else { - printk(KERN_WARNING "EEH: disabled PCI Enhanced I/O Error Handling\n"); - } + else + printk(KERN_WARNING "EEH: No capable adapters found\n"); } /** @@ -701,39 +697,6 @@ void eeh_remove_device(struct pci_dev *dev) } EXPORT_SYMBOL(eeh_remove_device); -/* - * If EEH is implemented, find the PCI device using given phys addr - * and check to see if eeh failure checking is disabled. - * Remap the addr (trivially) to the EEH region if EEH checking enabled. - * For addresses not known to PCI the vaddr is simply returned unchanged. - */ -void *eeh_ioremap(unsigned long addr, void *vaddr) -{ - struct pci_dev *dev; - struct device_node *dn; - - if (!eeh_subsystem_enabled) - return vaddr; - - dev = pci_get_device_by_addr(addr); - if (!dev) - return vaddr; - - dn = pci_device_to_OF_node(dev); - if (!dn) { - pci_dev_put(dev); - return vaddr; - } - - if (dn->eeh_mode & EEH_MODE_NOCHECK) { - pci_dev_put(dev); - return vaddr; - } - - pci_dev_put(dev); - return (void *)IO_ADDR_TO_TOKEN(vaddr); -} - static int proc_eeh_show(struct seq_file *m, void *v) { unsigned int cpu; @@ -784,129 +747,3 @@ static int __init eeh_init_proc(void) return 0; } __initcall(eeh_init_proc); - -/* - * Test if "dev" should be configured on or off. - * This processes the options literally from left to right. - * This lets the user specify stupid combinations of options, - * but at least the result should be very predictable. - */ -static int eeh_check_opts_config(struct device_node *dn, - int class_code, int vendor_id, int device_id, - int default_state) -{ - char devname[32], classname[32]; - char *strs[8], *s; - int nstrs, i; - int ret = default_state; - - /* Build list of strings to match */ - nstrs = 0; - s = (char *)get_property(dn, "ibm,loc-code", NULL); - if (s) - strs[nstrs++] = s; - sprintf(devname, "dev%04x:%04x", vendor_id, device_id); - strs[nstrs++] = devname; - sprintf(classname, "class%04x", class_code); - strs[nstrs++] = classname; - strs[nstrs++] = ""; /* yes, this matches the empty string */ - - /* - * Now see if any string matches the eeh_opts list. - * The eeh_opts list entries start with + or -. - */ - for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); - s += strlen(s)+1) { - for (i = 0; i < nstrs; i++) { - if (strcasecmp(strs[i], s+1) == 0) { - ret = (strs[i][0] == '+') ? 1 : 0; - } - } - } - return ret; -} - -/* - * Handle kernel eeh-on & eeh-off cmd line options for eeh. - * - * We support: - * eeh-off=loc1,loc2,loc3... - * - * and this option can be repeated so - * eeh-off=loc1,loc2 eeh-off=loc3 - * is the same as eeh-off=loc1,loc2,loc3 - * - * loc is an IBM location code that can be found in a manual or - * via openfirmware (or the Hardware Management Console). - * - * We also support these additional "loc" values: - * - * dev#:# vendor:device id in hex (e.g. dev1022:2000) - * class# class id in hex (e.g. class0200) - * - * If no location code is specified all devices are assumed - * so eeh-off means eeh by default is off. - */ - -/* - * This is implemented as a null separated list of strings. - * Each string looks like this: "+X" or "-X" - * where X is a loc code, vendor:device, class (as shown above) - * or empty which is used to indicate all. - * - * We interpret this option string list so that it will literally - * behave left-to-right even if some combinations don't make sense. - */ -static int __init eeh_parm(char *str, int state) -{ - char *s, *cur, *curend; - - if (!eeh_opts) { - eeh_opts = alloc_bootmem(EEH_MAX_OPTS); - eeh_opts[eeh_opts_last++] = '+'; /* default */ - eeh_opts[eeh_opts_last++] = '\0'; - } - if (*str == '\0') { - eeh_opts[eeh_opts_last++] = state ? '+' : '-'; - eeh_opts[eeh_opts_last++] = '\0'; - return 1; - } - if (*str == '=') - str++; - for (s = str; s && *s != '\0'; s = curend) { - cur = s; - /* ignore empties. Don't treat as "all-on" or "all-off" */ - while (*cur == ',') - cur++; - curend = strchr(cur, ','); - if (!curend) - curend = cur + strlen(cur); - if (*cur) { - int curlen = curend-cur; - if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) { - printk(KERN_WARNING "EEH: sorry...too many " - "eeh cmd line options\n"); - return 1; - } - eeh_opts[eeh_opts_last++] = state ? '+' : '-'; - strncpy(eeh_opts+eeh_opts_last, cur, curlen); - eeh_opts_last += curlen; - eeh_opts[eeh_opts_last++] = '\0'; - } - } - - return 1; -} - -static int __init eehoff_parm(char *str) -{ - return eeh_parm(str, 0); -} - -static int __init eehon_parm(char *str) -{ - return eeh_parm(str, 1); -} - -__setup("eeh-off", eehoff_parm); -__setup("eeh-on", eehon_parm); diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index 2d48d24e7..f0a12eaa3 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -122,7 +122,7 @@ SystemCall_common: andi. r11,r10,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace syscall_dotrace_cont: - cmpli 0,r0,NR_syscalls + cmpldi 0,r0,NR_syscalls bge- syscall_enosys system_call: /* label this so stack traces look sane */ @@ -204,7 +204,7 @@ syscall_enosys: syscall_error: lbz r11,TI_SC_NOERR(r12) - cmpi 0,r11,0 + cmpwi 0,r11,0 bne- syscall_error_cont neg r3,r3 oris r5,r5,0x1000 /* Set SO bit in CR */ @@ -393,9 +393,17 @@ BEGIN_FTR_SECTION cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ cror eq,4*cr1+eq,eq beq 2f /* if yes, don't slbie it */ - oris r6,r6,0x0800 /* set C (class) bit */ - slbie r6 - slbie r6 /* Workaround POWER5 < DD2.1 issue */ + oris r0,r6,0x0800 /* set C (class) bit */ + + /* Bolt in the new stack SLB entry */ + ld r7,KSP_VSID(r4) /* Get new stack's VSID */ + oris r6,r6,(SLB_ESID_V)@h + ori r6,r6,(SLB_NUM_BOLTED-1)@l + slbie r0 + slbie r0 /* Workaround POWER5 < DD2.1 issue */ + slbmte r7,r6 + isync + 2: END_FTR_SECTION_IFSET(CPU_FTR_SLB) clrrdi r7,r8,THREAD_SHIFT /* base of new stack */ @@ -738,6 +746,10 @@ _STATIC(rtas_restore_regs) mtlr r0 blr /* return to caller */ +#endif /* CONFIG_PPC_PSERIES */ + +#ifdef CONFIG_PPC_MULTIPLATFORM + _GLOBAL(enter_prom) mflr r0 std r0,16(r1) @@ -769,11 +781,8 @@ _GLOBAL(enter_prom) std r11,_MSR(r1) /* Get the PROM entrypoint */ - bl .reloc_offset - LOADADDR(r12,prom) - sub r12,r12,r3 - ld r12,PROMENTRY(r12) - mtlr r12 + ld r0,GPR4(r1) + mtlr r0 /* Switch MSR to 32 bits mode */ @@ -826,4 +835,4 @@ _GLOBAL(enter_prom) mtlr r0 blr -#endif /* defined(CONFIG_PPC_PSERIES) */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index a5d67f599..90be51ae4 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -83,13 +83,14 @@ .text .globl _stext _stext: -#ifdef CONFIG_PPC_PSERIES -_STATIC(__start) +#ifdef CONFIG_PPC_MULTIPLATFORM +_GLOBAL(__start) /* NOP this out unconditionally */ BEGIN_FTR_SECTION - b .__start_initialization_pSeries + b .__start_initialization_multiplatform END_FTR_SECTION(0, 1) -#endif +#endif /* CONFIG_PPC_MULTIPLATFORM */ + /* Catch branch to 0 in real mode */ trap #ifdef CONFIG_PPC_ISERIES @@ -117,7 +118,8 @@ embedded_sysmap_start: .globl embedded_sysmap_end embedded_sysmap_end: .llong 0 -#else + +#else /* CONFIG_PPC_ISERIES */ /* Secondary processors spin on this value until it goes to 1. */ .globl __secondary_hold_spinloop @@ -199,6 +201,7 @@ exception_marker: #define EX_R12 24 #define EX_R13 32 #define EX_SRR0 40 +#define EX_R3 40 /* SLB miss saves R3, but not SRR0 */ #define EX_DAR 48 #define EX_LR 48 /* SLB miss saves LR, but not DAR */ #define EX_DSISR 56 @@ -322,36 +325,11 @@ label##_Iseries: \ HMT_MEDIUM; \ mtspr SPRG1,r13; /* save r13 */ \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ - lbz r10,PACAPROFENABLED(r13); \ - cmpwi r10,0; \ - bne- label##_Iseries_profile; \ -label##_Iseries_prof_ret: \ lbz r10,PACAPROCENABLED(r13); \ cmpwi 0,r10,0; \ beq- label##_Iseries_masked; \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \ -label##_Iseries_profile: \ - ld r12,PACALPPACA+LPPACASRR1(r13); \ - andi. r12,r12,MSR_PR; /* Test if in kernel */ \ - bne label##_Iseries_prof_ret; \ - ld r11,PACALPPACA+LPPACASRR0(r13); \ - ld r12,PACAPROFSTEXT(r13); /* _stext */ \ - subf r11,r12,r11; /* offset into kernel */ \ - lwz r12,PACAPROFSHIFT(r13); \ - srd r11,r11,r12; \ - lwz r12,PACAPROFLEN(r13); /* profile table length - 1 */ \ - cmpd r11,r12; /* off end? */ \ - ble 1f; \ - mr r11,r12; /* force into last entry */ \ -1: sldi r11,r11,2; /* convert to offset */ \ - ld r12,PACAPROFBUFFER(r13);/* profile buffer */ \ - add r12,r12,r11; \ -2: lwarx r11,0,r12; /* atomically increment */ \ - addi r11,r11,1; \ - stwcx. r11,0,r12; \ - bne- 2b; \ - b label##_Iseries_prof_ret #ifdef DO_SOFT_DISABLE #define DISABLE_INTS \ @@ -446,21 +424,13 @@ DataAccessSLB_Pseries: std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - std r3,PACASLBR3(r13) + std r3,PACA_EXSLB+EX_R3(r13) mfspr r9,SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - clrrdi r12,r13,32 /* get high part of &label */ - mfmsr r10 - mfspr r11,SRR0 /* save SRR0 */ - ori r12,r12,(.do_slb_miss)@l - ori r10,r10,MSR_IR|MSR_DR /* DON'T set RI for SLB miss */ - mtspr SRR0,r12 mfspr r12,SRR1 /* and SRR1 */ - mtspr SRR1,r10 mfspr r3,DAR - rfid - b . /* prevent speculative execution */ + b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x400, InstructionAccess) @@ -474,21 +444,13 @@ InstructionAccessSLB_Pseries: std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - std r3,PACASLBR3(r13) + std r3,PACA_EXSLB+EX_R3(r13) mfspr r9,SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - clrrdi r12,r13,32 /* get high part of &label */ - mfmsr r10 - mfspr r11,SRR0 /* save SRR0 */ - ori r12,r12,(.do_slb_miss)@l - ori r10,r10,MSR_IR|MSR_DR /* DON'T set RI for SLB miss */ - mtspr SRR0,r12 mfspr r12,SRR1 /* and SRR1 */ - mtspr SRR1,r10 - mr r3,r11 /* SRR0 is faulting address */ - rfid - b . /* prevent speculative execution */ + mfspr r3,SRR0 /* SRR0 is faulting address */ + b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x500, HardwareInterrupt) STD_EXCEPTION_PSERIES(0x600, Alignment) @@ -580,7 +542,7 @@ __end_systemcfg: * VSID generation algorithm. See include/asm/mmu_context.h. */ - .llong 1 /* # ESIDs to be mapped by hypervisor */ + .llong 2 /* # ESIDs to be mapped by hypervisor */ .llong 1 /* # memory ranges to be mapped by hypervisor */ .llong STAB0_PAGE /* Page # of segment table within load area */ .llong 0 /* Reserved */ @@ -588,11 +550,15 @@ __end_systemcfg: .llong 0 /* Reserved */ .llong 0 /* Reserved */ .llong 0 /* Reserved */ - .llong 0x0c00000000 /* ESID to map (Kernel at EA = 0xC000000000000000) */ - .llong 0x06a99b4b14 /* VSID to map (Kernel at VA = 0x6a99b4b140000000) */ + .llong (KERNELBASE>>SID_SHIFT) + .llong 0x408f92c94 /* KERNELBASE VSID */ + /* We have to list the bolted VMALLOC segment here, too, so that it + * will be restored on shared processor switch */ + .llong (VMALLOCBASE>>SID_SHIFT) + .llong 0xf09b89af5 /* VMALLOCBASE VSID */ .llong 8192 /* # pages to map (32 MB) */ .llong 0 /* Offset from start of loadarea to start of map */ - .llong 0x0006a99b4b140000 /* VPN of first page to map */ + .llong 0x408f92c940000 /* VPN of first page to map */ . = 0x6100 @@ -630,8 +596,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) DataAccessSLB_Iseries: mtspr SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - std r3,PACASLBR3(r13) - ld r11,PACALPPACA+LPPACASRR0(r13) + std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) mfspr r3,DAR b .do_slb_miss @@ -642,10 +607,9 @@ DataAccessSLB_Iseries: InstructionAccessSLB_Iseries: mtspr SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - std r3,PACASLBR3(r13) - ld r11,PACALPPACA+LPPACASRR0(r13) + std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) - mr r3,r11 + ld r3,PACALPPACA+LPPACASRR0(r13) b .do_slb_miss MASKABLE_EXCEPTION_ISERIES(0x500, HardwareInterrupt) @@ -1033,6 +997,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 @@ -1043,6 +1010,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 @@ -1062,6 +1031,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 */ @@ -1088,18 +1066,9 @@ _GLOBAL(do_stab_bolted) rldimi r10,r11,7,52 /* r10 = first ste of the group */ /* Calculate VSID */ - /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */ - rldic r11,r11,15,36 - ori r11,r11,0xc - - /* VSID_RANDOMIZER */ - li r9,9 - sldi r9,r9,32 - oris r9,r9,58231 - ori r9,r9,39831 - - mulld r9,r11,r9 - rldic r9,r9,12,16 /* r9 = vsid << 12 */ + /* This is a kernel address, so protovsid = ESID */ + ASM_VSID_SCRAMBLE(r11, r9) + rldic r9,r11,12,16 /* r9 = vsid << 12 */ /* Search the primary group for a free entry */ 1: ld r11,0(r10) /* Test valid bit of the current ste */ @@ -1176,7 +1145,6 @@ _GLOBAL(do_slb_miss) mflr r10 stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ bl .slb_allocate /* handle it */ @@ -1184,9 +1152,11 @@ _GLOBAL(do_slb_miss) /* All done -- return from exception. */ ld r10,PACA_EXSLB+EX_LR(r13) - ld r3,PACASLBR3(r13) + ld r3,PACA_EXSLB+EX_R3(r13) lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - ld r11,PACA_EXSLB+EX_SRR0(r13) /* get saved SRR0 */ +#ifdef CONFIG_PPC_ISERIES + ld r11,PACALPPACA+LPPACASRR0(r13) /* get SRR0 value */ +#endif /* CONFIG_PPC_ISERIES */ mtlr r10 @@ -1199,8 +1169,10 @@ _GLOBAL(do_slb_miss) mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ .machine pop +#ifdef CONFIG_PPC_ISERIES mtspr SRR0,r11 mtspr SRR1,r12 +#endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) ld r11,PACA_EXSLB+EX_R11(r13) @@ -1253,12 +1225,10 @@ _GLOBAL(pseries_secondary_smp_init) #endif b 1b /* Loop until told to go */ #ifdef CONFIG_PPC_ISERIES -_GLOBAL(__start_initialization_iSeries) +_STATIC(__start_initialization_iSeries) /* Clear out the BSS */ LOADADDR(r11,__bss_stop) - LOADADDR(r8,__bss_start) - sub r11,r11,r8 /* bss size */ addi r11,r11,7 /* round up to an even double word */ rldicl. r11,r11,61,3 /* shift right by 3 */ @@ -1295,32 +1265,73 @@ _GLOBAL(__start_initialization_iSeries) ld r6,PACA(r4) /* Get the base paca pointer */ ld r4,PACASTABVIRT(r6) - bl .iSeries_fixup_klimit + bl .iSeries_early_setup /* relocation is on at this point */ b .start_here_common -#endif +#endif /* CONFIG_PPC_ISERIES */ -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM -_STATIC(mmu_off) +_STATIC(__mmu_off) mfmsr r3 andi. r0,r3,MSR_IR|MSR_DR beqlr andc r3,r3,r0 - mtspr SRR0,r4 - mtspr SRR1,r3 + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 sync rfid b . /* prevent speculative execution */ -_GLOBAL(__start_initialization_pSeries) - mr r31,r3 /* save parameters */ + + +/* + * Here is our main kernel entry point. We support currently 2 kind of entries + * depending on the value of r5. + * + * r5 != NULL -> OF entry, we go to prom_init, "legacy" parameter content + * in r3...r7 + * + * r5 == NULL -> kexec style entry. r3 is a physical pointer to the + * DT block, r4 is a physical pointer to the kernel itself + * + */ +_GLOBAL(__start_initialization_multiplatform) + /* + * Are we booted from a PROM Of-type client-interface ? + */ + cmpldi cr0,r5,0 + bne .__boot_from_prom /* yes -> prom */ + + /* Save parameters */ + mr r31,r3 + mr r30,r4 + + /* Make sure we are running in 64 bits mode */ + bl .enable_64b_mode + + /* Setup some critical 970 SPRs before switching MMU off */ + bl .__970_cpu_preinit + + /* cpu # */ + li r24,0 + + /* Switch off MMU if not already */ + LOADADDR(r4, .__after_prom_start - KERNELBASE) + add r4,r4,r30 + bl .__mmu_off + b .__after_prom_start + +_STATIC(__boot_from_prom) + /* Save parameters */ + mr r31,r3 mr r30,r4 mr r29,r5 mr r28,r6 mr r27,r7 + /* Make sure we are running in 64 bits mode */ bl .enable_64b_mode /* put a relocation offset into r3 */ @@ -1333,7 +1344,7 @@ _GLOBAL(__start_initialization_pSeries) /* Relocate the TOC from a virt addr to a real addr */ sub r2,r2,r3 - /* Save parameters */ + /* Restore parameters */ mr r3,r31 mr r4,r30 mr r5,r29 @@ -1342,17 +1353,8 @@ _GLOBAL(__start_initialization_pSeries) /* Do all of the interaction with OF client interface */ bl .prom_init - mr r23,r3 /* Save phys address we are running at */ - - /* Setup some critical 970 SPRs before switching MMU off */ - bl .__970_cpu_preinit - - li r24,0 /* cpu # */ - - /* Switch off MMU if not already */ - LOADADDR(r4, .__after_prom_start - KERNELBASE) - add r4,r4,r23 - bl .mmu_off + /* We never return */ + trap /* * At this point, r3 contains the physical address we are running at, @@ -1378,7 +1380,7 @@ _STATIC(__after_prom_start) li r3,0 /* target addr */ - // XXX FIXME: Use phys returned by OF (r23) + // XXX FIXME: Use phys returned by OF (r30) sub r4,r27,r26 /* source addr */ /* current address of _start */ /* i.e. where we are running */ @@ -1403,8 +1405,9 @@ _STATIC(__after_prom_start) ld r5,0(r5) /* get the value of klimit */ sub r5,r5,r27 bl .copy_and_flush /* copy the rest */ - b .start_here_pSeries -#endif + b .start_here_multiplatform + +#endif /* CONFIG_PPC_MULTIPLATFORM */ /* * Copy routine used to copy the kernel to start at physical address 0 @@ -1609,6 +1612,7 @@ _STATIC(load_up_altivec) li r10,THREAD_VSCR stw r4,THREAD_USED_VR(r5) lvx vr0,r10,r5 + mtvscr vr0 REST_32VRS(0,r4,r5) #ifndef CONFIG_SMP /* Update last_task_used_math to 'current' */ @@ -1823,15 +1827,33 @@ _GLOBAL(enable_64b_mode) isync blr -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM /* * This is where the main kernel code starts. */ -_STATIC(start_here_pSeries) +_STATIC(start_here_multiplatform) /* get a new offset, now that the kernel has moved. */ bl .reloc_offset mr r26,r3 + /* Clear out the BSS. It may have been done in prom_init, + * already but that's irrelevant since prom_init will soon + * be detached from the kernel completely. Besides, we need + * to clear it now for kexec-style entry. + */ + LOADADDR(r11,__bss_stop) + LOADADDR(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + mfmsr r6 ori r6,r6,MSR_RI mtmsrd r6 /* RI on */ @@ -1904,8 +1926,11 @@ _STATIC(start_here_pSeries) mr r5,r26 bl .identify_cpu - /* Get the pointer to the segment table which is used by */ - /* stab_initialize */ + /* Setup a valid physical PACA pointer in SPRG3 for early_setup + * note that boot_cpuid can always be 0 nowadays since there is + * nowhere it can be initialized differently before we reach this + * code + */ LOADADDR(r27, boot_cpuid) sub r27,r27,r26 lwz r27,0(r27) @@ -1914,12 +1939,18 @@ _STATIC(start_here_pSeries) mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ sub r13,r13,r26 /* convert to physical addr */ - mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ - ld r3,PACASTABREAL(r13) - ori r4,r3,1 /* turn on valid bit */ + /* Do very early kernel initializations, including initial hash table, + * stab and slb setup before we turn on relocation. */ + + /* Restore parameters passed from prom_init/kexec */ + mr r3,r31 + bl .early_setup + /* set the ASR */ + ld r3,PACASTABREAL(r13) + ori r4,r3,1 /* turn on valid bit */ li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES_LPAR @@ -1938,13 +1969,7 @@ _STATIC(start_here_pSeries) 98: /* !(rpa hypervisor) || !(star) */ mtasr r4 /* set the stab location */ 99: - mfspr r6,SPRG3 - ld r3,PACASTABREAL(r6) /* restore r3 for stab_initialize */ - - /* Initialize an initial memory mapping and turn on relocation. */ - bl .stab_initialize - bl .htab_initialize - + /* Set SDR1 (hash table pointer) */ li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ /* Test if bit 0 is set (LPAR bit) */ @@ -1961,7 +1986,7 @@ _STATIC(start_here_pSeries) mtspr SRR1,r4 rfid b . /* prevent speculative execution */ -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ /* This is where all platforms converge execution */ _STATIC(start_here_common) @@ -2009,13 +2034,6 @@ _STATIC(start_here_common) ld r2,PACATOC(r13) std r1,PACAKSAVE(r13) - /* Restore the parms passed in from the bootloader. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - bl .setup_system /* Load up the kernel context */ diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c index dedefb305..c72fb8ffe 100644 --- a/arch/ppc64/kernel/hvconsole.c +++ b/arch/ppc64/kernel/hvconsole.c @@ -1,6 +1,10 @@ /* * hvconsole.c * Copyright (C) 2004 Hollis Blanchard, IBM Corporation + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold * * LPAR console support. * @@ -22,14 +26,22 @@ #include #include #include -#include #include +#include -int hvc_get_chars(int index, char *buf, int count) +/** + * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper + * @vtermno: The vtermno or unit_address of the adapter from which to fetch the + * data. + * @buf: The character buffer into which to put the character data fetched from + * firmware. + * @count: not used? + */ +int hvc_get_chars(uint32_t vtermno, char *buf, int count) { unsigned long got; - if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got, + if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { /* * Work around a HV bug where it gives us a null @@ -53,40 +65,56 @@ int hvc_get_chars(int index, char *buf, int count) EXPORT_SYMBOL(hvc_get_chars); -int hvc_put_chars(int index, const char *buf, int count) +/** + * hvc_put_chars: send characters to firmware for denoted vterm adapter + * @vtermno: The vtermno or unit_address of the adapter from which the data + * originated. + * @buf: The character buffer that contains the character data to send to + * firmware. + * @count: Send this number of characters. + */ +int hvc_put_chars(uint32_t vtermno, const char *buf, int count) { unsigned long *lbuf = (unsigned long *) buf; long ret; - ret = plpar_hcall_norets(H_PUT_TERM_CHAR, index, count, lbuf[0], + ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], lbuf[1]); if (ret == H_Success) return count; if (ret == H_Busy) return 0; - return -1; + return -EIO; } EXPORT_SYMBOL(hvc_put_chars); -/* return the number of client vterms present */ -/* XXX this requires an interface change to handle multiple discontiguous - * vterms */ -int hvc_count(int *start_termno) +/* + * We hope/assume that the first vty found corresponds to the first console + * device. + */ +int hvc_find_vtys(void) { struct device_node *vty; int num_found = 0; - /* consider only the first vty node. - * we should _always_ be able to find one. */ - vty = of_find_node_by_name(NULL, "vty"); - if (vty && device_is_compatible(vty, "hvterm1")) { - u32 *termno = (u32 *)get_property(vty, "reg", NULL); + for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; + vty = of_find_node_by_name(vty, "vty")) { + uint32_t *vtermno; + + /* We have statically defined space for only a certain number of + * console adapters. */ + if (num_found >= MAX_NR_HVC_CONSOLES) + break; - if (termno && start_termno) - *start_termno = *termno; - num_found = 1; - of_node_put(vty); + vtermno = (uint32_t *)get_property(vty, "reg", NULL); + if (!vtermno) + continue; + + if (device_is_compatible(vty, "hvterm1")) { + hvc_instantiate(*vtermno, num_found); + ++num_found; + } } return num_found; diff --git a/arch/ppc64/kernel/hvcserver.c b/arch/ppc64/kernel/hvcserver.c index fbe445ec0..bde8f42da 100644 --- a/arch/ppc64/kernel/hvcserver.c +++ b/arch/ppc64/kernel/hvcserver.c @@ -61,14 +61,21 @@ int hvcs_convert(long to_convert) } } +/** + * hvcs_free_partner_info - free pi allocated by hvcs_get_partner_info + * @head: list_head pointer for an allocated list of partner info structs to + * free. + * + * This function is used to free the partner info list that was returned by + * calling hvcs_get_partner_info(). + */ int hvcs_free_partner_info(struct list_head *head) { struct hvcs_partner_info *pi; struct list_head *element; - if (!head) { + if (!head) return -EINVAL; - } while (!list_empty(head)) { element = head->next; @@ -82,7 +89,7 @@ int hvcs_free_partner_info(struct list_head *head) EXPORT_SYMBOL(hvcs_free_partner_info); /* Helper function for hvcs_get_partner_info */ -int hvcs_next_partner(unsigned int unit_address, +int hvcs_next_partner(uint32_t unit_address, unsigned long last_p_partition_ID, unsigned long last_p_unit_address, unsigned long *pi_buff) @@ -94,25 +101,37 @@ int hvcs_next_partner(unsigned int unit_address, return hvcs_convert(retval); } -/* - * The unit_address parameter is the unit address of the vty-server vdevice - * in whose partner information the caller is interested. This function - * uses a pointer to a list_head instance in which to store the partner info. +/** + * hvcs_get_partner_info - Get all of the partner info for a vty-server adapter + * @unit_address: The unit_address of the vty-server adapter for which this + * function is fetching partner info. + * @head: An initialized list_head pointer to an empty list to use to return the + * list of partner info fetched from the hypervisor to the caller. + * @pi_buff: A page sized buffer pre-allocated prior to calling this function + * that is to be used to be used by firmware as an iterator to keep track + * of the partner info retrieval. + * * This function returns non-zero on success, or if there is no partner info. * + * The pi_buff is pre-allocated prior to calling this function because this + * function may be called with a spin_lock held and kmalloc of a page is not + * recommended as GFP_ATOMIC. + * + * The first long of this buffer is used to store a partner unit address. The + * second long is used to store a partner partition ID and starting at + * pi_buff[2] is the 79 character Converged Location Code (diff size than the + * unsigned longs, hence the casting mumbo jumbo you see later). + * * Invocation of this function should always be followed by an invocation of * hvcs_free_partner_info() using a pointer to the SAME list head instance - * that was used to store the partner_info list. + * that was passed as a parameter to this function. */ -int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, +int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head, unsigned long *pi_buff) { /* - * This is a page sized buffer to be passed to hvcall per invocation. - * NOTE: the first long returned is unit_address. The second long - * returned is the partition ID and starting with pi_buff[2] are - * HVCS_CLC_LENGTH characters, which are diff size than the unsigned - * long, hence the casting mumbojumbo you see later. + * Dealt with as longs because of the hcall interface even though the + * values are uint32_t. */ unsigned long last_p_partition_ID; unsigned long last_p_unit_address; @@ -122,15 +141,12 @@ int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, memset(pi_buff, 0x00, PAGE_SIZE); /* invalid parameters */ - if (!head) + if (!head || !pi_buff) return -EINVAL; last_p_partition_ID = last_p_unit_address = ~0UL; INIT_LIST_HEAD(head); - if (!pi_buff) - return -ENOMEM; - do { retval = hvcs_next_partner(unit_address, last_p_partition_ID, last_p_unit_address, pi_buff); @@ -183,21 +199,29 @@ int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, } EXPORT_SYMBOL(hvcs_get_partner_info); -/* +/** + * hvcs_register_connection - establish a connection between this vty-server and + * a vty. + * @unit_address: The unit address of the vty-server adapter that is to be + * establish a connection. + * @p_partition_ID: The partition ID of the vty adapter that is to be connected. + * @p_unit_address: The unit address of the vty adapter to which the vty-server + * is to be connected. + * * If this function is called once and -EINVAL is returned it may * indicate that the partner info needs to be refreshed for the * target unit address at which point the caller must invoke * hvcs_get_partner_info() and then call this function again. If, * for a second time, -EINVAL is returned then it indicates that * there is probably already a partner connection registered to a - * different vty-server@ vdevice. It is also possible that a second + * different vty-server adapter. It is also possible that a second * -EINVAL may indicate that one of the parms is not valid, for - * instance if the link was removed between the vty-server@ vdevice - * and the vty@ vdevice that you are trying to open. Don't shoot the + * instance if the link was removed between the vty-server adapter + * and the vty adapter that you are trying to open. Don't shoot the * messenger. Firmware implemented it this way. */ -int hvcs_register_connection( unsigned int unit_address, - unsigned int p_partition_ID, unsigned int p_unit_address) +int hvcs_register_connection( uint32_t unit_address, + uint32_t p_partition_ID, uint32_t p_unit_address) { long retval; retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address, @@ -206,11 +230,17 @@ int hvcs_register_connection( unsigned int unit_address, } EXPORT_SYMBOL(hvcs_register_connection); -/* - * If -EBUSY is returned continue to call this function - * until 0 is returned. +/** + * hvcs_free_connection - free the connection between a vty-server and vty + * @unit_address: The unit address of the vty-server that is to have its + * connection severed. + * + * This function is used to free the partner connection between a vty-server + * adapter and a vty adapter. + * + * If -EBUSY is returned continue to call this function until 0 is returned. */ -int hvcs_free_connection(unsigned int unit_address) +int hvcs_free_connection(uint32_t unit_address) { long retval; retval = plpar_hcall_norets(H_FREE_VTERM, unit_address); diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c index 2456227b4..b1177b476 100644 --- a/arch/ppc64/kernel/iSeries_htab.c +++ b/arch/ppc64/kernel/iSeries_htab.c @@ -233,4 +233,6 @@ void hpte_init_iSeries(void) ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; ppc_md.hpte_insert = iSeries_hpte_insert; ppc_md.hpte_remove = iSeries_hpte_remove; + + htab_finish_init(); } diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 3472d188e..d3715a153 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -419,46 +419,39 @@ static int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, * I/0 Memory copy MUST use mmio commands on iSeries * To do; For performance, include the hv call directly */ -void *iSeries_memset_io(void *dest, char c, size_t Count) +void iSeries_memset_io(volatile void __iomem *dest, char c, size_t Count) { u8 ByteValue = c; long NumberOfBytes = Count; - char *IoBuffer = dest; while (NumberOfBytes > 0) { - iSeries_Write_Byte(ByteValue, (void *)IoBuffer); - ++IoBuffer; + iSeries_Write_Byte(ByteValue, dest++); -- NumberOfBytes; } - return dest; } EXPORT_SYMBOL(iSeries_memset_io); -void *iSeries_memcpy_toio(void *dest, void *source, size_t count) +void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t count) { - char *dst = dest; char *src = source; long NumberOfBytes = count; while (NumberOfBytes > 0) { - iSeries_Write_Byte(*src++, (void *)dst++); + iSeries_Write_Byte(*src++, dest++); -- NumberOfBytes; } - return dest; } EXPORT_SYMBOL(iSeries_memcpy_toio); -void *iSeries_memcpy_fromio(void *dest, void *source, size_t count) +void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *src, size_t count) { char *dst = dest; - char *src = source; long NumberOfBytes = count; while (NumberOfBytes > 0) { - *dst++ = iSeries_Read_Byte((void *)src++); + *dst++ = iSeries_Read_Byte(src++); -- NumberOfBytes; } - return dest; } EXPORT_SYMBOL(iSeries_memcpy_fromio); @@ -612,17 +605,19 @@ static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, * Note: Make sure the passed variable end up on the stack to avoid * the exposure of being device global. */ -static inline struct iSeries_Device_Node *xlateIoMmAddress(void *IoAddress, +static inline struct iSeries_Device_Node *xlateIoMmAddress(const volatile void __iomem *IoAddress, u64 *dsaptr, u64 *BarOffsetPtr) { + unsigned long OrigIoAddr; unsigned long BaseIoAddr; unsigned long TableIndex; struct iSeries_Device_Node *DevNode; - if (((unsigned long)IoAddress < iSeries_Base_Io_Memory) || - ((unsigned long)IoAddress >= iSeries_Max_Io_Memory)) + OrigIoAddr = (unsigned long __force)IoAddress; + if ((OrigIoAddr < iSeries_Base_Io_Memory) || + (OrigIoAddr >= iSeries_Max_Io_Memory)) return NULL; - BaseIoAddr = (unsigned long)IoAddress - iSeries_Base_Io_Memory; + BaseIoAddr = OrigIoAddr - iSeries_Base_Io_Memory; TableIndex = BaseIoAddr / iSeries_IoMmTable_Entry_Size; DevNode = iSeries_IoMmTable[TableIndex]; @@ -644,7 +639,7 @@ static inline struct iSeries_Device_Node *xlateIoMmAddress(void *IoAddress, * iSeries_Read_Word = Read Word (16 bit) * iSeries_Read_Long = Read Long (32 bit) */ -u8 iSeries_Read_Byte(void *IoAddress) +u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -673,7 +668,7 @@ u8 iSeries_Read_Byte(void *IoAddress) } EXPORT_SYMBOL(iSeries_Read_Byte); -u16 iSeries_Read_Word(void *IoAddress) +u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -703,7 +698,7 @@ u16 iSeries_Read_Word(void *IoAddress) } EXPORT_SYMBOL(iSeries_Read_Word); -u32 iSeries_Read_Long(void *IoAddress) +u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -740,7 +735,7 @@ EXPORT_SYMBOL(iSeries_Read_Long); * iSeries_Write_Word = Write Word(16 bit) * iSeries_Write_Long = Write Long(32 bit) */ -void iSeries_Write_Byte(u8 data, void *IoAddress) +void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -767,7 +762,7 @@ void iSeries_Write_Byte(u8 data, void *IoAddress) } EXPORT_SYMBOL(iSeries_Write_Byte); -void iSeries_Write_Word(u16 data, void *IoAddress) +void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -794,7 +789,7 @@ void iSeries_Write_Word(u16 data, void *IoAddress) } EXPORT_SYMBOL(iSeries_Write_Word); -void iSeries_Write_Long(u32 data, void *IoAddress) +void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; @@ -820,7 +815,3 @@ void iSeries_Write_Long(u32 data, void *IoAddress) } while (CheckReturnCode("WWL", DevNode, rc) != 0); } EXPORT_SYMBOL(iSeries_Write_Long); - -void pcibios_name_device(struct pci_dev *dev) -{ -} diff --git a/arch/ppc64/kernel/iSeries_pci_reset.c b/arch/ppc64/kernel/iSeries_pci_reset.c index e1e48c35e..8848ece79 100644 --- a/arch/ppc64/kernel/iSeries_pci_reset.c +++ b/arch/ppc64/kernel/iSeries_pci_reset.c @@ -65,7 +65,8 @@ int iSeries_Device_ToggleReset(struct pci_dev *PciDev, int AssertTime, AssertDelay = (5 * HZ) / 10; else AssertDelay = (AssertTime * HZ) / 10; - if (WaitDelay == 0) + + if (DelayTime == 0) WaitDelay = (30 * HZ) / 10; else WaitDelay = (DelayTime * HZ) / 10; diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index e12b50f8c..9b59f5165 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -16,6 +16,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -36,6 +38,7 @@ #include #include #include +#include #include #include "iSeries_setup.h" @@ -53,18 +56,21 @@ #include #include +extern void hvlog(char *fmt, ...); + +#ifdef DEBUG +#define DBG(fmt...) hvlog(fmt) +#else +#define DBG(fmt...) +#endif + /* Function Prototypes */ -extern void abort(void); extern void ppcdbg_initialize(void); -extern void iSeries_pcibios_init(void); extern void tce_init_iSeries(void); static void build_iSeries_Memory_Map(void); static void setup_iSeries_cache_sizes(void); static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); -extern void build_valid_hpte(unsigned long vsid, unsigned long ea, unsigned long pa, - pte_t *ptep, unsigned hpteflags, unsigned bolted); -static void iSeries_setup_dprofile(void); extern void iSeries_setup_arch(void); extern void iSeries_pci_final_fixup(void); @@ -77,16 +83,8 @@ static unsigned long tbFreqHz; static unsigned long tbFreqMhz; static unsigned long tbFreqMhzHundreths; -unsigned long dprof_shift; -unsigned long dprof_len; -unsigned int *dprof_buffer; - int piranha_simulator; -int boot_cpuid; - -extern char _end[]; - extern int rd_size; /* Defined in drivers/block/rd.c */ extern unsigned long klimit; extern unsigned long embedded_sysmap_start; @@ -285,8 +283,28 @@ unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, return mem_blocks; } -void __init iSeries_init_early(void) +static void __init iSeries_parse_cmdline(void) +{ + char *p, *q; + + /* copy the command line parameter from the primary VSP */ + HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, + HvLpDma_Direction_RemoteToLocal); + + p = cmd_line; + q = cmd_line + 255; + while(p < q) { + if (!*p || *p == '\n') + break; + ++p; + } + *p = 0; +} + +/*static*/ void __init iSeries_init_early(void) { + DBG(" -> iSeries_init_early()\n"); + ppcdbg_initialize(); #if defined(CONFIG_BLK_DEV_INITRD) @@ -310,25 +328,20 @@ void __init iSeries_init_early(void) iSeries_recal_tb = get_tb(); iSeries_recal_titan = HvCallXm_loadTod(); - ppc_md.setup_arch = iSeries_setup_arch; - ppc_md.get_cpuinfo = iSeries_get_cpuinfo; - ppc_md.init_IRQ = iSeries_init_IRQ; - ppc_md.get_irq = iSeries_get_irq; - ppc_md.init = NULL; - - ppc_md.pcibios_fixup = iSeries_pci_final_fixup; - - ppc_md.restart = iSeries_restart; - ppc_md.power_off = iSeries_power_off; - ppc_md.halt = iSeries_halt; - - ppc_md.get_boot_time = iSeries_get_boot_time; - ppc_md.set_rtc_time = iSeries_set_rtc_time; - ppc_md.get_rtc_time = iSeries_get_rtc_time; - ppc_md.calibrate_decr = iSeries_calibrate_decr; - ppc_md.progress = iSeries_progress; + /* + * Cache sizes must be initialized before hpte_init_iSeries is called + * as the later need them for flush_icache_range() + */ + setup_iSeries_cache_sizes(); + /* + * Initialize the hash table management pointers + */ hpte_init_iSeries(); + + /* + * Initialize the DMA/TCE management + */ tce_init_iSeries(); /* @@ -336,63 +349,36 @@ void __init iSeries_init_early(void) * AS/400 absolute addresses */ build_iSeries_Memory_Map(); - setup_iSeries_cache_sizes(); + /* Initialize machine-dependency vectors */ #ifdef CONFIG_SMP smp_init_iSeries(); #endif if (itLpNaca.xPirEnvironMode == 0) piranha_simulator = 1; -} - -void __init iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - char *p, *q; /* Associate Lp Event Queue 0 with processor 0 */ HvCallEvent_setLpEventQueueInterruptProc(0, 0); - /* copy the command line parameter from the primary VSP */ - HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, - HvLpDma_Direction_RemoteToLocal); - - p = cmd_line; - q = cmd_line + 255; - while( p < q ) { - if (!*p || *p == '\n') - break; - ++p; - } - *p = 0; - - if (strstr(cmd_line, "dprofile=")) { - for (q = cmd_line; (p = strstr(q, "dprofile=")) != 0; ) { - unsigned long size, new_klimit; - - q = p + 9; - if ((p > cmd_line) && (p[-1] != ' ')) - continue; - dprof_shift = simple_strtoul(q, &q, 0); - dprof_len = (unsigned long)_etext - - (unsigned long)_stext; - dprof_len >>= dprof_shift; - size = ((dprof_len * sizeof(unsigned int)) + - (PAGE_SIZE-1)) & PAGE_MASK; - dprof_buffer = (unsigned int *)((klimit + - (PAGE_SIZE-1)) & PAGE_MASK); - new_klimit = ((unsigned long)dprof_buffer) + size; - lmb_reserve(__pa(klimit), (new_klimit-klimit)); - klimit = new_klimit; - memset(dprof_buffer, 0, size); - } - } - - iSeries_setup_dprofile(); - mf_init(); mf_initialized = 1; mb(); + + /* If we were passed an initrd, set the ROOT_DEV properly if the values + * look sensible. If not, clear initrd reference. + */ +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && + initrd_end > initrd_start) + ROOT_DEV = Root_RAM0; + else + initrd_start = initrd_end = 0; +#endif /* CONFIG_BLK_DEV_INITRD */ + + + iSeries_parse_cmdline(); + + DBG(" <- iSeries_init_early()\n"); } /* @@ -816,7 +802,7 @@ void __init iSeries_progress(char * st, unsigned short code) } } -void iSeries_fixup_klimit(void) +static void __init iSeries_fixup_klimit(void) { /* * Change klimit to take into account any ram disk @@ -837,22 +823,6 @@ void iSeries_fixup_klimit(void) } } -static void iSeries_setup_dprofile(void) -{ - if (dprof_buffer) { - unsigned i; - - for (i = 0; i < NR_CPUS; ++i) { - paca[i].prof_shift = dprof_shift; - paca[i].prof_len = dprof_len - 1; - paca[i].prof_buffer = dprof_buffer; - paca[i].prof_stext = (unsigned *)_stext; - mb(); - paca[i].prof_enabled = 1; - } - } -} - int __init iSeries_src_init(void) { /* clear the progress line */ @@ -861,3 +831,27 @@ int __init iSeries_src_init(void) } late_initcall(iSeries_src_init); + +void __init iSeries_early_setup(void) +{ + iSeries_fixup_klimit(); + + ppc_md.setup_arch = iSeries_setup_arch; + ppc_md.get_cpuinfo = iSeries_get_cpuinfo; + ppc_md.init_IRQ = iSeries_init_IRQ; + ppc_md.get_irq = iSeries_get_irq; + ppc_md.init_early = iSeries_init_early, + + ppc_md.pcibios_fixup = iSeries_pci_final_fixup; + + ppc_md.restart = iSeries_restart; + ppc_md.power_off = iSeries_power_off; + ppc_md.halt = iSeries_halt; + + ppc_md.get_boot_time = iSeries_get_boot_time; + ppc_md.set_rtc_time = iSeries_set_rtc_time; + ppc_md.get_rtc_time = iSeries_get_rtc_time; + ppc_md.calibrate_decr = iSeries_calibrate_decr; + ppc_md.progress = iSeries_progress; +} + diff --git a/arch/ppc64/kernel/iSeries_setup.h b/arch/ppc64/kernel/iSeries_setup.h index 240dad4ef..098041b4c 100644 --- a/arch/ppc64/kernel/iSeries_setup.h +++ b/arch/ppc64/kernel/iSeries_setup.h @@ -19,10 +19,6 @@ #ifndef __ISERIES_SETUP_H__ #define __ISERIES_SETUP_H__ -extern void iSeries_init_early(void); -extern void iSeries_init(unsigned long r3, unsigned long ird_start, - unsigned long ird_end, unsigned long cline_start, - unsigned long cline_end); extern void iSeries_setup_arch(void); extern void iSeries_setup_residual(struct seq_file *m, int cpu_id); extern void iSeries_get_cpuinfo(struct seq_file *m); diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index bc7dbbd2d..62e509d96 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -16,40 +16,29 @@ */ #include -#include #include #include -#include #include -#include -#include -#include -#include -#include #include +#include +#include -#include -#include #include -#include #include #include -#include #include #include -#include #include #include +#include -extern long cede_processor(void); -extern long poll_pending(void); extern void power4_idle(void); -int (*idle_loop)(void); +static int (*idle_loop)(void); #ifdef CONFIG_PPC_ISERIES -unsigned long maxYieldTime = 0; -unsigned long minYieldTime = 0xffffffffffffffffUL; +static unsigned long maxYieldTime = 0; +static unsigned long minYieldTime = 0xffffffffffffffffUL; static void yield_shared_processor(void) { @@ -80,7 +69,7 @@ static void yield_shared_processor(void) process_iSeries_events(); } -int iSeries_idle(void) +static int iSeries_idle(void) { struct paca_struct *lpaca; long oldval; @@ -91,13 +80,10 @@ int iSeries_idle(void) CTRL = mfspr(CTRLF); CTRL &= ~RUNLATCH; mtspr(CTRLT, CTRL); -#if 0 - init_idle(); -#endif lpaca = get_paca(); - for (;;) { + while (1) { if (lpaca->lppaca.xSharedProc) { if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr)) process_iSeries_events(); @@ -125,13 +111,16 @@ int iSeries_idle(void) schedule(); } + return 0; } -#endif -int default_idle(void) +#else + +static int default_idle(void) { long oldval; + unsigned int cpu = smp_processor_id(); while (1) { oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); @@ -139,9 +128,14 @@ int default_idle(void) if (!oldval) { set_thread_flag(TIF_POLLING_NRFLAG); - while (!need_resched()) { + while (!need_resched() && !cpu_is_offline(cpu)) { barrier(); + /* + * Go into low thread priority and possibly + * low power mode. + */ HMT_low(); + HMT_very_low(); } HMT_medium(); @@ -151,8 +145,7 @@ int default_idle(void) } schedule(); - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } @@ -169,12 +162,15 @@ int dedicated_idle(void) struct paca_struct *lpaca = get_paca(), *ppaca; unsigned long start_snooze; unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); + unsigned int cpu = smp_processor_id(); - ppaca = &paca[smp_processor_id() ^ 1]; + ppaca = &paca[cpu ^ 1]; while (1) { - /* Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. */ + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ lpaca->lppaca.xIdle = 1; oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); @@ -182,42 +178,32 @@ int dedicated_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); start_snooze = __get_tb() + *smt_snooze_delay * tb_ticks_per_usec; - while (!need_resched()) { - /* need_resched could be 1 or 0 at this - * point. If it is 0, set it to 0, so - * an IPI/Prod is sent. If it is 1, keep - * it that way & schedule work. + while (!need_resched() && !cpu_is_offline(cpu)) { + /* + * Go into low thread priority and possibly + * low power mode. */ + HMT_low(); + HMT_very_low(); + if (*smt_snooze_delay == 0 || - __get_tb() < start_snooze) { - HMT_low(); /* Low thread priority */ + __get_tb() < start_snooze) continue; - } - HMT_very_low(); /* Low power mode */ + HMT_medium(); - /* If the SMT mode is system controlled & the - * partner thread is doing work, switch into - * ST mode. - */ - if((naca->smt_state == SMT_DYNAMIC) && - (!(ppaca->lppaca.xIdle))) { - /* Indicate we are no longer polling for - * work, and then clear need_resched. If - * need_resched was 1, set it back to 1 - * and schedule work + if (!(ppaca->lppaca.xIdle)) { + local_irq_disable(); + + /* + * We are about to sleep the thread + * and so wont be polling any + * more. */ clear_thread_flag(TIF_POLLING_NRFLAG); - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - if(oldval == 1) { - set_need_resched(); - break; - } - /* DRENG: Go HMT_medium here ? */ - local_irq_disable(); - - /* SMT dynamic mode. Cede will result + /* + * SMT dynamic mode. Cede will result * in this thread going dormant, if the * partner thread is still doing work. * Thread wakes up if partner goes idle, @@ -225,15 +211,21 @@ int dedicated_idle(void) * occurs. Returning from the cede * enables external interrupts. */ - cede_processor(); + if (!need_resched()) + cede_processor(); + else + local_irq_enable(); } else { - /* Give the HV an opportunity at the + /* + * Give the HV an opportunity at the * processor, since we are not doing * any work. */ poll_pending(); } } + + clear_thread_flag(TIF_POLLING_NRFLAG); } else { set_need_resched(); } @@ -241,57 +233,60 @@ int dedicated_idle(void) HMT_medium(); lpaca->lppaca.xIdle = 0; schedule(); - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } return 0; } -int shared_idle(void) +static int shared_idle(void) { struct paca_struct *lpaca = get_paca(); + unsigned int cpu = smp_processor_id(); while (1) { - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) - cpu_die(); - - /* Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. */ + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ lpaca->lppaca.xIdle = 1; - if (!need_resched()) { - local_irq_disable(); - - /* + while (!need_resched() && !cpu_is_offline(cpu)) { + local_irq_disable(); + + /* * Yield the processor to the hypervisor. We return if * an external interrupt occurs (which are driven prior * to returning here) or if a prod occurs from another - * processor. When returning here, external interrupts + * processor. When returning here, external interrupts * are enabled. + * + * Check need_resched() again with interrupts disabled + * to avoid a race. */ - cede_processor(); + if (!need_resched()) + cede_processor(); + else + local_irq_enable(); } HMT_medium(); lpaca->lppaca.xIdle = 0; schedule(); + if (cpu_is_offline(smp_processor_id()) && + system_state == SYSTEM_RUNNING) + cpu_die(); } return 0; } -#endif -int cpu_idle(void) -{ - idle_loop(); - return 0; -} +#endif /* CONFIG_PPC_PSERIES */ -int native_idle(void) +static int native_idle(void) { while(1) { + /* check CPU type here */ if (!need_resched()) power4_idle(); if (need_resched()) @@ -300,33 +295,80 @@ int native_idle(void) return 0; } +#endif /* CONFIG_PPC_ISERIES */ + +int cpu_idle(void) +{ + idle_loop(); + return 0; +} + +int powersave_nap; + +#ifdef CONFIG_SYSCTL +/* + * Register the sysctl to set/clear 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 + int idle_setup(void) { + /* + * Move that junk to each platform specific file, eventually define + * a pSeries_idle for shared processor stuff + */ #ifdef CONFIG_PPC_ISERIES idle_loop = iSeries_idle; + return 1; #else + idle_loop = default_idle; +#endif +#ifdef CONFIG_PPC_PSERIES if (systemcfg->platform & PLATFORM_PSERIES) { if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { if (get_paca()->lppaca.xSharedProc) { - printk("idle = shared_idle\n"); + printk(KERN_INFO "Using shared processor idle loop\n"); idle_loop = shared_idle; } else { - printk("idle = dedicated_idle\n"); + printk(KERN_INFO "Using dedicated idle loop\n"); idle_loop = dedicated_idle; } } else { - printk("idle = default_idle\n"); + printk(KERN_INFO "Using default idle loop\n"); idle_loop = default_idle; } - } else if (systemcfg->platform == PLATFORM_POWERMAC) { - printk("idle = native_idle\n"); + } +#endif /* CONFIG_PPC_PSERIES */ +#ifdef CONFIG_PPC_PMAC + if (systemcfg->platform == PLATFORM_POWERMAC) { + printk(KERN_INFO "Using native/NAP idle loop\n"); idle_loop = native_idle; - } else { - printk("idle_setup: unknown platform, use default_idle\n"); - idle_loop = default_idle; } -#endif +#endif /* CONFIG_PPC_PMAC */ return 1; } - diff --git a/arch/ppc64/kernel/idle_power4.S b/arch/ppc64/kernel/idle_power4.S index fb983069d..97e4a2655 100644 --- a/arch/ppc64/kernel/idle_power4.S +++ b/arch/ppc64/kernel/idle_power4.S @@ -46,7 +46,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) /* Now check if user or arch enabled NAP mode */ LOADBASE(r3,powersave_nap) lwz r4,powersave_nap@l(r3) - cmpi 0,r4,0 + cmpwi 0,r4,0 beqlr /* Clear MSR:EE */ diff --git a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c index 40ba4c17e..94d1a05b7 100644 --- a/arch/ppc64/kernel/ioctl32.c +++ b/arch/ppc64/kernel/ioctl32.c @@ -22,9 +22,7 @@ #define INCLUDES #include "compat_ioctl.c" -#include #include -#include #define CODE #include "compat_ioctl.c" diff --git a/arch/ppc64/kernel/iomap.c b/arch/ppc64/kernel/iomap.c new file mode 100644 index 000000000..b70a9240c --- /dev/null +++ b/arch/ppc64/kernel/iomap.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +/* + * Here comes the ppc64 implementation of the IOMAP + * interfaces. + */ +unsigned int fastcall ioread8(void __iomem *addr) +{ + return readb(addr); +} +unsigned int fastcall ioread16(void __iomem *addr) +{ + return readw(addr); +} +unsigned int fastcall ioread32(void __iomem *addr) +{ + return readl(addr); +} +EXPORT_SYMBOL(ioread8); +EXPORT_SYMBOL(ioread16); +EXPORT_SYMBOL(ioread32); + +void fastcall iowrite8(u8 val, void __iomem *addr) +{ + writeb(val, addr); +} +void fastcall iowrite16(u16 val, void __iomem *addr) +{ + writew(val, addr); +} +void fastcall iowrite32(u32 val, void __iomem *addr) +{ + writel(val, addr); +} +EXPORT_SYMBOL(iowrite8); +EXPORT_SYMBOL(iowrite16); +EXPORT_SYMBOL(iowrite32); + +/* + * These are the "repeat read/write" functions. Note the + * non-CPU byte order. We do things in "IO byteorder" + * here. + * + * FIXME! We could make these do EEH handling if we really + * wanted. Not clear if we do. + */ +void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) +{ + _insb((u8 __force *) addr, dst, count); +} +void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) +{ + _insw_ns((u16 __force *) addr, dst, count); +} +void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) +{ + _insl_ns((u32 __force *) addr, dst, count); +} +EXPORT_SYMBOL(ioread8_rep); +EXPORT_SYMBOL(ioread16_rep); +EXPORT_SYMBOL(ioread32_rep); + +void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) +{ + _outsb((u8 __force *) addr, src, count); +} +void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) +{ + _outsw_ns((u16 __force *) addr, src, count); +} +void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) +{ + _outsl_ns((u32 __force *) addr, src, count); +} +EXPORT_SYMBOL(iowrite8_rep); +EXPORT_SYMBOL(iowrite16_rep); +EXPORT_SYMBOL(iowrite32_rep); + +void __iomem *ioport_map(unsigned long port, unsigned int len) +{ + if (!_IO_IS_VALID(port)) + return NULL; + return (void __iomem *) (port+pci_io_base); +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len) + return NULL; + if (max && len > max) + len = max; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + return (void __iomem *) start; + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c index 5cac0d240..d5d64d1d7 100644 --- a/arch/ppc64/kernel/iommu.c +++ b/arch/ppc64/kernel/iommu.c @@ -229,7 +229,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - dma_addr_t dma_next, dma_addr; + dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart; int outcount; diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 846168746..3ebe47340 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -362,14 +363,16 @@ skip: int handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) { int status = 0; - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -586,13 +589,13 @@ void do_IRQ(struct pt_regs *regs) irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 4KB free? */ + /* Debugging check for stack overflow: is there less than 2KB free? */ { long sp; sp = __get_SP() & (THREAD_SIZE-1); - if (unlikely(sp < (sizeof(struct thread_info) + 4096))) { + if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { printk("do_IRQ: stack overflow: %ld\n", sp - sizeof(struct thread_info)); dump_stack(); @@ -629,13 +632,13 @@ void do_IRQ(struct pt_regs *regs) irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 4KB free? */ + /* Debugging check for stack overflow: is there less than 2KB free? */ { long sp; sp = __get_SP() & (THREAD_SIZE-1); - if (unlikely(sp < (sizeof(struct thread_info) + 4096))) { + if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { printk("do_IRQ: stack overflow: %ld\n", sp - sizeof(struct thread_info)); dump_stack(); @@ -674,6 +677,8 @@ unsigned int probe_irq_mask(unsigned long irqs) return 0; } +EXPORT_SYMBOL(probe_irq_mask); + void __init init_IRQ(void) { static int once = 0; @@ -757,44 +762,6 @@ out: return ret; } -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - -#ifdef CONFIG_PPC_ISERIES - { - unsigned i; - for (i=0; inlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. @@ -977,7 +933,7 @@ void irq_ctx_init(void) struct thread_info *tp; int i; - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu(i) { memset((void *)softirq_ctx[i], 0, THREAD_SIZE); tp = softirq_ctx[i]; tp->cpu = i; diff --git a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c index c2e320635..56a26eec0 100644 --- a/arch/ppc64/kernel/lmb.c +++ b/arch/ppc64/kernel/lmb.c @@ -20,7 +20,44 @@ #include #include -struct lmb lmb __initdata; +struct lmb lmb; + +#undef DEBUG + +void lmb_dump_all(void) +{ +#ifdef DEBUG + unsigned long i; + struct lmb *_lmb = &lmb; + + udbg_printf("lmb_dump_all:\n"); + udbg_printf(" memory.cnt = 0x%lx\n", + _lmb->memory.cnt); + udbg_printf(" memory.size = 0x%lx\n", + _lmb->memory.size); + for (i=0; i < _lmb->memory.cnt ;i++) { + udbg_printf(" memory.region[0x%x].base = 0x%lx\n", + i, _lmb->memory.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + _lmb->memory.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + _lmb->memory.region[i].size); + } + + udbg_printf("\n reserved.cnt = 0x%lx\n", + _lmb->reserved.cnt); + udbg_printf(" reserved.size = 0x%lx\n", + _lmb->reserved.size); + for (i=0; i < _lmb->reserved.cnt ;i++) { + udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", + i, _lmb->reserved.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + _lmb->reserved.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + _lmb->reserved.region[i].size); + } +#endif /* DEBUG */ +} static unsigned long __init lmb_addrs_overlap(unsigned long base1, unsigned long size1, @@ -71,8 +108,7 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2) void __init lmb_init(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; /* Create a dummy zero size LMB which will get coalesced away later. * This simplifies the lmb_add() code below... @@ -94,8 +130,7 @@ lmb_analyze(void) unsigned long i; unsigned long mem_size = 0; unsigned long size_mask = 0; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; #ifdef CONFIG_MSCHUNKS unsigned long physbase = 0; #endif @@ -178,8 +213,7 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size) long __init lmb_add(unsigned long base, unsigned long size) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_rgn = &(_lmb->memory); /* On pSeries LPAR systems, the first LMB is our RMO region. */ @@ -193,8 +227,7 @@ lmb_add(unsigned long base, unsigned long size) long __init lmb_reserve(unsigned long base, unsigned long size) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_rgn = &(_lmb->reserved); return lmb_add_region(_rgn, base, size); @@ -227,8 +260,7 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) { long i, j; unsigned long base = 0; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); struct lmb_region *_rsv = &(_lmb->reserved); @@ -263,8 +295,7 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) unsigned long __init lmb_phys_mem_size(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; #ifdef CONFIG_MSCHUNKS return _lmb->memory.size; #else @@ -282,8 +313,7 @@ lmb_phys_mem_size(void) unsigned long __init lmb_end_of_DRAM(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); int idx = _mem->cnt - 1; @@ -300,8 +330,7 @@ unsigned long __init lmb_abs_to_phys(unsigned long aa) { unsigned long i, pa = aa; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); for (i=0; i < _mem->cnt; i++) { diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index d729105e5..f7ac3f742 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c @@ -34,31 +34,37 @@ #include #include -#define MODULE_VERS "1.3" +#define MODULE_VERS "1.4" #define MODULE_NAME "lparcfg" /* #define LPARCFG_DEBUG */ /* find a better place for this function... */ -void log_plpar_hcall_return(unsigned long rc,char * tag) +void log_plpar_hcall_return(unsigned long rc, char *tag) { - if (rc ==0 ) /* success, return */ + if (rc == 0) /* success, return */ return; /* check for null tag ? */ if (rc == H_Hardware) - printk(KERN_INFO "plpar-hcall (%s) failed with hardware fault\n",tag); + printk(KERN_INFO + "plpar-hcall (%s) failed with hardware fault\n", tag); else if (rc == H_Function) - printk(KERN_INFO "plpar-hcall (%s) failed; function not allowed\n",tag); + printk(KERN_INFO + "plpar-hcall (%s) failed; function not allowed\n", tag); else if (rc == H_Authority) - printk(KERN_INFO "plpar-hcall (%s) failed; not authorized to this function\n",tag); + printk(KERN_INFO + "plpar-hcall (%s) failed; not authorized to this function\n", + tag); else if (rc == H_Parameter) - printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",tag); + printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", + tag); else - printk(KERN_INFO "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",tag,rc); + printk(KERN_INFO + "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n", + tag, rc); } - static struct proc_dir_entry *proc_ppc64_lparcfg; #define LPARCFG_BUFF_SIZE 4096 @@ -78,59 +84,60 @@ static int lparcfg_data(struct seq_file *m, void *v) shared = (int)(lpaca->lppaca_ptr->xSharedProc); seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n", - e2a(xItExtVpdPanel.mfgID[2]), - e2a(xItExtVpdPanel.mfgID[3]), - e2a(xItExtVpdPanel.systemSerial[1]), - e2a(xItExtVpdPanel.systemSerial[2]), - e2a(xItExtVpdPanel.systemSerial[3]), - e2a(xItExtVpdPanel.systemSerial[4]), - e2a(xItExtVpdPanel.systemSerial[5])); + e2a(xItExtVpdPanel.mfgID[2]), + e2a(xItExtVpdPanel.mfgID[3]), + e2a(xItExtVpdPanel.systemSerial[1]), + e2a(xItExtVpdPanel.systemSerial[2]), + e2a(xItExtVpdPanel.systemSerial[3]), + e2a(xItExtVpdPanel.systemSerial[4]), + e2a(xItExtVpdPanel.systemSerial[5])); seq_printf(m, "system_type=%c%c%c%c\n", - e2a(xItExtVpdPanel.machineType[0]), - e2a(xItExtVpdPanel.machineType[1]), - e2a(xItExtVpdPanel.machineType[2]), - e2a(xItExtVpdPanel.machineType[3])); + e2a(xItExtVpdPanel.machineType[0]), + e2a(xItExtVpdPanel.machineType[1]), + e2a(xItExtVpdPanel.machineType[2]), + e2a(xItExtVpdPanel.machineType[3])); - lp_index = HvLpConfig_getLpIndex(); + lp_index = HvLpConfig_getLpIndex(); seq_printf(m, "partition_id=%d\n", (int)lp_index); seq_printf(m, "system_active_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); + (int)HvLpConfig_getSystemPhysicalProcessors()); seq_printf(m, "system_potential_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); + (int)HvLpConfig_getSystemPhysicalProcessors()); - processors = (int)HvLpConfig_getPhysicalProcessors(); + processors = (int)HvLpConfig_getPhysicalProcessors(); seq_printf(m, "partition_active_processors=%d\n", processors); - max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); + max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); seq_printf(m, "partition_potential_processors=%d\n", max_processors); - if(shared) { - entitled_capacity = HvLpConfig_getSharedProcUnits(); - max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); + if (shared) { + entitled_capacity = HvLpConfig_getSharedProcUnits(); + max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); } else { - entitled_capacity = processors * 100; - max_entitled_capacity = max_processors * 100; + entitled_capacity = processors * 100; + max_entitled_capacity = max_processors * 100; } seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); seq_printf(m, "partition_max_entitled_capacity=%d\n", - max_entitled_capacity); + max_entitled_capacity); - if(shared) { - pool_id = HvLpConfig_getSharedPoolIndex(); + if (shared) { + pool_id = HvLpConfig_getSharedPoolIndex(); seq_printf(m, "pool=%d\n", (int)pool_id); seq_printf(m, "pool_capacity=%d\n", - (int)(HvLpConfig_getNumProcsInSharedPool(pool_id)*100)); + (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * + 100)); } seq_printf(m, "shared_processor_mode=%d\n", shared); return 0; } -#endif /* CONFIG_PPC_ISERIES */ +#endif /* CONFIG_PPC_ISERIES */ #ifdef CONFIG_PPC_PSERIES /* @@ -158,11 +165,13 @@ static int lparcfg_data(struct seq_file *m, void *v) * XXXX - Processors active on platform. */ static unsigned int h_get_ppp(unsigned long *entitled, - unsigned long *unallocated, unsigned long *aggregation, - unsigned long *resource) + unsigned long *unallocated, + unsigned long *aggregation, + unsigned long *resource) { unsigned long rc; - rc = plpar_hcall_4out(H_GET_PPP,0,0,0,0,entitled,unallocated,aggregation,resource); + rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated, + aggregation, resource); log_plpar_hcall_return(rc, "H_GET_PPP"); @@ -185,7 +194,7 @@ static unsigned long get_purr(void); */ static unsigned long get_purr() { - unsigned long sum_purr=0; + unsigned long sum_purr = 0; return sum_purr; } @@ -202,7 +211,7 @@ static void parse_system_parameter_string(struct seq_file *m) { int call_status; - char * local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); + char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!local_buffer) { printk(KERN_ERR "%s %s kmalloc failure at line %d \n", __FILE__, __FUNCTION__, __LINE__); @@ -219,22 +228,23 @@ static void parse_system_parameter_string(struct seq_file *m) spin_unlock(&rtas_data_buf_lock); if (call_status != 0) { - printk(KERN_INFO "%s %s Error calling get-system-parameter (0x%x)\n", + printk(KERN_INFO + "%s %s Error calling get-system-parameter (0x%x)\n", __FILE__, __FUNCTION__, call_status); } else { int splpar_strlen; int idx, w_idx; - char * workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); + char *workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!workbuffer) { - printk(KERN_ERR "%s %s kmalloc failure at line %d \n",__FILE__,__FUNCTION__,__LINE__); + printk(KERN_ERR "%s %s kmalloc failure at line %d \n", + __FILE__, __FUNCTION__, __LINE__); return; } - #ifdef LPARCFG_DEBUG printk(KERN_INFO "success calling get-system-parameter \n"); #endif splpar_strlen = local_buffer[0] * 16 + local_buffer[1]; - local_buffer += 2; /* step over strlen value */ + local_buffer += 2; /* step over strlen value */ memset(workbuffer, 0, SPLPAR_MAXLENGTH); w_idx = 0; @@ -253,13 +263,15 @@ static void parse_system_parameter_string(struct seq_file *m) w_idx = 0; } else if (local_buffer[idx] == '=') { /* code here to replace workbuffer contents - with different keyword strings */ - if (0 == strcmp(workbuffer,"MaxEntCap")) { - strcpy(workbuffer, "partition_max_entitled_capacity"); + with different keyword strings */ + if (0 == strcmp(workbuffer, "MaxEntCap")) { + strcpy(workbuffer, + "partition_max_entitled_capacity"); w_idx = strlen(workbuffer); } - if (0 == strcmp(workbuffer,"MaxPlatProcs")) { - strcpy(workbuffer, "system_potential_processors"); + if (0 == strcmp(workbuffer, "MaxPlatProcs")) { + strcpy(workbuffer, + "system_potential_processors"); w_idx = strlen(workbuffer); } } @@ -283,7 +295,7 @@ static int lparcfg_count_active_processors(void) while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) { #ifdef LPARCFG_DEBUG - printk(KERN_ERR "cpus_dn %p \n",cpus_dn); + printk(KERN_ERR "cpus_dn %p \n", cpus_dn); #endif count++; } @@ -292,7 +304,8 @@ static int lparcfg_count_active_processors(void) static int lparcfg_data(struct seq_file *m, void *v) { - int system_active_processors; + int partition_potential_processors; + int partition_active_processors; struct device_node *rootdn; const char *model = ""; const char *system_id = ""; @@ -305,12 +318,11 @@ static int lparcfg_data(struct seq_file *m, void *v) model = get_property(rootdn, "model", NULL); system_id = get_property(rootdn, "system-id", NULL); lp_index_ptr = (unsigned int *) - get_property(rootdn, "ibm,partition-no", NULL); + get_property(rootdn, "ibm,partition-no", NULL); if (lp_index_ptr) lp_index = *lp_index_ptr; } - seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); seq_printf(m, "serial_number=%s\n", system_id); @@ -323,11 +335,13 @@ static int lparcfg_data(struct seq_file *m, void *v) lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL); if (lrdrp == NULL) { - system_active_processors = systemcfg->processorCount; + partition_potential_processors = systemcfg->processorCount; } else { - system_active_processors = *(lrdrp + 4); + partition_potential_processors = *(lrdrp + 4); } + partition_active_processors = lparcfg_count_active_processors(); + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { unsigned long h_entitled, h_unallocated; unsigned long h_aggregation, h_resource; @@ -342,71 +356,69 @@ static int lparcfg_data(struct seq_file *m, void *v) seq_printf(m, "R6=0x%lx\n", h_aggregation); seq_printf(m, "R7=0x%lx\n", h_resource); - h_pic(&pool_idle_time, &pool_procs); - purr = get_purr(); /* this call handles the ibm,get-system-parameter contents */ parse_system_parameter_string(m); - seq_printf(m, "partition_entitled_capacity=%ld\n", - h_entitled); - - seq_printf(m, "pool=%ld\n", - (h_aggregation >> 0*8) & 0xffff); + seq_printf(m, "partition_entitled_capacity=%ld\n", h_entitled); - seq_printf(m, "group=%ld\n", - (h_aggregation >> 2*8) & 0xffff); + seq_printf(m, "group=%ld\n", (h_aggregation >> 2 * 8) & 0xffff); seq_printf(m, "system_active_processors=%ld\n", - (h_resource >> 0*8) & 0xffff); + (h_resource >> 0 * 8) & 0xffff); + + /* pool related entries are apropriate for shared configs */ + if (paca[0].lppaca.xSharedProc) { - seq_printf(m, "pool_capacity=%ld\n", - (h_resource >> 2*8) & 0xffff); + h_pic(&pool_idle_time, &pool_procs); + + seq_printf(m, "pool=%ld\n", + (h_aggregation >> 0 * 8) & 0xffff); + + /* report pool_capacity in percentage */ + seq_printf(m, "pool_capacity=%ld\n", + ((h_resource >> 2 * 8) & 0xffff) * 100); + + seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time); + + seq_printf(m, "pool_num_procs=%ld\n", pool_procs); + } seq_printf(m, "unallocated_capacity_weight=%ld\n", - (h_resource >> 4*8) & 0xFF); + (h_resource >> 4 * 8) & 0xFF); seq_printf(m, "capacity_weight=%ld\n", - (h_resource >> 5*8) & 0xFF); - - seq_printf(m, "capped=%ld\n", - (h_resource >> 6*8) & 0x01); + (h_resource >> 5 * 8) & 0xFF); - seq_printf(m, "unallocated_capacity=%ld\n", - h_unallocated); + seq_printf(m, "capped=%ld\n", (h_resource >> 6 * 8) & 0x01); - seq_printf(m, "pool_idle_time=%ld\n", - pool_idle_time); + seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); - seq_printf(m, "pool_num_procs=%ld\n", - pool_procs); + seq_printf(m, "purr=%ld\n", purr); - seq_printf(m, "purr=%ld\n", - purr); + } else { /* non SPLPAR case */ - } else /* non SPLPAR case */ { seq_printf(m, "system_active_processors=%d\n", - system_active_processors); + partition_potential_processors); seq_printf(m, "system_potential_processors=%d\n", - system_active_processors); + partition_potential_processors); seq_printf(m, "partition_max_entitled_capacity=%d\n", - 100*system_active_processors); + partition_potential_processors * 100); seq_printf(m, "partition_entitled_capacity=%d\n", - system_active_processors*100); + partition_active_processors * 100); } seq_printf(m, "partition_active_processors=%d\n", - (int) lparcfg_count_active_processors()); + partition_active_processors); seq_printf(m, "partition_potential_processors=%d\n", - system_active_processors); + partition_potential_processors); - seq_printf(m, "shared_processor_mode=%d\n", - paca[0].lppaca.xSharedProc); + seq_printf(m, "shared_processor_mode=%d\n", paca[0].lppaca.xSharedProc); return 0; } @@ -421,14 +433,15 @@ static int lparcfg_data(struct seq_file *m, void *v) * This function should be invoked only on systems with * FW_FEATURE_SPLPAR. */ -static ssize_t lparcfg_write(struct file *file, const char __user *buf, size_t count, loff_t *off) +static ssize_t lparcfg_write(struct file *file, const char __user * buf, + size_t count, loff_t * off) { char *kbuf; char *tmp; u64 new_entitled, *new_entitled_ptr = &new_entitled; u8 new_weight, *new_weight_ptr = &new_weight; - unsigned long current_entitled; /* parameters for h_get_ppp */ + unsigned long current_entitled; /* parameters for h_get_ppp */ unsigned long dummy; unsigned long resource; u8 current_weight; @@ -453,13 +466,13 @@ static ssize_t lparcfg_write(struct file *file, const char __user *buf, size_t c if (!strcmp(kbuf, "partition_entitled_capacity")) { char *endp; - *new_entitled_ptr = (u64)simple_strtoul(tmp, &endp, 10); + *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10); if (endp == tmp) goto out; new_weight_ptr = ¤t_weight; } else if (!strcmp(kbuf, "capacity_weight")) { char *endp; - *new_weight_ptr = (u8)simple_strtoul(tmp, &endp, 10); + *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10); if (endp == tmp) goto out; new_entitled_ptr = ¤t_entitled; @@ -473,7 +486,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user *buf, size_t c goto out; } - current_weight = (resource>>5*8)&0xFF; + current_weight = (resource >> 5 * 8) & 0xFF; pr_debug("%s: current_entitled = %lu, current_weight = %lu\n", __FUNCTION__, current_entitled, current_weight); @@ -498,23 +511,23 @@ static ssize_t lparcfg_write(struct file *file, const char __user *buf, size_t c retval = -EIO; } -out: + out: kfree(kbuf); return retval; } -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_PSERIES */ -static int lparcfg_open(struct inode * inode, struct file * file) +static int lparcfg_open(struct inode *inode, struct file *file) { - return single_open(file,lparcfg_data,NULL); + return single_open(file, lparcfg_data, NULL); } struct file_operations lparcfg_fops = { - owner: THIS_MODULE, - read: seq_read, - open: lparcfg_open, - release: single_release, + owner:THIS_MODULE, + read:seq_read, + open:lparcfg_open, + release:single_release, }; int __init lparcfg_init(void) @@ -533,7 +546,8 @@ int __init lparcfg_init(void) ent->proc_fops = &lparcfg_fops; ent->data = kmalloc(LPARCFG_BUFF_SIZE, GFP_KERNEL); if (!ent->data) { - printk(KERN_ERR "Failed to allocate buffer for lparcfg\n"); + printk(KERN_ERR + "Failed to allocate buffer for lparcfg\n"); remove_proc_entry("lparcfg", ent->parent); return -ENOMEM; } @@ -550,7 +564,7 @@ void __exit lparcfg_cleanup(void) { if (proc_ppc64_lparcfg) { if (proc_ppc64_lparcfg->data) { - kfree(proc_ppc64_lparcfg->data); + kfree(proc_ppc64_lparcfg->data); } remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); } diff --git a/arch/ppc64/kernel/mf_proc.c b/arch/ppc64/kernel/mf_proc.c index 3ac36a5b9..f98f35569 100644 --- a/arch/ppc64/kernel/mf_proc.c +++ b/arch/ppc64/kernel/mf_proc.c @@ -167,22 +167,29 @@ static int proc_mf_change_cmdline(struct file *file, const char *buffer, return count; } -static int proc_mf_change_vmlinux(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t proc_mf_change_vmlinux(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) { + struct inode * inode = file->f_dentry->d_inode; + struct proc_dir_entry * dp = PDE(inode); int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - rc = mf_setVmlinuxChunk(buffer, count, file->f_pos, (u64)data); + rc = mf_setVmlinuxChunk(buf, count, *ppos, (u64)dp->data); if (rc < 0) return rc; - file->f_pos += count; + *ppos += count; return count; } +static struct file_operations proc_vmlinux_operations = { + .write = proc_mf_change_vmlinux, +}; + static int __init mf_proc_init(void) { struct proc_dir_entry *mf_proc_root; @@ -218,20 +225,7 @@ static int __init mf_proc_init(void) return 1; ent->nlink = 1; ent->data = (void *)(long)i; -#if 0 - if (i == 3) { - /* - * if we had a 'D' vmlinux entry, it would only - * be readable. - */ - ent->read_proc = proc_mf_dump_vmlinux; - ent->write_proc = NULL; - } else -#endif - { - ent->write_proc = proc_mf_change_vmlinux; - ent->read_proc = NULL; - } + ent->proc_fops = &proc_vmlinux_operations; } ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index d0d509e4a..30314c596 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -127,6 +127,47 @@ _GLOBAL(call_handle_irq_event) blr #endif /* CONFIG_IRQSTACKS */ + /* + * To be called by C code which needs to do some operations with MMU + * disabled. Note that interrupts have to be disabled by the caller + * prior to calling us. The code called _MUST_ be in the RMO of course + * and part of the linear mapping as we don't attempt to translate the + * stack pointer at all. The function is called with the stack switched + * to this CPU emergency stack + * + * prototype is void *call_with_mmu_off(void *func, void *data); + * + * the called function is expected to be of the form + * + * void *called(void *data); + */ +_GLOBAL(call_with_mmu_off) + mflr r0 /* get link, save it on stackframe */ + std r0,16(r1) + mr r1,r5 /* save old stack ptr */ + ld r1,PACAEMERGSP(r13) /* get emerg. stack */ + subi r1,r1,STACK_FRAME_OVERHEAD + std r0,16(r1) /* save link on emerg. stack */ + std r5,0(r1) /* save old stack ptr in backchain */ + ld r3,0(r3) /* get to real function ptr (assume same TOC) */ + bl 2f /* we need LR to return, continue at label 2 */ + + ld r0,16(r1) /* we return here from the call, get LR and */ + ld r1,0(r1) /* .. old stack ptr */ + mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ + mfmsr r4 + ori r4,r4,MSR_IR|MSR_DR + mtspr SPRN_SRR1,r4 + rfid + +2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ + mr r3,r4 /* get parameter */ + mfmsr r0 + ori r0,r0,MSR_IR|MSR_DR + xori r0,r0,MSR_IR|MSR_DR + mtspr SPRN_SRR1,r0 + rfid + /* * Flush instruction cache. */ @@ -454,23 +495,6 @@ _GLOBAL(_outsl_ns) sync blr -_GLOBAL(abs) - cmpi 0,r3,0 - bge 10f - neg r3,r3 -10: blr - -_GLOBAL(_get_PVR) - mfspr r3,PVR - blr - -_GLOBAL(_get_PIR) - mfspr r3,PIR - blr - -_GLOBAL(_get_HID0) - mfspr r3,HID0 - blr _GLOBAL(cvt_fd) lfd 0,0(r5) /* load up fpscr value */ @@ -567,6 +591,69 @@ _GLOBAL(do_cpu_ftr_fixups) isync b 1b +#ifdef CONFIG_PPC_PMAC +/* + * Do an IO access in real mode + */ +_GLOBAL(real_readb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + mfspr r6,SPRN_HID4 + rldicl r5,r6,32,0 + ori r5,r5,0x100 + rldicl r5,r5,32,0 + sync + mtspr SPRN_HID4,r5 + isync + slbia + isync + lbz r3,0(r3) + sync + mtspr SPRN_HID4,r6 + isync + slbia + isync + mtmsrd r7 + sync + isync + blr + + /* + * Do an IO access in real mode + */ +_GLOBAL(real_writeb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + mfspr r6,SPRN_HID4 + rldicl r5,r6,32,0 + ori r5,r5,0x100 + rldicl r5,r5,32,0 + sync + mtspr SPRN_HID4,r5 + isync + slbia + isync + stb r3,0(r4) + sync + mtspr SPRN_HID4,r6 + isync + slbia + isync + mtmsrd r7 + sync + isync + blr +#endif /* CONFIG_PPC_PMAC */ /* * Create a kernel thread @@ -583,7 +670,7 @@ _GLOBAL(kernel_thread) li r4,0 /* new sp (unused) */ li r0,__NR_clone sc - cmpi 0,r3,0 /* parent or child? */ + cmpdi 0,r3,0 /* parent or child? */ bne 1f /* return if parent */ li r0,0 stdu r0,-STACK_FRAME_OVERHEAD(r1) @@ -600,7 +687,7 @@ _GLOBAL(kernel_thread) ld r30,-16(r1) blr -#ifdef CONFIG_PPC_ISERIES /* hack hack hack */ +#ifndef CONFIG_PPC_PSERIES /* hack hack hack */ #define ppc_rtas sys_ni_syscall #endif @@ -866,9 +953,9 @@ _GLOBAL(sys_call_table32) .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ .llong .sys_ni_syscall /* 257 reserved for vserver */ .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .sys_ni_syscall /* 259 reserved for new sys_mbind */ - .llong .sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ - .llong .sys_ni_syscall /* 261 reserved for new sys_set_mempolicy */ + .llong .compat_mbind + .llong .compat_get_mempolicy /* 260 */ + .llong .compat_set_mempolicy .llong .compat_sys_mq_open .llong .sys_mq_unlink .llong .compat_sys_mq_timedsend @@ -1138,9 +1225,9 @@ _GLOBAL(sys_call_table) .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ .llong .sys_ni_syscall /* 257 reserved for vserver */ .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .sys_ni_syscall /* 259 reserved for new sys_mbind */ - .llong .sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ - .llong .sys_ni_syscall /* 261 reserved for new sys_set_mempolicy */ + .llong .sys_mbind + .llong .sys_get_mempolicy /* 260 */ + .llong .sys_set_mempolicy .llong .sys_mq_open .llong .sys_mq_unlink .llong .sys_mq_timedsend diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c index 89d6a0ad7..49ddf5e09 100644 --- a/arch/ppc64/kernel/nvram.c +++ b/arch/ppc64/kernel/nvram.c @@ -340,7 +340,7 @@ static int nvram_create_os_partition(void) struct list_head * p; struct nvram_partition * part; struct nvram_partition * new_part = NULL; - struct nvram_partition * free_part; + struct nvram_partition * free_part = NULL; int seq_init[2] = { 0, 0 }; loff_t tmp_index; long size = 0; @@ -603,6 +603,7 @@ void __exit nvram_cleanup(void) } +#ifdef CONFIG_PPC_PSERIES /* nvram_write_error_log * @@ -727,6 +728,7 @@ int nvram_clear_error_log() return 0; } +#endif /* CONFIG_PPC_PSERIES */ module_init(nvram_init); module_exit(nvram_cleanup); diff --git a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c index f0afedd20..656a493bf 100644 --- a/arch/ppc64/kernel/open_pic.c +++ b/arch/ppc64/kernel/open_pic.c @@ -362,7 +362,6 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, find_ISUs(); /* Initialize timer interrupts */ - ppc64_boot_msg(0x21, "OpenPic Timer"); for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { /* Disabled, Priority 0 */ openpic_inittimer(i, 0, openpic_vec_timer+i); @@ -372,7 +371,6 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, #ifdef CONFIG_SMP /* Initialize IPI interrupts */ - ppc64_boot_msg(0x22, "OpenPic IPI"); openpic_test_broken_IPI(); for (i = 0; i < OPENPIC_NUM_IPI; i++) { /* Disabled, Priority 10..13 */ @@ -384,8 +382,6 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, #endif /* Initialize external interrupts */ - ppc64_boot_msg(0x23, "OpenPic Ext"); - openpic_set_priority(0xf); /* SIOint (8259 cascade) is special */ @@ -420,7 +416,6 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, irq_desc[i].handler = &open_pic; /* Initialize the spurious interrupt */ - ppc64_boot_msg(0x24, "OpenPic Spurious"); openpic_set_spurious(openpic_vec_spurious); openpic_set_priority(0); diff --git a/arch/ppc64/kernel/open_pic_u3.c b/arch/ppc64/kernel/open_pic_u3.c index 4f9832a3b..42376756c 100644 --- a/arch/ppc64/kernel/open_pic_u3.c +++ b/arch/ppc64/kernel/open_pic_u3.c @@ -344,5 +344,5 @@ void __init openpic2_init(int offset) openpic2_set_priority(0); openpic2_disable_8259_pass_through(); - ppc64_boot_msg(0x25, "OpenPic2 Done"); + ppc64_boot_msg(0x25, "OpenPic U3 Done"); } diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index 91749173f..abbbe2823 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "pci.h" @@ -88,9 +89,153 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) } +static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, + long npages, unsigned long uaddr, + enum dma_data_direction direction) +{ + u64 rc; + union tce_entry tce; + + tce.te_word = 0; + tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + tce.te_rdwr = 1; + if (direction != DMA_TO_DEVICE) + tce.te_pciwr = 1; + + while (npages--) { + rc = plpar_tce_put((u64)tbl->it_index, + (u64)tcenum << 12, + tce.te_word ); + + if (rc && printk_ratelimit()) { + printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\ttcenum = 0x%lx\n", (u64)tcenum); + printk("\ttce val = 0x%lx\n", tce.te_word ); + show_stack(current, (unsigned long *)__get_SP()); + } + + tcenum++; + tce.te_rpn++; + } +} + +DEFINE_PER_CPU(void *, tce_page) = NULL; + +static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, + long npages, unsigned long uaddr, + enum dma_data_direction direction) +{ + u64 rc; + union tce_entry tce, *tcep; + long l, limit; + + if (npages == 1) + return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, + direction); + + tcep = __get_cpu_var(tce_page); + + /* This is safe to do since interrupts are off when we're called + * from iommu_alloc{,_sg}() + */ + if (!tcep) { + tcep = (void *)__get_free_page(GFP_ATOMIC); + /* If allocation fails, fall back to the loop implementation */ + if (!tcep) + return tce_build_pSeriesLP(tbl, tcenum, npages, + uaddr, direction); + __get_cpu_var(tce_page) = tcep; + } + + tce.te_word = 0; + tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + tce.te_rdwr = 1; + if (direction != DMA_TO_DEVICE) + tce.te_pciwr = 1; + + /* We can map max one pageful of TCEs at a time */ + do { + /* + * Set up the page with TCE data, looping through and setting + * the values. + */ + limit = min_t(long, npages, PAGE_SIZE/sizeof(union tce_entry)); + + for (l = 0; l < limit; l++) { + tcep[l] = tce; + tce.te_rpn++; + } + + rc = plpar_tce_put_indirect((u64)tbl->it_index, + (u64)tcenum << 12, + (u64)virt_to_abs(tcep), + limit); + + npages -= limit; + tcenum += limit; + } while (npages > 0 && !rc); + + if (rc && printk_ratelimit()) { + printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\tnpages = 0x%lx\n", (u64)npages); + printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word); + show_stack(current, (unsigned long *)__get_SP()); + } +} + +static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) +{ + u64 rc; + union tce_entry tce; + + tce.te_word = 0; + + while (npages--) { + rc = plpar_tce_put((u64)tbl->it_index, + (u64)tcenum << 12, + tce.te_word); + + if (rc && printk_ratelimit()) { + printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\ttcenum = 0x%lx\n", (u64)tcenum); + printk("\ttce val = 0x%lx\n", tce.te_word ); + show_stack(current, (unsigned long *)__get_SP()); + } + + tcenum++; + } +} + + +static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) +{ + u64 rc; + union tce_entry tce; + + tce.te_word = 0; + + rc = plpar_tce_stuff((u64)tbl->it_index, + (u64)tcenum << 12, + tce.te_word, + npages); + + if (rc && printk_ratelimit()) { + printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); + printk("\trc = %ld\n", rc); + printk("\tindex = 0x%lx\n", (u64)tbl->it_index); + printk("\tnpages = 0x%lx\n", (u64)npages); + printk("\ttce val = 0x%lx\n", tce.te_word ); + show_stack(current, (unsigned long *)__get_SP()); + } +} + + static void iommu_buses_init(void) { - struct pci_controller* phb; + struct pci_controller *phb, *tmp; struct device_node *dn, *first_dn; int num_slots, num_slots_ilog2; int first_phb = 1; @@ -106,10 +251,10 @@ static void iommu_buses_init(void) else tcetable_ilog2 = 22; - /* XXX Should we be using pci_root_buses instead? -ojn + /* XXX Should we be using pci_root_buses instead? -ojn */ - for (phb=hose_head; phb; phb=phb->next) { + list_for_each_entry_safe(phb, tmp, &hose_list, list_node) { first_dn = ((struct device_node *)phb->arch_data)->child; /* Carve 2GB into the largest dma_window_size possible */ @@ -166,24 +311,25 @@ static void iommu_table_setparms(struct pci_controller *phb, struct device_node *dn, struct iommu_table *tbl) { - phandle node; - unsigned long i; - struct of_tce_table *oft; - - node = ((struct device_node *)(phb->arch_data))->node; + struct device_node *node; + unsigned long *basep; + unsigned int *sizep; - oft = NULL; + node = (struct device_node *)phb->arch_data; - for (i=0; of_tce_table[i].node; i++) - if(of_tce_table[i].node == node) { - oft = &of_tce_table[i]; - break; - } - - if (!oft) - panic("PCI_DMA: iommu_table_setparms: Can't find phb named '%s' in of_tce_table\n", dn->full_name); - - memset((void *)oft->base, 0, oft->size); + if (get_property(node, "linux,has-tce-table", NULL) == NULL) { + printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has no tce table !\n", + dn->full_name); + return; + } + basep = (unsigned long *)get_property(node, "linux,tce-base", NULL); + sizep = (unsigned int *)get_property(node, "linux,tce-size", NULL); + if (basep == NULL || sizep == NULL) { + printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has missing tce" + " entries !\n", dn->full_name); + return; + } + memset((void *)(*basep), 0, *sizep); tbl->it_busno = phb->bus->number; @@ -207,10 +353,11 @@ static void iommu_table_setparms(struct pci_controller *phb, if (phb->dma_window_base_cur > (1 << 19)) panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); - tbl->it_base = oft->base; + tbl->it_base = *basep; tbl->it_index = 0; tbl->it_entrysize = sizeof(union tce_entry); tbl->it_blocksize = 16; + tbl->it_type = TCE_PCI; } /* @@ -246,6 +393,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, tbl->it_index = dma_window[0]; tbl->it_entrysize = sizeof(union tce_entry); tbl->it_blocksize = 16; + tbl->it_type = TCE_PCI; } @@ -293,8 +441,16 @@ void iommu_setup_pSeries(void) /* These are called very early. */ void tce_init_pSeries(void) { - ppc_md.tce_build = tce_build_pSeries; - ppc_md.tce_free = tce_free_pSeries; + if (!(systemcfg->platform & PLATFORM_LPAR)) { + ppc_md.tce_build = tce_build_pSeries; + ppc_md.tce_free = tce_free_pSeries; + } else if (cur_cpu_spec->firmware_features & FW_FEATURE_MULTITCE) { + ppc_md.tce_build = tce_buildmulti_pSeriesLP; + ppc_md.tce_free = tce_freemulti_pSeriesLP; + } else { + ppc_md.tce_build = tce_build_pSeriesLP; + ppc_md.tce_free = tce_free_pSeriesLP; + } pci_iommu_init(); } diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index a44c33268..68eeb7a81 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define DEBUG + #include #include #include @@ -34,10 +36,16 @@ #include #include #include -#include #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif /* in pSeries_hvCall.S */ EXPORT_SYMBOL(plpar_hcall); @@ -45,146 +53,9 @@ EXPORT_SYMBOL(plpar_hcall_4out); EXPORT_SYMBOL(plpar_hcall_norets); EXPORT_SYMBOL(plpar_hcall_8arg_2ret); -long poll_pending(void) -{ - unsigned long dummy; - return plpar_hcall(H_POLL_PENDING, 0, 0, 0, 0, - &dummy, &dummy, &dummy); -} - -long prod_processor(void) -{ - plpar_hcall_norets(H_PROD); - return(0); -} - -long cede_processor(void) -{ - plpar_hcall_norets(H_CEDE); - return(0); -} - -long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa) -{ - plpar_hcall_norets(H_REGISTER_VPA, flags, proc, vpa); - return(0); -} - -long plpar_pte_remove(unsigned long flags, - unsigned long ptex, - unsigned long avpn, - unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) -{ - unsigned long dummy; - return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0, - old_pteh_ret, old_ptel_ret, &dummy); -} - -long plpar_pte_read(unsigned long flags, - unsigned long ptex, - unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) -{ - unsigned long dummy; - return plpar_hcall(H_READ, flags, ptex, 0, 0, - old_pteh_ret, old_ptel_ret, &dummy); -} - -long plpar_pte_protect(unsigned long flags, - unsigned long ptex, - unsigned long avpn) -{ - return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn); -} - -long plpar_tce_get(unsigned long liobn, - unsigned long ioba, - unsigned long *tce_ret) -{ - unsigned long dummy; - return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0, - tce_ret, &dummy, &dummy); -} - -long plpar_tce_put(unsigned long liobn, - unsigned long ioba, - unsigned long tceval) -{ - return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval); -} +extern void fw_feature_init(void); +extern void pSeries_find_serial_port(void); -long plpar_get_term_char(unsigned long termno, - unsigned long *len_ret, - char *buf_ret) -{ - unsigned long *lbuf = (unsigned long *)buf_ret; /* ToDo: alignment? */ - return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0, - len_ret, lbuf+0, lbuf+1); -} - -long plpar_put_term_char(unsigned long termno, - unsigned long len, - const char *buffer) -{ - unsigned long *lbuf = (unsigned long *)buffer; /* ToDo: alignment? */ - return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0], - lbuf[1]); -} - -static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; - tce.te_rdwr = 1; - if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - tce.te_rpn++; - } -} - -static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_free_pSeriesLP: plpar_tce_put failed\n"); - printk("\trc = %ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - } -} int vtermno; /* virtual terminal# for udbg */ @@ -249,8 +120,19 @@ static unsigned char udbg_getcLP(void) } } +/* call this from early_init() for a working debug console on + * vterm capable LPAR machines + */ +void udbg_init_debug_lpar(void) +{ + vtermno = 0; + ppc_md.udbg_putc = udbg_putcLP; + ppc_md.udbg_getc = udbg_getcLP; + ppc_md.udbg_getc_poll = udbg_getc_pollLP; +} + /* returns 0 if couldn't find or use /chosen/stdout as console */ -static int find_udbg_vterm(void) +int find_udbg_vterm(void) { struct device_node *stdout_node; u32 *termno; @@ -258,15 +140,14 @@ static int find_udbg_vterm(void) int found = 0; /* find the boot console from /chosen/stdout */ - if (!of_stdout_device) { - printk(KERN_WARNING "couldn't get path from /chosen/stdout!\n"); - return found; - } - stdout_node = of_find_node_by_path(of_stdout_device); - if (!stdout_node) { - printk(KERN_WARNING "couldn't find node from /chosen/stdout\n"); - return found; - } + if (!of_chosen) + return 0; + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) + return 0; + stdout_node = of_find_node_by_path(name); + if (!stdout_node) + return 0; /* now we have the stdout node; figure out what type of device it is. */ name = (char *)get_property(stdout_node, "name", NULL); @@ -288,15 +169,17 @@ static int find_udbg_vterm(void) } else { /* XXX implement udbg_putcLP_vtty for hvterm-protocol1 case */ printk(KERN_WARNING "%s doesn't speak hvterm1; " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } } else if (strncmp(name, "serial", 6)) { /* XXX fix ISA serial console */ printk(KERN_WARNING "serial stdout on LPAR ('%s')! " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } else { printk(KERN_WARNING "don't know how to print to stdout '%s'\n", - of_stdout_device); + stdout_node->full_name); } out: @@ -304,35 +187,6 @@ out: return found; } -void pSeries_lpar_mm_init(void); - -/* This is called early in setup.c. - * Use it to setup page table ppc_md stuff as well as udbg. - */ -void pSeriesLP_init_early(void) -{ - pSeries_lpar_mm_init(); - - tce_init_pSeries(); - - ppc_md.tce_build = tce_build_pSeriesLP; - ppc_md.tce_free = tce_free_pSeriesLP; - - pci_iommu_init(); - -#ifdef CONFIG_SMP - smp_init_pSeries(); -#endif - - /* The keyboard is not useful in the LPAR environment. - * Leave all the ppc_md keyboard interfaces NULL. - */ - - if (0 == find_udbg_vterm()) { - printk(KERN_WARNING - "can't use stdout; can't print early debug messages.\n"); - } -} long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long prpn, @@ -377,7 +231,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 +239,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 +269,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; @@ -426,6 +278,18 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group) return -1; } +static void pSeries_lpar_hptab_clear(void) +{ + unsigned long size_bytes = 1UL << naca->pftSize; + unsigned long hpte_count = size_bytes >> 4; + unsigned long dummy1, dummy2; + int i; + + /* TODO: Use bulk call */ + for (i = 0; i < hpte_count; i++) + plpar_pte_remove(0, i, 0, &dummy1, &dummy2); +} + /* * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up. So no transform is needed. @@ -447,8 +311,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; } @@ -464,11 +327,10 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) /* Do not need RPN to logical page translation */ /* No cross CEC PFT access */ flags = 0; - + 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 +381,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 +405,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); } /* @@ -560,18 +418,19 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, int i; unsigned long flags; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); for (i = 0; i < number; i++) flush_hash_page(context, batch->addr[i], batch->pte[i], local); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); } -void pSeries_lpar_mm_init(void) +void hpte_init_lpar(void) { ppc_md.hpte_invalidate = pSeries_lpar_hpte_invalidate; ppc_md.hpte_updatepp = pSeries_lpar_hpte_updatepp; @@ -579,4 +438,7 @@ void pSeries_lpar_mm_init(void) ppc_md.hpte_insert = pSeries_lpar_hpte_insert; ppc_md.hpte_remove = pSeries_lpar_hpte_remove; ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; + ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; + + htab_finish_init(); } diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c index 92bc868f3..a9afded6c 100644 --- a/arch/ppc64/kernel/pSeries_pci.c +++ b/arch/ppc64/kernel/pSeries_pci.c @@ -45,12 +45,6 @@ #include "open_pic.h" #include "pci.h" -/* legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch - devices we don't have access to. */ -unsigned long io_page_mask; - -EXPORT_SYMBOL(io_page_mask); - /* RTAS tokens */ static int read_pci_config; static int write_pci_config; @@ -68,7 +62,9 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va int ret; if (!dn) - return -2; + return PCIBIOS_DEVICE_NOT_FOUND; + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = (dn->busno << 16) | (dn->devfn << 8) | where; buid = dn->phb->buid; @@ -79,7 +75,15 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); } *val = returnval; - return ret; + + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (returnval == EEH_IO_ERROR_VALUE(size) + && eeh_dn_check_failure (dn, NULL)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; } static int rtas_pci_read_config(struct pci_bus *bus, @@ -106,7 +110,9 @@ static int rtas_write_config(struct device_node *dn, int where, int size, u32 va int ret; if (!dn) - return -2; + return PCIBIOS_DEVICE_NOT_FOUND; + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = (dn->busno << 16) | (dn->devfn << 8) | where; buid = dn->phb->buid; @@ -115,7 +121,11 @@ static int rtas_write_config(struct device_node *dn, int where, int size, u32 va } else { ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); } - return ret; + + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; } static int rtas_pci_write_config(struct pci_bus *bus, @@ -141,189 +151,6 @@ struct pci_ops rtas_pci_ops = { rtas_pci_write_config }; -/****************************************************************** - * pci_read_irq_line - * - * Reads the Interrupt Pin to determine if interrupt is use by card. - * If the interrupt is used, then gets the interrupt line from the - * openfirmware and sets it in the pci_dev and pci_config line. - * - ******************************************************************/ -int pci_read_irq_line(struct pci_dev *pci_dev) -{ - u8 intpin; - struct device_node *node; - - pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin); - - if (intpin == 0) { - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n", pci_name(pci_dev)); - return 0; - } - - node = pci_device_to_OF_node(pci_dev); - if (node == NULL) { - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n", - pci_name(pci_dev)); - return -1; - } - if (node->n_intrs == 0) { - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n", pci_name(pci_dev)); - return -1; - } - pci_dev->irq = node->intrs[0].line; - - if (s7a_workaround) { - if (pci_dev->irq > 16) - pci_dev->irq -= 3; - } - - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); - - PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n", - pci_name(pci_dev), pci_dev->irq); - return 0; -} -EXPORT_SYMBOL(pci_read_irq_line); - -#define ISA_SPACE_MASK 0x1 -#define ISA_SPACE_IO 0x1 - -static void pci_process_ISA_OF_ranges(struct device_node *isa_node, - unsigned long phb_io_base_phys, - void * phb_io_base_virt) -{ - struct isa_range *range; - unsigned long pci_addr; - unsigned int isa_addr; - unsigned int size; - int rlen = 0; - - range = (struct isa_range *) get_property(isa_node, "ranges", &rlen); - if (rlen < sizeof(struct isa_range)) { - printk(KERN_ERR "unexpected isa range size: %s\n", - __FUNCTION__); - return; - } - - /* From "ISA Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 1: an ISA address - * cells 2 - 4: a PCI address - * (size depending on dev->n_addr_cells) - * cell 5: the size of the range - */ - if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) { - isa_addr = range->isa_addr.a_lo; - pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | - range->pci_addr.a_lo; - - /* Assume these are both zero */ - if ((pci_addr != 0) || (isa_addr != 0)) { - printk(KERN_ERR "unexpected isa to pci mapping: %s\n", - __FUNCTION__); - return; - } - - size = PAGE_ALIGN(range->size); - - __ioremap_explicit(phb_io_base_phys, - (unsigned long) phb_io_base_virt, - size, _PAGE_NO_CACHE); - } -} - -static void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, - int primary) -{ - unsigned int *ranges; - unsigned long size; - int rlen = 0; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - unsigned long pci_addr, cpu_phys_addr; - struct device_node *isa_dn; - - np = na + 5; - - /* From "PCI Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (size depending on dev->n_addr_cells) - * cells 4+5 or 5+6: the size of the range - */ - rlen = 0; - hose->io_base_phys = 0; - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - while ((rlen -= np * sizeof(unsigned int)) >= 0) { - res = NULL; - pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; - - cpu_phys_addr = ranges[3]; - if (na == 2) - cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; - - size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; - - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - hose->io_base_phys = cpu_phys_addr; - hose->io_base_virt = reserve_phb_iospace(size); - PPCDBG(PPCDBG_PHBINIT, - "phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", - hose->global_number, hose->io_base_phys, - (unsigned long) hose->io_base_virt); - - if (primary) { - pci_io_base = (unsigned long)hose->io_base_virt; - isa_dn = of_find_node_by_type(NULL, "isa"); - if (isa_dn) { - isa_io_base = pci_io_base; - pci_process_ISA_OF_ranges(isa_dn, - hose->io_base_phys, - hose->io_base_virt); - of_node_put(isa_dn); - /* Allow all IO */ - io_page_mask = -1; - } - } - - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = pci_addr; - res->start += (unsigned long)hose->io_base_virt - - pci_io_base; - break; - case 2: /* memory space */ - memno = 0; - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - - if (memno == 0) - hose->pci_mem_offset = cpu_phys_addr - pci_addr; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = cpu_phys_addr; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} - static void python_countermeasures(unsigned long addr) { void *chip_regs; @@ -481,7 +308,7 @@ unsigned long __init find_and_init_phbs(void) struct pci_controller *phb; unsigned int root_size_cells = 0; unsigned int index; - unsigned int *opprop; + unsigned int *opprop = NULL; struct device_node *root = of_find_node_by_path("/"); if (naca->interrupt_controller == IC_OPEN_PIC) { @@ -519,9 +346,9 @@ unsigned long __init find_and_init_phbs(void) return 0; } +#if 0 void pcibios_name_device(struct pci_dev *dev) { -#if 0 struct device_node *dn; /* @@ -541,98 +368,9 @@ void pcibios_name_device(struct pci_dev *dev) } } } -#endif } - -void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) -{ - /* Update device resources. */ - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; - unsigned long start, end, mask; - - start = dev->resource[i].start += offset; - end = dev->resource[i].end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1))-1) ^ ((1 << start)-1); - io_page_mask |= mask; - } - } - else if (dev->resource[i].flags & IORESOURCE_MEM) { - dev->resource[i].start += hose->pci_mem_offset; - dev->resource[i].end += hose->pci_mem_offset; - } - } -} -EXPORT_SYMBOL(pcibios_fixup_device_resources); - -void __devinit pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); - struct list_head *ln; - - /* XXX or bus->parent? */ - struct pci_dev *dev = bus->self; - struct resource *res; - int i; - - if (!dev) { - /* Root bus. */ - - hose->bus = bus; - bus->resource[0] = res = &hose->io_resource; - if (!res->flags) - BUG(); /* No I/O resource for this PHB? */ - - if (request_resource(&ioport_resource, res)) - printk(KERN_ERR "Failed to request IO on " - "PCI domain %d\n", pci_domain_nr(bus)); - - - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - if (!res->flags && i == 0) - BUG(); /* No memory resource for this PHB? */ - bus->resource[i+1] = res; - if (res->flags && request_resource(&iomem_resource, res)) - printk(KERN_ERR "Failed to request MEM on " - "PCI domain %d\n", - pci_domain_nr(bus)); - } - } else if (pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - /* This is a subordinate bridge */ - - pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(dev, bus); - } - - /* XXX Need to check why Alpha doesnt do this - Anton */ - if (!pci_probe_only) - return; - - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *dev = pci_dev_b(ln); - if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) - pcibios_fixup_device_resources(dev, bus); - } -} -EXPORT_SYMBOL(pcibios_fixup_bus); +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); +#endif static void check_s7a(void) { @@ -728,13 +466,34 @@ EXPORT_SYMBOL(remap_bus_range); static void phbs_fixup_io(void) { - struct pci_controller *hose; + struct pci_controller *hose, *tmp; - for (hose=hose_head;hose;hose=hose->next) + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) remap_bus_range(hose->bus); } -extern void chrp_request_regions(void); +static void __init pSeries_request_regions(void) +{ + struct device_node *i8042; + + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + +#define I8042_DATA_REG 0x60 + + /* + * Some machines have an unterminated i8042 so check the device + * tree and reserve the region if it does not appear. Later on + * the i8042 code will try and reserve this region and fail. + */ + if (!(i8042 = of_find_node_by_type(NULL, "8042"))) + request_region(I8042_DATA_REG, 16, "reserved (no i8042)"); + of_node_put(i8042); +} void __init pSeries_final_fixup(void) { @@ -742,58 +501,23 @@ void __init pSeries_final_fixup(void) check_s7a(); - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_irq_line(dev); + if (s7a_workaround) { + if (dev->irq > 16) { + dev->irq -= 3; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + } + } phbs_fixup_io(); - chrp_request_regions(); + pSeries_request_regions(); pci_fix_bus_sysdata(); - if (!ppc64_iommu_off) + + if (!of_chosen || !get_property(of_chosen, "linux,iommu-off", NULL)) iommu_setup_pSeries(); -} -/*********************************************************************** - * pci_find_hose_for_OF_device - * - * This function finds the PHB that matching device_node in the - * OpenFirmware by scanning all the pci_controllers. - * - ***********************************************************************/ -struct pci_controller* -pci_find_hose_for_OF_device(struct device_node *node) -{ - while (node) { - struct pci_controller *hose; - for (hose=hose_head;hose;hose=hose->next) - if (hose->arch_data == node) - return hose; - node=node->parent; - } - return NULL; + pci_addr_cache_build(); } -/* - * ppc64 can have multifunction devices that do not respond to function 0. - * In this case we must scan all functions. - */ -int -pcibios_scan_all_fns(struct pci_bus *bus, int devfn) -{ - struct device_node *busdn, *dn; - - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = bus->sysdata; /* must be a phb */ - - /* - * Check to see if there is any of the 8 functions are in the - * device tree. If they are then we need to scan all the - * functions of this slot. - */ - for (dn = busdn->child; dn; dn = dn->sibling) - if ((dn->devfn >> 3) == (devfn >> 3)) - return 1; - - return 0; -} diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c new file mode 100644 index 000000000..80e028904 --- /dev/null +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -0,0 +1,579 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified by PPC64 Team, IBM Corp + * + * 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. + */ + +/* + * bootup setup stuff.. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i8259.h" +#include "open_pic.h" +#include +#include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +extern void pSeries_init_openpic(void); + +extern void find_and_init_phbs(void); +extern void pSeries_final_fixup(void); + +extern void pSeries_get_boot_time(struct rtc_time *rtc_time); +extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); +extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); +extern void find_udbg_vterm(void); +extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void); /* from head.S */ +int fwnmi_active; /* TRUE if an FWNMI handler is present */ + +unsigned long virtPython0Facilities = 0; // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address. + +extern unsigned long loops_per_jiffy; + +extern unsigned long ppc_proc_freq; +extern unsigned long ppc_tb_freq; + +void pSeries_get_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *model = ""; + + root = of_find_node_by_path("/"); + if (root) + model = get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: CHRP %s\n", model); + of_node_put(root); +} + +/* Initialize firmware assisted non-maskable interrupts if + * the firmware supports this feature. + * + */ +static void __init fwnmi_init(void) +{ + int ret; + int ibm_nmi_register = rtas_token("ibm,nmi-register"); + if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE) + return; + ret = rtas_call(ibm_nmi_register, 2, 1, NULL, + __pa((unsigned long)SystemReset_FWNMI), + __pa((unsigned long)MachineCheck_FWNMI)); + if (ret == 0) + fwnmi_active = 1; +} + +static void __init pSeries_setup_arch(void) +{ + struct device_node *root; + unsigned int *opprop; + + /* Fixup ppc_md depending on the type of interrupt controller */ + if (naca->interrupt_controller == IC_OPEN_PIC) { + ppc_md.init_IRQ = pSeries_init_openpic; + ppc_md.get_irq = openpic_get_irq; + } else { + ppc_md.init_IRQ = xics_init_IRQ; + ppc_md.get_irq = xics_get_irq; + } + +#ifdef CONFIG_SMP + smp_init_pSeries(); +#endif + /* openpic global configuration register (64-bit format). */ + /* openpic Interrupt Source Unit pointer (64-bit format). */ + /* python0 facility area (mmio) (64-bit format) REAL address. */ + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + if (ROOT_DEV == 0) { + printk("No ramdisk, default root is /dev/sda2\n"); + ROOT_DEV = Root_SDA2; + } + + fwnmi_init(); + + /* Find and initialize PCI host bridges */ + /* iSeries needs to be done much later. */ + eeh_init(); + find_and_init_phbs(); + + /* Find the Open PIC if present */ + root = of_find_node_by_path("/"); + opprop = (unsigned int *) get_property(root, + "platform-open-pic", NULL); + if (opprop != 0) { + int n = prom_n_addr_cells(root); + unsigned long openpic; + + for (openpic = 0; n > 0; --n) + openpic = (openpic << 32) + *opprop++; + printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic); + OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE); + } + of_node_put(root); + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + pSeries_nvram_init(); +} + +static int __init pSeries_init_panel(void) +{ + /* Manually leave the kernel version on the panel. */ + ppc_md.progress("Linux ppc64\n", 0); + ppc_md.progress(UTS_RELEASE, 0); + + return 0; +} +arch_initcall(pSeries_init_panel); + + + +void __init pSeries_find_serial_port(void) +{ + struct device_node *np; + unsigned long encode_phys_size = 32; + u32 *sizeprop; + + struct isa_reg_property { + u32 space; + u32 address; + u32 size; + }; + struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; + }; + + DBG(" -> pSeries_find_serial_port()\n"); + + naca->serialPortAddr = 0; + + np = of_find_node_by_path("/"); + if (!np) + return; + sizeprop = (u32 *)get_property(np, "#size-cells", NULL); + if (sizeprop != NULL) + encode_phys_size = (*sizeprop) << 5; + + for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { + struct device_node *isa, *pci; + struct isa_reg_property *reg; + union pci_range *rangesp; + char *typep; + + typep = (char *)get_property(np, "ibm,aix-loc", NULL); + if ((typep == NULL) || (typep && strcmp(typep, "S1"))) + continue; + + reg = (struct isa_reg_property *)get_property(np, "reg", NULL); + + isa = of_get_parent(np); + if (!isa) { + DBG("no isa parent found\n"); + break; + } + pci = of_get_parent(isa); + if (!pci) { + DBG("no pci parent found\n"); + break; + } + + rangesp = (union pci_range *)get_property(pci, "ranges", NULL); + + if ( encode_phys_size == 32 ) + naca->serialPortAddr = rangesp->pci32.phys+reg->address; + else { + naca->serialPortAddr = + ((((unsigned long)rangesp->pci64.phys_hi) << 32) + | + (rangesp->pci64.phys_lo)) + reg->address; + } + break; + } + + DBG(" <- pSeries_find_serial_port()\n"); +} + + +/* Build up the firmware_features bitmask field + * using contents of device-tree/ibm,hypertas-functions. + * Ultimately this functionality may be moved into prom.c prom_init(). + */ +void __init fw_feature_init(void) +{ + struct device_node * dn; + char * hypertas; + unsigned int len; + + DBG(" -> fw_feature_init()\n"); + + cur_cpu_spec->firmware_features = 0; + dn = of_find_node_by_path("/rtas"); + if (dn == NULL) { + printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n"); + goto no_rtas; + } + + hypertas = get_property(dn, "ibm,hypertas-functions", &len); + if (hypertas) { + while (len > 0){ + int i, hypertas_len; + /* check value against table of strings */ + for(i=0; i < FIRMWARE_MAX_FEATURES ;i++) { + if ((firmware_features_table[i].name) && + (strcmp(firmware_features_table[i].name,hypertas))==0) { + /* we have a match */ + cur_cpu_spec->firmware_features |= + (firmware_features_table[i].val); + break; + } + } + hypertas_len = strlen(hypertas); + len -= hypertas_len +1; + hypertas+= hypertas_len +1; + } + } + + of_node_put(dn); + no_rtas: + printk(KERN_INFO "firmware_features = 0x%lx\n", + cur_cpu_spec->firmware_features); + + DBG(" <- fw_feature_init()\n"); +} + + +static void __init pSeries_discover_pic(void) +{ + struct device_node *np; + char *typep; + + /* + * Setup interrupt mapping options that are needed for finish_device_tree + * to properly parse the OF interrupt tree & do the virtual irq mapping + */ + __irq_offset_value = NUM_ISA_INTERRUPTS; + naca->interrupt_controller = IC_INVALID; + for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { + typep = (char *)get_property(np, "compatible", NULL); + if (strstr(typep, "open-pic")) + naca->interrupt_controller = IC_OPEN_PIC; + else if (strstr(typep, "ppc-xicp")) + naca->interrupt_controller = IC_PPC_XIC; + else + printk("initialize_naca: failed to recognize" + " interrupt-controller\n"); + break; + } +} + +/* + * Early initialization. Relocation is on but do not reference unbolted pages + */ +static void __init pSeries_init_early(void) +{ + void *comport; + int iommu_off = 0; + + DBG(" -> pSeries_init_early()\n"); + + fw_feature_init(); + + if (systemcfg->platform & PLATFORM_LPAR) + hpte_init_lpar(); + else { + hpte_init_native(); + iommu_off = (of_chosen && + get_property(of_chosen, "linux,iommu-off", NULL)); + } + + pSeries_find_serial_port(); + + if (systemcfg->platform & PLATFORM_LPAR) + find_udbg_vterm(); + else if (naca->serialPortAddr) { + /* Map the uart for udbg. */ + comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE); + udbg_init_uart(comport); + + ppc_md.udbg_putc = udbg_putc; + ppc_md.udbg_getc = udbg_getc; + ppc_md.udbg_getc_poll = udbg_getc_poll; + DBG("Hello World !\n"); + } + + + if (iommu_off) + pci_dma_init_direct(); + else + tce_init_pSeries(); + + pSeries_discover_pic(); + + DBG(" <- pSeries_init_early()\n"); +} + + +static void pSeries_progress(char *s, unsigned short hex) +{ + struct device_node *root; + int width, *p; + char *os; + static int display_character, set_indicator; + static int max_width; + static spinlock_t progress_lock = SPIN_LOCK_UNLOCKED; + static int pending_newline = 0; /* did last write end with unprinted newline? */ + + if (!rtas.base) + return; + + if (max_width == 0) { + if ((root = find_path_device("/rtas")) && + (p = (unsigned int *)get_property(root, + "ibm,display-line-length", + NULL))) + max_width = *p; + else + max_width = 0x10; + display_character = rtas_token("display-character"); + set_indicator = rtas_token("set-indicator"); + } + + if (display_character == RTAS_UNKNOWN_SERVICE) { + /* use hex display if available */ + if (set_indicator != RTAS_UNKNOWN_SERVICE) + rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); + return; + } + + spin_lock(&progress_lock); + + /* + * Last write ended with newline, but we didn't print it since + * it would just clear the bottom line of output. Print it now + * instead. + * + * If no newline is pending, print a CR to start output at the + * beginning of the line. + */ + if (pending_newline) { + rtas_call(display_character, 1, 1, NULL, '\r'); + rtas_call(display_character, 1, 1, NULL, '\n'); + pending_newline = 0; + } else { + rtas_call(display_character, 1, 1, NULL, '\r'); + } + + width = max_width; + os = s; + while (*os) { + if (*os == '\n' || *os == '\r') { + /* Blank to end of line. */ + while (width-- > 0) + rtas_call(display_character, 1, 1, NULL, ' '); + + /* If newline is the last character, save it + * until next call to avoid bumping up the + * display output. + */ + if (*os == '\n' && !os[1]) { + pending_newline = 1; + spin_unlock(&progress_lock); + return; + } + + /* RTAS wants CR-LF, not just LF */ + + if (*os == '\n') { + rtas_call(display_character, 1, 1, NULL, '\r'); + rtas_call(display_character, 1, 1, NULL, '\n'); + } else { + /* CR might be used to re-draw a line, so we'll + * leave it alone and not add LF. + */ + rtas_call(display_character, 1, 1, NULL, *os); + } + + width = max_width; + } else { + width--; + rtas_call(display_character, 1, 1, NULL, *os); + } + + os++; + + /* if we overwrite the screen length */ + if (width <= 0) + while ((*os != 0) && (*os != '\n') && (*os != '\r')) + os++; + } + + /* Blank to end of line. */ + while (width-- > 0) + rtas_call(display_character, 1, 1, NULL, ' '); + + spin_unlock(&progress_lock); +} + +extern void setup_default_decr(void); + +/* Some sane defaults: 125 MHz timebase, 1GHz processor */ +#define DEFAULT_TB_FREQ 125000000UL +#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) + +static void __init pSeries_calibrate_decr(void) +{ + struct device_node *cpu; + struct div_result divres; + unsigned int *fp; + int node_found; + + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + cpu = of_find_node_by_type(NULL, "cpu"); + + ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */ + node_found = 0; + if (cpu != 0) { + fp = (unsigned int *)get_property(cpu, "timebase-frequency", + NULL); + if (fp != 0) { + node_found = 1; + ppc_tb_freq = *fp; + } + } + if (!node_found) + printk(KERN_ERR "WARNING: Estimating decrementer frequency " + "(not found)\n"); + + ppc_proc_freq = DEFAULT_PROC_FREQ; + node_found = 0; + if (cpu != 0) { + fp = (unsigned int *)get_property(cpu, "clock-frequency", + NULL); + if (fp != 0) { + node_found = 1; + ppc_proc_freq = *fp; + } + } + if (!node_found) + printk(KERN_ERR "WARNING: Estimating processor frequency " + "(not found)\n"); + + of_node_put(cpu); + + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + ppc_tb_freq/1000000, ppc_tb_freq%1000000); + printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", + ppc_proc_freq/1000000, ppc_proc_freq%1000000); + + tb_ticks_per_jiffy = ppc_tb_freq / HZ; + tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; + tb_ticks_per_usec = ppc_tb_freq / 1000000; + tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); + div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); + tb_to_xs = divres.result_low; + + setup_default_decr(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +extern struct machdep_calls pSeries_md; + +static int __init pSeries_probe(int platform) +{ + if (platform != PLATFORM_PSERIES && + platform != PLATFORM_PSERIES_LPAR) + return 0; + + /* if we have some ppc_md fixups for LPAR to do, do + * it here ... + */ + + return 1; +} + +struct machdep_calls __initdata pSeries_md = { + .probe = pSeries_probe, + .setup_arch = pSeries_setup_arch, + .init_early = pSeries_init_early, + .get_cpuinfo = pSeries_get_cpuinfo, + .log_error = pSeries_log_error, + .pcibios_fixup = pSeries_final_fixup, + .restart = rtas_restart, + .power_off = rtas_power_off, + .halt = rtas_halt, + .panic = rtas_os_term, + .get_boot_time = pSeries_get_boot_time, + .get_rtc_time = pSeries_get_rtc_time, + .set_rtc_time = pSeries_set_rtc_time, + .calibrate_decr = pSeries_calibrate_decr, + .progress = pSeries_progress, +}; diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c index 0e4228316..61d7f8e33 100644 --- a/arch/ppc64/kernel/pacaData.c +++ b/arch/ppc64/kernel/pacaData.c @@ -27,13 +27,6 @@ struct systemcfg *systemcfg; * field correctly */ extern unsigned long __toc_start; -/* Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. - * - * ABI requires stack to be 128-byte aligned - */ -char emergency_stack[PAGE_SIZE * NR_CPUS] __attribute__((aligned(128))); - /* The Paca is an array with one entry per processor. Each contains an * ItLpPaca, which contains the information shared between the * hypervisor and Linux. Each also contains an ItLpRegSave area which @@ -44,18 +37,27 @@ char emergency_stack[PAGE_SIZE * NR_CPUS] __attribute__((aligned(128))); * processors. The processor VPD array needs one entry per physical * processor (not thread). */ -#define PACAINITDATA(number,start,lpq,asrr,asrv) \ -{ \ +#ifdef CONFIG_PPC_ISERIES +#define EXTRA_INITS(number, lpq) \ .lppaca_ptr = &paca[number].lppaca, \ + .lpqueue_ptr = (lpq), /* &xItLpQueue, */ \ .reg_save_ptr = &paca[number].reg_save, \ + .reg_save = { \ + .xDesc = 0xd397d9e2, /* "LpRS" */ \ + .xSize = sizeof(struct ItLpRegSave) \ + }, +#else +#define EXTRA_INITS(number, lpq) +#endif + +#define PACAINITDATA(number,start,lpq,asrr,asrv) \ +{ \ .lock_token = 0x8000, \ .paca_index = (number), /* Paca Index */ \ - .lpqueue_ptr = (lpq), /* &xItLpQueue, */ \ .default_decr = 0x00ff0000, /* Initial Decr */ \ .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ .stab_real = (asrr), /* Real pointer to segment table */ \ .stab_addr = (asrv), /* Virt pointer to segment table */ \ - .emergency_sp = &emergency_stack[((number)+1) * PAGE_SIZE], \ .cpu_start = (start), /* Processor start */ \ .lppaca = { \ .xDesc = 0xd397d781, /* "LpPa" */ \ @@ -66,13 +68,10 @@ char emergency_stack[PAGE_SIZE * NR_CPUS] __attribute__((aligned(128))); .xEndOfQuantum = 0xfffffffffffffffful, \ .xSLBCount = 64, \ }, \ - .reg_save = { \ - .xDesc = 0xd397d9e2, /* "LpRS" */ \ - .xSize = sizeof(struct ItLpRegSave) \ - }, \ + EXTRA_INITS((number), (lpq)) \ } -struct paca_struct paca[] __page_aligned = { +struct paca_struct paca[] = { #ifdef CONFIG_PPC_ISERIES PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR), #else diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 30e50023c..751071af3 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,13 @@ unsigned long pci_probe_only = 1; unsigned long pci_assign_all_buses = 0; +/* legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch + devices we don't have access to. */ +unsigned long io_page_mask; + +EXPORT_SYMBOL(io_page_mask); + + unsigned int pcibios_assign_all_busses(void) { return pci_assign_all_buses; @@ -55,16 +63,9 @@ unsigned int pcibios_assign_all_busses(void) unsigned long isa_io_base; /* NULL if no ISA bus */ unsigned long pci_io_base; -void pcibios_name_device(struct pci_dev* dev); -void pcibios_final_fixup(void); -static void fixup_broken_pcnet32(struct pci_dev* dev); -static void fixup_windbond_82c105(struct pci_dev* dev); -extern void fixup_k2_sata(struct pci_dev* dev); - void iSeries_pcibios_init(void); -struct pci_controller *hose_head; -struct pci_controller **hose_tail = &hose_head; +LIST_HEAD(hose_list); struct pci_dma_ops pci_dma_ops; EXPORT_SYMBOL(pci_dma_ops); @@ -74,20 +75,6 @@ int global_phb_number; /* Global phb counter */ /* Cached ISA bridge dev. */ struct pci_dev *ppc64_isabridge_dev = NULL; -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, - fixup_broken_pcnet32 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, - fixup_windbond_82c105 }, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, - pcibios_name_device }, -#ifdef CONFIG_PPC_PMAC - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, - fixup_k2_sata }, -#endif - { 0 } -}; - static void fixup_broken_pcnet32(struct pci_dev* dev) { if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { @@ -96,6 +83,7 @@ static void fixup_broken_pcnet32(struct pci_dev* dev) pci_name_device(dev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); static void fixup_windbond_82c105(struct pci_dev* dev) { @@ -118,6 +106,7 @@ static void fixup_windbond_82c105(struct pci_dev* dev) dev->resource[i].flags &= ~IORESOURCE_IO; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105); void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, @@ -239,9 +228,9 @@ pci_alloc_pci_controller(enum phb_types controller_type) memcpy(hose->what,model,7); hose->type = controller_type; hose->global_number = global_phb_number++; - - *hose_tail = hose; - hose_tail = &hose->next; + + list_add_tail(&hose->list_node, &hose_list); + return hose; } @@ -281,18 +270,17 @@ static void __init pcibios_claim_of_setup(void) static int __init pcibios_init(void) { - struct pci_controller *hose; + struct pci_controller *hose, *tmp; struct pci_bus *bus; #ifdef CONFIG_PPC_ISERIES iSeries_pcibios_init(); #endif - //ppc64_boot_msg(0x40, "PCI Probe"); printk("PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ - for (hose = hose_head; hose; hose = hose->next) { + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data); @@ -308,7 +296,7 @@ static int __init pcibios_init(void) pci_assign_unassigned_resources() is able to work correctly with [partially] allocated PCI tree. */ pci_assign_unassigned_resources(); -#endif +#endif /* !CONFIG_PPC_ISERIES */ /* Call machine dependent final fixup */ if (ppc_md.pcibios_fixup) @@ -320,11 +308,6 @@ static int __init pcibios_init(void) printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); printk("PCI: Probing PCI hardware done\n"); - //ppc64_boot_msg(0x41, "PCI Done"); - -#ifdef CONFIG_PPC_PSERIES - pci_addr_cache_build(); -#endif return 0; } @@ -524,7 +507,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, return ret; } -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM static ssize_t pci_show_devspec(struct device *dev, char *buf) { struct pci_dev *pdev; @@ -537,11 +520,329 @@ static ssize_t pci_show_devspec(struct device *dev, char *buf) return sprintf(buf, "%s", np->full_name); } static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ void pcibios_add_platform_entries(struct pci_dev *pdev) { -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM device_create_file(&pdev->dev, &dev_attr_devspec); -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ +} + +#ifdef CONFIG_PPC_MULTIPLATFORM + +#define ISA_SPACE_MASK 0x1 +#define ISA_SPACE_IO 0x1 + +static void pci_process_ISA_OF_ranges(struct device_node *isa_node, + unsigned long phb_io_base_phys, + void * phb_io_base_virt) +{ + struct isa_range *range; + unsigned long pci_addr; + unsigned int isa_addr; + unsigned int size; + int rlen = 0; + + range = (struct isa_range *) get_property(isa_node, "ranges", &rlen); + if (rlen < sizeof(struct isa_range)) { + printk(KERN_ERR "unexpected isa range size: %s\n", + __FUNCTION__); + return; + } + + /* From "ISA Binding to 1275" + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 1: an ISA address + * cells 2 - 4: a PCI address + * (size depending on dev->n_addr_cells) + * cell 5: the size of the range + */ + if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) { + isa_addr = range->isa_addr.a_lo; + pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | + range->pci_addr.a_lo; + + /* Assume these are both zero */ + if ((pci_addr != 0) || (isa_addr != 0)) { + printk(KERN_ERR "unexpected isa to pci mapping: %s\n", + __FUNCTION__); + return; + } + + size = PAGE_ALIGN(range->size); + + __ioremap_explicit(phb_io_base_phys, + (unsigned long) phb_io_base_virt, + size, _PAGE_NO_CACHE); + } +} + +void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + unsigned int *ranges; + unsigned long size; + int rlen = 0; + int memno = 0; + struct resource *res; + int np, na = prom_n_addr_cells(dev); + unsigned long pci_addr, cpu_phys_addr; + struct device_node *isa_dn; + + np = na + 5; + + /* From "PCI Binding to 1275" + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 2: a PCI address + * cells 3 or 3+4: a CPU physical address + * (size depending on dev->n_addr_cells) + * cells 4+5 or 5+6: the size of the range + */ + rlen = 0; + hose->io_base_phys = 0; + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + res = NULL; + pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; + + cpu_phys_addr = ranges[3]; + if (na == 2) + cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; + + size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; + + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + hose->io_base_phys = cpu_phys_addr; + hose->io_base_virt = reserve_phb_iospace(size); + PPCDBG(PPCDBG_PHBINIT, + "phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", + hose->global_number, hose->io_base_phys, + (unsigned long) hose->io_base_virt); + + if (primary) { + pci_io_base = (unsigned long)hose->io_base_virt; + isa_dn = of_find_node_by_type(NULL, "isa"); + if (isa_dn) { + isa_io_base = pci_io_base; + pci_process_ISA_OF_ranges(isa_dn, + hose->io_base_phys, + hose->io_base_virt); + of_node_put(isa_dn); + /* Allow all IO */ + io_page_mask = -1; + } + } + + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = pci_addr; + res->start += (unsigned long)hose->io_base_virt - + pci_io_base; + break; + case 2: /* memory space */ + memno = 0; + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + + if (memno == 0) + hose->pci_mem_offset = cpu_phys_addr - pci_addr; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = cpu_phys_addr; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + size - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += np; + } +} + +/*********************************************************************** + * pci_find_hose_for_OF_device + * + * This function finds the PHB that matching device_node in the + * OpenFirmware by scanning all the pci_controllers. + * + ***********************************************************************/ +struct pci_controller* pci_find_hose_for_OF_device(struct device_node *node) +{ + while (node) { + struct pci_controller *hose, *tmp; + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + if (hose->arch_data == node) + return hose; + node=node->parent; + } + return NULL; +} + +/* + * ppc64 can have multifunction devices that do not respond to function 0. + * In this case we must scan all functions. + */ +int pcibios_scan_all_fns(struct pci_bus *bus, int devfn) +{ + struct device_node *busdn, *dn; + + if (bus->self) + busdn = pci_device_to_OF_node(bus->self); + else + busdn = bus->sysdata; /* must be a phb */ + + /* + * Check to see if there is any of the 8 functions are in the + * device tree. If they are then we need to scan all the + * functions of this slot. + */ + for (dn = busdn->child; dn; dn = dn->sibling) + if ((dn->devfn >> 3) == (devfn >> 3)) + return 1; + + return 0; +} + + +void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, + struct pci_bus *bus) +{ + /* Update device resources. */ + struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; + unsigned long start, end, mask; + + start = dev->resource[i].start += offset; + end = dev->resource[i].end += offset; + + /* Need to allow IO access to pages that are in the + ISA range */ + if (start < MAX_ISA_PORT) { + if (end > MAX_ISA_PORT) + end = MAX_ISA_PORT; + + start >>= PAGE_SHIFT; + end >>= PAGE_SHIFT; + + /* get the range of pages for the map */ + mask = ((1 << (end+1))-1) ^ ((1 << start)-1); + io_page_mask |= mask; + } + } + else if (dev->resource[i].flags & IORESOURCE_MEM) { + dev->resource[i].start += hose->pci_mem_offset; + dev->resource[i].end += hose->pci_mem_offset; + } + } +} +EXPORT_SYMBOL(pcibios_fixup_device_resources); + +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct list_head *ln; + + /* XXX or bus->parent? */ + struct pci_dev *dev = bus->self; + struct resource *res; + int i; + + if (!dev) { + /* Root bus. */ + + hose->bus = bus; + bus->resource[0] = res = &hose->io_resource; + if (!res->flags) + BUG(); /* No I/O resource for this PHB? */ + + if (request_resource(&ioport_resource, res)) + printk(KERN_ERR "Failed to request IO on " + "PCI domain %d\n", pci_domain_nr(bus)); + + + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + if (!res->flags && i == 0) + BUG(); /* No memory resource for this PHB? */ + bus->resource[i+1] = res; + if (res->flags && request_resource(&iomem_resource, res)) + printk(KERN_ERR "Failed to request MEM on " + "PCI domain %d\n", + pci_domain_nr(bus)); + } + } else if (pci_probe_only && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + /* This is a subordinate bridge */ + + pci_read_bridge_bases(bus); + pcibios_fixup_device_resources(dev, bus); + } + + /* XXX Need to check why Alpha doesnt do this - Anton */ + if (!pci_probe_only) + return; + + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { + struct pci_dev *dev = pci_dev_b(ln); + if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + pcibios_fixup_device_resources(dev, bus); + } +} +EXPORT_SYMBOL(pcibios_fixup_bus); + +/****************************************************************** + * pci_read_irq_line + * + * Reads the Interrupt Pin to determine if interrupt is use by card. + * If the interrupt is used, then gets the interrupt line from the + * openfirmware and sets it in the pci_dev and pci_config line. + * + ******************************************************************/ +int pci_read_irq_line(struct pci_dev *pci_dev) +{ + u8 intpin; + struct device_node *node; + + pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin); + + if (intpin == 0) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n", + pci_name(pci_dev)); + return 0; + } + + node = pci_device_to_OF_node(pci_dev); + if (node == NULL) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n", + pci_name(pci_dev)); + return -1; + } + if (node->n_intrs == 0) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n", + pci_name(pci_dev)); + return -1; + } + pci_dev->irq = node->intrs[0].line; + + pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); + + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n", + pci_name(pci_dev), pci_dev->irq); + return 0; } +EXPORT_SYMBOL(pci_read_irq_line); + +#endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h index 2ca27ccc7..9e85ebd48 100644 --- a/arch/ppc64/kernel/pci.h +++ b/arch/ppc64/kernel/pci.h @@ -17,9 +17,7 @@ extern unsigned long isa_io_base; extern struct pci_controller* pci_alloc_pci_controller(enum phb_types controller_type); extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node); -extern struct pci_controller* hose_head; -extern struct pci_controller** hose_tail; - +extern struct list_head hose_list; extern int global_phb_number; /******************************************************************* diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c index c771bdc64..2ef21d7da 100644 --- a/arch/ppc64/kernel/pci_dn.c +++ b/arch/ppc64/kernel/pci_dn.c @@ -129,10 +129,10 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, */ static void *traverse_all_pci_devices(traverse_func pre) { - struct pci_controller *phb; + struct pci_controller *phb, *tmp; void *ret; - for (phb = hose_head; phb; phb = phb->next) + list_for_each_entry_safe(phb, tmp, &hose_list, list_node) if ((ret = traverse_pci_devices(phb->arch_data, pre, phb)) != NULL) return ret; diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c index 4d99851fe..951831f99 100644 --- a/arch/ppc64/kernel/pci_iommu.c +++ b/arch/ppc64/kernel/pci_iommu.c @@ -54,9 +54,9 @@ static inline struct iommu_table *devnode_table(struct pci_dev *dev) return ISERIES_DEVNODE(dev)->iommu_table; #endif /* CONFIG_PPC_ISERIES */ -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM return PCI_GET_DN(dev)->iommu_table; -#endif /* CONFIG_PPC_PSERIES */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ } diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c index c059a7608..c45ecbdb2 100644 --- a/arch/ppc64/kernel/pmac_feature.c +++ b/arch/ppc64/kernel/pmac_feature.c @@ -44,9 +44,9 @@ #undef DEBUG_FEATURE #ifdef DEBUG_FEATURE -#define DBG(fmt,...) printk(KERN_DEBUG fmt) +#define DBG(fmt...) printk(KERN_DEBUG fmt) #else -#define DBG(fmt,...) +#define DBG(fmt...) #endif /* @@ -343,6 +343,10 @@ static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { PMAC_TYPE_POWERMAC_G5, g5_features, 0, }, + { "PowerMac7,3", "PowerMac G5", + PMAC_TYPE_POWERMAC_G5, g5_features, + 0, + }, { "RackMac3,1", "XServe G5", PMAC_TYPE_POWERMAC_G5, g5_features, 0, @@ -611,7 +615,7 @@ int __init pmac_feature_late_init(void) device_initcall(pmac_feature_late_init); - +#if 0 static void dump_HT_speeds(char *name, u32 cfg, u32 frq) { int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; @@ -625,6 +629,7 @@ static void dump_HT_speeds(char *name, u32 cfg, u32 frq) name, freqs[freq], bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); } +#endif void __init pmac_check_ht_link(void) { diff --git a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c index d07579f2b..52da75719 100644 --- a/arch/ppc64/kernel/pmac_low_i2c.c +++ b/arch/ppc64/kernel/pmac_low_i2c.c @@ -50,7 +50,7 @@ struct low_i2c_host struct device_node *np; /* OF device node */ struct semaphore mutex; /* Access mutex for use by i2c-keywest */ low_i2c_func_t func; /* Access function */ - int is_open : 1; /* Poor man's access control */ + unsigned is_open : 1; /* Poor man's access control */ int mode; /* Current mode */ int channel; /* Current channel */ int num_channels; /* Number of channels */ diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index 169195713..9e1a06955 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -271,7 +271,7 @@ static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { struct pci_controller *hose; - struct device_node *busdn; + struct device_node *busdn, *dn; unsigned long addr; if (bus->self) @@ -284,6 +284,16 @@ static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; + /* We only allow config cycles to devices that are in OF device-tree + * as we are apparently having some weird things going on with some + * revs of K2 on recent G5s + */ + for (dn = busdn->child; dn; dn = dn->sibling) + if (dn->devfn == devfn) + break; + if (dn == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -419,7 +429,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) * properties or figuring out the U3 address space decoding logic and * then read it's configuration register (if any). */ - hose->io_base_phys = 0xf4000000 + 0x00400000; + hose->io_base_phys = 0xf4000000; hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; hose->io_resource.name = np->full_name; @@ -664,17 +674,15 @@ void __init pmac_pcibios_fixup(void) pci_fix_bus_sysdata(); -#ifdef CONFIG_PMAC_DART - iommu_setup_pmac(); -#endif /* CONFIG_PMAC_DART */ + iommu_setup_u3(); } static void __init pmac_fixup_phb_resources(void) { - struct pci_controller *hose; + struct pci_controller *hose, *tmp; - for (hose = hose_head; hose; hose = hose->next) { + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; hose->io_resource.start += offset; hose->io_resource.end += offset; @@ -746,6 +754,9 @@ void __init pmac_pci_init(void) * the exception of U3/AGP (hook into pci_set_mwi) */ pci_cache_line_size = 16; /* 64 bytes */ + + /* Allow all IO */ + io_page_mask = -1; } /* @@ -777,3 +788,4 @@ void fixup_k2_sata(struct pci_dev* dev) } } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 58e8b392e..3d1de0f9b 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -23,6 +23,8 @@ * bootup setup stuff.. */ +#undef DEBUG + #include #include #include @@ -63,7 +65,6 @@ #include #include #include -#include #include #include #include @@ -73,6 +74,13 @@ #include "pmac.h" +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + + static int current_root_goodness = -1; #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ @@ -81,10 +89,6 @@ int sccdbg; extern void udbg_init_scc(struct device_node *np); -#ifdef CONFIG_BOOTX_TEXT -void pmac_progress(char *s, unsigned short hex); -#endif - void __pmac pmac_show_cpuinfo(struct seq_file *m) { struct device_node *np; @@ -134,28 +138,20 @@ void __pmac pmac_show_cpuinfo(struct seq_file *m) void __init pmac_setup_arch(void) { - struct device_node *cpu; - int *fp; - unsigned long pvr; - - pvr = PVR_VER(mfspr(PVR)); - - /* Set loops_per_jiffy to a half-way reasonable value, - for use until calibrate_delay gets called. */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (int *) get_property(cpu, "clock-frequency", NULL); - if (fp != 0) { - if (pvr == 4 || pvr >= 8) - /* 604, G3, G4 etc. */ - loops_per_jiffy = *fp / HZ; - else - /* 601, 603, etc. */ - loops_per_jiffy = *fp / (2*HZ); - } else - loops_per_jiffy = 50000000 / HZ; + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + /* Probe motherboard chipset */ + pmac_feature_init(); +#if 0 + /* Lock-enable the SCC channel used for debug */ + if (sccdbg) { + np = of_find_node_by_name(NULL, "escc"); + if (np) + pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, + PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); } - +#endif /* We can NAP */ powersave_nap = 1; @@ -183,67 +179,13 @@ void __init pmac_setup_arch(void) #endif } -extern char *bootpath; -extern char *bootdevice; -void *boot_host; -int boot_target; -int boot_part; -extern dev_t boot_dev; - #ifdef CONFIG_SCSI -void __init note_scsi_host(struct device_node *node, void *host) +void note_scsi_host(struct device_node *node, void *host) { - int l; - char *p; - - l = strlen(node->full_name); - if (bootpath != NULL && bootdevice != NULL - && strncmp(node->full_name, bootdevice, l) == 0 - && (bootdevice[l] == '/' || bootdevice[l] == 0)) { - boot_host = host; - /* - * There's a bug in OF 1.0.5. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - * So we pick the target number out of bootpath and use that. - */ - p = strstr(bootpath, "/sd@"); - if (p != NULL) { - p += 4; - boot_target = simple_strtoul(p, NULL, 10); - p = strchr(p, ':'); - if (p != NULL) - boot_part = simple_strtoul(p + 1, NULL, 10); - } - } + /* Obsolete */ } #endif -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -static dev_t __init find_ide_boot(void) -{ - char *p; - int n; - dev_t __init pmac_find_ide_boot(char *bootdevice, int n); - - if (bootdevice == NULL) - return 0; - p = strrchr(bootdevice, '/'); - if (p == NULL) - return 0; - n = p - bootdevice; - - return pmac_find_ide_boot(bootdevice, n); -} -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -void __init find_boot_device(void) -{ -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - boot_dev = find_ide_boot(); -#endif -} static int initializing = 1; @@ -258,7 +200,7 @@ late_initcall(pmac_late_init); /* can't be __init - can be called whenever a disk is first accessed */ void __pmac note_bootable_part(dev_t dev, int part, int goodness) { - static int found_boot = 0; + extern dev_t boot_dev; char *p; if (!initializing) @@ -270,10 +212,6 @@ void __pmac note_bootable_part(dev_t dev, int part, int goodness) if (p != NULL && (p == saved_command_line || p[-1] == ' ')) return; - if (!found_boot) { - find_boot_device(); - found_boot = 1; - } if (!boot_dev || dev == boot_dev) { ROOT_DEV = dev + part; boot_dev = 0; @@ -313,21 +251,73 @@ static void btext_putc(unsigned char c) } #endif /* CONFIG_BOOTX_TEXT */ +static void __init init_boot_display(void) +{ + char *name; + struct device_node *np = NULL; + int rc = -ENODEV; + + printk("trying to initialize btext ...\n"); + + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name != NULL) { + np = of_find_node_by_path(name); + if (np != NULL) { + if (strcmp(np->type, "display") != 0) { + printk("boot stdout isn't a display !\n"); + of_node_put(np); + np = NULL; + } + } + } + if (np) + rc = btext_initialize(np); + if (rc == 0) + return; + + for (np = NULL; (np = of_find_node_by_type(np, "display"));) { + if (get_property(np, "linux,opened", NULL)) { + printk("trying %s ...\n", np->full_name); + rc = btext_initialize(np); + printk("result: %d\n", rc); + } + if (rc == 0) + return; + } +} + /* * Early initialization. - * Relocation is on but do not reference unbolted pages - * Also, device-tree hasn't been "finished", so don't muck with - * it too much */ void __init pmac_init_early(void) { - hpte_init_pSeries(); + DBG(" -> pmac_init_early\n"); + + /* Initialize hash table, from now on, we can take hash faults + * and call ioremap + */ + hpte_init_native(); + /* Init SCC */ + if (strstr(cmd_line, "sccdbg")) { + sccdbg = 1; + udbg_init_scc(NULL); + } + + else { #ifdef CONFIG_BOOTX_TEXT - ppc_md.udbg_putc = btext_putc; - ppc_md.udbg_getc = dummy_getc; - ppc_md.udbg_getc_poll = dummy_getc_poll; + init_boot_display(); + + ppc_md.udbg_putc = btext_putc; + ppc_md.udbg_getc = dummy_getc; + ppc_md.udbg_getc_poll = dummy_getc_poll; #endif /* CONFIG_BOOTX_TEXT */ + } + + /* Setup interrupt mapping options */ + naca->interrupt_controller = IC_OPEN_PIC; + + DBG(" <- pmac_init_early\n"); } extern void* OpenPIC_Addr; @@ -417,60 +407,19 @@ static int __init pmac_irq_cascade_init(void) core_initcall(pmac_irq_cascade_init); -void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* Probe motherboard chipset */ - pmac_feature_init(); - - /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { - sccdbg = 1; - udbg_init_scc(NULL); - } - - /* Fill up the machine description */ - ppc_md.setup_arch = pmac_setup_arch; - ppc_md.get_cpuinfo = pmac_show_cpuinfo; - - ppc_md.init_IRQ = pmac_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - - ppc_md.pcibios_fixup = pmac_pcibios_fixup; - - ppc_md.restart = pmac_restart; - ppc_md.power_off = pmac_power_off; - ppc_md.halt = pmac_halt; - - ppc_md.get_boot_time = pmac_get_boot_time; - ppc_md.set_rtc_time = pmac_set_rtc_time; - ppc_md.get_rtc_time = pmac_get_rtc_time; - ppc_md.calibrate_decr = pmac_calibrate_decr; - - ppc_md.feature_call = pmac_do_feature_call; - - -#ifdef CONFIG_BOOTX_TEXT - ppc_md.progress = pmac_progress; -#endif /* CONFIG_BOOTX_TEXT */ - - if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); - -} - -#ifdef CONFIG_BOOTX_TEXT -void __init pmac_progress(char *s, unsigned short hex) +static void __init pmac_progress(char *s, unsigned short hex) { if (sccdbg) { udbg_puts(s); - udbg_putc('\n'); + udbg_puts("\n"); } +#ifdef CONFIG_BOOTX_TEXT else if (boot_text_mapped) { btext_drawstring(s); - btext_drawchar('\n'); + btext_drawstring("\n"); } -} #endif /* CONFIG_BOOTX_TEXT */ +} static int __init pmac_declare_of_platform_devices(void) { @@ -489,3 +438,41 @@ static int __init pmac_declare_of_platform_devices(void) } device_initcall(pmac_declare_of_platform_devices); + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init pmac_probe(int platform) +{ + if (platform != PLATFORM_POWERMAC) + return 0; + + /* + * On U3, the DART (iommu) must be allocated now since it + * has an impact on htab_initialize (due to the large page it + * occupies having to be broken up so the DART itself is not + * part of the cacheable linar mapping + */ + alloc_u3_dart_table(); + + return 1; +} + +struct machdep_calls __initdata pmac_md = { + .probe = pmac_probe, + .setup_arch = pmac_setup_arch, + .init_early = pmac_init_early, + .get_cpuinfo = pmac_show_cpuinfo, + .init_IRQ = pmac_init_IRQ, + .get_irq = openpic_get_irq, + .pcibios_fixup = pmac_pcibios_fixup, + .restart = pmac_restart, + .power_off = pmac_power_off, + .halt = pmac_halt, + .get_boot_time = pmac_get_boot_time, + .set_rtc_time = pmac_set_rtc_time, + .get_rtc_time = pmac_get_rtc_time, + .calibrate_decr = pmac_calibrate_decr, + .feature_call = pmac_do_feature_call, + .progress = pmac_progress, +}; diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index a67e2a595..fb6ab4014 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index aea28b989..06f379855 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c index 836cf2a43..3732fe048 100644 --- a/arch/ppc64/kernel/ppc_ksyms.c +++ b/arch/ppc64/kernel/ppc_ksyms.c @@ -119,7 +119,6 @@ EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(flush_instruction_cache); -EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(giveup_altivec); @@ -137,7 +136,7 @@ EXPORT_SYMBOL(local_irq_restore); EXPORT_SYMBOL(ppc_md); -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -148,12 +147,12 @@ EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); #endif -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memchr); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(irq_desc); diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 5acc56729..821133707 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -147,7 +147,6 @@ EXPORT_SYMBOL(enable_kernel_altivec); */ void flush_altivec_to_thread(struct task_struct *tsk) { -#ifdef CONFIG_ALTIVEC if (tsk->thread.regs) { preempt_disable(); if (tsk->thread.regs->msr & MSR_VEC) { @@ -158,7 +157,6 @@ void flush_altivec_to_thread(struct task_struct *tsk) } preempt_enable(); } -#endif } int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) @@ -356,6 +354,16 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, kregs = (struct pt_regs *) sp; sp -= STACK_FRAME_OVERHEAD; p->thread.ksp = sp; + if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { + unsigned long sp_vsid = get_kernel_vsid(sp); + + sp_vsid <<= SLB_VSID_SHIFT; + sp_vsid |= SLB_VSID_KERNEL; + if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + sp_vsid |= SLB_VSID_L; + + p->thread.ksp_vsid = sp_vsid; + } /* * The PPC64 ABI makes use of a TOC to contain function @@ -387,11 +395,22 @@ void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp) /* Check whether the e_entry function descriptor entries * need to be relocated before we can use them. */ - if ( load_addr != 0 ) { + if (load_addr != 0) { entry += load_addr; toc += load_addr; } + /* + * If we exec out of a kernel thread then thread.regs will not be + * set. Do it now. + */ + if (!current->thread.regs) { + unsigned long childregs = (unsigned long)current->thread_info + + THREAD_SIZE; + childregs -= sizeof(struct pt_regs); + current->thread.regs = (struct pt_regs *)childregs; + } + regs->nip = entry; regs->gpr[1] = sp; regs->gpr[2] = toc; @@ -458,7 +477,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/prom.c b/arch/ppc64/kernel/prom.c index bdf5e3a47..f121ffbc2 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG_PROM +#undef DEBUG #include #include @@ -54,1806 +54,58 @@ #include #include "open_pic.h" -#ifdef CONFIG_LOGO_LINUX_CLUT224 -#include -extern const struct linux_logo logo_linux_clut224; -#endif - -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This value does need to be big enough to - * ensure that we don't lose things like the interrupt-map property - * on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) - -/* - * prom_init() is called very early on, before the kernel text - * and data have been mapped to KERNELBASE. At this point the code - * is running at whatever address it has been loaded at, so - * references to extern and static variables must be relocated - * explicitly. The procedure reloc_offset() returns the address - * we're currently running at minus the address we were linked at. - * (Note that strings count as static variables.) - * - * Because OF may have mapped I/O devices into the area starting at - * KERNELBASE, particularly on CHRP machines, we can't safely call - * OF once the kernel has been mapped to KERNELBASE. Therefore all - * OF calls should be done within prom_init(), and prom_init() - * and all routines called within it must be careful to relocate - * references as necessary. - * - * Note that the bss is cleared *after* prom_init runs, so we have - * to make sure that any static or extern variables it accesses - * are put in the data segment. - */ - - -#define PROM_BUG() do { \ - prom_printf("kernel BUG at %s line 0x%x!\n", \ - RELOC(__FILE__), __LINE__); \ - __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ -} while (0) - -#ifdef DEBUG_PROM -#define prom_debug(x...) prom_printf(x) -#else -#define prom_debug(x...) -#endif - - -struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; -}; - - -struct isa_reg_property { - u32 space; - u32 address; - u32 size; -}; - -struct pci_intr_map { - struct pci_address addr; - u32 dunno; - phandle int_ctrler; - u32 intr; -}; - - -typedef unsigned long interpret_func(struct device_node *, unsigned long, - int, int, int); - -#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ -#define FB_MAX 8 -#endif - -/* prom structure */ -struct prom_t prom; - -char *prom_display_paths[FB_MAX] __initdata = { NULL, }; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays = 0; -char *of_stdout_device = NULL; - -static int iommu_force_on; -int ppc64_iommu_off; - -extern struct rtas_t rtas; -extern unsigned long klimit; -extern struct lmb lmb; - -#define MAX_PHB (32 * 6) /* 32 drawers * 6 PHBs/drawer */ -struct of_tce_table of_tce_table[MAX_PHB + 1]; - -char *bootpath = NULL; -char *bootdevice = NULL; - -int boot_cpuid = 0; -#define MAX_CPU_THREADS 2 - -struct device_node *allnodes = NULL; -/* use when traversing tree through the allnext, child, sibling, - * or parent members of struct device_node. - */ -static rwlock_t devtree_lock = RW_LOCK_UNLOCKED; - -extern unsigned long reloc_offset(void); - -extern void enter_prom(struct prom_args *args); -extern void copy_and_flush(unsigned long dest, unsigned long src, - unsigned long size, unsigned long offset); - -unsigned long dev_tree_size; -unsigned long _get_PIR(void); - -#ifdef CONFIG_HMT -struct { - unsigned int pir; - unsigned int threadid; -} hmt_thread_data[NR_CPUS]; -#endif /* CONFIG_HMT */ - -char testString[] = "LINUX\n"; - -/* - * This are used in calls to call_prom. The 4th and following - * arguments to call_prom should be 32-bit values. 64 bit values - * are truncated to 32 bits (and fortunately don't get interpreted - * as two arguments). - */ -#define ADDR(x) (u32) ((unsigned long)(x) - offset) - -/* This is the one and *ONLY* place where we actually call open - * firmware from, since we need to make sure we're running in 32b - * mode when we do. We switch back to 64b mode upon return. - */ - -#define PROM_ERROR (-1) - -static int __init call_prom(const char *service, int nargs, int nret, ...) -{ - int i; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - va_list list; - - _prom->args.service = ADDR(service); - _prom->args.nargs = nargs; - _prom->args.nret = nret; - _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); - - va_start(list, nret); - for (i=0; i < nargs; i++) - _prom->args.args[i] = va_arg(list, prom_arg_t); - va_end(list); - - for (i=0; i < nret ;i++) - _prom->args.rets[i] = 0; - - enter_prom(&_prom->args); - - return (nret > 0)? _prom->args.rets[0]: 0; -} - - -static void __init prom_print(const char *msg) -{ - const char *p, *q; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - if (_prom->stdout == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - ++q; - call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); - } -} - - -static void __init prom_print_hex(unsigned long val) -{ - unsigned long offset = reloc_offset(); - int i, nibbles = sizeof(val)*2; - char buf[sizeof(val)*2+1]; - struct prom_t *_prom = PTRRELOC(&prom); - - for (i = nibbles-1; i >= 0; i--) { - buf[i] = (val & 0xf) + '0'; - if (buf[i] > '9') - buf[i] += ('a'-'0'-10); - val >>= 4; - } - buf[nibbles] = '\0'; - call_prom("write", 3, 1, _prom->stdout, buf, nibbles); -} - - -static void __init prom_printf(const char *format, ...) -{ - unsigned long offset = reloc_offset(); - const char *p, *q, *s; - va_list args; - unsigned long v; - struct prom_t *_prom = PTRRELOC(&prom); - - va_start(args, format); - for (p = PTRRELOC(format); *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - if (*q == '\n') { - ++q; - call_prom("write", 3, 1, _prom->stdout, - ADDR("\r\n"), 2); - continue; - } - ++q; - if (*q == 0) - break; - switch (*q) { - case 's': - ++q; - s = va_arg(args, const char *); - prom_print(s); - break; - case 'x': - ++q; - v = va_arg(args, unsigned long); - prom_print_hex(v); - break; - } - } -} - - -static void __init __attribute__((noreturn)) prom_panic(const char *reason) -{ - unsigned long offset = reloc_offset(); - - prom_print(PTRRELOC(reason)); - /* ToDo: should put up an SRC here */ - call_prom("exit", 0, 0); - - for (;;) /* should never get here */ - ; -} - - -static int __init prom_next_node(phandle *nodep) -{ - phandle node; - - if ((node = *nodep) != 0 - && (*nodep = call_prom("child", 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom("parent", 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - } -} - -static int __init prom_getprop(phandle node, const char *pname, - void *value, size_t valuelen) -{ - unsigned long offset = reloc_offset(); - - return call_prom("getprop", 4, 1, node, ADDR(pname), - (u32)(unsigned long) value, (u32) valuelen); -} - -static void __init prom_initialize_naca(void) -{ - phandle node; - char type[64]; - unsigned long num_cpus = 0; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct naca_struct *_naca = RELOC(naca); - struct systemcfg *_systemcfg = RELOC(systemcfg); - - /* NOTE: _naca->debug_switch is already initialized. */ - prom_debug("prom_initialize_naca: start...\n"); - - _naca->pftSize = 0; /* ilog2 of htab size. computed below. */ - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (!strcmp(type, RELOC("cpu"))) { - num_cpus += 1; - - /* We're assuming *all* of the CPUs have the same - * d-cache and i-cache sizes... -Peter - */ - if ( num_cpus == 1 ) { - u32 size, lsize; - const char *dc, *ic; - - if (_systemcfg->platform == PLATFORM_POWERMAC){ - dc = "d-cache-block-size"; - ic = "i-cache-block-size"; - } else { - dc = "d-cache-line-size"; - ic = "i-cache-line-size"; - } - - prom_getprop(node, "d-cache-size", - &size, sizeof(size)); - - prom_getprop(node, dc, &lsize, sizeof(lsize)); - - _systemcfg->dCacheL1Size = size; - _systemcfg->dCacheL1LineSize = lsize; - _naca->dCacheL1LogLineSize = __ilog2(lsize); - _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize; - - prom_getprop(node, "i-cache-size", - &size, sizeof(size)); - - prom_getprop(node, ic, &lsize, sizeof(lsize)); - - _systemcfg->iCacheL1Size = size; - _systemcfg->iCacheL1LineSize = lsize; - _naca->iCacheL1LogLineSize = __ilog2(lsize); - _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize; - - if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) { - u32 pft_size[2]; - prom_getprop(node, "ibm,pft-size", - &pft_size, sizeof(pft_size)); - /* pft_size[0] is the NUMA CEC cookie */ - _naca->pftSize = pft_size[1]; - } - } - } else if (!strcmp(type, RELOC("serial"))) { - phandle isa, pci; - struct isa_reg_property reg; - union pci_range ranges; - - if (_systemcfg->platform == PLATFORM_POWERMAC) - continue; - type[0] = 0; - prom_getprop(node, "ibm,aix-loc", type, sizeof(type)); - - if (strcmp(type, RELOC("S1"))) - continue; - - prom_getprop(node, "reg", ®, sizeof(reg)); - - isa = call_prom("parent", 1, 1, node); - if (!isa) - PROM_BUG(); - pci = call_prom("parent", 1, 1, isa); - if (!pci) - PROM_BUG(); - - prom_getprop(pci, "ranges", &ranges, sizeof(ranges)); - - if ( _prom->encode_phys_size == 32 ) - _naca->serialPortAddr = ranges.pci32.phys+reg.address; - else { - _naca->serialPortAddr = - ((((unsigned long)ranges.pci64.phys_hi) << 32) | - (ranges.pci64.phys_lo)) + reg.address; - } - } - } - - if (_systemcfg->platform == PLATFORM_POWERMAC) - _naca->interrupt_controller = IC_OPEN_PIC; - else { - _naca->interrupt_controller = IC_INVALID; - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "name", type, sizeof(type)); - if (strcmp(type, RELOC("interrupt-controller"))) - continue; - prom_getprop(node, "compatible", type, sizeof(type)); - if (strstr(type, RELOC("open-pic"))) - _naca->interrupt_controller = IC_OPEN_PIC; - else if (strstr(type, RELOC("ppc-xicp"))) - _naca->interrupt_controller = IC_PPC_XIC; - else - prom_printf("prom: failed to recognize" - " interrupt-controller\n"); - break; - } - } - - if (_naca->interrupt_controller == IC_INVALID) { - prom_printf("prom: failed to find interrupt-controller\n"); - PROM_BUG(); - } - - /* We gotta have at least 1 cpu... */ - if ( (_systemcfg->processorCount = num_cpus) < 1 ) - PROM_BUG(); - - _systemcfg->physicalMemorySize = lmb_phys_mem_size(); - - if (_systemcfg->platform == PLATFORM_PSERIES || - _systemcfg->platform == PLATFORM_POWERMAC) { - unsigned long rnd_mem_size, pteg_count; - - /* round mem_size up to next power of 2 */ - rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize); - if (rnd_mem_size < _systemcfg->physicalMemorySize) - rnd_mem_size <<= 1; - - /* # pages / 2 */ - pteg_count = (rnd_mem_size >> (12 + 1)); - - _naca->pftSize = __ilog2(pteg_count << 7); - } - - if (_naca->pftSize == 0) { - prom_printf("prom: failed to compute pftSize!\n"); - PROM_BUG(); - } - - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64")); - _systemcfg->version.major = SYSTEMCFG_MAJOR; - _systemcfg->version.minor = SYSTEMCFG_MINOR; - _systemcfg->processor = _get_PVR(); - - prom_debug("systemcfg->processorCount = 0x%x\n", - _systemcfg->processorCount); - prom_debug("systemcfg->physicalMemorySize = 0x%x\n", - _systemcfg->physicalMemorySize); - prom_debug("naca->pftSize = 0x%x\n", - _naca->pftSize); - prom_debug("systemcfg->dCacheL1LineSize = 0x%x\n", - _systemcfg->dCacheL1LineSize); - prom_debug("systemcfg->iCacheL1LineSize = 0x%x\n", - _systemcfg->iCacheL1LineSize); - prom_debug("naca->serialPortAddr = 0x%x\n", - _naca->serialPortAddr); - prom_debug("naca->interrupt_controller = 0x%x\n", - _naca->interrupt_controller); - prom_debug("systemcfg->platform = 0x%x\n", - _systemcfg->platform); - prom_debug("prom_initialize_naca: end...\n"); -} - - -static void __init early_cmdline_parse(void) -{ - unsigned long offset = reloc_offset(); - char *opt; -#ifndef CONFIG_PMAC_DART - struct systemcfg *_systemcfg = RELOC(systemcfg); -#endif - - opt = strstr(RELOC(cmd_line), RELOC("iommu=")); - if (opt) { - prom_printf("opt is:%s\n", opt); - opt += 6; - while (*opt && *opt == ' ') - opt++; - if (!strncmp(opt, RELOC("off"), 3)) - RELOC(ppc64_iommu_off) = 1; - else if (!strncmp(opt, RELOC("force"), 5)) - RELOC(iommu_force_on) = 1; - } - -#ifndef CONFIG_PMAC_DART - if (_systemcfg->platform == PLATFORM_POWERMAC) { - RELOC(ppc64_iommu_off) = 1; - prom_printf("DART disabled on PowerMac !\n"); - } -#endif -} - -#ifdef DEBUG_PROM -void prom_dump_lmb(void) -{ - unsigned long i; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); - - prom_printf("\nprom_dump_lmb:\n"); - prom_printf(" memory.cnt = 0x%x\n", - _lmb->memory.cnt); - prom_printf(" memory.size = 0x%x\n", - _lmb->memory.size); - for (i=0; i < _lmb->memory.cnt ;i++) { - prom_printf(" memory.region[0x%x].base = 0x%x\n", - i, _lmb->memory.region[i].base); - prom_printf(" .physbase = 0x%x\n", - _lmb->memory.region[i].physbase); - prom_printf(" .size = 0x%x\n", - _lmb->memory.region[i].size); - } - - prom_printf("\n reserved.cnt = 0x%x\n", - _lmb->reserved.cnt); - prom_printf(" reserved.size = 0x%x\n", - _lmb->reserved.size); - for (i=0; i < _lmb->reserved.cnt ;i++) { - prom_printf(" reserved.region[0x%x\n].base = 0x%x\n", - i, _lmb->reserved.region[i].base); - prom_printf(" .physbase = 0x%x\n", - _lmb->reserved.region[i].physbase); - prom_printf(" .size = 0x%x\n", - _lmb->reserved.region[i].size); - } -} -#endif /* DEBUG_PROM */ - -static void __init prom_initialize_lmb(void) -{ - phandle node; - char type[64]; - unsigned long i, offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct systemcfg *_systemcfg = RELOC(systemcfg); - union lmb_reg_property reg; - unsigned long lmb_base, lmb_size; - unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8; - - lmb_init(); - - /* XXX Quick HACK. Proper fix is to drop those structures and properly use - * #address-cells. PowerMac has #size-cell set to 1 and #address-cells to 2 - */ - if (_systemcfg->platform == PLATFORM_POWERMAC) - bytes_per_reg = 12; - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (strcmp(type, RELOC("memory"))) - continue; - - num_regs = prom_getprop(node, "reg", ®, sizeof(reg)) - / bytes_per_reg; - - for (i=0; i < num_regs ;i++) { - if (_systemcfg->platform == PLATFORM_POWERMAC) { - lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32; - lmb_base |= (unsigned long)reg.addrPM[i].address_lo; - lmb_size = reg.addrPM[i].size; - } else if (_prom->encode_phys_size == 32) { - lmb_base = reg.addr32[i].address; - lmb_size = reg.addr32[i].size; - } else { - lmb_base = reg.addr64[i].address; - lmb_size = reg.addr64[i].size; - } - - /* We limit memory to 2GB if the IOMMU is off */ - if (RELOC(ppc64_iommu_off)) { - if (lmb_base >= 0x80000000UL) - continue; - - if ((lmb_base + lmb_size) > 0x80000000UL) - lmb_size = 0x80000000UL - lmb_base; - } - - if (lmb_add(lmb_base, lmb_size) < 0) - prom_printf("Too many LMB's, discarding this one...\n"); - } - - } - - lmb_analyze(); -#ifdef DEBUG_PROM - prom_dump_lmb(); -#endif /* DEBUG_PROM */ -} - -static void __init -prom_instantiate_rtas(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct rtas_t *_rtas = PTRRELOC(&rtas); - struct systemcfg *_systemcfg = RELOC(systemcfg); - ihandle prom_rtas; - u32 getprop_rval; - char hypertas_funcs[4]; - - prom_debug("prom_instantiate_rtas: start...\n"); - - prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (prom_rtas != (ihandle) -1) { - unsigned long x; - x = prom_getprop(prom_rtas, "ibm,hypertas-functions", - hypertas_funcs, sizeof(hypertas_funcs)); - - if (x != PROM_ERROR) { - prom_printf("Hypertas detected, assuming LPAR !\n"); - _systemcfg->platform = PLATFORM_PSERIES_LPAR; - } - - prom_getprop(prom_rtas, "rtas-size", - &getprop_rval, sizeof(getprop_rval)); - _rtas->size = getprop_rval; - prom_printf("instantiating rtas"); - if (_rtas->size != 0) { - unsigned long rtas_region = RTAS_INSTANTIATE_MAX; - - /* Grab some space within the first RTAS_INSTANTIATE_MAX bytes - * of physical memory (or within the RMO region) because RTAS - * runs in 32-bit mode and relocate off. - */ - if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) { - struct lmb *_lmb = PTRRELOC(&lmb); - rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX); - } - - _rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region); - - prom_printf(" at 0x%x", _rtas->base); - - prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); - prom_printf("..."); - - if (call_prom("call-method", 3, 2, - ADDR("instantiate-rtas"), - prom_rtas, - _rtas->base) != PROM_ERROR) { - _rtas->entry = (long)_prom->args.rets[1]; - } - RELOC(rtas_rmo_buf) - = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, - rtas_region); - } - - if (_rtas->entry <= 0) { - prom_printf(" failed\n"); - } else { - prom_printf(" done\n"); - } - - prom_debug("rtas->base = 0x%x\n", _rtas->base); - prom_debug("rtas->entry = 0x%x\n", _rtas->entry); - prom_debug("rtas->size = 0x%x\n", _rtas->size); - } - prom_debug("prom_instantiate_rtas: end...\n"); -} - - -#ifdef CONFIG_PMAC_DART -static void __init prom_initialize_dart_table(void) -{ - unsigned long offset = reloc_offset(); - extern unsigned long dart_tablebase; - extern unsigned long dart_tablesize; - - /* Only reserve DART space if machine has more than 2GB of RAM - * or if requested with iommu=on on cmdline. - */ - if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(iommu_force_on)) - return; - - /* 512 pages (2MB) is max DART tablesize. */ - RELOC(dart_tablesize) = 1UL << 21; - /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we - * will blow up an entire large page anyway in the kernel mapping - */ - RELOC(dart_tablebase) = (unsigned long) - abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); - - prom_printf("Dart at: %x\n", RELOC(dart_tablebase)); -} -#endif /* CONFIG_PMAC_DART */ - -static void __init prom_initialize_tce_table(void) -{ - phandle node; - ihandle phb_node; - unsigned long offset = reloc_offset(); - char compatible[64], path[64], type[64], model[64]; - unsigned long i, table = 0; - unsigned long base, vbase, align; - unsigned int minalign, minsize; - struct of_tce_table *prom_tce_table = RELOC(of_tce_table); - unsigned long tce_entry, *tce_entryp; - - if (RELOC(ppc64_iommu_off)) - return; - - prom_debug("starting prom_initialize_tce_table\n"); - - /* Search all nodes looking for PHBs. */ - for (node = 0; prom_next_node(&node); ) { - if (table == MAX_PHB) { - prom_printf("WARNING: PCI host bridge ignored, " - "need to increase MAX_PHB\n"); - continue; - } - - compatible[0] = 0; - type[0] = 0; - model[0] = 0; - prom_getprop(node, "compatible", - compatible, sizeof(compatible)); - prom_getprop(node, "device_type", type, sizeof(type)); - prom_getprop(node, "model", model, sizeof(model)); - - /* Keep the old logic in tack to avoid regression. */ - if (compatible[0] != 0) { - if ((strstr(compatible, RELOC("python")) == NULL) && - (strstr(compatible, RELOC("Speedwagon")) == NULL) && - (strstr(compatible, RELOC("Winnipeg")) == NULL)) - continue; - } else if (model[0] != 0) { - if ((strstr(model, RELOC("ython")) == NULL) && - (strstr(model, RELOC("peedwagon")) == NULL) && - (strstr(model, RELOC("innipeg")) == NULL)) - continue; - } - - if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) { - continue; - } - - if (prom_getprop(node, "tce-table-minalign", &minalign, - sizeof(minalign)) == PROM_ERROR) { - minalign = 0; - } - - if (prom_getprop(node, "tce-table-minsize", &minsize, - sizeof(minsize)) == PROM_ERROR) { - minsize = 4UL << 20; - } - - /* - * Even though we read what OF wants, we just set the table - * size to 4 MB. This is enough to map 2GB of PCI DMA space. - * By doing this, we avoid the pitfalls of trying to DMA to - * MMIO space and the DMA alias hole. - * - * On POWER4, firmware sets the TCE region by assuming - * each TCE table is 8MB. Using this memory for anything - * else will impact performance, so we always allocate 8MB. - * Anton - */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) - minsize = 8UL << 20; - else - minsize = 4UL << 20; - - /* Align to the greater of the align or size */ - align = max(minalign, minsize); - - /* Carve out storage for the TCE table. */ - base = lmb_alloc(minsize, align); - - if ( !base ) { - prom_panic("ERROR, cannot find space for TCE table.\n"); - } - - vbase = (unsigned long)abs_to_virt(base); - - /* Save away the TCE table attributes for later use. */ - prom_tce_table[table].node = node; - prom_tce_table[table].base = vbase; - prom_tce_table[table].size = minsize; - - prom_debug("TCE table: 0x%x\n", table); - prom_debug("\tnode = 0x%x\n", node); - prom_debug("\tbase = 0x%x\n", vbase); - prom_debug("\tsize = 0x%x\n", minsize); - - /* Initialize the table to have a one-to-one mapping - * over the allocated size. - */ - tce_entryp = (unsigned long *)base; - for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { - tce_entry = (i << PAGE_SHIFT); - tce_entry |= 0x3; - *tce_entryp = tce_entry; - } - - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - /* Call OF to setup the TCE hardware */ - if (call_prom("package-to-path", 3, 1, node, - path, sizeof(path)-1) == PROM_ERROR) { - prom_printf("package-to-path failed\n"); - } else { - prom_printf("opening PHB %s", path); - } - - phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) { - prom_printf("... failed\n"); - } else { - prom_printf("... done\n"); - } - call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), - phb_node, -1, minsize, - (u32) base, (u32) (base >> 32)); - call_prom("close", 1, 0, phb_node); - - table++; - } - - /* Flag the first invalid entry */ - prom_tce_table[table].node = 0; - prom_debug("ending prom_initialize_tce_table\n"); -} - -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of low memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. The holding pattern - * checks that address until its cpu # is there, when it is that - * cpu jumps to __secondary_start(). smp_boot_cpus() takes care - * of setting those values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * Fixup comment... DRENG / PPPBBB - Peter - * - * -- Cort - */ -static void __init prom_hold_cpus(unsigned long mem) -{ - unsigned long i; - unsigned int reg; - phandle node; - unsigned long offset = reloc_offset(); - char type[64], *path; - int cpuid = 0; - unsigned int interrupt_server[MAX_CPU_THREADS]; - unsigned int cpu_threads, hw_cpu_num; - int propsize; - extern void __secondary_hold(void); - extern unsigned long __secondary_hold_spinloop; - extern unsigned long __secondary_hold_acknowledge; - unsigned long *spinloop - = (void *)virt_to_abs(&__secondary_hold_spinloop); - unsigned long *acknowledge - = (void *)virt_to_abs(&__secondary_hold_acknowledge); - unsigned long secondary_hold - = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); - struct systemcfg *_systemcfg = RELOC(systemcfg); - struct paca_struct *lpaca = PTRRELOC(&paca[0]); - struct prom_t *_prom = PTRRELOC(&prom); -#ifdef CONFIG_SMP - struct naca_struct *_naca = RELOC(naca); -#endif - - /* On pmac, we just fill out the various global bitmasks and - * arrays indicating our CPUs are here, they are actually started - * later on from pmac_smp - */ - if (_systemcfg->platform == PLATFORM_POWERMAC) { - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - reg = -1; - prom_getprop(node, "reg", ®, sizeof(reg)); - lpaca[cpuid].hw_cpu_id = reg; - -#ifdef CONFIG_SMP - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_possible_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); - if (reg == 0) - cpu_set(cpuid, RELOC(cpu_online_map)); -#endif /* CONFIG_SMP */ - cpuid++; - } - return; - } - - /* Initially, we must have one active CPU. */ - _systemcfg->processorCount = 1; - - prom_debug("prom_hold_cpus: start...\n"); - prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); - prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); - prom_debug(" 1) acknowledge = 0x%x\n", - (unsigned long)acknowledge); - prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); - prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); - - /* Set the common spinloop variable, so all of the secondary cpus - * will block when they are awakened from their OF spinloop. - * This must occur for both SMP and non SMP kernels, since OF will - * be trashed when we move the kernel. - */ - *spinloop = 0; - -#ifdef CONFIG_HMT - for (i=0; i < NR_CPUS; i++) { - RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; - } -#endif - /* look for cpus */ - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - - /* Skip non-configured cpus. */ - prom_getprop(node, "status", type, sizeof(type)); - if (strcmp(type, RELOC("okay")) != 0) - continue; - - reg = -1; - prom_getprop(node, "reg", ®, sizeof(reg)); - - path = (char *) mem; - memset(path, 0, 256); - if (call_prom("package-to-path", 3, 1, - node, path, 255) == PROM_ERROR) - continue; - - prom_debug("\ncpuid = 0x%x\n", cpuid); - prom_debug("cpu hw idx = 0x%x\n", reg); - lpaca[cpuid].hw_cpu_id = reg; - - /* Init the acknowledge var which will be reset by - * the secondary cpu when it awakens from its OF - * spinloop. - */ - *acknowledge = (unsigned long)-1; - - propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", - &interrupt_server, - sizeof(interrupt_server)); - if (propsize < 0) { - /* no property. old hardware has no SMT */ - cpu_threads = 1; - interrupt_server[0] = reg; /* fake it with phys id */ - } else { - /* We have a threaded processor */ - cpu_threads = propsize / sizeof(u32); - if (cpu_threads > MAX_CPU_THREADS) { - prom_printf("SMT: too many threads!\n" - "SMT: found %x, max is %x\n", - cpu_threads, MAX_CPU_THREADS); - cpu_threads = 1; /* ToDo: panic? */ - } - } - - hw_cpu_num = interrupt_server[0]; - if (hw_cpu_num != _prom->cpu) { - /* Primary Thread of non-boot cpu */ - prom_printf("%x : starting cpu %s... ", cpuid, path); - call_prom("start-cpu", 3, 0, node, - secondary_hold, cpuid); - - for ( i = 0 ; (i < 100000000) && - (*acknowledge == ((unsigned long)-1)); i++ ) ; - - if (*acknowledge == cpuid) { - prom_printf("... done\n"); - /* We have to get every CPU out of OF, - * even if we never start it. */ - if (cpuid >= NR_CPUS) - goto next; -#ifdef CONFIG_SMP - /* Set the number of active processors. */ - _systemcfg->processorCount++; - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_possible_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); -#endif - } else { - prom_printf("... failed: %x\n", *acknowledge); - } - } -#ifdef CONFIG_SMP - else { - prom_printf("%x : booting cpu %s\n", cpuid, path); - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_possible_map)); - cpu_set(cpuid, RELOC(cpu_online_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); - } -#endif -next: -#ifdef CONFIG_SMP - /* Init paca for secondary threads. They start later. */ - for (i=1; i < cpu_threads; i++) { - cpuid++; - if (cpuid >= NR_CPUS) - continue; - lpaca[cpuid].hw_cpu_id = interrupt_server[i]; - prom_printf("%x : preparing thread ... ", - interrupt_server[i]); - if (_naca->smt_state) { - cpu_set(cpuid, RELOC(cpu_available_map)); - cpu_set(cpuid, RELOC(cpu_present_at_boot)); - prom_printf("available\n"); - } else { - prom_printf("not available\n"); - } - } -#endif - cpuid++; - } -#ifdef CONFIG_HMT - /* Only enable HMT on processors that provide support. */ - if (__is_processor(PV_PULSAR) || - __is_processor(PV_ICESTAR) || - __is_processor(PV_SSTAR)) { - prom_printf(" starting secondary threads\n"); - - for (i = 0; i < NR_CPUS; i += 2) { - if (!cpu_online(i)) - continue; - - if (i == 0) { - unsigned long pir = _get_PIR(); - if (__is_processor(PV_PULSAR)) { - RELOC(hmt_thread_data)[i].pir = - pir & 0x1f; - } else { - RELOC(hmt_thread_data)[i].pir = - pir & 0x3ff; - } - } -/* cpu_set(i+1, cpu_online_map); */ - cpu_set(i+1, RELOC(cpu_possible_map)); - } - _systemcfg->processorCount *= 2; - } else { - prom_printf("Processor is not HMT capable\n"); - } -#endif - - if (cpuid > NR_CPUS) - prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) - ") exceeded: ignoring extras\n"); - - prom_debug("prom_hold_cpus: end...\n"); -} - -static void __init smt_setup(void) -{ - char *p, *q; - char my_smt_enabled = SMT_DYNAMIC; - ihandle prom_options = 0; - char option[9]; - unsigned long offset = reloc_offset(); - struct naca_struct *_naca = RELOC(naca); - char found = 0; - - if (strstr(RELOC(cmd_line), RELOC("smt-enabled="))) { - for (q = RELOC(cmd_line); (p = strstr(q, RELOC("smt-enabled="))) != 0; ) { - q = p + 12; - if (p > RELOC(cmd_line) && p[-1] != ' ') - continue; - found = 1; - if (q[0] == 'o' && q[1] == 'f' && - q[2] == 'f' && (q[3] == ' ' || q[3] == '\0')) { - my_smt_enabled = SMT_OFF; - } else if (q[0]=='o' && q[1] == 'n' && - (q[2] == ' ' || q[2] == '\0')) { - my_smt_enabled = SMT_ON; - } else { - my_smt_enabled = SMT_DYNAMIC; - } - } - } - if (!found) { - prom_options = call_prom("finddevice", 1, 1, ADDR("/options")); - if (prom_options != (ihandle) -1) { - prom_getprop(prom_options, "ibm,smt-enabled", - option, sizeof(option)); - if (option[0] != 0) { - found = 1; - if (!strcmp(option, RELOC("off"))) - my_smt_enabled = SMT_OFF; - else if (!strcmp(option, RELOC("on"))) - my_smt_enabled = SMT_ON; - else - my_smt_enabled = SMT_DYNAMIC; - } - } - } - - if (!found ) - my_smt_enabled = SMT_DYNAMIC; /* default to on */ - - _naca->smt_state = my_smt_enabled; -} - - -#ifdef CONFIG_BOOTX_TEXT - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -static void __init setup_disp_fake_bi(ihandle dp) -{ - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - struct pci_reg_property addrs[8]; - int i, naddrs; - char name[64]; - unsigned long offset = reloc_offset(); - - memset(name, 0, sizeof(name)); - prom_getprop(dp, "name", name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_printf("Initializing fake screen: %s\n", name); - - prom_getprop(dp, "width", &width, sizeof(width)); - prom_getprop(dp, "height", &height, sizeof(height)); - prom_getprop(dp, "depth", &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - prom_getprop(dp, "linebytes", &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - - prom_printf("width %x height %x depth %x linebytes %x\n", - width, height, depth, depth); - - prom_getprop(dp, "address", &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = prom_getprop(dp, "assigned-addresses", - addrs, sizeof(addrs)); - naddrs /= sizeof(struct pci_reg_property); - for (i = 0; i < naddrs; ++i) { - if (addrs[i].size_lo >= (1 << 20)) { - address = addrs[i].addr.a_lo; - /* use the BE aperture if possible */ - if (addrs[i].size_lo >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_printf("Failed to get address of frame buffer\n"); - return; - } - } - btext_setup_display(width, height, depth, pitch, address); - prom_printf("Addr of fb: %x\n", address); - RELOC(boot_text_mapped) = 0; -} -#endif /* CONFIG_BOOTX_TEXT */ - -static void __init prom_init_client_services(unsigned long pp) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - /* Get a handle to the prom entry point before anything else */ - _prom->entry = pp; - - /* Init default value for phys size */ - _prom->encode_phys_size = 32; - - /* get a handle for the stdout device */ - _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) - prom_panic("cannot find chosen"); /* msg won't be printed :( */ - - /* get device tree root */ - _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) - prom_panic("cannot find device tree root"); /* msg won't be printed :( */ -} - -static void __init prom_init_stdout(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - u32 val; - - if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) - prom_panic("cannot find stdout"); - - _prom->stdout = val; -} - -static int __init prom_find_machine_type(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char compat[256]; - int len, i = 0; - - len = prom_getprop(_prom->root, "compatible", - compat, sizeof(compat)-1); - if (len > 0) { - compat[len] = 0; - while (i < len) { - char *p = &compat[i]; - int sl = strlen(p); - if (sl == 0) - break; - if (strstr(p, RELOC("Power Macintosh")) || - strstr(p, RELOC("MacRISC4"))) - return PLATFORM_POWERMAC; - i += sl + 1; - } - } - /* Default to pSeries */ - return PLATFORM_PSERIES; -} - -static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - unsigned long offset = reloc_offset(); - - return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); -} - -/* - * If we have a display that we don't know how to drive, - * we will want to try to execute OF's open method for it - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static unsigned long __init check_display(unsigned long mem) -{ - phandle node; - ihandle ih; - int i, j; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char type[16], *path; - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - const unsigned char *clut; - - _prom->disp_node = 0; - - prom_printf("Looking for displays\n"); - if (RELOC(of_stdout_device) != 0) - prom_printf("OF stdout is : %s\n", - PTRRELOC(RELOC(of_stdout_device))); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("display")) != 0) - continue; - /* It seems OF doesn't null-terminate the path :-( */ - path = (char *) mem; - memset(path, 0, 256); - - /* - * leave some room at the end of the path for appending extra - * arguments - */ - if (call_prom("package-to-path", 3, 1, node, path, 250) < 0) - continue; - prom_printf("found display : %s\n", path); - - /* - * If this display is the device that OF is using for stdout, - * move it to the front of the list. - */ - mem += strlen(path) + 1; - i = RELOC(prom_num_displays); - RELOC(prom_num_displays) = i + 1; - if (RELOC(of_stdout_device) != 0 && i > 0 - && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { - for (; i > 0; --i) { - RELOC(prom_display_paths[i]) - = RELOC(prom_display_paths[i-1]); - RELOC(prom_display_nodes[i]) - = RELOC(prom_display_nodes[i-1]); - } - _prom->disp_node = node; - } - RELOC(prom_display_paths[i]) = PTRUNRELOC(path); - RELOC(prom_display_nodes[i]) = node; - if (_prom->disp_node == 0) - _prom->disp_node = node; - if (RELOC(prom_num_displays) >= FB_MAX) - break; - } - prom_printf("Opening displays...\n"); - for (j = RELOC(prom_num_displays) - 1; j >= 0; j--) { - path = PTRRELOC(RELOC(prom_display_paths[j])); - prom_printf("opening display : %s", path); - ih = call_prom("open", 1, 1, path); - if (ih == (ihandle)0 || ih == (ihandle)-1) { - prom_printf("... failed\n"); - continue; - } - - prom_printf("... done\n"); - - /* Setup a useable color table when the appropriate - * method is available. Should update this to set-colors */ - clut = RELOC(default_colors); - for (i = 0; i < 32; i++, clut += 3) - if (prom_set_color(ih, i, clut[0], clut[1], - clut[2]) != 0) - break; - -#ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); - for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) - if (prom_set_color(ih, i + 32, clut[0], clut[1], - clut[2]) != 0) - break; -#endif /* CONFIG_LOGO_LINUX_CLUT224 */ - } - - return DOUBLEWORD_ALIGN(mem); -} - -/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ -static void __init *__make_room(unsigned long *mem_start, unsigned long *mem_end, - unsigned long needed, unsigned long align) -{ - void *ret; - - *mem_start = ALIGN(*mem_start, align); - if (*mem_start + needed > *mem_end) { -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long offset = reloc_offset(); - /* FIXME: Apple OF doesn't map unclaimed mem. If this - * ever happened on G5, we'd need to fix. */ - unsigned long initrd_len; - - if (*mem_end != RELOC(initrd_start)) - prom_panic("No memory for copy_device_tree"); - - prom_printf("Huge device_tree: moving initrd\n"); - /* Move by 4M. */ - initrd_len = RELOC(initrd_end) - RELOC(initrd_start); - *mem_end = RELOC(initrd_start) + 4 * 1024 * 1024; - memmove((void *)*mem_end, (void *)RELOC(initrd_start), - initrd_len); - RELOC(initrd_start) = *mem_end; - RELOC(initrd_end) = RELOC(initrd_start) + initrd_len; -#else - prom_panic("No memory for copy_device_tree"); -#endif - } - - ret = (void *)*mem_start; - *mem_start += needed; - - return ret; -} - -#define make_room(startp, endp, type) \ - __make_room(startp, endp, sizeof(type), __alignof__(type)) - -static void __init -inspect_node(phandle node, struct device_node *dad, - unsigned long *mem_start, unsigned long *mem_end, - struct device_node ***allnextpp) -{ - int l; - phandle child; - struct device_node *np; - struct property *pp, **prev_propp; - char *prev_name, *namep; - unsigned char *valp; - unsigned long offset = reloc_offset(); - phandle ibm_phandle; - - np = make_room(mem_start, mem_end, struct device_node); - memset(np, 0, sizeof(*np)); - - np->node = node; - **allnextpp = PTRUNRELOC(np); - *allnextpp = &np->allnext; - if (dad != 0) { - np->parent = PTRUNRELOC(dad); - /* we temporarily use the `next' field as `last_child'. */ - if (dad->next == 0) - dad->child = PTRUNRELOC(np); - else - dad->next->sibling = PTRUNRELOC(np); - dad->next = np; - } - - /* get and store all properties */ - prev_propp = &np->properties; - prev_name = RELOC(""); - for (;;) { - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, char[32]); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { - /* No more nodes: unwind alloc */ - *mem_start = (unsigned long)namep; - break; - } - /* Trim off some if we can */ - *mem_start = DOUBLEWORD_ALIGN((unsigned long)namep - + strlen(namep) + 1); - pp = make_room(mem_start, mem_end, struct property); - pp->name = PTRUNRELOC(namep); - prev_name = namep; - - pp->length = call_prom("getproplen", 2, 1, node, namep); - if (pp->length < 0) - continue; - if (pp->length > MAX_PROPERTY_LENGTH) { - char path[128]; - - prom_printf("WARNING: ignoring large property "); - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - if (call_prom("package-to-path", 3, 1, node, - path, sizeof(path)-1) > 0) - prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", namep, pp->length); - continue; - } - valp = __make_room(mem_start, mem_end, pp->length, 1); - pp->value = PTRUNRELOC(valp); - call_prom("getprop", 4, 1, node, namep, valp, pp->length); - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - } - - /* Add a "linux,phandle" property. */ - namep = make_room(mem_start, mem_end, char[16]); - strcpy(namep, RELOC("linux,phandle")); - pp = make_room(mem_start, mem_end, struct property); - pp->name = PTRUNRELOC(namep); - pp->length = sizeof(phandle); - valp = make_room(mem_start, mem_end, phandle); - pp->value = PTRUNRELOC(valp); - *(phandle *)valp = node; - *prev_propp = PTRUNRELOC(pp); - pp->next = NULL; - - /* Set np->linux_phandle to the value of the ibm,phandle property - if it exists, otherwise to the phandle for this node. */ - np->linux_phandle = node; - if (prom_getprop(node, "ibm,phandle", - &ibm_phandle, sizeof(ibm_phandle)) > 0) - np->linux_phandle = ibm_phandle; - - /* get the node's full name */ - namep = (char *)*mem_start; - l = call_prom("package-to-path", 3, 1, node, - namep, *mem_end - *mem_start); - if (l >= 0) { - /* Didn't fit? Get more room. */ - if (l+1 > *mem_end - *mem_start) { - namep = __make_room(mem_start, mem_end, l+1, 1); - call_prom("package-to-path", 3, 1, node, namep, l); - } - np->full_name = PTRUNRELOC(namep); - namep[l] = '\0'; - *mem_start = DOUBLEWORD_ALIGN(*mem_start + l + 1); - } - - /* do all our children */ - child = call_prom("child", 1, 1, node); - while (child != (phandle)0) { - inspect_node(child, np, mem_start, mem_end, - allnextpp); - child = call_prom("peer", 1, 1, child); - } -} - -/* - * Make a copy of the device tree from the PROM. - */ -static unsigned long __init -copy_device_tree(unsigned long mem_start) -{ - phandle root; - struct device_node **allnextp; - unsigned long offset = reloc_offset(); - unsigned long mem_end; - - /* We pass mem_end-mem_start to OF: keep it well under 32-bit */ - mem_end = mem_start + 1024*1024*1024; -#ifdef CONFIG_BLK_DEV_INITRD - if (RELOC(initrd_start) && RELOC(initrd_start) > mem_start) - mem_end = RELOC(initrd_start); -#endif /* CONFIG_BLK_DEV_INITRD */ - - root = call_prom("peer", 1, 1, (phandle)0); - if (root == (phandle)0) { - prom_panic("couldn't get device tree root\n"); - } - allnextp = &RELOC(allnodes); - inspect_node(root, NULL, &mem_start, &mem_end, &allnextp); - *allnextp = NULL; - return mem_start; -} - -/* Verify bi_recs are good */ -static struct bi_record * __init prom_bi_rec_verify(struct bi_record *bi_recs) -{ - struct bi_record *first, *last; - - prom_debug("birec_verify: r6=0x%x\n", (unsigned long)bi_recs); - if (bi_recs != NULL) - prom_debug(" tag=0x%x\n", bi_recs->tag); - - if ( bi_recs == NULL || bi_recs->tag != BI_FIRST ) - return NULL; - - last = (struct bi_record *)(long)bi_recs->data[0]; - - prom_debug(" last=0x%x\n", (unsigned long)last); - if (last != NULL) - prom_debug(" last_tag=0x%x\n", last->tag); - - if ( last == NULL || last->tag != BI_LAST ) - return NULL; - - first = (struct bi_record *)(long)last->data[0]; - prom_debug(" first=0x%x\n", (unsigned long)first); - - if ( first == NULL || first != bi_recs ) - return NULL; - - return bi_recs; -} - -static void __init prom_bi_rec_reserve(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct bi_record *rec; - - if ( _prom->bi_recs != NULL) { - - for ( rec=_prom->bi_recs; - rec->tag != BI_LAST; - rec=bi_rec_next(rec) ) { - prom_debug("bi: 0x%x\n", rec->tag); - switch (rec->tag) { -#ifdef CONFIG_BLK_DEV_INITRD - case BI_INITRD: - RELOC(initrd_start) = (unsigned long)(rec->data[0]); - RELOC(initrd_end) = RELOC(initrd_start) + rec->data[1]; - break; -#endif /* CONFIG_BLK_DEV_INITRD */ - } - } - /* The next use of this field will be after relocation - * is enabled, so convert this physical address into a - * virtual address. - */ - _prom->bi_recs = PTRUNRELOC(_prom->bi_recs); - } -} - -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. - */ - -unsigned long __init -prom_init(unsigned long r3, unsigned long r4, unsigned long pp, - unsigned long r6, unsigned long r7) -{ - unsigned long mem; - ihandle prom_cpu; - phandle cpu_pkg; - unsigned long offset = reloc_offset(); - long l; - char *p, *d; - unsigned long phys; - u32 getprop_rval; - struct systemcfg *_systemcfg; - struct paca_struct *lpaca = PTRRELOC(&paca[0]); - struct prom_t *_prom = PTRRELOC(&prom); - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); - - /* Setup systemcfg and NACA pointers now */ - RELOC(systemcfg) = _systemcfg = (struct systemcfg *)(SYSTEMCFG_VIRT_ADDR - offset); - RELOC(naca) = (struct naca_struct *)(NACA_VIRT_ADDR - offset); - - /* Init interface to Open Firmware and pickup bi-recs */ - prom_init_client_services(pp); - - /* Init prom stdout device */ - prom_init_stdout(); - - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug("offset=0x%x\n", offset); - prom_debug("->mem=0x%x\n", RELOC(klimit) - offset); - - /* check out if we have bi_recs */ - _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6); - if ( _prom->bi_recs != NULL ) { - RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + - _prom->bi_recs->data[1]); - prom_debug("bi_recs=0x%x\n", (unsigned long)_prom->bi_recs); - prom_debug("new mem=0x%x\n", RELOC(klimit) - offset); - } - - /* If we don't have birec's or didn't find them, check for an initrd - * using the "yaboot" way - */ -#ifdef CONFIG_BLK_DEV_INITRD - if ( _prom->bi_recs == NULL && r3 && r4 && r4 != 0xdeadbeef) { - RELOC(initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; - RELOC(initrd_end) = RELOC(initrd_start) + r4; - RELOC(initrd_below_start_ok) = 1; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Default machine type. */ - _systemcfg->platform = prom_find_machine_type(); - - /* On pSeries, copy the CPU hold code */ - if (_systemcfg->platform == PLATFORM_PSERIES) - copy_and_flush(0, KERNELBASE - offset, 0x100, 0); - - /* Start storing things at klimit */ - mem = RELOC(klimit) - offset; - - /* Get the full OF pathname of the stdout device */ - p = (char *) mem; - memset(p, 0, 256); - call_prom("instance-to-path", 3, 1, _prom->stdout, p, 255); - RELOC(of_stdout_device) = PTRUNRELOC(p); - mem += strlen(p) + 1; - - getprop_rval = 1; - prom_getprop(_prom->root, "#size-cells", - &getprop_rval, sizeof(getprop_rval)); - _prom->encode_phys_size = (getprop_rval == 1) ? 32 : 64; - - /* Determine which cpu is actually running right _now_ */ - if (prom_getprop(_prom->chosen, "cpu", - &prom_cpu, sizeof(prom_cpu)) <= 0) - prom_panic("cannot find boot cpu"); - - cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); - prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); - _prom->cpu = getprop_rval; - lpaca[0].hw_cpu_id = _prom->cpu; - - RELOC(boot_cpuid) = 0; - - prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); - - /* Get the boot device and translate it to a full OF pathname. */ - p = (char *) mem; - l = prom_getprop(_prom->chosen, "bootpath", p, 1<<20); - if (l > 0) { - p[l] = 0; /* should already be null-terminated */ - RELOC(bootpath) = PTRUNRELOC(p); - mem += l + 1; - d = (char *) mem; - *d = 0; - call_prom("canon", 3, 1, p, d, 1<<20); - RELOC(bootdevice) = PTRUNRELOC(d); - mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1); - } - - RELOC(cmd_line[0]) = 0; - if ((long)_prom->chosen > 0) { - prom_getprop(_prom->chosen, "bootargs", p, sizeof(cmd_line)); - if (p != NULL && p[0] != 0) - strlcpy(RELOC(cmd_line), p, sizeof(cmd_line)); - } - - early_cmdline_parse(); - - prom_initialize_lmb(); - - prom_bi_rec_reserve(); - - mem = check_display(mem); - - if (_systemcfg->platform != PLATFORM_POWERMAC) - prom_instantiate_rtas(); - - /* Initialize some system info into the Naca early... */ - prom_initialize_naca(); - - smt_setup(); - - /* If we are on an SMP machine, then we *MUST* do the - * following, regardless of whether we have an SMP - * kernel or not. - */ - prom_hold_cpus(mem); - - prom_debug("after basic inits, mem=0x%x\n", mem); -#ifdef CONFIG_BLK_DEV_INITRD - prom_debug("initrd_start=0x%x\n", RELOC(initrd_start)); - prom_debug("initrd_end=0x%x\n", RELOC(initrd_end)); -#endif /* CONFIG_BLK_DEV_INITRD */ - prom_debug("copying OF device tree...\n"); - - mem = copy_device_tree(mem); - - RELOC(klimit) = mem + offset; +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif - prom_debug("new klimit is\n"); - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug(" ->mem=0x%x\n", mem); +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; - lmb_reserve(0, __pa(RELOC(klimit))); +struct isa_reg_property { + u32 space; + u32 address; + u32 size; +}; -#ifdef CONFIG_BLK_DEV_INITRD - if (RELOC(initrd_start)) { - unsigned long initrd_len; - initrd_len = RELOC(initrd_end) - RELOC(initrd_start); - /* Move initrd if it's where we're going to copy kernel. */ - if (RELOC(initrd_start) < __pa(RELOC(klimit))) { - memmove((void *)mem, (void *)RELOC(initrd_start), - initrd_len); - RELOC(initrd_start) = mem; - RELOC(initrd_end) = mem + initrd_len; - } +typedef unsigned long interpret_func(struct device_node *, unsigned long, + int, int, int); - lmb_reserve(RELOC(initrd_start), initrd_len); - } -#endif /* CONFIG_BLK_DEV_INITRD */ +extern struct rtas_t rtas; +extern struct lmb lmb; +extern unsigned long klimit; - if (_systemcfg->platform == PLATFORM_PSERIES) - prom_initialize_tce_table(); +static int __initdata dt_root_addr_cells; +static int __initdata dt_root_size_cells; +static int __initdata iommu_is_off; +int __initdata iommu_force_on; +typedef u32 cell_t; -#ifdef CONFIG_PMAC_DART - if (_systemcfg->platform == PLATFORM_POWERMAC) - prom_initialize_dart_table(); +#if 0 +static struct boot_param_header *initial_boot_params __initdata; +#else +struct boot_param_header *initial_boot_params; #endif -#ifdef CONFIG_BOOTX_TEXT - if (_prom->disp_node) { - prom_printf("Setting up bi display...\n"); - setup_disp_fake_bi(_prom->disp_node); - } -#endif /* CONFIG_BOOTX_TEXT */ - - prom_printf("Calling quiesce ...\n"); - call_prom("quiesce", 0, 0); - phys = KERNELBASE - offset; +static struct device_node *allnodes = NULL; -#ifdef CONFIG_BLK_DEV_INITRD - /* If we had an initrd, we convert its address to virtual */ - if (RELOC(initrd_start)) { - RELOC(initrd_start) = (unsigned long)__va(RELOC(initrd_start)); - RELOC(initrd_end) = (unsigned long)__va(RELOC(initrd_end)); - } -#endif /* CONFIG_BLK_DEV_INITRD */ +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. + */ +static rwlock_t devtree_lock = RW_LOCK_UNLOCKED; - prom_printf("returning from prom_init\n"); - return phys; -} +/* export that to outside world */ +struct device_node *of_chosen; /* * Find the device_node with a given phandle. */ -static struct device_node * __devinit -find_phandle(phandle ph) +static struct device_node * find_phandle(phandle ph) { struct device_node *np; @@ -1866,8 +118,7 @@ find_phandle(phandle ph) /* * Find the interrupt parent of a node. */ -static struct device_node * __devinit -intr_parent(struct device_node *p) +static struct device_node * __devinit intr_parent(struct device_node *p) { phandle *parp; @@ -1908,14 +159,14 @@ int __devinit prom_n_intr_cells(struct device_node *np) * Map an interrupt from a device up to the platform interrupt * descriptor. */ -static int __devinit -map_interrupt(unsigned int **irq, struct device_node **ictrler, - struct device_node *np, unsigned int *ints, int nintrc) +static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler, + struct device_node *np, unsigned int *ints, + int nintrc) { struct device_node *p, *ipar; unsigned int *imap, *imask, *ip; int i, imaplen, match; - int newintrc, newaddrc; + int newintrc = 0, newaddrc = 0; unsigned int *reg; int naddrc; @@ -2004,9 +255,9 @@ map_interrupt(unsigned int **irq, struct device_node **ictrler, return nintrc; } -static unsigned long __init -finish_node_interrupts(struct device_node *np, unsigned long mem_start, - int measure_only) +static unsigned long __init finish_node_interrupts(struct device_node *np, + unsigned long mem_start, + int measure_only) { unsigned int *ints; int intlen, intrcells, intrcount; @@ -2067,9 +318,10 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start, return mem_start; } -static unsigned long __init -interpret_pci_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_pci_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct address_range *adr; struct pci_reg_property *pci_addrs; @@ -2095,9 +347,10 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start, return mem_start; } -static unsigned long __init -interpret_dbdma_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_dbdma_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct reg_property32 *rp; struct address_range *adr; @@ -2135,9 +388,10 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start, return mem_start; } -static unsigned long __init -interpret_macio_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_macio_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct reg_property32 *rp; struct address_range *adr; @@ -2175,9 +429,10 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start, return mem_start; } -static unsigned long __init -interpret_isa_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_isa_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct isa_reg_property *rp; struct address_range *adr; @@ -2203,9 +458,10 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start, return mem_start; } -static unsigned long __init -interpret_root_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_root_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct address_range *adr; int i, l; @@ -2233,21 +489,15 @@ interpret_root_props(struct device_node *np, unsigned long mem_start, return mem_start; } -static unsigned long __init -finish_node(struct device_node *np, unsigned long mem_start, - interpret_func *ifunc, int naddrc, int nsizec, int measure_only) +static unsigned long __init finish_node(struct device_node *np, + unsigned long mem_start, + interpret_func *ifunc, + int naddrc, int nsizec, + int measure_only) { struct device_node *child; int *ip; - np->name = get_property(np, "name", NULL); - np->type = get_property(np, "device_type", NULL); - - if (!np->name) - np->name = ""; - if (!np->type) - np->type = ""; - /* get the device addresses and interrupts */ if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec, measure_only); @@ -2298,24 +548,516 @@ finish_node(struct device_node *np, unsigned long mem_start, /** * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). - * It traverses the device tree and fills in the name, type, - * {n_}addrs and {n_}intrs fields of each node. + * It traverses the device tree and fills in some of the additional, + * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt + * mapping is also initialized at this point. */ -void __init -finish_device_tree(void) +void __init finish_device_tree(void) { - unsigned long mem = klimit; + unsigned long mem, size; + + DBG(" -> finish_device_tree\n"); + if (naca->interrupt_controller == IC_INVALID) { + DBG("failed to configure interrupt controller type\n"); + panic("failed to configure interrupt controller type\n"); + } + + /* Initialize virtual IRQ map */ virt_irq_init(); - dev_tree_size = finish_node(allnodes, 0, NULL, 0, 0, 1); - mem = (long)abs_to_virt(lmb_alloc(dev_tree_size, - __alignof__(struct device_node))); - if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + dev_tree_size) + /* Finish device-tree (pre-parsing some properties etc...) */ + size = finish_node(allnodes, 0, NULL, 0, 0, 1); + mem = (unsigned long)abs_to_virt(lmb_alloc(size, 128)); + if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + size) BUG(); - rtas.dev = of_find_node_by_name(NULL, "rtas"); + + DBG(" <- finish_device_tree\n"); +} + +#ifdef DEBUG +#define printk udbg_printf +#endif + +static inline char *find_flat_dt_string(u32 offset) +{ + return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings + + offset; +} + +/** + * This function is used to scan the flattened device-tree, it is + * used to extract the memory informations at boot before we can + * unflatten the tree + */ +static int __init scan_flat_dt(int (*it)(unsigned long node, + const char *full_path, void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + int rc = 0; + + do { + u32 tag = *((u32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = *((u32 *)p); + p += 8; + p = _ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = _ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + printk(KERN_WARNING "Invalid tag %x scanning flattened" + " device tree !\n", tag); + return -EINVAL; + } + pathp = (char *)p; + p = _ALIGN(p + strlen(pathp) + 1, 4); + rc = it(p, pathp, data); + if (rc != 0) + break; + } while(1); + + return rc; +} + +/** + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +static void* __init get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = *((u32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag != OF_DT_PROP) + return NULL; + + sz = *((u32 *)p); + noff = *((u32 *)(p + 4)); + p += 8; + p = _ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = find_flat_dt_string(noff); + if (nstr == NULL) { + printk(KERN_WARNING "Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = _ALIGN(p, 4); + } while(1); +} + +static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = _ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +static unsigned long __init unflatten_dt_node(unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp) +{ + struct device_node *np; + struct property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_BEGIN_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = strlen(pathp) + 1; + *p = _ALIGN(*p + l, 4); + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, + __alignof__(struct device_node)); + if (allnextpp) { + memset(np, 0, sizeof(*np)); + np->full_name = ((char*)np) + sizeof(struct device_node); + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if (dad != NULL) { + np->parent = dad; + /* we temporarily use the `next' field as `last_child'. */ + if (dad->next == 0) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + } + while(1) { + u32 sz, noff; + char *pname; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_PROP) + break; + *p += 4; + sz = *((u32 *)(*p)); + noff = *((u32 *)((*p) + 4)); + *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); + + pname = find_flat_dt_string(noff); + if (pname == NULL) { + printk("Can't find property name in list !\n"); + break; + } + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (allnextpp) { + if (strcmp(pname, "linux,phandle") == 0) { + np->node = *((u32 *)*p); + if (np->linux_phandle == 0) + np->linux_phandle = np->node; + } + if (strcmp(pname, "ibm,phandle") == 0) + np->linux_phandle = *((u32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = _ALIGN((*p) + sz, 4); + } + if (allnextpp) { + *prev_pp = NULL; + np->name = get_property(np, "name", NULL); + np->type = get_property(np, "device_type", NULL); + + if (!np->name) + np->name = ""; + if (!np->type) + np->type = ""; + } + while (tag == OF_DT_BEGIN_NODE) { + mem = unflatten_dt_node(mem, p, np, allnextpp); + tag = *((u32 *)(*p)); + } + if (tag != OF_DT_END_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + return mem; +} + + +/** + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used (this used to be done by finish_device_tree) + */ +void __init unflatten_device_tree(void) +{ + unsigned long start, mem, size; + struct device_node **allnextp = &allnodes; + char *p; + int l = 0; + + DBG(" -> unflatten_device_tree()\n"); + + /* First pass, scan for size */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + size = unflatten_dt_node(0, &start, NULL, NULL); + + DBG(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = (unsigned long)abs_to_virt(lmb_alloc(size, + __alignof__(struct device_node))); + DBG(" unflattening...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + unflatten_dt_node(mem, &start, NULL, &allnextp); + if (*((u32 *)start) != OF_DT_END) + printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); + *allnextp = NULL; + + /* Get pointer to OF "/chosen" node for use everywhere */ + of_chosen = of_find_node_by_path("/chosen"); + + /* Retreive command line */ + if (of_chosen != NULL) { + p = (char *)get_property(of_chosen, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); + } +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ + + DBG("Command line is: %s\n", cmd_line); + + DBG(" <- unflatten_device_tree()\n"); +} + + +static int __init early_init_dt_scan_cpus(unsigned long node, + const char *full_path, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + + /* We are scanning "cpu" nodes only */ + if (type == NULL || strcmp(type, "cpu") != 0) + return 0; + + /* On LPAR, look for the first ibm,pft-size property for the hash table size + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && naca->pftSize == 0) { + u32 *pft_size; + pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL); + if (pft_size != NULL) { + /* pft_size[0] is the NUMA CEC cookie */ + naca->pftSize = pft_size[1]; + } + } + + /* Check if it's the boot-cpu, set it's hw index in paca now */ + if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { + u32 *prop = get_flat_dt_prop(node, "reg", NULL); + paca[0].hw_cpu_id = prop == NULL ? 0 : *prop; + } + + return 0; +} + +static int __init early_init_dt_scan_chosen(unsigned long node, + const char *full_path, void *data) +{ + u32 *prop; + + if (strcmp(full_path, "/chosen") != 0) + return 0; + + /* get platform type */ + prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL); + if (prop == NULL) + return 0; + systemcfg->platform = *prop; + + /* check if iommu is forced on or off */ + if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) + iommu_is_off = 1; + if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL) + iommu_force_on = 1; + +#ifdef CONFIG_PPC_PSERIES + /* To help early debugging via the front panel, we retreive a minimal + * set of RTAS infos now if available + */ + { + u64 *basep, *entryp; + + basep = (u64*)get_flat_dt_prop(node, "linux,rtas-base", NULL); + entryp = (u64*)get_flat_dt_prop(node, "linux,rtas-entry", NULL); + prop = (u32*)get_flat_dt_prop(node, "linux,rtas-size", NULL); + if (basep && entryp && prop) { + rtas.base = *basep; + rtas.entry = *entryp; + rtas.size = *prop; + } + } +#endif /* CONFIG_PPC_PSERIES */ + + /* break now */ + return 1; +} + +static int __init early_init_dt_scan_root(unsigned long node, + const char *full_path, void *data) +{ + u32 *prop; + + if (strcmp(full_path, "/") != 0) + return 0; + + prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); + dt_root_size_cells = (prop == NULL) ? 1 : *prop; + + prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); + dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + + /* break now */ + return 1; +} + +static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > 2) { + p++; + s--; + } + while (s) { + r <<= 32; + r |= *(p++); + s--; + } + + *cellp = p; + return r; +} + + +static int __init early_init_dt_scan_memory(unsigned long node, + const char *full_path, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + cell_t *reg, *endp; + unsigned long l; + + /* We are scanning "memory" nodes only */ + if (type == NULL || strcmp(type, "memory") != 0) + return 0; + + reg = (cell_t *)get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(cell_t)); + + DBG("memory scan node %s ...\n", full_path); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + unsigned long base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + if (size == 0) + continue; + DBG(" - %lx , %lx\n", base, size); + if (iommu_is_off) { + if (base >= 0x80000000ul) + continue; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } + lmb_add(base, size); + } + return 0; +} + +static void __init early_reserve_mem(void) +{ + u64 base, size; + u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) + + initial_boot_params->off_mem_rsvmap); + while (1) { + base = *(reserve_map++); + size = *(reserve_map++); + if (size == 0) + break; + DBG("reserving: %lx -> %lx\n", base, size); + lmb_reserve(base, size); + } + +#if 0 + DBG("memory reserved, lmbs :\n"); + lmb_dump_all(); +#endif +} + +void __init early_init_devtree(void *params) +{ + DBG(" -> early_init_devtree()\n"); + + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* By default, hash size is not set */ + naca->pftSize = 0; + + /* Retreive various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size, TCE reserve, and more ... + */ + scan_flat_dt(early_init_dt_scan_chosen, NULL); + + /* Scan memory nodes and rebuild LMBs */ + lmb_init(); + scan_flat_dt(early_init_dt_scan_root, NULL); + scan_flat_dt(early_init_dt_scan_memory, NULL); + lmb_analyze(); + systemcfg->physicalMemorySize = lmb_phys_mem_size(); + + DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize); + + /* Reserve LMB regions used by kernel, initrd, dt, etc... */ + early_reserve_mem(); + + DBG("Scanning CPUs ...\n"); + + /* Retreive hash table size from flattened tree */ + scan_flat_dt(early_init_dt_scan_cpus, NULL); + + /* If hash size wasn't obtained above, we calculate it now based on + * the total RAM size + */ + if (naca->pftSize == 0) { + unsigned long rnd_mem_size, pteg_count; + + /* round mem_size up to next power of 2 */ + rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); + if (rnd_mem_size < systemcfg->physicalMemorySize) + rnd_mem_size <<= 1; + + /* # pages / 2 */ + pteg_count = (rnd_mem_size >> (12 + 1)); + + naca->pftSize = __ilog2(pteg_count << 7); + } + + DBG("Hash pftSize: %x\n", (int)naca->pftSize); + DBG(" <- early_init_devtree()\n"); } +#undef printk + int prom_n_addr_cells(struct device_node* np) { @@ -2627,6 +1369,28 @@ struct device_node *of_find_node_by_path(const char *path) } EXPORT_SYMBOL(of_find_node_by_path); +/** + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + read_lock(&devtree_lock); + for (np = allnodes; np != 0; np = np->allnext) + if (np->linux_phandle == handle) + break; + if (np) + of_node_get(np); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_phandle); + /** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration @@ -2886,6 +1650,7 @@ static int of_finish_dynamic_node_interrupts(struct device_node *node) return 0; } + /* * Fix up the uninitialized fields in a new device node: * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields @@ -2971,12 +1736,14 @@ static int of_finish_dynamic_node(struct device_node *node) /* fixing up iommu_table */ +#ifdef CONFIG_PPC_PSERIES if (strcmp(node->name, "pci") == 0 && get_property(node, "ibm,dma-window", NULL)) { node->bussubno = node->busno; iommu_devnode_init(node); } else node->iommu_table = parent->iommu_table; +#endif /* CONFIG_PPC_PSERIES */ out: of_node_put(parent); @@ -3163,3 +1930,13 @@ print_properties(struct device_node *np) } } #endif + + + + + + + + + + diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c new file mode 100644 index 000000000..f62bda79e --- /dev/null +++ b/arch/ppc64/kernel/prom_init.c @@ -0,0 +1,1714 @@ +/* + * + * + * Procedures for interfacing to Open Firmware. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.com + * + * 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. + */ + +#undef DEBUG_PROM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "open_pic.h" + +#ifdef CONFIG_LOGO_LINUX_CLUT224 +#include +extern const struct linux_logo logo_linux_clut224; +#endif + +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This value does need to be big enough to + * ensure that we don't lose things like the interrupt-map property + * on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) + +/* + * Eventually bump that one up + */ +#define DEVTREE_CHUNK_SIZE 0x100000 + +/* + * This is the size of the local memory reserve map that gets copied + * into the boot params passed to the kernel. That size is totally + * flexible as the kernel just reads the list until it encounters an + * entry with size 0, so it can be changed without breaking binary + * compatibility + */ +#define MEM_RESERVE_MAP_SIZE 8 + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls should be done within prom_init(), and prom_init() + * and all routines called within it must be careful to relocate + * references as necessary. + * + * Note that the bss is cleared *after* prom_init runs, so we have + * to make sure that any static or extern variables it accesses + * are put in the data segment. + */ + + +#define PROM_BUG() do { \ + prom_printf("kernel BUG at %s line 0x%x!\n", \ + RELOC(__FILE__), __LINE__); \ + __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ +} while (0) + +#ifdef DEBUG_PROM +#define prom_debug(x...) prom_printf(x) +#else +#define prom_debug(x...) +#endif + + +typedef u32 prom_arg_t; + +struct prom_args { + u32 service; + u32 nargs; + u32 nret; + prom_arg_t args[10]; + prom_arg_t *rets; /* Pointer to return values in args[16]. */ +}; + +struct prom_t { + unsigned long entry; + ihandle root; + ihandle chosen; + int cpu; + ihandle stdout; + ihandle disp_node; + struct prom_args args; + unsigned long version; + unsigned long root_size_cells; + unsigned long root_addr_cells; +}; + +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; + +struct mem_map_entry { + u64 base; + u64 size; +}; + +typedef u32 cell_t; + +extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); + +extern unsigned long reloc_offset(void); +extern void enter_prom(struct prom_args *args, unsigned long entry); +extern void copy_and_flush(unsigned long dest, unsigned long src, + unsigned long size, unsigned long offset); + +extern unsigned long klimit; + +//int global_width = 640, global_height = 480, global_depth = 8, global_pitch; +//unsigned global_address; +/* prom structure */ +static struct prom_t __initdata prom; + +#define PROM_SCRATCH_SIZE 256 + +static char __initdata of_stdout_device[256]; +static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; + +static unsigned long __initdata dt_header_start; +static unsigned long __initdata dt_struct_start, dt_struct_end; +static unsigned long __initdata dt_string_start, dt_string_end; + +static unsigned long __initdata prom_initrd_start, prom_initrd_end; + +static int __initdata iommu_force_on; +static int __initdata ppc64_iommu_off; +static int __initdata of_platform; + +static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; + +static unsigned long __initdata alloc_top; +static unsigned long __initdata alloc_top_high; +static unsigned long __initdata alloc_bottom; +static unsigned long __initdata rmo_top; +static unsigned long __initdata ram_top; + +static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; +static int __initdata mem_reserve_cnt; + +static cell_t __initdata regbuf[1024]; + + +#define MAX_CPU_THREADS 2 + +/* TO GO */ +#ifdef CONFIG_HMT +struct { + unsigned int pir; + unsigned int threadid; +} hmt_thread_data[NR_CPUS]; +#endif /* CONFIG_HMT */ + +/* + * This are used in calls to call_prom. The 4th and following + * arguments to call_prom should be 32-bit values. 64 bit values + * are truncated to 32 bits (and fortunately don't get interpreted + * as two arguments). + */ +#define ADDR(x) (u32) ((unsigned long)(x) - offset) + +/* This is the one and *ONLY* place where we actually call open + * firmware from, since we need to make sure we're running in 32b + * mode when we do. We switch back to 64b mode upon return. + */ + +#define PROM_ERROR (-1) + +static int __init call_prom(const char *service, int nargs, int nret, ...) +{ + int i; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + va_list list; + + _prom->args.service = ADDR(service); + _prom->args.nargs = nargs; + _prom->args.nret = nret; + _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); + + va_start(list, nret); + for (i=0; i < nargs; i++) + _prom->args.args[i] = va_arg(list, prom_arg_t); + va_end(list); + + for (i=0; i < nret ;i++) + _prom->args.rets[i] = 0; + + enter_prom(&_prom->args, _prom->entry); + + return (nret > 0) ? _prom->args.rets[0] : 0; +} + + +static unsigned int __init prom_claim(unsigned long virt, unsigned long size, + unsigned long align) +{ + return (unsigned int)call_prom("claim", 3, 1, + (prom_arg_t)virt, (prom_arg_t)size, + (prom_arg_t)align); +} + +static void __init prom_print(const char *msg) +{ + const char *p, *q; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if (_prom->stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + ++q; + call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); + } +} + + +static void __init prom_print_hex(unsigned long val) +{ + unsigned long offset = reloc_offset(); + int i, nibbles = sizeof(val)*2; + char buf[sizeof(val)*2+1]; + struct prom_t *_prom = PTRRELOC(&prom); + + for (i = nibbles-1; i >= 0; i--) { + buf[i] = (val & 0xf) + '0'; + if (buf[i] > '9') + buf[i] += ('a'-'0'-10); + val >>= 4; + } + buf[nibbles] = '\0'; + call_prom("write", 3, 1, _prom->stdout, buf, nibbles); +} + + +static void __init prom_printf(const char *format, ...) +{ + unsigned long offset = reloc_offset(); + const char *p, *q, *s; + va_list args; + unsigned long v; + struct prom_t *_prom = PTRRELOC(&prom); + + va_start(args, format); + for (p = PTRRELOC(format); *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + if (*q == '\n') { + ++q; + call_prom("write", 3, 1, _prom->stdout, + ADDR("\r\n"), 2); + continue; + } + ++q; + if (*q == 0) + break; + switch (*q) { + case 's': + ++q; + s = va_arg(args, const char *); + prom_print(s); + break; + case 'x': + ++q; + v = va_arg(args, unsigned long); + prom_print_hex(v); + break; + } + } +} + + +static void __init __attribute__((noreturn)) prom_panic(const char *reason) +{ + unsigned long offset = reloc_offset(); + + prom_print(PTRRELOC(reason)); + /* ToDo: should put up an SRC here */ + call_prom("exit", 0, 0); + + for (;;) /* should never get here */ + ; +} + + +static int __init prom_next_node(phandle *nodep) +{ + phandle node; + + if ((node = *nodep) != 0 + && (*nodep = call_prom("child", 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom("parent", 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + } +} + +static int __init prom_getprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + unsigned long offset = reloc_offset(); + + return call_prom("getprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + +static int __init prom_getproplen(phandle node, const char *pname) +{ + unsigned long offset = reloc_offset(); + + return call_prom("getproplen", 2, 1, node, ADDR(pname)); +} + +static int __init prom_setprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + unsigned long offset = reloc_offset(); + + return call_prom("setprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + + +/* + * Early parsing of the command line passed to the kernel, used for + * the options that affect the iommu + */ +static void __init early_cmdline_parse(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char *opt, *p; + int l = 0; + + RELOC(prom_cmd_line[0]) = 0; + p = RELOC(prom_cmd_line); + if ((long)_prom->chosen > 0) + l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(RELOC(prom_cmd_line), + RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line)); +#endif /* CONFIG_CMDLINE */ + prom_printf("command line: %s\n", RELOC(prom_cmd_line)); + + opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); + if (opt) { + prom_printf("iommu opt is: %s\n", opt); + opt += 6; + while (*opt && *opt == ' ') + opt++; + if (!strncmp(opt, RELOC("off"), 3)) + RELOC(ppc64_iommu_off) = 1; + else if (!strncmp(opt, RELOC("force"), 5)) + RELOC(iommu_force_on) = 1; + } +} + +/* + * Memory allocation strategy... our layout is normally: + * + * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd + * might end up beeing before the kernel though. We assume this won't override + * the final kernel at 0, we have no provision to handle that in this version, + * but it should hopefully never happen. + * + * alloc_top is set to the top of RMO, eventually shrink down if the TCEs overlap + * alloc_bottom is set to the top of kernel/initrd + * + * from there, allocations are done that way : rtas is allocated topmost, and + * the device-tree is allocated from the bottom. We try to grow the device-tree + * allocation as we progress. If we can't, then we fail, we don't currently have + * a facility to restart elsewhere, but that shouldn't be necessary neither + * + * Note that calls to reserve_mem have to be done explicitely, memory allocated + * with either alloc_up or alloc_down isn't automatically reserved. + */ + + +/* + * Allocates memory in the RMO upward from the kernel/initrd + * + * When align is 0, this is a special case, it means to allocate in place + * at the current location of alloc_bottom or fail (that is basically + * extending the previous allocation). Used for the device-tree flattening + */ +static unsigned long __init alloc_up(unsigned long size, unsigned long align) +{ + unsigned long offset = reloc_offset(); + unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); + unsigned long addr = 0; + + prom_debug("alloc_up(%x, %x)\n", size, align); + if (RELOC(ram_top) == 0) + prom_panic("alloc_up() called with mem not initialized\n"); + + if (align) + base = _ALIGN_UP(RELOC(alloc_bottom), align); + else + base = RELOC(alloc_bottom); + + for(; (base + size) <= RELOC(alloc_top); + base = _ALIGN_UP(base + 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if ((int)addr != PROM_ERROR) + break; + addr = 0; + if (align == 0) + break; + } + if (addr == 0) + return 0; + RELOC(alloc_bottom) = addr; + + prom_debug(" -> %x\n", addr); + prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); + prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); + prom_debug(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Allocates memory downard, either from top of RMO, or if highmem + * is set, from the top of RAM. Note that this one doesn't handle + * failures. In does claim memory if highmem is not set. + */ +static unsigned long __init alloc_down(unsigned long size, unsigned long align, + int highmem) +{ + unsigned long offset = reloc_offset(); + unsigned long base, addr = 0; + + prom_debug("alloc_down(%x, %x, %s)\n", size, align, + highmem ? RELOC("(high)") : RELOC("(low)")); + if (RELOC(ram_top) == 0) + prom_panic("alloc_down() called with mem not initialized\n"); + + if (highmem) { + /* Carve out storage for the TCE table. */ + addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align); + if (addr <= RELOC(alloc_bottom)) + return 0; + else { + /* Will we bump into the RMO ? If yes, check out that we + * didn't overlap existing allocations there, if we did, + * we are dead, we must be the first in town ! + */ + if (addr < RELOC(rmo_top)) { + /* Good, we are first */ + if (RELOC(alloc_top) == RELOC(rmo_top)) + RELOC(alloc_top) = RELOC(rmo_top) = addr; + else + return 0; + } + RELOC(alloc_top_high) = addr; + } + goto bail; + } + + base = _ALIGN_DOWN(RELOC(alloc_top) - size, align); + for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if ((int)addr != PROM_ERROR) + break; + addr = 0; + } + if (addr == 0) + return 0; + RELOC(alloc_top) = addr; + + bail: + prom_debug(" -> %x\n", addr); + prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); + prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); + prom_debug(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Parse a "reg" cell + */ +static unsigned long __init prom_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > 2) { + p++; + s--; + } + while (s) { + r <<= 32; + r |= *(p++); + s--; + } + + *cellp = p; + return r; +} + +/* + * Very dumb function for adding to the memory reserve list, but + * we don't need anything smarter at this point + * + * XXX Eventually check for collisions. They should NEVER happen + * if problems seem to show up, it would be a good start to track + * them down. + */ +static void reserve_mem(unsigned long base, unsigned long size) +{ + unsigned long offset = reloc_offset(); + unsigned long top = base + size; + unsigned long cnt = RELOC(mem_reserve_cnt); + + if (size == 0) + return; + + /* We need to always keep one empty entry so that we + * have our terminator with "size" set to 0 since we are + * dumb and just copy this entire array to the boot params + */ + base = _ALIGN_DOWN(base, PAGE_SIZE); + top = _ALIGN_UP(top, PAGE_SIZE); + size = top - base; + + if (cnt >= (MEM_RESERVE_MAP_SIZE - 1)) + prom_panic("Memory reserve map exhausted !\n"); + RELOC(mem_reserve_map)[cnt].base = base; + RELOC(mem_reserve_map)[cnt].size = size; + RELOC(mem_reserve_cnt) = cnt + 1; +} + +/* + * Initialize memory allocation mecanism, parse "memory" nodes and + * obtain that way the top of memory and RMO to setup out local allocator + */ +static void __init prom_init_mem(void) +{ + phandle node; + char *path, type[64]; + unsigned int plen; + cell_t *p, *endp; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + /* + * We iterate the memory nodes to find + * 1) top of RMO (first node) + * 2) top of memory + */ + prom_debug("root_addr_cells: %x\n", (long)_prom->root_addr_cells); + prom_debug("root_size_cells: %x\n", (long)_prom->root_size_cells); + + prom_debug("scanning memory:\n"); + path = RELOC(prom_scratch); + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + + if (strcmp(type, RELOC("memory"))) + continue; + + plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); + if (plen > sizeof(regbuf)) { + prom_printf("memory node too large for buffer !\n"); + plen = sizeof(regbuf); + } + p = RELOC(regbuf); + endp = p + (plen / sizeof(cell_t)); + +#ifdef DEBUG_PROM + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + prom_debug(" node %s :\n", path); +#endif /* DEBUG_PROM */ + + while ((endp - p) >= (_prom->root_addr_cells + _prom->root_size_cells)) { + unsigned long base, size; + + base = prom_next_cell(_prom->root_addr_cells, &p); + size = prom_next_cell(_prom->root_size_cells, &p); + + if (size == 0) + continue; + prom_debug(" %x %x\n", base, size); + if (base == 0) + RELOC(rmo_top) = size; + if ((base + size) > RELOC(ram_top)) + RELOC(ram_top) = base + size; + } + } + + /* Setup our top/bottom alloc points, that is top of RMO or top of + * segment 0 when running non-LPAR + */ + if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR ) + RELOC(alloc_top) = RELOC(rmo_top); + else + RELOC(alloc_top) = min(0x40000000ul, RELOC(ram_top)); + RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000); + RELOC(alloc_top_high) = RELOC(ram_top); + + /* Check if we have an initrd after the kernel, if we do move our bottom + * point to after it + */ + if (RELOC(prom_initrd_start)) { + if ((RELOC(prom_initrd_start) + RELOC(prom_initrd_end)) + > RELOC(alloc_bottom)) + RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end)); + } + + prom_printf("memory layout at init:\n"); + prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); + prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); + prom_printf(" ram_top : %x\n", RELOC(ram_top)); +} + + +/* + * Allocate room for and instanciate RTAS + */ +static void __init prom_instantiate_rtas(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + phandle prom_rtas; + u64 base, entry = 0; + u32 size; + + prom_debug("prom_instantiate_rtas: start...\n"); + + prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (prom_rtas != (phandle) -1) { + prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); + if (size != 0) { + base = alloc_down(size, PAGE_SIZE, 0); + if (base == 0) { + prom_printf("RTAS allocation failed !\n"); + return; + } + prom_printf("instantiating rtas at 0x%x", base); + + prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); + prom_printf("..."); + + if (call_prom("call-method", 3, 2, + ADDR("instantiate-rtas"), + prom_rtas, base) != PROM_ERROR) { + entry = (long)_prom->args.rets[1]; + } + if (entry == 0) { + prom_printf(" failed\n"); + return; + } + prom_printf(" done\n"); + + reserve_mem(base, size); + } + + prom_setprop(_prom->chosen, "linux,rtas-base", &base, sizeof(base)); + prom_setprop(_prom->chosen, "linux,rtas-entry", &entry, sizeof(entry)); + prom_setprop(_prom->chosen, "linux,rtas-size", &size, sizeof(size)); + + prom_debug("rtas base = 0x%x\n", base); + prom_debug("rtas entry = 0x%x\n", entry); + prom_debug("rtas size = 0x%x\n", (long)size); + } + prom_debug("prom_instantiate_rtas: end...\n"); +} + + +/* + * Allocate room for and initialize TCE tables + */ +static void __init prom_initialize_tce_table(void) +{ + phandle node; + ihandle phb_node; + unsigned long offset = reloc_offset(); + char compatible[64], type[64], model[64]; + char *path = RELOC(prom_scratch); + u64 base, vbase, align; + u32 minalign, minsize; + u64 tce_entry, *tce_entryp; + u64 local_alloc_top, local_alloc_bottom; + u64 i; + + if (RELOC(ppc64_iommu_off)) + return; + + prom_debug("starting prom_initialize_tce_table\n"); + + /* Cache current top of allocs so we reserve a single block */ + local_alloc_top = RELOC(alloc_top_high); + local_alloc_bottom = local_alloc_top; + + /* Search all nodes looking for PHBs. */ + for (node = 0; prom_next_node(&node); ) { + compatible[0] = 0; + type[0] = 0; + model[0] = 0; + prom_getprop(node, "compatible", + compatible, sizeof(compatible)); + prom_getprop(node, "device_type", type, sizeof(type)); + prom_getprop(node, "model", model, sizeof(model)); + + if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) + continue; + + /* Keep the old logic in tack to avoid regression. */ + if (compatible[0] != 0) { + if ((strstr(compatible, RELOC("python")) == NULL) && + (strstr(compatible, RELOC("Speedwagon")) == NULL) && + (strstr(compatible, RELOC("Winnipeg")) == NULL)) + continue; + } else if (model[0] != 0) { + if ((strstr(model, RELOC("ython")) == NULL) && + (strstr(model, RELOC("peedwagon")) == NULL) && + (strstr(model, RELOC("innipeg")) == NULL)) + continue; + } + + if (prom_getprop(node, "tce-table-minalign", &minalign, + sizeof(minalign)) == PROM_ERROR) + minalign = 0; + if (prom_getprop(node, "tce-table-minsize", &minsize, + sizeof(minsize)) == PROM_ERROR) + minsize = 4UL << 20; + + /* + * Even though we read what OF wants, we just set the table + * size to 4 MB. This is enough to map 2GB of PCI DMA space. + * By doing this, we avoid the pitfalls of trying to DMA to + * MMIO space and the DMA alias hole. + * + * On POWER4, firmware sets the TCE region by assuming + * each TCE table is 8MB. Using this memory for anything + * else will impact performance, so we always allocate 8MB. + * Anton + */ + if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) + minsize = 8UL << 20; + else + minsize = 4UL << 20; + + /* Align to the greater of the align or size */ + align = max(minalign, minsize); + base = alloc_down(minsize, align, 1); + if (base == 0) + prom_panic("ERROR, cannot find space for TCE table.\n"); + if (base < local_alloc_bottom) + local_alloc_bottom = base; + + vbase = (unsigned long)abs_to_virt(base); + + /* Save away the TCE table attributes for later use. */ + prom_setprop(node, "linux,tce-base", &vbase, sizeof(vbase)); + prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); + prom_setprop(node, "linux,has-tce-table", NULL, 0); + + /* It seems OF doesn't null-terminate the path :-( */ + memset(path, 0, sizeof(path)); + /* Call OF to setup the TCE hardware */ + if (call_prom("package-to-path", 3, 1, node, + path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) { + prom_printf("package-to-path failed\n"); + } + + prom_debug("TCE table: %s\n", path); + prom_debug("\tnode = 0x%x\n", node); + prom_debug("\tbase = 0x%x\n", vbase); + prom_debug("\tsize = 0x%x\n", minsize); + + /* Initialize the table to have a one-to-one mapping + * over the allocated size. + */ + tce_entryp = (unsigned long *)base; + for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { + tce_entry = (i << PAGE_SHIFT); + tce_entry |= 0x3; + *tce_entryp = tce_entry; + } + + prom_printf("opening PHB %s", path); + phb_node = call_prom("open", 1, 1, path); + if ( (long)phb_node <= 0) + prom_printf("... failed\n"); + else + prom_printf("... done\n"); + + call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), + phb_node, -1, minsize, + (u32) base, (u32) (base >> 32)); + call_prom("close", 1, 0, phb_node); + } + + reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); + + /* Flag the first invalid entry */ + prom_debug("ending prom_initialize_tce_table\n"); +} + +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of low memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. The holding pattern + * checks that address until its cpu # is there, when it is that + * cpu jumps to __secondary_start(). smp_boot_cpus() takes care + * of setting those values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * Fixup comment... DRENG / PPPBBB - Peter + * + * -- Cort + */ +static void __init prom_hold_cpus(void) +{ + unsigned long i; + unsigned int reg; + phandle node; + unsigned long offset = reloc_offset(); + char type[64]; + int cpuid = 0; + unsigned int interrupt_server[MAX_CPU_THREADS]; + unsigned int cpu_threads, hw_cpu_num; + int propsize; + extern void __secondary_hold(void); + extern unsigned long __secondary_hold_spinloop; + extern unsigned long __secondary_hold_acknowledge; + unsigned long *spinloop + = (void *)virt_to_abs(&__secondary_hold_spinloop); + unsigned long *acknowledge + = (void *)virt_to_abs(&__secondary_hold_acknowledge); + unsigned long secondary_hold + = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); + struct prom_t *_prom = PTRRELOC(&prom); + + prom_debug("prom_hold_cpus: start...\n"); + prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); + prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); + prom_debug(" 1) acknowledge = 0x%x\n", + (unsigned long)acknowledge); + prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); + prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); + + /* Set the common spinloop variable, so all of the secondary cpus + * will block when they are awakened from their OF spinloop. + * This must occur for both SMP and non SMP kernels, since OF will + * be trashed when we move the kernel. + */ + *spinloop = 0; + +#ifdef CONFIG_HMT + for (i=0; i < NR_CPUS; i++) { + RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; + } +#endif + /* look for cpus */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + + /* Skip non-configured cpus. */ + prom_getprop(node, "status", type, sizeof(type)); + if (strcmp(type, RELOC("okay")) != 0) + continue; + + reg = -1; + prom_getprop(node, "reg", ®, sizeof(reg)); + + prom_debug("\ncpuid = 0x%x\n", cpuid); + prom_debug("cpu hw idx = 0x%x\n", reg); + + /* Init the acknowledge var which will be reset by + * the secondary cpu when it awakens from its OF + * spinloop. + */ + *acknowledge = (unsigned long)-1; + + propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", + &interrupt_server, + sizeof(interrupt_server)); + if (propsize < 0) { + /* no property. old hardware has no SMT */ + cpu_threads = 1; + interrupt_server[0] = reg; /* fake it with phys id */ + } else { + /* We have a threaded processor */ + cpu_threads = propsize / sizeof(u32); + if (cpu_threads > MAX_CPU_THREADS) { + prom_printf("SMT: too many threads!\n" + "SMT: found %x, max is %x\n", + cpu_threads, MAX_CPU_THREADS); + cpu_threads = 1; /* ToDo: panic? */ + } + } + + hw_cpu_num = interrupt_server[0]; + if (hw_cpu_num != _prom->cpu) { + /* Primary Thread of non-boot cpu */ + prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); + call_prom("start-cpu", 3, 0, node, + secondary_hold, cpuid); + + for ( i = 0 ; (i < 100000000) && + (*acknowledge == ((unsigned long)-1)); i++ ) ; + + if (*acknowledge == cpuid) { + prom_printf("done\n"); + /* We have to get every CPU out of OF, + * even if we never start it. */ + if (cpuid >= NR_CPUS) + goto next; + } else { + prom_printf("failed: %x\n", *acknowledge); + } + } +#ifdef CONFIG_SMP + else + prom_printf("%x : boot cpu %x\n", cpuid, reg); +#endif +next: +#ifdef CONFIG_SMP + /* Init paca for secondary threads. They start later. */ + for (i=1; i < cpu_threads; i++) { + cpuid++; + if (cpuid >= NR_CPUS) + continue; + } +#endif /* CONFIG_SMP */ + cpuid++; + } +#ifdef CONFIG_HMT + /* Only enable HMT on processors that provide support. */ + if (__is_processor(PV_PULSAR) || + __is_processor(PV_ICESTAR) || + __is_processor(PV_SSTAR)) { + prom_printf(" starting secondary threads\n"); + + for (i = 0; i < NR_CPUS; i += 2) { + if (!cpu_online(i)) + continue; + + if (i == 0) { + unsigned long pir = mfspr(SPRN_PIR); + if (__is_processor(PV_PULSAR)) { + RELOC(hmt_thread_data)[i].pir = + pir & 0x1f; + } else { + RELOC(hmt_thread_data)[i].pir = + pir & 0x3ff; + } + } + } + } else { + prom_printf("Processor is not HMT capable\n"); + } +#endif + + if (cpuid > NR_CPUS) + prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) + ") exceeded: ignoring extras\n"); + + prom_debug("prom_hold_cpus: end...\n"); +} + + +static void __init prom_init_client_services(unsigned long pp) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + /* Get a handle to the prom entry point before anything else */ + _prom->entry = pp; + + /* Init default value for phys size */ + _prom->root_size_cells = 1; + _prom->root_addr_cells = 2; + + /* get a handle for the stdout device */ + _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); + if ((long)_prom->chosen <= 0) + prom_panic("cannot find chosen"); /* msg won't be printed :( */ + + /* get device tree root */ + _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); + if ((long)_prom->root <= 0) + prom_panic("cannot find device tree root"); /* msg won't be printed :( */ +} + +static void __init prom_init_stdout(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char *path = RELOC(of_stdout_device); + char type[16]; + u32 val; + + if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) + prom_panic("cannot find stdout"); + + _prom->stdout = val; + + /* Get the full OF pathname of the stdout device */ + memset(path, 0, 256); + call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); + val = call_prom("instance-to-package", 1, 1, _prom->stdout); + prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); + prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); + prom_setprop(_prom->chosen, "linux,stdout-path", + RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); + + /* If it's a display, note it */ + memset(type, 0, sizeof(type)); + prom_getprop(val, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) == 0) { + _prom->disp_node = val; + prom_setprop(val, "linux,boot-display", NULL, 0); + } +} + +static int __init prom_find_machine_type(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char compat[256]; + int len, i = 0; + phandle rtas; + + len = prom_getprop(_prom->root, "compatible", + compat, sizeof(compat)-1); + if (len > 0) { + compat[len] = 0; + while (i < len) { + char *p = &compat[i]; + int sl = strlen(p); + if (sl == 0) + break; + if (strstr(p, RELOC("Power Macintosh")) || + strstr(p, RELOC("MacRISC4"))) + return PLATFORM_POWERMAC; + i += sl + 1; + } + } + /* Default to pSeries. We need to know if we are running LPAR */ + rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (rtas != (phandle) -1) { + unsigned long x; + x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (x != PROM_ERROR) { + prom_printf("Hypertas detected, assuming LPAR !\n"); + return PLATFORM_PSERIES_LPAR; + } + } + return PLATFORM_PSERIES; +} + +static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + unsigned long offset = reloc_offset(); + + return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); +} + +/* + * If we have a display that we don't know how to drive, + * we will want to try to execute OF's open method for it + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static unsigned long __init prom_check_displays(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char type[16], *path; + phandle node; + ihandle ih; + int i; + + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + const unsigned char *clut; + + prom_printf("Looking for displays\n"); + for (node = 0; prom_next_node(&node); ) { + memset(type, 0, sizeof(type)); + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) != 0) + continue; + + /* It seems OF doesn't null-terminate the path :-( */ + path = RELOC(prom_scratch); + memset(path, 0, PROM_SCRATCH_SIZE); + + /* + * leave some room at the end of the path for appending extra + * arguments + */ + if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + continue; + prom_printf("found display : %s, opening ... ", path); + + ih = call_prom("open", 1, 1, path); + if (ih == (ihandle)0 || ih == (ihandle)-1) { + prom_printf("failed\n"); + continue; + } + + /* Success */ + prom_printf("done\n"); + prom_setprop(node, "linux,opened", NULL, 0); + + /* + * stdout wasn't a display node, pick the first we can find + * for btext + */ + if (_prom->disp_node == 0) + _prom->disp_node = node; + + /* Setup a useable color table when the appropriate + * method is available. Should update this to set-colors */ + clut = RELOC(default_colors); + for (i = 0; i < 32; i++, clut += 3) + if (prom_set_color(ih, i, clut[0], clut[1], + clut[2]) != 0) + break; + +#ifdef CONFIG_LOGO_LINUX_CLUT224 + clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); + for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) + if (prom_set_color(ih, i + 32, clut[0], clut[1], + clut[2]) != 0) + break; +#endif /* CONFIG_LOGO_LINUX_CLUT224 */ + } +} + + +/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ +static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, + unsigned long needed, unsigned long align) +{ + unsigned long offset = reloc_offset(); + void *ret; + + *mem_start = _ALIGN(*mem_start, align); + while ((*mem_start + needed) > *mem_end) { + unsigned long room, chunk; + + prom_debug("Chunk exhausted, claiming more at %x...\n", + RELOC(alloc_bottom)); + room = RELOC(alloc_top) - RELOC(alloc_bottom); + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + if (room < PAGE_SIZE) + prom_panic("No memory for flatten_device_tree (no room)"); + chunk = alloc_up(room, 0); + if (chunk == 0) + prom_panic("No memory for flatten_device_tree (claim failed)"); + *mem_end = RELOC(alloc_top); + } + + ret = (void *)*mem_start; + *mem_start += needed; + + return ret; +} + +#define dt_push_token(token, mem_start, mem_end) \ + do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0) + +static unsigned long __init dt_find_string(char *str) +{ + unsigned long offset = reloc_offset(); + char *s, *os; + + s = os = (char *)RELOC(dt_string_start); + s += 4; + while (s < (char *)RELOC(dt_string_end)) { + if (strcmp(s, str) == 0) + return s - os; + s += strlen(s) + 1; + } + return 0; +} + +static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + unsigned long offset = reloc_offset(); + char *prev_name, *namep, *sstart; + unsigned long soff; + phandle child; + + sstart = (char *)RELOC(dt_string_start); + + /* get and store all property names */ + prev_name = RELOC(""); + for (;;) { + + /* 32 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, 32, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + /* No more nodes: unwind alloc */ + *mem_start = (unsigned long)namep; + break; + } + soff = dt_find_string(namep); + if (soff != 0) { + *mem_start = (unsigned long)namep; + namep = sstart + soff; + } else { + /* Trim off some if we can */ + *mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = *mem_start; + } + prev_name = namep; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (phandle)0) { + scan_dt_build_strings(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } +} + +static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + int l, align; + phandle child; + char *namep, *prev_name, *sstart; + unsigned long soff; + unsigned char *valp; + unsigned long offset = reloc_offset(); + char pname[32]; + char *path; + + path = RELOC(prom_scratch); + + dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); + + /* get the node's full name */ + namep = (char *)*mem_start; + l = call_prom("package-to-path", 3, 1, node, + namep, *mem_end - *mem_start); + if (l >= 0) { + /* Didn't fit? Get more room. */ + if (l+1 > *mem_end - *mem_start) { + namep = make_room(mem_start, mem_end, l+1, 1); + call_prom("package-to-path", 3, 1, node, namep, l); + } + namep[l] = '\0'; + *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); + } + + /* get it again for debugging */ + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + + /* get and store all properties */ + prev_name = RELOC(""); + sstart = (char *)RELOC(dt_string_start); + for (;;) { + if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + break; + + /* find string offset */ + soff = dt_find_string(pname); + if (soff == 0) { + prom_printf("WARNING: Can't find string index for <%s>, node %s\n", + pname, path); + break; + } + prev_name = sstart + soff; + + /* get length */ + l = call_prom("getproplen", 2, 1, node, pname); + + /* sanity checks */ + if (l < 0) + continue; + if (l > MAX_PROPERTY_LENGTH) { + prom_printf("WARNING: ignoring large property "); + /* It seems OF doesn't null-terminate the path :-( */ + prom_printf("[%s] ", path); + prom_printf("%s length 0x%x\n", pname, l); + continue; + } + + /* push property head */ + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(l, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + + /* push property content */ + align = (l >= 8) ? 8 : 4; + valp = make_room(mem_start, mem_end, l, align); + call_prom("getprop", 4, 1, node, pname, valp, l); + *mem_start = _ALIGN(*mem_start, 4); + } + + /* Add a "linux,phandle" property. */ + soff = dt_find_string(RELOC("linux,phandle")); + if (soff == 0) + prom_printf("WARNING: Can't find string index for " + " node %s\n", path); + else { + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(4, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + valp = make_room(mem_start, mem_end, 4, 4); + *(u32 *)valp = node; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (phandle)0) { + scan_dt_build_struct(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } + + dt_push_token(OF_DT_END_NODE, mem_start, mem_end); +} + +static void __init flatten_device_tree(void) +{ + phandle root; + unsigned long offset = reloc_offset(); + unsigned long mem_start, mem_end, room; + struct boot_param_header *hdr; + char *namep; + u64 *rsvmap; + + /* + * Check how much room we have between alloc top & bottom (+/- a + * few pages), crop to 4Mb, as this is our "chuck" size + */ + room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); + + /* Now try to claim that */ + mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); + if (mem_start == 0) + prom_panic("Can't allocate initial device-tree chunk\n"); + mem_end = RELOC(alloc_top); + + /* Get root of tree */ + root = call_prom("peer", 1, 1, (phandle)0); + if (root == (phandle)0) + prom_panic ("couldn't get device tree root\n"); + + /* Build header and make room for mem rsv map */ + mem_start = _ALIGN(mem_start, 4); + hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); + RELOC(dt_header_start) = (unsigned long)hdr; + rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); + + /* Start of strings */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_string_start) = mem_start; + mem_start += 4; /* hole */ + + /* Add "linux,phandle" in there, we'll need it */ + namep = make_room(&mem_start, &mem_end, 16, 1); + strcpy(namep, RELOC("linux,phandle")); + mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = mem_start; + + /* Build string array */ + prom_printf("Building dt strings...\n"); + scan_dt_build_strings(root, &mem_start, &mem_end); + + /* Build structure */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_struct_start) = mem_start; + prom_printf("Building dt structure...\n"); + scan_dt_build_struct(root, &mem_start, &mem_end); + dt_push_token(OF_DT_END, &mem_start, &mem_end); + RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); + + /* Finish header */ + hdr->magic = OF_DT_HEADER; + hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); + hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); + hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); + hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); + hdr->version = OF_DT_VERSION; + hdr->last_comp_version = 1; + + /* Reserve the whole thing and copy the reserve map in, we + * also bump mem_reserve_cnt to cause further reservations to + * fail since it's too late. + */ + reserve_mem(RELOC(dt_header_start), hdr->totalsize); + memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); + +#ifdef DEBUG_PROM + { + int i; + prom_printf("reserved memory map:\n"); + for (i = 0; i < RELOC(mem_reserve_cnt); i++) + prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base, + RELOC(mem_reserve_map)[i].size); + } +#endif + RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; + + prom_printf("Device tree strings 0x%x -> 0x%x\n", + RELOC(dt_string_start), RELOC(dt_string_end)); + prom_printf("Device tree struct 0x%x -> 0x%x\n", + RELOC(dt_struct_start), RELOC(dt_struct_end)); + + } + +static void __init prom_find_boot_cpu(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + u32 getprop_rval; + ihandle prom_cpu; + phandle cpu_pkg; + + if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) + prom_panic("cannot find boot cpu"); + + cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); + + prom_setprop(cpu_pkg, "linux,boot-cpu", NULL, 0); + prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); + _prom->cpu = getprop_rval; + + prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); +} + +static void __init prom_check_initrd(unsigned long r3, unsigned long r4) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if ( r3 && r4 && r4 != 0xdeadbeef) { + u64 val; + + RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; + RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; + + val = (u64)RELOC(prom_initrd_start); + prom_setprop(_prom->chosen, "linux,initrd-start", &val, sizeof(val)); + val = (u64)RELOC(prom_initrd_end); + prom_setprop(_prom->chosen, "linux,initrd-end", &val, sizeof(val)); + + reserve_mem(RELOC(prom_initrd_start), + RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); + + prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); + prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ + +unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, + unsigned long r6, unsigned long r7) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + unsigned long phys = KERNELBASE - offset; + u32 getprop_rval; + + /* + * First zero the BSS + */ + memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); + + /* + * Init interface to Open Firmware, get some node references, + * like /chosen + */ + prom_init_client_services(pp); + + /* + * Init prom stdout device + */ + prom_init_stdout(); + prom_debug("klimit=0x%x\n", RELOC(klimit)); + prom_debug("offset=0x%x\n", offset); + + /* + * Reserve kernel in reserve map + */ + reserve_mem(0, __pa(RELOC(klimit))); + + /* + * Check for an initrd + */ + prom_check_initrd(r3, r4); + + /* + * Get default machine type. At this point, we do not differenciate + * between pSeries SMP and pSeries LPAR + */ + RELOC(of_platform) = prom_find_machine_type(); + getprop_rval = RELOC(of_platform); + prom_setprop(_prom->chosen, "linux,platform", + &getprop_rval, sizeof(getprop_rval)); + + /* + * On pSeries, copy the CPU hold code + */ + if (RELOC(of_platform) & PLATFORM_PSERIES) + copy_and_flush(0, KERNELBASE - offset, 0x100, 0); + + /* + * Get memory cells format + */ + getprop_rval = 1; + prom_getprop(_prom->root, "#size-cells", + &getprop_rval, sizeof(getprop_rval)); + _prom->root_size_cells = getprop_rval; + getprop_rval = 2; + prom_getprop(_prom->root, "#address-cells", + &getprop_rval, sizeof(getprop_rval)); + _prom->root_addr_cells = getprop_rval; + + /* + * Do early parsing of command line + */ + early_cmdline_parse(); + + /* + * Initialize memory management within prom_init + */ + prom_init_mem(); + + /* + * Determine which cpu is actually running right _now_ + */ + prom_find_boot_cpu(); + + /* + * Initialize display devices + */ + prom_check_displays(); + + /* + * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else + * that uses the allocator, we need to make sure we get the top of memory + * available for us here... + */ + if (RELOC(of_platform) == PLATFORM_PSERIES) + prom_initialize_tce_table(); + + /* + * On non-powermacs, try to instantiate RTAS and puts all CPUs + * in spin-loops. PowerMacs don't have a working RTAS and use + * a different way to spin CPUs + */ + if (RELOC(of_platform) != PLATFORM_POWERMAC) { + prom_instantiate_rtas(); + prom_hold_cpus(); + } + + /* + * Fill in some infos for use by the kernel later on + */ + if (RELOC(ppc64_iommu_off)) + prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); + if (RELOC(iommu_force_on)) + prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); + + /* + * Now finally create the flattened device-tree + */ + prom_printf("copying OF device tree ...\n"); + flatten_device_tree(); + + /* + * Call OF "quiesce" method to shut down pending DMA's from + * devices etc... + */ + prom_printf("Calling quiesce ...\n"); + call_prom("quiesce", 0, 0); + + /* + * And finally, call the kernel passing it the flattened device + * tree and NULL as r5, thus triggering the new entry point which + * is common to us and kexec + */ + prom_printf("returning from prom_init\n"); + prom_debug("->dt_header_start=0x%x\n", RELOC(dt_header_start)); + prom_debug("->phys=0x%x\n", phys); + + __start(RELOC(dt_header_start), phys, 0); + + return 0; +} + diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c index 595ae6ec2..75ced99c5 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/ppc64/kernel/ras.c @@ -161,7 +161,8 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) RAS_VECTOR_OFFSET, virt_irq_to_real(irq_offset_down(irq)), RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, - critical, __pa(&ras_log_buf), RTAS_ERROR_LOG_MAX); + critical, __pa(&ras_log_buf), + rtas_get_error_log_max()); udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n", *((unsigned long *)&ras_log_buf), status, state); @@ -196,11 +197,12 @@ ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) RAS_VECTOR_OFFSET, virt_irq_to_real(irq_offset_down(irq)), RTAS_INTERNAL_ERROR, 1 /*Time Critical */, - __pa(&ras_log_buf), RTAS_ERROR_LOG_MAX); + __pa(&ras_log_buf), + rtas_get_error_log_max()); rtas_elog = (struct rtas_error_log *)ras_log_buf; - if ((status == 0) && (rtas_elog->severity >= SEVERITY_ERROR_SYNC)) + if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC)) fatal = 1; else fatal = 0; diff --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c index a055759b6..bd75066cc 100644 --- a/arch/ppc64/kernel/rtas-proc.c +++ b/arch/ppc64/kernel/rtas-proc.c @@ -580,7 +580,7 @@ static void ppc_rtas_process_sensor(struct seq_file *m, } break; case THERMAL_SENSOR: - seq_printf(m, "Temp. (°C/°F):\t"); + seq_printf(m, "Temp. (C/F):\t"); temperature = 1; break; case LID_STATUS: diff --git a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c index 438d258dc..becb652e1 100644 --- a/arch/ppc64/kernel/rtas.c +++ b/arch/ppc64/kernel/rtas.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -37,17 +36,22 @@ struct rtas_t rtas = { .lock = SPIN_LOCK_UNLOCKED }; +EXPORT_SYMBOL(rtas); + char rtas_err_buf[RTAS_ERROR_LOG_MAX]; spinlock_t rtas_data_buf_lock = SPIN_LOCK_UNLOCKED; char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; +unsigned long rtas_rmo_buf; void -call_rtas_display_status(char c) +call_rtas_display_status(unsigned char c) { struct rtas_args *args = &rtas.args; unsigned long s; + if (!rtas.base) + return; spin_lock_irqsave(&rtas.lock, s); args->token = 10; @@ -61,6 +65,31 @@ call_rtas_display_status(char c) spin_unlock_irqrestore(&rtas.lock, s); } +void +call_rtas_display_status_delay(unsigned char c) +{ + static int pending_newline = 0; /* did last write end with unprinted newline? */ + static int width = 16; + + if (c == '\n') { + while (width-- > 0) + call_rtas_display_status(' '); + width = 16; + udelay(500000); + pending_newline = 1; + } else { + if (pending_newline) { + call_rtas_display_status('\r'); + call_rtas_display_status('\n'); + } + pending_newline = 0; + if (width--) { + call_rtas_display_status(c); + udelay(10000); + } + } +} + int rtas_token(const char *service) { @@ -73,7 +102,6 @@ rtas_token(const char *service) return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; } - /** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, @@ -84,28 +112,32 @@ static int __fetch_rtas_last_error(void) { struct rtas_args err_args, save_args; + u32 bufsz; + + bufsz = rtas_token ("rtas-error-log-max"); + if ((bufsz == RTAS_UNKNOWN_SERVICE) || + (bufsz > RTAS_ERROR_LOG_MAX)) { + printk (KERN_WARNING "RTAS: bad log buffer size %d\n", bufsz); + bufsz = RTAS_ERROR_LOG_MAX; + } err_args.token = rtas_token("rtas-last-error"); err_args.nargs = 2; err_args.nret = 1; - err_args.rets = (rtas_arg_t *)&(err_args.args[2]); err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); - err_args.args[1] = RTAS_ERROR_LOG_MAX; + err_args.args[1] = bufsz; err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; - PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", - __pa(&err_args)); enter_rtas(__pa(&rtas.args)); - PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); err_args = rtas.args; rtas.args = save_args; - return err_args.rets[0]; + return err_args.args[2]; } int rtas_call(int token, int nargs, int nret, int *outputs, ...) @@ -165,9 +197,12 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { - buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); - if (buff_copy) { - memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); + buff_copy = rtas_err_buf; + if (mem_init_done) { + buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); + if (buff_copy) + memcpy(buff_copy, rtas_err_buf, + RTAS_ERROR_LOG_MAX); } } @@ -176,7 +211,8 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); - kfree(buff_copy); + if (mem_init_done) + kfree(buff_copy); } return ret; } @@ -417,7 +453,6 @@ void rtas_os_term(char *str) } while (status == RTAS_BUSY); } -unsigned long rtas_rmo_buf = 0; asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { @@ -508,6 +543,73 @@ void rtas_stop_self(void) } #endif /* CONFIG_HOTPLUG_CPU */ +/* + * Return the firmware-specified size of the error log buffer + * for all rtas calls that require an error buffer argument. + * This includes 'check-exception' and 'rtas-last-error'. + */ +int rtas_get_error_log_max(void) +{ + static int rtas_error_log_max; + if (rtas_error_log_max) + return rtas_error_log_max; + + rtas_error_log_max = rtas_token ("rtas-error-log-max"); + if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) || + (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) { + printk (KERN_WARNING "RTAS: bad log buffer size %d\n", rtas_error_log_max); + rtas_error_log_max = RTAS_ERROR_LOG_MAX; + } + return rtas_error_log_max; +} + +/* + * Call early during boot, before mem init or bootmem, to retreive the RTAS + * informations from the device-tree and allocate the RMO buffer for userland + * accesses. + */ +void __init rtas_initialize(void) +{ + /* Get RTAS dev node and fill up our "rtas" structure with infos + * about it. + */ + rtas.dev = of_find_node_by_name(NULL, "rtas"); + if (rtas.dev) { + u64 *basep, *entryp; + u32 *sizep; + + basep = (u64 *)get_property(of_chosen, "linux,rtas-base", NULL); + sizep = (u32 *)get_property(of_chosen, "linux,rtas-size", NULL); + if (basep != NULL && sizep != NULL) { + rtas.base = *basep; + rtas.size = *sizep; + entryp = (u64 *)get_property(of_chosen, "linux,rtas-entry", NULL); + if (entryp == NULL) /* Ugh */ + rtas.entry = rtas.base; + else + rtas.entry = *entryp; + } else + rtas.dev = NULL; + } + /* If RTAS was found, allocate the RMO buffer for it and look for + * the stop-self token if any + */ + if (rtas.dev) { + unsigned long rtas_region = RTAS_INSTANTIATE_MAX; + if (systemcfg->platform == PLATFORM_PSERIES_LPAR) + rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); + + rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, + rtas_region); + +#ifdef CONFIG_HOTPLUG_CPU + rtas_stop_self_args.token = rtas_token("stop-self"); +#endif /* CONFIG_HOTPLUG_CPU */ + } + +} + + EXPORT_SYMBOL(rtas_firmware_flash_list); EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); @@ -518,3 +620,4 @@ EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); EXPORT_SYMBOL(rtas_set_indicator); +EXPORT_SYMBOL(rtas_get_error_log_max); diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c index 7538cea27..c6370a8e3 100644 --- a/arch/ppc64/kernel/rtasd.c +++ b/arch/ppc64/kernel/rtasd.c @@ -46,6 +46,8 @@ static unsigned int rtas_event_scan_rate; static unsigned int rtas_error_log_max; static unsigned int rtas_error_log_buffer_max; +static int full_rtas_msgs = 0; + extern volatile int no_more_logging; volatile int error_log_cnt = 0; @@ -57,6 +59,37 @@ volatile int error_log_cnt = 0; */ static unsigned char logdata[RTAS_ERROR_LOG_MAX]; +static int get_eventscan_parms(void); + +static char *rtas_type[] = { + "Unknown", "Retry", "TCE Error", "Internal Device Failure", + "Timeout", "Data Parity", "Address Parity", "Cache Parity", + "Address Invalid", "ECC Uncorrected", "ECC Corrupted", +}; + +static char *rtas_event_type(int type) +{ + if ((type > 0) && (type < 11)) + return rtas_type[type]; + + switch (type) { + case RTAS_TYPE_EPOW: + return "EPOW"; + case RTAS_TYPE_PLATFORM: + return "Platform Error"; + case RTAS_TYPE_IO: + return "I/O Event"; + case RTAS_TYPE_INFO: + return "Platform Information Event"; + case RTAS_TYPE_DEALLOC: + return "Resource Deallocation Event"; + case RTAS_TYPE_DUMP: + return "Dump Notification Event"; + } + + return rtas_type[0]; +} + /* To see this info, grep RTAS /var/log/messages and each entry * will be collected together with obvious begin/end. * There will be a unique identifier on the begin and end lines. @@ -73,38 +106,48 @@ static unsigned char logdata[RTAS_ERROR_LOG_MAX]; static void printk_log_rtas(char *buf, int len) { - int i,j,n; + int i,j,n = 0; int perline = 16; char buffer[64]; char * str = "RTAS event"; - printk(RTAS_DEBUG "%d -------- %s begin --------\n", error_log_cnt, str); - - /* - * Print perline bytes on each line, each line will start - * with RTAS and a changing number, so syslogd will - * print lines that are otherwise the same. Separate every - * 4 bytes with a space. - */ - for (i=0; i < len; i++) { - j = i % perline; - if (j == 0) { - memset(buffer, 0, sizeof(buffer)); - n = sprintf(buffer, "RTAS %d:", i/perline); + if (full_rtas_msgs) { + printk(RTAS_DEBUG "%d -------- %s begin --------\n", + error_log_cnt, str); + + /* + * Print perline bytes on each line, each line will start + * with RTAS and a changing number, so syslogd will + * print lines that are otherwise the same. Separate every + * 4 bytes with a space. + */ + for (i = 0; i < len; i++) { + j = i % perline; + if (j == 0) { + memset(buffer, 0, sizeof(buffer)); + n = sprintf(buffer, "RTAS %d:", i/perline); + } + + if ((i % 4) == 0) + n += sprintf(buffer+n, " "); + + n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); + + if (j == (perline-1)) + printk(KERN_DEBUG "%s\n", buffer); } + if ((i % perline) != 0) + printk(KERN_DEBUG "%s\n", buffer); - if ((i % 4) == 0) - n += sprintf(buffer+n, " "); - - n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); + printk(RTAS_DEBUG "%d -------- %s end ----------\n", + error_log_cnt, str); + } else { + struct rtas_error_log *errlog = (struct rtas_error_log *)buf; - if (j == (perline-1)) - printk(KERN_DEBUG "%s\n", buffer); + printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", + error_log_cnt, rtas_event_type(errlog->type), + errlog->severity); } - if ((i % perline) != 0) - printk(KERN_DEBUG "%s\n", buffer); - - printk(RTAS_DEBUG "%d -------- %s end ----------\n", error_log_cnt, str); } static int log_rtas_len(char * buf) @@ -121,6 +164,9 @@ static int log_rtas_len(char * buf) len += err->extended_log_length; } + if (rtas_error_log_max == 0) { + get_eventscan_parms(); + } if (len > rtas_error_log_max) len = rtas_error_log_max; @@ -148,7 +194,6 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) int len = 0; DEBUG("logging event\n"); - if (buf == NULL) return; @@ -171,6 +216,14 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) if (!no_more_logging && !(err_type & ERR_FLAG_BOOT)) nvram_write_error_log(buf, len, err_type); + /* + * rtas errors can occur during boot, and we do want to capture + * those somewhere, even if nvram isn't ready (why not?), and even + * if rtasd isn't ready. Put them into the boot log, at least. + */ + if ((err_type & ERR_TYPE_MASK) == ERR_TYPE_RTAS_LOG) + printk_log_rtas(buf, len); + /* Check to see if we need to or have stopped logging */ if (fatal || no_more_logging) { no_more_logging = 1; @@ -181,9 +234,6 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) /* call type specific method for error */ switch (err_type & ERR_TYPE_MASK) { case ERR_TYPE_RTAS_LOG: - /* put into syslog and error_log file */ - printk_log_rtas(buf, len); - offset = rtas_error_log_buffer_max * ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); @@ -291,15 +341,18 @@ static int enable_surveillance(int timeout) { int error; - error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, - SURVEILLANCE_TOKEN, 0, timeout); + error = rtas_set_indicator(SURVEILLANCE_TOKEN, 0, timeout); - if (error) { - printk(KERN_ERR "rtasd: could not enable surveillance\n"); - return -1; + if (error == 0) + return 0; + + if (error == RTAS_NO_SUCH_INDICATOR) { + printk(KERN_INFO "rtasd: surveillance not supported\n"); + return 0; } - return 0; + printk(KERN_ERR "rtasd: could not update surveillance\n"); + return -1; } static int get_eventscan_parms(void) @@ -318,21 +371,8 @@ static int get_eventscan_parms(void) rtas_event_scan_rate = *ip; DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); - ip = (int *)get_property(node, "rtas-error-log-max", NULL); - if (ip == NULL) { - printk(KERN_ERR "rtasd: no rtas-error-log-max\n"); - of_node_put(node); - return -1; - } - rtas_error_log_max = *ip; - DEBUG("rtas-error-log-max %d\n", rtas_error_log_max); - - if (rtas_error_log_max > RTAS_ERROR_LOG_MAX) { - printk(KERN_ERR "rtasd: truncated error log from %d to %d bytes\n", rtas_error_log_max, RTAS_ERROR_LOG_MAX); - rtas_error_log_max = RTAS_ERROR_LOG_MAX; - } - /* Make room for the sequence number */ + rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); of_node_put(node); @@ -473,5 +513,15 @@ static int __init surveillance_setup(char *str) return 1; } +static int __init rtasmsgs_setup(char *str) +{ + if (strcmp(str, "on") == 0) + full_rtas_msgs = 1; + else if (strcmp(str, "off") == 0) + full_rtas_msgs = 0; + + return 1; +} __initcall(rtas_init); __setup("surveillance=", surveillance_setup); +__setup("rtasmsgs=", rtasmsgs_setup); diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 7bf41f3ca..536a49918 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -34,8 +34,8 @@ #include #include #include +#include -#include #include #include #include diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index dc090d425..1951866a7 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -10,6 +10,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -47,60 +50,79 @@ #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* + * Here are some early debugging facilities. You can enable one + * but your kernel will not boot on anything else if you do so + */ + +/* This one is for use on LPAR machines that support an HVC console + * on vterm 0 + */ +extern void udbg_init_debug_lpar(void); +/* This one is for use on Apple G5 machines + */ +extern void udbg_init_pmac_realmode(void); +/* That's RTAS panel debug */ +extern void call_rtas_display_status_delay(unsigned char c); + +#define EARLY_DEBUG_INIT() do {} while(0) + +#if 0 +#define EARLY_DEBUG_INIT() udbg_init_debug_lpar() +#define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() +#define EARLY_DEBUG_INIT() \ + do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) +#endif -extern unsigned long klimit; /* extern void *stab; */ extern HTAB htab_data; -extern unsigned long loops_per_jiffy; - -int have_of = 1; +extern unsigned long klimit; -extern void chrp_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); - -extern void pmac_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); - -extern void iSeries_init( void ); -extern void iSeries_init_early( void ); -extern void pSeries_init_early( void ); -extern void pSeriesLP_init_early(void); -extern void pmac_init_early(void); -extern void mm_init_ppc64( void ); -extern void pseries_secondary_smp_init(unsigned long); +extern void mm_init_ppc64(void); extern int idle_setup(void); -extern void vpa_init(int cpu); +extern void stab_initialize(unsigned long stab); +extern void htab_initialize(void); +extern void early_init_devtree(void *flat_dt); +extern void unflatten_device_tree(void); unsigned long decr_overclock = 1; unsigned long decr_overclock_proc0 = 1; unsigned long decr_overclock_set = 0; unsigned long decr_overclock_proc0_set = 0; -int powersave_nap; +int have_of = 1; +int boot_cpuid = 0; +dev_t boot_dev; -unsigned char aux_device_present; +/* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. + */ +int dcache_bsize; +int icache_bsize; +int ucache_bsize; -void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7); -int parse_bootinfo(void); +/* The main machine-dep calls structure + */ +struct machdep_calls ppc_md; #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; #endif /* CONFIG_MAGIC_SYSRQ */ -struct machdep_calls ppc_md; static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); - static struct notifier_block ppc64_panic_block = { - notifier_call: ppc64_panic_event, - priority: INT_MIN /* may not return; must be done last */ + .notifier_call = ppc64_panic_event, + .priority = INT_MIN /* may not return; must be done last */ }; /* @@ -112,42 +134,32 @@ static struct notifier_block ppc64_panic_block = { * these processors use on existing boards. -- Dan */ struct screen_info screen_info = { - 0, 25, /* orig-x, orig-y */ - 0, /* unused */ - 0, /* orig-video-page */ - 0, /* orig-video-mode */ - 80, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 25, /* orig-video-lines */ - 1, /* orig-video-isVGA */ - 16 /* orig-video-points */ + .orig_x = 0, + .orig_y = 25, + .orig_video_cols = 80, + .orig_video_lines = 25, + .orig_video_isVGA = 1, + .orig_video_points = 16 }; -/* - * These are used in binfmt_elf.c to put aux entries on the stack - * for each elf executable being started. - */ -int dcache_bsize; -int icache_bsize; -int ucache_bsize; - /* * Initialize the PPCDBG state. Called before relocation has been enabled. */ -void ppcdbg_initialize(void) { - unsigned long offset = reloc_offset(); - struct naca_struct *_naca = RELOC(naca); - - _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; +void __init ppcdbg_initialize(void) +{ + naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ + /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; } +/* + * Early boot console based on udbg + */ static struct console udbg_console = { .name = "udbg", .write = udbg_console_write, .flags = CON_PRINTBUFFER, .index = -1, }; - static int early_console_initialized; void __init disable_early_printk(void) @@ -158,111 +170,457 @@ void __init disable_early_printk(void) early_console_initialized = 0; } -/* - * Do some initial setup of the system. The parameters are those which - * were passed in from the bootloader. +#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) + +static int smt_enabled_cmdline; + +/* Look for ibm,smt-enabled OF option */ +static void check_smt_enabled(void) +{ + struct device_node *dn; + char *smt_option; + + /* Allow the command line to overrule the OF option */ + if (smt_enabled_cmdline) + return; + + dn = of_find_node_by_path("/options"); + + if (dn) { + smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); + + if (smt_option) { + if (!strcmp(smt_option, "on")) + smt_enabled_at_boot = 1; + else if (!strcmp(smt_option, "off")) + smt_enabled_at_boot = 0; + } + } +} + +/* Look for smt-enabled= cmdline option */ +static int __init early_smt_enabled(char *p) +{ + smt_enabled_cmdline = 1; + + if (!p) + return 0; + + if (!strcmp(p, "on") || !strcmp(p, "1")) + smt_enabled_at_boot = 1; + else if (!strcmp(p, "off") || !strcmp(p, "0")) + smt_enabled_at_boot = 0; + + return 0; +} +early_param("smt-enabled", early_smt_enabled); + +/** + * setup_cpu_maps - initialize the following cpu maps: + * cpu_possible_map + * cpu_present_map + * cpu_sibling_map + * + * Having the possible map set up early allows us to restrict allocations + * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. + * + * We do not initialize the online map here; cpus set their own bits in + * cpu_online_map as they come up. + * + * This function is valid only for Open Firmware systems. finish_device_tree + * must be called before using this. + * + * While we're here, we may as well set the "physical" cpu ids in the paca. */ -void setup_system(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +static void __init setup_cpu_maps(void) { -#if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES) - int ret, i; -#endif + struct device_node *dn = NULL; + int cpu = 0; + + check_smt_enabled(); + + while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { + u32 *intserv; + int j, len = sizeof(u32), nthreads; + + intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", + &len); + if (!intserv) + intserv = (u32 *)get_property(dn, "reg", NULL); + + nthreads = len / sizeof(u32); + + for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { + /* + * Only spin up secondary threads if SMT is enabled. + * We must leave space in the logical map for the + * threads. + */ + if (j == 0 || smt_enabled_at_boot) { + cpu_set(cpu, cpu_present_map); + set_hard_smp_processor_id(cpu, intserv[j]); + } + cpu_set(cpu, cpu_possible_map); + cpu++; + } + } -#ifdef CONFIG_XMON_DEFAULT - xmon_init(); -#endif + /* + * On pSeries LPAR, we need to know how many cpus + * could possibly be added to this partition. + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && + (dn = of_find_node_by_path("/rtas"))) { + int num_addr_cell, num_size_cell, maxcpus; + unsigned int *ireg; + + num_addr_cell = prom_n_addr_cells(dn); + num_size_cell = prom_n_size_cells(dn); + + ireg = (unsigned int *) + get_property(dn, "ibm,lrdr-capacity", NULL); + + if (!ireg) + goto out; + + maxcpus = ireg[num_addr_cell + num_size_cell]; + + /* Double maxcpus for processors which have SMT capability */ + if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + maxcpus *= 2; + + if (maxcpus > NR_CPUS) { + printk(KERN_WARNING + "Partition configured for %d cpus, " + "operating system maximum is %d.\n", + maxcpus, NR_CPUS); + maxcpus = NR_CPUS; + } else + printk(KERN_INFO "Partition configured for %d cpus.\n", + maxcpus); + + for (cpu = 0; cpu < maxcpus; cpu++) + cpu_set(cpu, cpu_possible_map); + out: + of_node_put(dn); + } + + /* + * Do the sibling map; assume only two threads per processor. + */ + 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]); + } + + systemcfg->processorCount = num_present_cpus(); +} +#endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ -#ifdef CONFIG_PPC_ISERIES - /* pSeries systems are identified in prom.c via OF. */ - if ( itLpNaca.xLparInstalled == 1 ) - systemcfg->platform = PLATFORM_ISERIES_LPAR; -#endif - - switch (systemcfg->platform) { -#ifdef CONFIG_PPC_ISERIES - case PLATFORM_ISERIES_LPAR: - iSeries_init_early(); - break; -#endif +#ifdef CONFIG_PPC_MULTIPLATFORM + +extern struct machdep_calls pSeries_md; +extern struct machdep_calls pmac_md; + +/* Ultimately, stuff them in an elf section like initcalls... */ +static struct machdep_calls __initdata *machines[] = { #ifdef CONFIG_PPC_PSERIES - case PLATFORM_PSERIES: - pSeries_init_early(); - parse_bootinfo(); - break; - - case PLATFORM_PSERIES_LPAR: - pSeriesLP_init_early(); - parse_bootinfo(); - break; + &pSeries_md, #endif /* CONFIG_PPC_PSERIES */ #ifdef CONFIG_PPC_PMAC - case PLATFORM_POWERMAC: - pmac_init_early(); - parse_bootinfo(); + &pmac_md, #endif /* CONFIG_PPC_PMAC */ + NULL +}; + +/* + * Early initialization entry point. This is called by head.S + * with MMU translation disabled. We rely on the "feature" of + * the CPU that ignores the top 2 bits of the address in real + * mode so we can access kernel globals normally provided we + * only toy with things in the RMO region. From here, we do + * some early parsing of the device-tree to setup out LMB + * data structures, and allocate & initialize the hash table + * and segment tables so we can start running with translation + * enabled. + * + * It is this function which will call the probe() callback of + * the various platform types and copy the matching one to the + * global ppc_md structure. Your platform can eventually do + * some very early initializations from the probe() routine, but + * this is not recommended, be very careful as, for example, the + * device-tree is not accessible via normal means at this point. + */ + +void __init early_setup(unsigned long dt_ptr) +{ + struct paca_struct *lpaca = get_paca(); + static struct machdep_calls **mach; + + /* + * Enable early debugging if any specified (see top of + * this file) + */ + EARLY_DEBUG_INIT(); + + DBG(" -> early_setup()\n"); + + /* + * Fill the default DBG level in naca (do we want to keep + * that old mecanism around forever ?) + */ + ppcdbg_initialize(); + + /* + * Do early initializations using the flattened device + * tree, like retreiving the physical memory map or + * calculating/retreiving the hash table size + */ + early_init_devtree(__va(dt_ptr)); + + /* + * Iterate all ppc_md structures until we find the proper + * one for the current machine type + */ + DBG("Probing machine type for platform %x...\n", + systemcfg->platform); + + for (mach = machines; *mach; mach++) { + if ((*mach)->probe(systemcfg->platform)) + break; + } + /* What can we do if we didn't find ? */ + if (*mach == NULL) { + DBG("No suitable machine found !\n"); + for (;;); + } + ppc_md = **mach; + + /* our udbg callbacks got overriden by the above, let's put them + * back in. Ultimately, I want those things to be split from the + * main ppc_md + */ + EARLY_DEBUG_INIT(); + + DBG("Found, Initializing memory management...\n"); + + /* + * Initialize stab / SLB management + */ + stab_initialize(lpaca->stab_real); + + /* + * Initialize the MMU Hash table and create the linear mapping + * of memory + */ + htab_initialize(); + + DBG(" <- early_setup()\n"); +} + + +/* + * Initialize some remaining members of the naca and systemcfg structures + * (at least until we get rid of them completely). This is mostly some + * cache informations about the CPU that will be used by cache flush + * routines and/or provided to userland + */ +static void __init initialize_naca(void) +{ + struct device_node *np; + unsigned long num_cpus = 0; + + DBG(" -> initialize_naca()\n"); + + for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { + num_cpus += 1; + + /* We're assuming *all* of the CPUs have the same + * d-cache and i-cache sizes... -Peter + */ + + if ( num_cpus == 1 ) { + u32 *sizep, *lsizep; + u32 size, lsize; + const char *dc, *ic; + + /* Then read cache informations */ + if (systemcfg->platform == PLATFORM_POWERMAC) { + dc = "d-cache-block-size"; + ic = "i-cache-block-size"; + } else { + dc = "d-cache-line-size"; + ic = "i-cache-line-size"; + } + + size = 0; + lsize = cur_cpu_spec->dcache_bsize; + sizep = (u32 *)get_property(np, "d-cache-size", NULL); + if (sizep != NULL) + size = *sizep; + lsizep = (u32 *) get_property(np, dc, NULL); + if (lsizep != NULL) + lsize = *lsizep; + + if (sizep == 0 || lsizep == 0) + DBG("Argh, can't find dcache properties ! " + "sizep: %p, lsizep: %p\n", sizep, lsizep); + + systemcfg->dCacheL1Size = size; + systemcfg->dCacheL1LineSize = lsize; + naca->dCacheL1LogLineSize = __ilog2(lsize); + naca->dCacheL1LinesPerPage = PAGE_SIZE/(lsize); + + size = 0; + lsize = cur_cpu_spec->icache_bsize; + sizep = (u32 *)get_property(np, "i-cache-size", NULL); + if (sizep != NULL) + size = *sizep; + lsizep = (u32 *)get_property(np, ic, NULL); + if (lsizep != NULL) + lsize = *lsizep; + if (sizep == 0 || lsizep == 0) + DBG("Argh, can't find icache properties ! " + "sizep: %p, lsizep: %p\n", sizep, lsizep); + + systemcfg->iCacheL1Size = size; + systemcfg->iCacheL1LineSize = lsize; + naca->iCacheL1LogLineSize = __ilog2(lsize); + naca->iCacheL1LinesPerPage = PAGE_SIZE/(lsize); + + } + } + + /* Add an eye catcher and the systemcfg layout version number */ + strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); + systemcfg->version.major = SYSTEMCFG_MAJOR; + systemcfg->version.minor = SYSTEMCFG_MINOR; + systemcfg->processor = mfspr(SPRN_PVR); + + DBG(" <- initialize_naca()\n"); +} + +static void __init check_for_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + u64 *prop; + + DBG(" -> check_for_initrd()\n"); + + prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); + if (prop != NULL) { + initrd_start = (unsigned long)__va(*prop); + prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); + if (prop != NULL) { + initrd_end = (unsigned long)__va(*prop); + initrd_below_start_ok = 1; + } else + initrd_start = 0; } /* If we were passed an initrd, set the ROOT_DEV properly if the values * look sensible. If not, clear initrd reference. */ -#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && initrd_end > initrd_start) ROOT_DEV = Root_RAM0; else initrd_start = initrd_end = 0; + + if (initrd_start) + printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); + + DBG(" <- check_for_initrd()\n"); #endif /* CONFIG_BLK_DEV_INITRD */ +} -#ifdef CONFIG_BOOTX_TEXT - map_boot_text(); - if (systemcfg->platform == PLATFORM_POWERMAC) { - early_console_initialized = 1; - register_console(&udbg_console); - } -#endif /* CONFIG_BOOTX_TEXT */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ -#ifdef CONFIG_PPC_PSERIES - if (systemcfg->platform & PLATFORM_PSERIES) { - early_console_initialized = 1; - register_console(&udbg_console); - __irq_offset_value = NUM_ISA_INTERRUPTS; - finish_device_tree(); - chrp_init(r3, r4, r5, r6, r7); +/* + * Do some initial setup of the system. The parameters are those which + * were passed in from the bootloader. + */ +void __init setup_system(void) +{ + DBG(" -> setup_system()\n"); -#ifdef CONFIG_SMP - /* Start secondary threads on SMT systems */ - for (i = 0; i < NR_CPUS; i++) { - if (cpu_available(i) && !cpu_possible(i)) { - printk("%16.16x : starting thread\n", i); - rtas_call(rtas_token("start-cpu"), 3, 1, &ret, - get_hard_smp_processor_id(i), - (u32)*((unsigned long *)pseries_secondary_smp_init), - i); - cpu_set(i, cpu_possible_map); - systemcfg->processorCount++; - } - } -#endif /* CONFIG_SMP */ - } +#ifdef CONFIG_PPC_ISERIES + /* pSeries systems are identified in prom.c via OF. */ + if (itLpNaca.xLparInstalled == 1) + systemcfg->platform = PLATFORM_ISERIES_LPAR; + + ppc_md.init_early(); +#else /* CONFIG_PPC_ISERIES */ + + /* + * Unflatten the device-tree passed by prom_init or kexec + */ + unflatten_device_tree(); + + /* + * Fill the naca & systemcfg structures with informations + * retreived from the device-tree. Need to be called before + * finish_device_tree() since the later requires some of the + * informations filled up here to properly parse the interrupt + * tree. + * It also sets up the cache line sizes which allows to call + * routines like flush_icache_range (used by the hash init + * later on). + */ + initialize_naca(); + +#ifdef CONFIG_PPC_PSERIES + /* + * Initialize RTAS if available + */ + rtas_initialize(); #endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_PPC_PMAC - if (systemcfg->platform == PLATFORM_POWERMAC) { - finish_device_tree(); - pmac_init(r3, r4, r5, r6, r7); - } -#endif /* CONFIG_PPC_PMAC */ + /* + * Check if we have an initrd provided via the device-tree + */ + check_for_initrd(); -#if defined(CONFIG_HOTPLUG_CPU) && !defined(CONFIG_PPC_PMAC) - rtas_stop_self_args.token = rtas_token("stop-self"); -#endif /* CONFIG_HOTPLUG_CPU && !CONFIG_PPC_PMAC */ + /* + * Do some platform specific early initializations, that includes + * setting up the hash table pointers. It also sets up some interrupt-mapping + * related options that will be used by finish_device_tree() + */ + ppc_md.init_early(); - /* Finish initializing the hash table (do the dynamic - * patching for the fast-path hashtable.S code) + /* + * "Finish" the device-tree, that is do the actual parsing of + * some of the properties like the interrupt map */ - htab_finish_init(); + finish_device_tree(); + + /* + * Initialize xmon + */ +#ifdef CONFIG_XMON_DEFAULT + xmon_init(); +#endif + /* + * Register early console + */ + early_console_initialized = 1; + register_console(&udbg_console); + +#endif /* !CONFIG_PPC_ISERIES */ + + /* Save unparsed command line copy for /proc/cmdline */ + strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); + + parse_early_param(); + +#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) + /* + * iSeries has already initialized the cpu maps at this point. + */ + setup_cpu_maps(); +#endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ printk("Starting Linux PPC64 %s\n", UTS_RELEASE); @@ -282,28 +640,10 @@ void setup_system(unsigned long r3, unsigned long r4, unsigned long r5, mm_init_ppc64(); -#if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES) - if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { - vpa_init(boot_cpuid); - } -#endif - - /* Select the correct idle loop for the platform. */ - idle_setup(); - - switch (systemcfg->platform) { -#ifdef CONFIG_PPC_ISERIES - case PLATFORM_ISERIES_LPAR: - iSeries_init(); - break; -#endif - default: - /* The following relies on the device tree being */ - /* fully configured. */ - parse_cmd_line(r3, r4, r5, r6, r7); - } + DBG(" <- setup_system()\n"); } + void machine_restart(char *cmd) { if (ppc_md.nvram_sync) @@ -373,7 +713,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) #ifdef CONFIG_SMP pvr = per_cpu(pvr, cpu_id); #else - pvr = _get_PVR(); + pvr = mfspr(SPRN_PVR); #endif maj = (pvr >> 8) & 0xFF; min = pvr & 0xFF; @@ -425,74 +765,75 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -/* - * Fetch the cmd_line from open firmware. - */ -void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - cmd_line[0] = 0; +#if 0 /* XXX not currently used */ +unsigned long memory_limit; -#ifdef CONFIG_CMDLINE - strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); -#endif /* CONFIG_CMDLINE */ +static int __init early_parsemem(char *p) +{ + if (!p) + return 0; -#ifdef CONFIG_PPC_PSERIES - { - struct device_node *chosen; - - chosen = of_find_node_by_name(NULL, "chosen"); - if (chosen != NULL) { - char *p; - p = get_property(chosen, "bootargs", NULL); - if (p != NULL && p[0] != 0) - strlcpy(cmd_line, p, sizeof(cmd_line)); - of_node_put(chosen); - } - } -#endif + memory_limit = memparse(p, &p); - /* Look for mem= option on command line */ - if (strstr(cmd_line, "mem=")) { - char *p, *q; - unsigned long maxmem = 0; - extern unsigned long __max_memory; - - for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { - q = p + 4; - if (p > cmd_line && p[-1] != ' ') - continue; - maxmem = simple_strtoul(q, &q, 0); - if (*q == 'k' || *q == 'K') { - maxmem <<= 10; - ++q; - } else if (*q == 'm' || *q == 'M') { - maxmem <<= 20; - ++q; - } - } - __max_memory = maxmem; - } + return 0; } +early_param("mem", early_parsemem); +#endif -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM static int __init set_preferred_console(void) { struct device_node *prom_stdout; char *name; - int offset; + int offset = 0; +#if 0 + phandle *stdout_ph; +#endif + DBG(" -> set_preferred_console()\n"); /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) + if (strstr(saved_command_line, "console=")) { + DBG(" console was specified !\n"); return -EBUSY; + } - prom_stdout = find_path_device(of_stdout_device); - if (!prom_stdout) + if (!of_chosen) { + DBG(" of_chosen is NULL !\n"); return -ENODEV; + } + /* We are getting a weird phandle from OF ... */ +#if 0 + stdout_ph = (phandle *)get_property(of_chosen, "linux,stdout-package", NULL); + if (stdout_ph == NULL) { + DBG(" no linux,stdout-package !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_phandle(*stdout_ph); + if (!prom_stdout) { + DBG(" can't find stdout package for phandle 0x%x !\n", *stdout_ph); + return -ENODEV; + } +#endif + /* ... So use the full path instead */ +#if 1 + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) { + DBG(" no linux,stdout-path !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_path(name); + if (!prom_stdout) { + DBG(" can't find stdout package %s !\n", name); + return -ENODEV; + } +#endif + DBG("stdout is %s\n", prom_stdout->full_name); name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) - return -ENODEV; + if (!name) { + DBG(" stdout package has no name !\n"); + goto not_found; + } if (strcmp(name, "serial") == 0) { int i; @@ -513,76 +854,69 @@ static int __init set_preferred_console(void) break; default: /* We dont recognise the serial port */ - return -ENODEV; + goto not_found; } } - } else if (strcmp(name, "vty") == 0) - /* pSeries LPAR virtual console */ - return add_preferred_console("hvc", 0, NULL); + } +#ifdef CONFIG_PPC_PSERIES + else if (strcmp(name, "vty") == 0) { + u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); + char *compat = (char *)get_property(prom_stdout, "compatible", NULL); + + if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { + /* Host Virtual Serial Interface */ + int offset; + switch (reg[0]) { + case 0x30000000: + offset = 0; + break; + case 0x30000001: + offset = 1; + break; + default: + goto not_found; + } + of_node_put(prom_stdout); + DBG("Found hvsi console at offset %d\n", offset); + return add_preferred_console("hvsi", offset, NULL); + } else { + /* pSeries LPAR virtual console */ + of_node_put(prom_stdout); + DBG("Found hvc console\n"); + return add_preferred_console("hvc", 0, NULL); + } + } +#endif /* CONFIG_PPC_PSERIES */ else if (strcmp(name, "ch-a") == 0) offset = 0; else if (strcmp(name, "ch-b") == 0) offset = 1; else - return -ENODEV; + goto not_found; + of_node_put(prom_stdout); + + DBG("Found serial console at ttyS%d\n", offset); return add_preferred_console("ttyS", offset, NULL); + not_found: + DBG("No preferred console found !\n"); + of_node_put(prom_stdout); + return -ENODEV; } console_initcall(set_preferred_console); - -int parse_bootinfo(void) -{ - struct bi_record *rec; - - rec = prom.bi_recs; - - if ( rec == NULL || rec->tag != BI_FIRST ) - return -1; - - for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) { - switch (rec->tag) { - case BI_CMD_LINE: - strlcpy(cmd_line, (void *)rec->data, sizeof(cmd_line)); - break; - } - } - - return 0; -} -#endif - -int __init ppc_init(void) -{ - /* clear the progress line */ - ppc_md.progress(" ", 0xffff); - - if (ppc_md.init != NULL) { - ppc_md.init(); - } - return 0; -} - -arch_initcall(ppc_init); - -void __init ppc64_calibrate_delay(void) -{ - loops_per_jiffy = tb_ticks_per_jiffy; - - printk("Calibrating delay loop... %lu.%02lu BogoMips\n", - loops_per_jiffy/(500000/HZ), - loops_per_jiffy/(5000/HZ) % 100); -} - -extern void (*calibrate_delay)(void); +#endif /* CONFIG_PPC_MULTIPLATFORM */ #ifdef CONFIG_IRQSTACKS static void __init irqstack_early_init(void) { - int i; + unsigned int i; - /* interrupt stacks must be under 256MB, we cannot afford to take SLB misses on them */ - for (i = 0; i < NR_CPUS; i++) { + /* + * interrupt stacks must be under 256MB, we cannot afford to take + * SLB misses on them. + */ + for_each_cpu(i) { softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, THREAD_SIZE, 0x10000000)); hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, @@ -593,6 +927,31 @@ static void __init irqstack_early_init(void) #define irqstack_early_init() #endif +/* + * Stack space used when we detect a bad kernel stack pointer, and + * early in SMP boots before relocation is enabled. + */ +static void __init emergency_stack_init(void) +{ + unsigned long limit; + unsigned int i; + + /* + * Emergency stacks must be under 256MB, we cannot afford to take + * SLB misses on them. The ABI also requires them to be 128-byte + * aligned. + * + * Since we use these as temporary stacks during secondary CPU + * bringup, we need to get at them in real mode. This means they + * must also be within the RMO region. + */ + limit = min(0x10000000UL, lmb.rmo_size); + + for_each_cpu(i) + paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, + limit)) + PAGE_SIZE; +} + /* * Called into from start_kernel, after lock_kernel has been called. * Initializes bootmem, which is unsed to manage page allocation until @@ -603,17 +962,9 @@ void __init setup_arch(char **cmdline_p) extern int panic_timeout; extern void do_init_bootmem(void); - calibrate_delay = ppc64_calibrate_delay; - ppc64_boot_msg(0x12, "Setup Arch"); -#ifdef CONFIG_XMON - if (strstr(cmd_line, "xmon")) { - /* ensure xmon is enabled */ - xmon_init(); - debugger(0); - } -#endif /* CONFIG_XMON */ + *cmdline_p = cmd_line; /* * Set cache line size based on type of cpu as a default. @@ -634,21 +985,22 @@ void __init setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) _edata; init_mm.brk = klimit; - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); - *cmdline_p = cmd_line; - irqstack_early_init(); + emergency_stack_init(); /* set up the bootmem stuff with available memory */ do_init_bootmem(); + /* Select the correct idle loop for the platform. */ + idle_setup(); + ppc_md.setup_arch(); paging_init(); ppc64_boot_msg(0x15, "Setup Done"); } + /* ToDo: do something useful if ppc_md is not yet setup. */ #define PPC64_LINUX_FUNCTION 0x0f000000 #define PPC64_IPL_MESSAGE 0xc0000000 @@ -753,3 +1105,16 @@ int set_decr_overclock( char * str ) __setup("spread_lpevents=", set_spread_lpevents ); __setup("decr_overclock_proc0=", set_decr_overclock_proc0 ); __setup("decr_overclock=", set_decr_overclock ); + +#ifdef CONFIG_XMON +static int __init early_xmon(char *p) +{ + /* ensure xmon is enabled */ + xmon_init(); + debugger(0); + + return 0; +} +early_param("xmon", early_xmon); +#endif + diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 8323d7355..ce616280b 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -127,7 +126,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, * v_regs pointer or not */ #ifdef CONFIG_ALTIVEC - elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve) & ~0xful); + elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful); #endif long err = 0; @@ -178,7 +177,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, elf_vrreg_t __user *v_regs; #endif unsigned long err = 0; - unsigned long save_r13; + unsigned long save_r13 = 0; elf_greg_t *gregs = (elf_greg_t *)regs; int i; @@ -371,7 +370,8 @@ badframe: printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n", regs, uc, &uc->uc_mcontext); #endif - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); + return 0; } static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, @@ -446,7 +446,7 @@ badframe: printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - do_exit(SIGSEGV); + force_sigsegv(signr, current); } @@ -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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->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 = ¤t->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 = ¤t->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 106f008af..79f7b8446 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -189,7 +189,7 @@ static long restore_user_regs(struct pt_regs *regs, elf_greg_t64 *gregs = (elf_greg_t64 *)regs; int i; long err = 0; - unsigned int save_r2; + unsigned int save_r2 = 0; #ifdef CONFIG_ALTIVEC unsigned long msr; #endif @@ -472,10 +472,14 @@ static long copy_siginfo_to_user32(compat_siginfo_t __user *d, siginfo_t *s) &d->si_addr); break; case __SI_POLL >> 16: - case __SI_TIMER >> 16: err |= __put_user(s->si_band, &d->si_band); err |= __put_user(s->si_fd, &d->si_fd); break; + case __SI_TIMER >> 16: + err |= __put_user(s->si_tid, &d->si_tid); + err |= __put_user(s->si_overrun, &d->si_overrun); + err |= __put_user(s->si_int, &d->si_int); + break; case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __put_user(s->si_int, &d->si_int); @@ -699,9 +703,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 +866,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 +928,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 = ¤t->blocked; newsp = frame = 0; - signr = get_signal_to_deliver(&info, regs, NULL); - - ka = (signr == 0)? NULL: ¤t->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 +948,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 +967,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 +975,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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, + &ka.sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 1f3003408..75ced7528 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -15,6 +15,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -53,14 +54,20 @@ #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif int smp_threads_ready; unsigned long cache_decay_ticks; cpumask_t cpu_possible_map = CPU_MASK_NONE; cpumask_t cpu_online_map = CPU_MASK_NONE; -cpumask_t cpu_available_map = CPU_MASK_NONE; -cpumask_t cpu_present_at_boot = 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); @@ -76,9 +83,13 @@ void smp_call_function_interrupt(void); extern long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa); +int smt_enabled_at_boot = 1; + /* Low level assembly function used to backup CPU 0 state */ extern void __save_cpu_setup(void); +extern void pseries_secondary_smp_init(unsigned long); + #ifdef CONFIG_PPC_ISERIES static unsigned long iSeries_smp_message[NR_CPUS]; @@ -124,9 +135,8 @@ static int smp_iSeries_numProcs(void) np = 0; for (i=0; i < NR_CPUS; ++i) { if (paca[i].lppaca.xDynProcStatus < 2) { - cpu_set(i, cpu_available_map); cpu_set(i, cpu_possible_map); - cpu_set(i, cpu_present_at_boot); + cpu_set(i, cpu_present_map); ++np; } } @@ -183,7 +193,7 @@ void __init smp_init_iSeries(void) } #endif -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM void smp_openpic_message_pass(int target, int msg) { /* make sure we're sending something that translates to an IPI */ @@ -224,7 +234,10 @@ static void __devinit smp_openpic_setup_cpu(int cpu) do_openpic_setup_cpu(); } -#ifdef CONFIG_HOTPLUG_CPU +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +#ifdef CONFIG_PPC_PSERIES + /* Get state of physical CPU. * Return codes: * 0 - The processor is in the RTAS stopped state @@ -233,13 +246,15 @@ static void __devinit smp_openpic_setup_cpu(int cpu) * -1 - Hardware Error * -2 - Hardware Busy, Try again later. */ -static int query_cpu_stopped(unsigned int pcpu) +int query_cpu_stopped(unsigned int pcpu) { int cpu_status; int status, qcss_tok; + DBG(" -> query_cpu_stopped(%d)\n", pcpu); qcss_tok = rtas_token("query-cpu-stopped-state"); - BUG_ON(qcss_tok == RTAS_UNKNOWN_SERVICE); + if (qcss_tok == RTAS_UNKNOWN_SERVICE) + return -1; status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu); if (status != 0) { printk(KERN_ERR @@ -247,9 +262,13 @@ static int query_cpu_stopped(unsigned int pcpu) return status; } + DBG(" <- query_cpu_stopped(), status: %d\n", cpu_status); + return cpu_status; } +#ifdef CONFIG_HOTPLUG_CPU + int __cpu_disable(void) { /* FIXME: go put this in a header somewhere */ @@ -272,13 +291,12 @@ void __cpu_die(unsigned int cpu) int cpu_status; unsigned int pcpu = get_hard_smp_processor_id(cpu); - for (tries = 0; tries < 5; tries++) { + for (tries = 0; tries < 25; tries++) { cpu_status = query_cpu_stopped(pcpu); - - if (cpu_status == 0) + if (cpu_status == 0 || cpu_status == -1) break; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(HZ/5); } if (cpu_status != 0) { printk("Querying DEAD? cpu %i (%i) shows %i\n", @@ -372,13 +390,13 @@ out: static inline int __devinit smp_startup_cpu(unsigned int lcpu) { int status; - extern void (*pseries_secondary_smp_init)(unsigned int cpu); - unsigned long start_here = __pa(pseries_secondary_smp_init); + unsigned long start_here = __pa((u32)*((unsigned long *) + pseries_secondary_smp_init)); unsigned int pcpu; /* At boot time the cpus are already spinning in hold * loops, so nothing to do. */ - if (system_state == SYSTEM_BOOTING) + if (system_state < SYSTEM_RUNNING) return 1; pcpu = find_physical_cpu_to_start(get_hard_smp_processor_id(lcpu)); @@ -401,56 +419,11 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) } return 1; } - -static inline void look_for_more_cpus(void) -{ - int num_addr_cell, num_size_cell, len, i, maxcpus; - struct device_node *np; - unsigned int *ireg; - - /* Find the property which will tell us about how many CPUs - * we're allowed to have. */ - if ((np = find_path_device("/rtas")) == NULL) { - printk(KERN_ERR "Could not find /rtas in device tree!"); - return; - } - num_addr_cell = prom_n_addr_cells(np); - num_size_cell = prom_n_size_cells(np); - - ireg = (unsigned int *)get_property(np, "ibm,lrdr-capacity", &len); - if (ireg == NULL) { - /* FIXME: make sure not marked as lrdr_capable() */ - return; - } - - maxcpus = ireg[num_addr_cell + num_size_cell]; - - /* Double maxcpus for processors which have SMT capability */ - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) - maxcpus *= 2; - - - if (maxcpus > NR_CPUS) { - printk(KERN_WARNING - "Partition configured for %d cpus, " - "operating system maximum is %d.\n", maxcpus, NR_CPUS); - maxcpus = NR_CPUS; - } else - printk(KERN_INFO "Partition configured for %d cpus.\n", - maxcpus); - - /* Make those cpus (which might appear later) possible too. */ - for (i = 0; i < maxcpus; i++) - cpu_set(i, cpu_possible_map); -} #else /* ... CONFIG_HOTPLUG_CPU */ static inline int __devinit smp_startup_cpu(unsigned int lcpu) { return 1; } -static inline void look_for_more_cpus(void) -{ -} #endif /* CONFIG_HOTPLUG_CPU */ static void smp_pSeries_kick_cpu(int nr) @@ -485,13 +458,13 @@ static void __init smp_space_timers(unsigned int max_cpus) } #ifdef CONFIG_PPC_PSERIES -void vpa_init(int cpu) +static void vpa_init(int cpu) { - unsigned long flags; + unsigned long flags, pcpu = get_hard_smp_processor_id(cpu); /* Register the Virtual Processor Area (VPA) */ flags = 1UL << (63 - 18); - register_vpa(flags, cpu, __pa((unsigned long)&(paca[cpu].lppaca))); + register_vpa(flags, pcpu, __pa((unsigned long)&(paca[cpu].lppaca))); } static inline void smp_xics_do_message(int cpu, int msg) @@ -576,26 +549,47 @@ static struct smp_ops_t pSeries_xics_smp_ops = { /* This is called very early */ void __init smp_init_pSeries(void) { + int ret, i; + + DBG(" -> smp_init_pSeries()\n"); if (naca->interrupt_controller == IC_OPEN_PIC) smp_ops = &pSeries_openpic_smp_ops; else smp_ops = &pSeries_xics_smp_ops; + /* Start secondary threads on SMT systems; primary threads + * are already in the running state. + */ + for_each_present_cpu(i) { + if (query_cpu_stopped(get_hard_smp_processor_id(i)) == 0) { + printk("%16.16x : starting thread\n", i); + DBG("%16.16x : starting thread\n", i); + rtas_call(rtas_token("start-cpu"), 3, 1, &ret, + get_hard_smp_processor_id(i), + __pa((u32)*((unsigned long *) + pseries_secondary_smp_init)), + i); + } + } + + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) + vpa_init(boot_cpuid); + /* Non-lpar has additional take/give timebase */ if (systemcfg->platform == PLATFORM_PSERIES) { smp_ops->give_timebase = pSeries_give_timebase; smp_ops->take_timebase = pSeries_take_timebase; } + + + DBG(" <- smp_init_pSeries()\n"); } -#endif +#endif /* CONFIG_PPC_PSERIES */ void smp_local_timer_interrupt(struct pt_regs * regs) { - if (!--(get_paca()->prof_counter)) { - update_process_times(user_mode(regs)); - (get_paca()->prof_counter)=get_paca()->prof_multiplier; - } + update_process_times(user_mode(regs)); } void smp_message_recv(int msg, struct pt_regs *regs) @@ -751,6 +745,8 @@ out: return ret; } +EXPORT_SYMBOL(smp_call_function); + void smp_call_function_interrupt(void) { void (*func) (void *info); @@ -794,26 +790,17 @@ DECLARE_PER_CPU(unsigned int, pvr); static void __devinit smp_store_cpu_info(int id) { - per_cpu(pvr, id) = _get_PVR(); + per_cpu(pvr, id) = mfspr(SPRN_PVR); } 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(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM | CLONE_IDLETASK, - 0, ®s, 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; } @@ -831,8 +818,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* Fixup boot cpu */ smp_store_cpu_info(boot_cpuid); cpu_callin_map[boot_cpuid] = 1; - paca[boot_cpuid].prof_counter = 1; - paca[boot_cpuid].prof_multiplier = 1; #ifndef CONFIG_PPC_ISERIES paca[boot_cpuid].next_jiffy_update_tb = tb_last_stamp = get_tb(); @@ -843,8 +828,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) * number of msecs off until someone does a settimeofday() */ do_gtod.tb_orig_stamp = tb_last_stamp; - - look_for_more_cpus(); + systemcfg->tb_orig_stamp = tb_last_stamp; #endif max_cpus = smp_ops->probe(); @@ -863,7 +847,6 @@ void __devinit smp_prepare_boot_cpu(void) { BUG_ON(smp_processor_id() != boot_cpuid); - /* cpu_possible is set up in prom.c */ cpu_set(boot_cpuid, cpu_online_map); paca[boot_cpuid].__current = current; @@ -875,11 +858,9 @@ int __devinit __cpu_up(unsigned int cpu) int c; /* At boot, don't bother with non-present cpus -JSCHOPP */ - if (system_state == SYSTEM_BOOTING && !cpu_present_at_boot(cpu)) + if (system_state < SYSTEM_RUNNING && !cpu_present(cpu)) return -ENOENT; - paca[cpu].prof_counter = 1; - paca[cpu].prof_multiplier = 1; paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock; if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) { @@ -909,7 +890,7 @@ int __devinit __cpu_up(unsigned int cpu) * use this value that I found through experimentation. * -- Cort */ - if (system_state == SYSTEM_BOOTING) + if (system_state < SYSTEM_RUNNING) for (c = 5000; c && !cpu_callin_map[cpu]; c--) udelay(100); #ifdef CONFIG_HOTPLUG_CPU @@ -1004,219 +985,12 @@ void __init smp_cpus_done(unsigned int max_cpus) smp_threads_ready = 1; 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); - } + /* + * We know at boot the maximum number of cpus we can add to + * a partition and set cpu_possible_map accordingly. cpu_present_map + * needs to match for the hotplug code to allow us to hot add + * any offline cpus. + */ + cpu_present_map = cpu_possible_map; } -#endif /* CONFIG_NUMA */ -#endif /* CONFIG_SCHED_SMT */ diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 26e5e8dd9..710b7cd9e 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -72,7 +72,6 @@ #include #include #include -#include #include #include "pci.h" @@ -634,8 +633,24 @@ out: void start_thread32(struct pt_regs* regs, unsigned long nip, unsigned long sp) { set_fs(USER_DS); - memset(regs->gpr, 0, sizeof(regs->gpr)); - memset(®s->ctr, 0, 4 * sizeof(regs->ctr)); + + /* + * If we exec out of a kernel thread then thread.regs will not be + * set. Do it now. + */ + if (!current->thread.regs) { + unsigned long childregs = (unsigned long)current->thread_info + + THREAD_SIZE; + childregs -= sizeof(struct pt_regs); + current->thread.regs = (struct pt_regs *)childregs; + } + + /* + * ELF_PLAT_INIT already clears all registers but it also sets r2. + * So just clear r2 here. + */ + regs->gpr[2] = 0; + regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER32; @@ -700,7 +715,7 @@ asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf (unsigned long) dfn, (unsigned long) off, (unsigned long) len, - (unsigned char __user *)AA(ubuf)); + compat_ptr(ubuf)); } asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) @@ -709,7 +724,7 @@ asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubu (unsigned long) dfn, (unsigned long) off, (unsigned long) len, - (unsigned char __user *)AA(ubuf)); + compat_ptr(ubuf)); } #define IOBASE_BRIDGE_NUMBER 0 @@ -1095,7 +1110,7 @@ struct __sysctl_args32 { u32 __unused[4]; }; -extern asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) +asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) { struct __sysctl_args32 tmp; int error; @@ -1114,19 +1129,20 @@ extern asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) glibc's __sysctl uses rw memory for the structure anyway. */ oldlenp = (size_t __user *)addr; - if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) || + if (get_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)) || put_user(oldlen, oldlenp)) return -EFAULT; } lock_kernel(); - error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval), - oldlenp, (void __user *)A(tmp.newval), tmp.newlen); + error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, + compat_ptr(tmp.oldval), oldlenp, + compat_ptr(tmp.newval), tmp.newlen); unlock_kernel(); if (oldlenp) { if (!error) { if (get_user(oldlen, oldlenp) || - put_user(oldlen, (u32 __user *)A(tmp.oldlenp))) + put_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp))) error = -EFAULT; } copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index 41b34932f..cfc3c0b7b 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,14 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay); /* PMC stuff */ +#ifdef CONFIG_PPC_ISERIES +void ppc64_enable_pmcs(void) +{ + /* XXX Implement for iseries */ +} +#endif + +#ifdef CONFIG_PPC_MULTIPLATFORM /* * Enabling PMCs will slow partition context switch times so we only do * it the first time we write to the PMCs. @@ -103,18 +112,14 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay); static DEFINE_PER_CPU(char, pmcs_enabled); -#ifdef CONFIG_PPC_ISERIES -void ppc64_enable_pmcs(void) -{ - /* XXX Implement for iseries */ -} -#else void ppc64_enable_pmcs(void) { unsigned long hid0; +#ifdef CONFIG_PPC_PSERIES unsigned long set, reset; int ret; unsigned int ctrl; +#endif /* CONFIG_PPC_PSERIES */ /* Only need to enable them once */ if (__get_cpu_var(pmcs_enabled)) @@ -123,37 +128,42 @@ void ppc64_enable_pmcs(void) __get_cpu_var(pmcs_enabled) = 1; switch (systemcfg->platform) { - case PLATFORM_PSERIES: - hid0 = mfspr(HID0); - hid0 |= 1UL << (63 - 20); - - /* POWER4 requires the following sequence */ - asm volatile( - "sync\n" - "mtspr %1, %0\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): - "memory"); - break; - - case PLATFORM_PSERIES_LPAR: - set = 1UL << 63; - reset = 0; - ret = plpar_hcall_norets(H_PERFMON, set, reset); - if (ret) - printk(KERN_ERR "H_PERFMON call returned %d", - ret); - break; - - default: - break; + case PLATFORM_PSERIES: + case PLATFORM_POWERMAC: + hid0 = mfspr(HID0); + hid0 |= 1UL << (63 - 20); + + /* POWER4 requires the following sequence */ + asm volatile( + "sync\n" + "mtspr %1, %0\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "mfspr %0, %1\n" + "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): + "memory"); + break; + +#ifdef CONFIG_PPC_PSERIES + case PLATFORM_PSERIES_LPAR: + set = 1UL << 63; + reset = 0; + ret = plpar_hcall_norets(H_PERFMON, set, reset); + if (ret) + printk(KERN_ERR "H_PERFMON call on cpu %u " + "returned %d\n", + smp_processor_id(), ret); + break; +#endif /* CONFIG_PPC_PSERIES */ + + default: + break; } +#ifdef CONFIG_PPC_PSERIES /* instruct hypervisor to maintain PMCs */ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { char *ptr = (char *)&paca[smp_processor_id()].lppaca; @@ -169,8 +179,11 @@ void ppc64_enable_pmcs(void) ctrl |= RUNLATCH; mtspr(CTRLT, ctrl); } +#endif /* CONFIG_PPC_PSERIES */ } -#endif +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +EXPORT_SYMBOL(ppc64_enable_pmcs); /* XXX convert to rusty's on_one_cpu */ static unsigned long run_on_cpu(unsigned long cpu, diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 64844df4a..ef44a3ec4 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -83,7 +84,7 @@ static unsigned long first_settimeofday = 1; #define XSEC_PER_SEC (1024*1024) unsigned long tb_ticks_per_jiffy; -unsigned long tb_ticks_per_usec; +unsigned long tb_ticks_per_usec = 100; /* sane default */ unsigned long tb_ticks_per_sec; unsigned long next_xtime_sync_tb; unsigned long xtime_sync_interval; @@ -101,50 +102,12 @@ extern unsigned long wall_jiffies; extern unsigned long lpevent_count; extern int smp_tb_synchronized; +extern struct timezone sys_tz; + void ppc_adjtimex(void); static unsigned adjusting_time = 0; -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void ppc64_do_profile(struct pt_regs *regs) -{ - unsigned long nip; - extern unsigned long prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - nip = instruction_pointer(regs); - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!((1<>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (nip > prof_len-1) - nip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[nip]); -} - static __inline__ void timer_check_rtc(void) { /* @@ -195,6 +158,19 @@ static __inline__ void timer_sync_xtime( unsigned long cur_tb ) } } +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return regs->link; + + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif + #ifdef CONFIG_PPC_ISERIES /* @@ -233,6 +209,8 @@ static void iSeries_tb_recal(void) do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; tb_to_xs = divres.result_low; do_gtod.varp->tb_to_xs = tb_to_xs; + systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; + systemcfg->tb_to_xs = tb_to_xs; } else { printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" @@ -273,7 +251,7 @@ int timer_interrupt(struct pt_regs * regs) irq_enter(); #ifndef CONFIG_PPC_ISERIES - ppc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #endif lpaca->lppaca.xIntDword.xFields.xDecrInt = 0; @@ -281,8 +259,20 @@ int timer_interrupt(struct pt_regs * regs) while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) { #ifdef CONFIG_SMP - smp_local_timer_interrupt(regs); + /* + * We cannot disable the decrementer, so in the period + * between this cpu's being marked offline in cpu_online_map + * and calling stop-self, it is taking timer interrupts. + * Avoid calling into the scheduler rebalancing code if this + * is the case. + */ + if (!cpu_is_offline(cpu)) + smp_local_timer_interrupt(regs); #endif + /* + * No need to check whether cpu is offline here; boot_cpuid + * should have been fixed up by now. + */ if (cpu == boot_cpuid) { write_seqlock(&xtime_lock); tb_last_stamp = lpaca->next_jiffy_update_tb; @@ -408,6 +398,7 @@ int do_settimeofday(struct timespec *tv) new_xsec += new_sec * XSEC_PER_SEC; if ( new_xsec > delta_xsec ) { do_gtod.varp->stamp_xsec = new_xsec - delta_xsec; + systemcfg->stamp_xsec = new_xsec - delta_xsec; } else { /* This is only for the case where the user is setting the time @@ -416,8 +407,13 @@ int do_settimeofday(struct timespec *tv) * the time to Jan 5, 1970 */ do_gtod.varp->stamp_xsec = new_xsec; do_gtod.tb_orig_stamp = tb_last_stamp; + systemcfg->stamp_xsec = new_xsec; + systemcfg->tb_orig_stamp = tb_last_stamp; } + systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; + systemcfg->tz_dsttime = sys_tz.tz_dsttime; + write_sequnlock_irqrestore(&xtime_lock, flags); clock_was_set(); return 0; @@ -520,6 +516,11 @@ void __init time_init(void) do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; do_gtod.varp->tb_to_xs = tb_to_xs; do_gtod.tb_to_us = tb_to_us; + systemcfg->tb_orig_stamp = tb_last_stamp; + systemcfg->tb_update_count = 0; + systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; + systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; + systemcfg->tb_to_xs = tb_to_xs; xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8); next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval; @@ -655,6 +656,22 @@ void ppc_adjtimex(void) do_gtod.varp = temp_varp; do_gtod.var_idx = temp_idx; + /* + * tb_update_count is used to allow the problem state gettimeofday code + * to assure itself that it sees a consistent view of the tb_to_xs and + * stamp_xsec variables. It reads the tb_update_count, then reads + * tb_to_xs and stamp_xsec and then reads tb_update_count again. If + * the two values of tb_update_count match and are even then the + * tb_to_xs and stamp_xsec values are consistent. If not, then it + * loops back and reads them again until this criteria is met. + */ + ++(systemcfg->tb_update_count); + wmb(); + systemcfg->tb_to_xs = new_tb_to_xs; + systemcfg->stamp_xsec = new_stamp_xsec; + wmb(); + ++(systemcfg->tb_update_count); + write_sequnlock_irqrestore( &xtime_lock, flags ); } diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index 5f70f7bc1..90700b414 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -134,14 +134,20 @@ int die(const char *str, struct pt_regs *regs, long err) } static void -_exception(int signr, siginfo_t *info, struct pt_regs *regs) +_exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { + siginfo_t info; + if (!user_mode(regs)) { if (die("Exception in kernel mode", regs, signr)) return; } - force_sig_info(signr, info, current); + memset(&info, 0, sizeof(info)); + info.si_signo = signr; + info.si_code = code; + info.si_addr = (void __user *) addr; + force_sig_info(signr, &info, current); } #ifdef CONFIG_PPC_PSERIES @@ -213,27 +219,21 @@ SystemResetException(struct pt_regs *regs) */ static int recover_mce(struct pt_regs *regs, struct rtas_error_log err) { - siginfo_t info; - - if (err.disposition == DISP_FULLY_RECOVERED) { + if (err.disposition == RTAS_DISP_FULLY_RECOVERED) { /* Platform corrected itself */ return 1; } else if ((regs->msr & MSR_RI) && user_mode(regs) && - err.severity == SEVERITY_ERROR_SYNC && - err.disposition == DISP_NOT_RECOVERED && - err.target == TARGET_MEMORY && - err.type == TYPE_ECC_UNCORR && + err.severity == RTAS_SEVERITY_ERROR_SYNC && + err.disposition == RTAS_DISP_NOT_RECOVERED && + err.target == RTAS_TARGET_MEMORY && + err.type == RTAS_TYPE_ECC_UNCORR && !(current->pid == 0 || current->pid == 1)) { /* Kill off a user process with an ECC error */ - info.si_signo = SIGBUS; - info.si_errno = 0; - /* XXX something better for ECC error? */ - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)regs->nip; printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n", current->pid); - _exception(SIGBUS, &info, regs); + /* XXX something better for ECC error? */ + _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); return 1; } return 0; @@ -278,35 +278,46 @@ MachineCheckException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { - siginfo_t info; - printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", regs->nip, regs->msr, regs->trap); - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = 0; - info.si_addr = NULL; - _exception(SIGTRAP, &info, regs); + _exception(SIGTRAP, regs, 0, 0); } void InstructionBreakpointException(struct pt_regs *regs) { - siginfo_t info; - if (debugger_iabr_match(regs)) return; - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - info.si_addr = (void __user *)regs->nip; - _exception(SIGTRAP, &info, regs); + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); +} + +void +SingleStepException(struct pt_regs *regs) +{ + regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ + + if (debugger_sstep(regs)) + return; + + _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); +} + +/* + * After we have successfully emulated an instruction, we have to + * check if the instruction was being single-stepped, and if so, + * pretend we got a single-step exception. This was pointed out + * by Kumar Gala. -- paulus + */ +static inline void emulate_single_step(struct pt_regs *regs) +{ + if (regs->msr & MSR_SE) + SingleStepException(regs); } static void parse_fpe(struct pt_regs *regs) { - siginfo_t info; + int code = 0; unsigned long fpscr; flush_fp_to_thread(current); @@ -315,31 +326,84 @@ static void parse_fpe(struct pt_regs *regs) /* Invalid operation */ if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) - info.si_code = FPE_FLTINV; + code = FPE_FLTINV; /* Overflow */ else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) - info.si_code = FPE_FLTOVF; + code = FPE_FLTOVF; /* Underflow */ else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) - info.si_code = FPE_FLTUND; + code = FPE_FLTUND; /* Divide by zero */ else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) - info.si_code = FPE_FLTDIV; + code = FPE_FLTDIV; /* Inexact result */ else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) - info.si_code = FPE_FLTRES; + code = FPE_FLTRES; + + _exception(SIGFPE, regs, code, regs->nip); +} + +/* + * Illegal instruction emulation support. Return non-zero if we can't + * emulate, or -EFAULT if the associated memory access caused an access + * fault. Return zero on success. + */ + +#define INST_DCBA 0x7c0005ec +#define INST_DCBA_MASK 0x7c0007fe + +#define INST_MCRXR 0x7c000400 +#define INST_MCRXR_MASK 0x7c0007fe + +static int emulate_instruction(struct pt_regs *regs) +{ + unsigned int instword; - else - info.si_code = 0; + if (!user_mode(regs)) + return -EINVAL; - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_addr = (void __user *)regs->nip; - _exception(SIGFPE, &info, regs); + CHECK_FULL_REGS(regs); + + if (get_user(instword, (unsigned int __user *)(regs->nip))) + return -EFAULT; + + /* Emulating the dcba insn is just a no-op. */ + if ((instword & INST_DCBA_MASK) == INST_DCBA) { + static int warned; + + if (!warned) { + printk(KERN_WARNING + "process %d (%s) uses obsolete 'dcba' insn\n", + current->pid, current->comm); + warned = 1; + } + return 0; + } + + /* Emulate the mcrxr insn. */ + if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { + static int warned; + unsigned int shift; + + if (!warned) { + printk(KERN_WARNING + "process %d (%s) uses obsolete 'mcrxr' insn\n", + current->pid, current->comm); + warned = 1; + } + + shift = (instword >> 21) & 0x1c; + regs->ccr &= ~(0xf0000000 >> shift); + regs->ccr |= (regs->xer & 0xf0000000) >> shift; + regs->xer &= ~0xf0000000; + return 0; + } + + return -EINVAL; } /* @@ -395,20 +459,14 @@ check_bug_trap(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { - siginfo_t info; - if (regs->msr & 0x100000) { /* IEEE FP exception */ - parse_fpe(regs); + } else if (regs->msr & 0x40000) { /* Privileged instruction */ + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_PRVOPC; - info.si_addr = (void __user *)regs->nip; - _exception(SIGILL, &info, regs); } else if (regs->msr & 0x20000) { /* trap exception */ @@ -419,19 +477,24 @@ ProgramCheckException(struct pt_regs *regs) regs->nip += 4; return; } - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - info.si_addr = (void __user *)regs->nip; - _exception(SIGTRAP, &info, regs); + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); + } else { - /* Illegal instruction */ + /* Illegal instruction; try to emulate it. */ + switch (emulate_instruction(regs)) { + case 0: + regs->nip += 4; + emulate_single_step(regs); + break; - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLTRP; - info.si_addr = (void __user *)regs->nip; - _exception(SIGILL, &info, regs); + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + break; + + default: + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + break; + } } } @@ -448,13 +511,7 @@ void AltivecUnavailableException(struct pt_regs *regs) if (user_mode(regs)) { /* A user program has executed an altivec instruction, but this kernel doesn't support altivec. */ - siginfo_t info; - - memset(&info, 0, sizeof(info)); - info.si_signo = SIGILL; - info.si_code = ILL_ILLOPC; - info.si_addr = (void *) regs->nip; - _exception(SIGILL, &info, regs); + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); return; } #endif @@ -463,41 +520,22 @@ void AltivecUnavailableException(struct pt_regs *regs) die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); } -void -SingleStepException(struct pt_regs *regs) -{ - siginfo_t info; - - regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ - - if (debugger_sstep(regs)) - return; - - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_TRACE; - info.si_addr = (void __user *)regs->nip; - _exception(SIGTRAP, &info, regs); -} - -/* - * After we have successfully emulated an instruction, we have to - * check if the instruction was being single-stepped, and if so, - * pretend we got a single-step exception. This was pointed out - * by Kumar Gala. -- paulus - */ -static inline void emulate_single_step(struct pt_regs *regs) -{ - if (regs->msr & MSR_SE) - SingleStepException(regs); -} +/* Ensure exceptions are disabled */ +#define MMCR0_PMXE (1UL << (31 - 5)) +#define MMCR0_PMAO (1UL << (31 - 24)) static void dummy_perf(struct pt_regs *regs) { + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + + mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); + mtspr(SPRN_MMCR0, mmcr0); } void (*perf_irq)(struct pt_regs *) = dummy_perf; +EXPORT_SYMBOL(perf_irq); + void PerformanceMonitorException(struct pt_regs *regs) { @@ -508,7 +546,6 @@ void AlignmentException(struct pt_regs *regs) { int fixed; - siginfo_t info; fixed = fix_alignment(regs); @@ -521,11 +558,7 @@ AlignmentException(struct pt_regs *regs) /* Operand address was bad */ if (fixed == -EFAULT) { if (user_mode(regs)) { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *)regs->dar; - force_sig_info(SIGSEGV, &info, current); + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->dar); } else { /* Search exception table */ bad_page_fault(regs, regs->dar, SIGSEGV); @@ -534,11 +567,7 @@ AlignmentException(struct pt_regs *regs) return; } - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRALN; - info.si_addr = (void __user *)regs->nip; - _exception(SIGBUS, &info, regs); + _exception(SIGBUS, regs, BUS_ADRALN, regs->nip); } #ifdef CONFIG_ALTIVEC diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c new file mode 100644 index 000000000..2bb0b39f6 --- /dev/null +++ b/arch/ppc64/kernel/u3_iommu.c @@ -0,0 +1,321 @@ +/* + * arch/ppc64/kernel/u3_iommu.c + * + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * + * Based on pSeries_iommu.c: + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * + * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu. + * + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +extern int iommu_force_on; + +/* physical base of DART registers */ +#define DART_BASE 0xf8033000UL + +/* Offset from base to control register */ +#define DARTCNTL 0 +/* Offset from base to exception register */ +#define DARTEXCP 0x10 +/* Offset from base to TLB tag registers */ +#define DARTTAG 0x1000 + + +/* Control Register fields */ + +/* base address of table (pfn) */ +#define DARTCNTL_BASE_MASK 0xfffff +#define DARTCNTL_BASE_SHIFT 12 + +#define DARTCNTL_FLUSHTLB 0x400 +#define DARTCNTL_ENABLE 0x200 + +/* size of table in pages */ +#define DARTCNTL_SIZE_MASK 0x1ff +#define DARTCNTL_SIZE_SHIFT 0 + +/* DART table fields */ +#define DARTMAP_VALID 0x80000000 +#define DARTMAP_RPNMASK 0x00ffffff + +/* Physical base address and size of the DART table */ +unsigned long dart_tablebase; /* exported to htab_initialize */ +static unsigned long dart_tablesize; + +/* Virtual base address of the DART table */ +static u32 *dart_vbase; + +/* Mapped base address for the dart */ +static unsigned int *dart; + +/* Dummy val that entries are set to when unused */ +static unsigned int dart_emptyval; + +static struct iommu_table iommu_table_u3; +static int dart_dirty; + +#define DBG(...) + +static inline void dart_tlb_invalidate_all(void) +{ + unsigned long l = 0; + unsigned int reg; + unsigned long limit; + + DBG("dart: flush\n"); + + /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the + * control register and wait for it to clear. + * + * Gotcha: Sometimes, the DART won't detect that the bit gets + * set. If so, clear it and set it again. + */ + + limit = 0; + +retry: + reg = in_be32((unsigned int *)dart+DARTCNTL); + reg |= DARTCNTL_FLUSHTLB; + out_be32((unsigned int *)dart+DARTCNTL, reg); + + l = 0; + while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && + l < (1L<it_base) + index; + + /* On U3, all memory is contigous, so we can move this + * out of the loop. + */ + while (npages--) { + rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; + + *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); + + rpn++; + uaddr += PAGE_SIZE; + } + + dart_dirty = 1; +} + + +static void dart_free(struct iommu_table *tbl, long index, long npages) +{ + unsigned int *dp; + + /* We don't worry about flushing the TLB cache. The only drawback of + * not doing it is that we won't catch buggy device drivers doing + * bad DMAs, but then no 32-bit architecture ever does either. + */ + + DBG("dart: free at: %lx, %lx\n", index, npages); + + dp = ((unsigned int *)tbl->it_base) + index; + + while (npages--) + *(dp++) = dart_emptyval; +} + + +static int dart_init(struct device_node *dart_node) +{ + unsigned int regword; + unsigned int i; + unsigned long tmp; + struct page *p; + + if (dart_tablebase == 0 || dart_tablesize == 0) { + printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); + return -ENODEV; + } + + /* Make sure nothing from the DART range remains in the CPU cache + * from a previous mapping that existed before the kernel took + * over + */ + flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); + + /* Allocate a spare page to map all invalid DART pages. We need to do + * that to work around what looks like a problem with the HT bridge + * prefetching into invalid pages and corrupting data + */ + tmp = __get_free_pages(GFP_ATOMIC, 1); + if (tmp == 0) + panic("U3-DART: Cannot allocate spare page !"); + dart_emptyval = DARTMAP_VALID | + ((virt_to_abs(tmp) >> PAGE_SHIFT) & DARTMAP_RPNMASK); + + /* Map in DART registers. FIXME: Use device node to get base address */ + dart = ioremap(DART_BASE, 0x7000); + if (dart == NULL) + panic("U3-DART: Cannot map registers !"); + + /* Set initial control register contents: table base, + * table size and enable bit + */ + regword = DARTCNTL_ENABLE | + ((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | + (((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK) + << DARTCNTL_SIZE_SHIFT); + p = virt_to_page(dart_tablebase); + dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); + + /* Fill initial table */ + for (i = 0; i < dart_tablesize/4; i++) + dart_vbase[i] = dart_emptyval; + + /* Initialize DART with table base and enable it. */ + out_be32((unsigned int *)dart, regword); + + /* Invalidate DART to get rid of possible stale TLBs */ + dart_tlb_invalidate_all(); + + iommu_table_u3.it_busno = 0; + + /* Units of tce entries */ + iommu_table_u3.it_offset = 0; + + /* Set the tce table size - measured in pages */ + iommu_table_u3.it_size = dart_tablesize >> PAGE_SHIFT; + + /* Initialize the common IOMMU code */ + iommu_table_u3.it_base = (unsigned long)dart_vbase; + iommu_table_u3.it_index = 0; + iommu_table_u3.it_blocksize = 1; + iommu_table_u3.it_entrysize = sizeof(u32); + iommu_init_table(&iommu_table_u3); + + /* Reserve the last page of the DART to avoid possible prefetch + * past the DART mapped area + */ + set_bit(iommu_table_u3.it_mapsize - 1, iommu_table_u3.it_map); + + printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n"); + + return 0; +} + +void iommu_setup_u3(void) +{ + struct pci_dev *dev = NULL; + struct device_node *dn; + + /* Find the DART in the device-tree */ + dn = of_find_compatible_node(NULL, "dart", "u3-dart"); + if (dn == NULL) + return; + + /* Setup low level TCE operations for the core IOMMU code */ + ppc_md.tce_build = dart_build; + ppc_md.tce_free = dart_free; + ppc_md.tce_flush = dart_flush; + + /* Initialize the DART HW */ + if (dart_init(dn)) + return; + + /* Setup pci_dma ops */ + pci_iommu_init(); + + /* We only have one iommu table on the mac for now, which makes + * things simple. Setup all PCI devices to point to this table + */ + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + /* We must use pci_device_to_OF_node() to make sure that + * we get the real "final" pointer to the device in the + * pci_dev sysdata and not the temporary PHB one + */ + struct device_node *dn = pci_device_to_OF_node(dev); + if (dn) + dn->iommu_table = &iommu_table_u3; + } +} + +void __init alloc_u3_dart_table(void) +{ + /* Only reserve DART space if machine has more than 2GB of RAM + * or if requested with iommu=on on cmdline. + */ + if (lmb_end_of_DRAM() <= 0x80000000ull && !iommu_force_on) + return; + + /* 512 pages (2MB) is max DART tablesize. */ + dart_tablesize = 1UL << 21; + /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we + * will blow up an entire large page anyway in the kernel mapping + */ + dart_tablebase = (unsigned long) + abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); + + printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); +} diff --git a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c index da2179154..2f0470dbd 100644 --- a/arch/ppc64/kernel/udbg.c +++ b/arch/ppc64/kernel/udbg.c @@ -84,23 +84,38 @@ static unsigned char scc_inittab[] = { void udbg_init_scc(struct device_node *np) { + u32 *reg; unsigned long addr; int i, x; if (np == NULL) np = of_find_node_by_name(NULL, "escc"); - if (np == NULL) + if (np == NULL || np->parent == NULL) + return; + + udbg_printf("found SCC...\n"); + /* Get address within mac-io ASIC */ + reg = (u32 *)get_property(np, "reg", NULL); + if (reg == NULL) + return; + addr = reg[0]; + udbg_printf("local addr: %lx\n", addr); + /* Get address of mac-io PCI itself */ + reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); + if (reg == NULL) return; - - /* Lock-enable the SCC channel */ - pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); + addr += reg[2]; + udbg_printf("final addr: %lx\n", addr); /* Setup for 57600 8N1 */ - addr = np->addrs[0].address + 0x20; + addr += 0x20; sccc = (volatile u8 *) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; sccc += addr & ~PAGE_MASK; sccd = sccc + 0x10; + udbg_printf("ioremap result sccc: %p\n", sccc); + mb(); + for (i = 20000; i != 0; --i) x = *sccc; eieio(); *sccc = 9; eieio(); /* reset A or B side */ @@ -119,6 +134,30 @@ void udbg_init_scc(struct device_node *np) #endif /* CONFIG_PPC_PMAC */ +#if CONFIG_PPC_PMAC +extern u8 real_readb(volatile u8 *addr); +extern void real_writeb(u8 data, volatile u8 *addr); + +static void udbg_real_putc(unsigned char c) +{ + while ((real_readb(sccc) & SCC_TXRDY) == 0) + ; + real_writeb(c, sccd); + if (c == '\n') + udbg_real_putc('\r'); +} + +void udbg_init_pmac_realmode(void) +{ + sccc = (volatile u8 *)0x80013020ul; + sccd = (volatile u8 *)0x80013030ul; + + ppc_md.udbg_putc = udbg_real_putc; + ppc_md.udbg_getc = NULL; + ppc_md.udbg_getc_poll = NULL; +} +#endif /* CONFIG_PPC_PMAC */ + void udbg_putc(unsigned char c) { if (udbg_comport) { @@ -191,9 +230,12 @@ void udbg_puts(const char *s) while ((c = *s++) != '\0') ppc_md.udbg_putc(c); } - } else { + } +#if 0 + else { printk("%s", s); } +#endif } int udbg_write(const char *s, int n) @@ -218,7 +260,7 @@ int udbg_read(char *buf, int buflen) char c, *p = buf; int i; - if (!ppc_md.udbg_putc) + if (!ppc_md.udbg_getc) return 0; for (i = 0; i < buflen; ++i) { diff --git a/arch/ppc64/kernel/vector.S b/arch/ppc64/kernel/vector.S index 940cd7287..b79d33e40 100644 --- a/arch/ppc64/kernel/vector.S +++ b/arch/ppc64/kernel/vector.S @@ -89,7 +89,7 @@ _GLOBAL(vmaddfp) 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fmadds fr0,fr0,fr1,fr2 + fmadds fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b @@ -109,7 +109,7 @@ _GLOBAL(vnmsubfp) 1: lfsx fr0,r4,r7 lfsx fr1,r5,r7 lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr1,fr2 + fnmsubs fr0,fr0,fr2,fr1 stfsx fr0,r3,r7 addi r7,r7,4 bdnz 1b diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c index a5fd6e772..48c4b0a0a 100644 --- a/arch/ppc64/kernel/vio.c +++ b/arch/ppc64/kernel/vio.c @@ -225,6 +225,10 @@ static void probe_bus_iseries(void) struct vio_dev *viodev; int i; + /* there is only one of each of these */ + vio_register_device_iseries("viocons", 0); + vio_register_device_iseries("vscsi", 0); + vlan_map = HvLpConfig_getVirtualLanIndexMap(); for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { if ((vlan_map & (0x8000 >> i)) == 0) diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c index 7b6c257f4..66a810239 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/ppc64/kernel/viopath.c @@ -38,8 +38,8 @@ #include #include #include +#include -#include #include #include #include diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S index 1d9b61143..4103cc13f 100644 --- a/arch/ppc64/kernel/vmlinux.lds.S +++ b/arch/ppc64/kernel/vmlinux.lds.S @@ -14,6 +14,7 @@ SECTIONS .text : { *(.text .text.*) SCHED_TEXT + LOCK_TEXT *(.fixup) . = ALIGN(4096); _etext = .; @@ -61,12 +62,6 @@ SECTIONS __setup_end = .; } - __param : { - __start___param = .; - *(__param) - __stop___param = .; - } - .initcall.init : { __initcall_start = .; *(.initcall1.init) @@ -122,10 +117,13 @@ SECTIONS .data : { *(.data .data.rel* .toc1) - *(.opd) *(.branch_lt) } + .opd : { + *(.opd) + } + .got : { __toc_start = .; *(.got) diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index c9f950c2c..ae15d2215 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -536,7 +536,7 @@ nextnode: #ifdef CONFIG_SMP for_each_cpu(i) { /* FIXME: Do this dynamically! --RR */ - if (!cpu_present_at_boot(i)) + if (!cpu_present(i)) continue; xics_per_cpu[i] = __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, (ulong)inodes[get_hard_smp_processor_id(i)].size, diff --git a/arch/ppc64/lib/checksum.S b/arch/ppc64/lib/checksum.S index 4ac6a63ca..ef96c6c58 100644 --- a/arch/ppc64/lib/checksum.S +++ b/arch/ppc64/lib/checksum.S @@ -92,19 +92,19 @@ _GLOBAL(csum_partial) adde r5,r5,r6 bdnz 2b andi. r4,r4,7 /* compute bytes left to sum after doublewords */ -3: cmpi 0,r4,4 /* is at least a full word left? */ +3: cmpwi 0,r4,4 /* is at least a full word left? */ blt 4f lwz r6,8(r3) /* sum this word */ addi r3,r3,4 subi r4,r4,4 adde r5,r5,r6 -4: cmpi 0,r4,2 /* is at least a halfword left? */ +4: cmpwi 0,r4,2 /* is at least a halfword left? */ blt+ 5f lhz r6,8(r3) /* sum this halfword */ addi r3,r3,2 subi r4,r4,2 adde r5,r5,r6 -5: cmpi 0,r4,1 /* is at least a byte left? */ +5: cmpwi 0,r4,1 /* is at least a byte left? */ bne+ 6f lbz r6,8(r3) /* sum this byte */ slwi r6,r6,8 /* this byte is assumed to be the upper byte of a halfword */ @@ -150,7 +150,7 @@ _GLOBAL(csum_partial_copy_generic) adde r0,r0,r6 bdnz 82b andi. r5,r5,3 -3: cmpi 0,r5,2 +3: cmpwi 0,r5,2 blt+ 4f 83: lhz r6,4(r3) addi r3,r3,2 @@ -158,7 +158,7 @@ _GLOBAL(csum_partial_copy_generic) 93: sth r6,4(r4) addi r4,r4,2 adde r0,r0,r6 -4: cmpi 0,r5,1 +4: cmpwi 0,r5,1 bne+ 5f 84: lbz r6,4(r3) 94: stb r6,4(r4) @@ -198,7 +198,7 @@ src_error_3: bdnz 97b .globl src_error src_error: - cmpi 0,r7,0 + cmpdi 0,r7,0 beq 1f li r6,-EFAULT stw r6,0(r7) @@ -207,7 +207,7 @@ src_error: .globl dst_error dst_error: - cmpi 0,r8,0 + cmpdi 0,r8,0 beq 1f li r6,-EFAULT stw r6,0(r8) diff --git a/arch/ppc64/lib/locks.c b/arch/ppc64/lib/locks.c index 58e973cc8..72d642d7e 100644 --- a/arch/ppc64/lib/locks.c +++ b/arch/ppc64/lib/locks.c @@ -20,28 +20,9 @@ #include #include -#ifndef CONFIG_SPINLINE - -/* - * On a system with shared processors (that is, where a physical - * processor is multiplexed between several virtual processors), - * there is no point spinning on a lock if the holder of the lock - * isn't currently scheduled on a physical processor. Instead - * we detect this situation and ask the hypervisor to give the - * rest of our timeslice to the lock holder. - * - * So that we can tell which virtual processor is holding a lock, - * we put 0x80000000 | smp_processor_id() in the lock when it is - * held. Conveniently, we have a word in the paca that holds this - * value. - */ - /* waiting for a spinlock... */ #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) -/* We only yield to the hypervisor if we are in shared processor mode */ -#define SHARED_PROCESSOR (get_paca()->lppaca.xSharedProc) - void __spin_yield(spinlock_t *lock) { unsigned int lock_value, holder_cpu, yield_count; @@ -63,100 +44,16 @@ void __spin_yield(spinlock_t *lock) HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, ((u64)holder_cpu << 32) | yield_count); #else - plpar_hcall_norets(H_CONFER, holder_cpu, yield_count); + plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), + yield_count); #endif } -#else /* SPLPAR || ISERIES */ -#define __spin_yield(x) barrier() -#define SHARED_PROCESSOR 0 -#endif - -/* - * This returns the old value in the lock, so we succeeded - * in getting the lock if the return value is 0. - */ -static __inline__ unsigned long __spin_trylock(spinlock_t *lock) -{ - unsigned long tmp, tmp2; - - __asm__ __volatile__( -" lwz %1,%3(13) # __spin_trylock\n\ -1: lwarx %0,0,%2\n\ - cmpwi 0,%0,0\n\ - bne- 2f\n\ - stwcx. %1,0,%2\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp), "=&r" (tmp2) - : "r" (&lock->lock), "i" (offsetof(struct paca_struct, lock_token)) - : "cr0", "memory"); - - return tmp; -} - -int _raw_spin_trylock(spinlock_t *lock) -{ - return __spin_trylock(lock) == 0; -} - -EXPORT_SYMBOL(_raw_spin_trylock); - -void _raw_spin_lock(spinlock_t *lock) -{ - while (1) { - if (likely(__spin_trylock(lock) == 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } while (likely(lock->lock != 0)); - HMT_medium(); - } -} - -EXPORT_SYMBOL(_raw_spin_lock); - -void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags) -{ - unsigned long flags_dis; - - while (1) { - if (likely(__spin_trylock(lock) == 0)) - break; - local_save_flags(flags_dis); - local_irq_restore(flags); - do { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } while (likely(lock->lock != 0)); - HMT_medium(); - local_irq_restore(flags_dis); - } -} - -EXPORT_SYMBOL(_raw_spin_lock_flags); - -void spin_unlock_wait(spinlock_t *lock) -{ - while (lock->lock) { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } - HMT_medium(); -} - -EXPORT_SYMBOL(spin_unlock_wait); - /* * Waiting for a read lock or a write lock on a rwlock... * This turns out to be the same for read and write locks, since * we only know the holder if it is write-locked. */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) void __rw_yield(rwlock_t *rw) { int lock_value; @@ -179,121 +76,20 @@ void __rw_yield(rwlock_t *rw) HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, ((u64)holder_cpu << 32) | yield_count); #else - plpar_hcall_norets(H_CONFER, holder_cpu, yield_count); + plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), + yield_count); #endif } - -#else /* SPLPAR || ISERIES */ -#define __rw_yield(x) barrier() #endif -/* - * This returns the old value in the lock + 1, - * so we got a read lock if the return value is > 0. - */ -static __inline__ long __read_trylock(rwlock_t *rw) -{ - long tmp; - - __asm__ __volatile__( -"1: lwarx %0,0,%1 # read_trylock\n\ - extsw %0,%0\n\ - addic. %0,%0,1\n\ - ble- 2f\n\ - stwcx. %0,0,%1\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp) - : "r" (&rw->lock) - : "cr0", "xer", "memory"); - - return tmp; -} - -int _raw_read_trylock(rwlock_t *rw) -{ - return __read_trylock(rw) > 0; -} - -EXPORT_SYMBOL(_raw_read_trylock); - -void _raw_read_lock(rwlock_t *rw) -{ - while (1) { - if (likely(__read_trylock(rw) > 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __rw_yield(rw); - } while (likely(rw->lock < 0)); - HMT_medium(); - } -} - -EXPORT_SYMBOL(_raw_read_lock); - -void _raw_read_unlock(rwlock_t *rw) -{ - long tmp; - - __asm__ __volatile__( - "eieio # read_unlock\n\ -1: lwarx %0,0,%1\n\ - addic %0,%0,-1\n\ - stwcx. %0,0,%1\n\ - bne- 1b" - : "=&r"(tmp) - : "r"(&rw->lock) - : "cr0", "memory"); -} - -EXPORT_SYMBOL(_raw_read_unlock); - -/* - * This returns the old value in the lock, - * so we got the write lock if the return value is 0. - */ -static __inline__ long __write_trylock(rwlock_t *rw) -{ - long tmp, tmp2; - - __asm__ __volatile__( -" lwz %1,%3(13) # write_trylock\n\ -1: lwarx %0,0,%2\n\ - cmpwi 0,%0,0\n\ - bne- 2f\n\ - stwcx. %1,0,%2\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp), "=&r" (tmp2) - : "r" (&rw->lock), "i" (offsetof(struct paca_struct, lock_token)) - : "cr0", "memory"); - - return tmp; -} - -int _raw_write_trylock(rwlock_t *rw) -{ - return __write_trylock(rw) == 0; -} - -EXPORT_SYMBOL(_raw_write_trylock); - -void _raw_write_lock(rwlock_t *rw) +void spin_unlock_wait(spinlock_t *lock) { - while (1) { - if (likely(__write_trylock(rw) == 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __rw_yield(rw); - } while (likely(rw->lock != 0)); - HMT_medium(); + while (lock->lock) { + HMT_low(); + if (SHARED_PROCESSOR) + __spin_yield(lock); } + HMT_medium(); } -EXPORT_SYMBOL(_raw_write_lock); - -#endif /* CONFIG_SPINLINE */ +EXPORT_SYMBOL(spin_unlock_wait); diff --git a/arch/ppc64/mm/Makefile b/arch/ppc64/mm/Makefile index 0306babff..ac522d57b 100644 --- a/arch/ppc64/mm/Makefile +++ b/arch/ppc64/mm/Makefile @@ -4,6 +4,8 @@ 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 +obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o tlb.o \ + slb_low.o slb.o stab.o mmap.o obj-$(CONFIG_DISCONTIGMEM) += numa.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += hash_native.o diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S index 0d6b5c29b..68dd4b9ad 100644 --- a/arch/ppc64/mm/hash_low.S +++ b/arch/ppc64/mm/hash_low.S @@ -172,9 +172,9 @@ htab_insert_pte: li r9,0 _GLOBAL(htab_call_hpte_insert1) bl . /* Will be patched by htab_finish_init() */ - cmpi 0,r3,0 + cmpdi 0,r3,0 bge htab_pte_insert_ok /* Insertion successful */ - cmpi 0,r3,-2 /* Critical failure */ + cmpdi 0,r3,-2 /* Critical failure */ beq- htab_pte_insert_failure /* Now try secondary slot */ @@ -194,9 +194,9 @@ _GLOBAL(htab_call_hpte_insert1) li r9,0 _GLOBAL(htab_call_hpte_insert2) bl . /* Will be patched by htab_finish_init() */ - cmpi 0,r3,0 + cmpdi 0,r3,0 bge+ htab_pte_insert_ok /* Insertion successful */ - cmpi 0,r3,-2 /* Critical failure */ + cmpdi 0,r3,-2 /* Critical failure */ beq- htab_pte_insert_failure /* Both are full, we need to evict something */ @@ -263,7 +263,7 @@ _GLOBAL(htab_call_hpte_updatepp) /* if we failed because typically the HPTE wasn't really here * we try an insertion. */ - cmpi 0,r3,-1 + cmpdi 0,r3,-1 beq- htab_insert_pte /* Clear the BUSY bit and Write out the PTE */ @@ -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_native.c b/arch/ppc64/mm/hash_native.c new file mode 100644 index 000000000..0d8c8ab19 --- /dev/null +++ b/arch/ppc64/mm/hash_native.c @@ -0,0 +1,419 @@ +/* + * native hashtable management. + * + * SMP scalability work: + * Copyright (C) 2001 Anton Blanchard , IBM + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HPTE_LOCK_BIT 3 + +static spinlock_t native_tlbie_lock = SPIN_LOCK_UNLOCKED; + +static inline void native_lock_hpte(HPTE *hptep) +{ + unsigned long *word = &hptep->dw0.dword0; + + while (1) { + if (!test_and_set_bit(HPTE_LOCK_BIT, word)) + break; + while(test_bit(HPTE_LOCK_BIT, word)) + cpu_relax(); + } +} + +static inline void native_unlock_hpte(HPTE *hptep) +{ + unsigned long *word = &hptep->dw0.dword0; + + asm volatile("lwsync":::"memory"); + clear_bit(HPTE_LOCK_BIT, word); +} + +long native_hpte_insert(unsigned long hpte_group, unsigned long va, + unsigned long prpn, int secondary, + unsigned long hpteflags, int bolted, int large) +{ + unsigned long arpn = physRpn_to_absRpn(prpn); + HPTE *hptep = htab_data.htab + hpte_group; + Hpte_dword0 dw0; + HPTE lhpte; + int i; + + for (i = 0; i < HPTES_PER_GROUP; i++) { + dw0 = hptep->dw0.dw0; + + if (!dw0.v) { + /* retry with lock held */ + native_lock_hpte(hptep); + dw0 = hptep->dw0.dw0; + if (!dw0.v) + break; + native_unlock_hpte(hptep); + } + + hptep++; + } + + if (i == HPTES_PER_GROUP) + return -1; + + lhpte.dw1.dword1 = 0; + lhpte.dw1.dw1.rpn = arpn; + lhpte.dw1.flags.flags = hpteflags; + + lhpte.dw0.dword0 = 0; + lhpte.dw0.dw0.avpn = va >> 23; + lhpte.dw0.dw0.h = secondary; + lhpte.dw0.dw0.bolted = bolted; + lhpte.dw0.dw0.v = 1; + + if (large) { + lhpte.dw0.dw0.l = 1; + lhpte.dw0.dw0.avpn &= ~0x1UL; + } + + hptep->dw1.dword1 = lhpte.dw1.dword1; + + /* Guarantee the second dword is visible before the valid bit */ + __asm__ __volatile__ ("eieio" : : : "memory"); + + /* + * Now set the first dword including the valid bit + * NOTE: this also unlocks the hpte + */ + hptep->dw0.dword0 = lhpte.dw0.dword0; + + __asm__ __volatile__ ("ptesync" : : : "memory"); + + return i | (secondary << 3); +} + +static long native_hpte_remove(unsigned long hpte_group) +{ + HPTE *hptep; + Hpte_dword0 dw0; + int i; + int slot_offset; + + /* pick a random entry to start at */ + slot_offset = mftb() & 0x7; + + for (i = 0; i < HPTES_PER_GROUP; i++) { + hptep = htab_data.htab + hpte_group + slot_offset; + dw0 = hptep->dw0.dw0; + + if (dw0.v && !dw0.bolted) { + /* retry with lock held */ + native_lock_hpte(hptep); + dw0 = hptep->dw0.dw0; + if (dw0.v && !dw0.bolted) + break; + native_unlock_hpte(hptep); + } + + slot_offset++; + slot_offset &= 0x7; + } + + if (i == HPTES_PER_GROUP) + return -1; + + /* Invalidate the hpte. NOTE: this also unlocks it */ + hptep->dw0.dword0 = 0; + + return i; +} + +static inline void set_pp_bit(unsigned long pp, HPTE *addr) +{ + unsigned long old; + unsigned long *p = &addr->dw1.dword1; + + __asm__ __volatile__( + "1: ldarx %0,0,%3\n\ + rldimi %0,%2,0,61\n\ + stdcx. %0,0,%3\n\ + bne 1b" + : "=&r" (old), "=m" (*p) + : "r" (pp), "r" (p), "m" (*p) + : "cc"); +} + +/* + * Only works on small pages. Yes its ugly to have to check each slot in + * the group but we only use this during bootup. + */ +static long native_hpte_find(unsigned long vpn) +{ + HPTE *hptep; + unsigned long hash; + unsigned long i, j; + long slot; + Hpte_dword0 dw0; + + hash = hpt_hash(vpn, 0); + + for (j = 0; j < 2; j++) { + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + for (i = 0; i < HPTES_PER_GROUP; i++) { + hptep = htab_data.htab + slot; + dw0 = hptep->dw0.dw0; + + if ((dw0.avpn == (vpn >> 11)) && dw0.v && + (dw0.h == j)) { + /* HPTE matches */ + if (j) + slot = -slot; + return slot; + } + ++slot; + } + hash = ~hash; + } + + return -1; +} + +static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, + unsigned long va, int large, int local) +{ + HPTE *hptep = htab_data.htab + slot; + Hpte_dword0 dw0; + unsigned long avpn = va >> 23; + int ret = 0; + + if (large) + avpn &= ~0x1UL; + + native_lock_hpte(hptep); + + dw0 = hptep->dw0.dw0; + + /* Even if we miss, we need to invalidate the TLB */ + if ((dw0.avpn != avpn) || !dw0.v) { + native_unlock_hpte(hptep); + ret = -1; + } else { + set_pp_bit(newpp, hptep); + native_unlock_hpte(hptep); + } + + /* Ensure it is out of the tlb too */ + if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + tlbiel(va); + } else { + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) + spin_lock(&native_tlbie_lock); + tlbie(va, large); + if (lock_tlbie) + spin_unlock(&native_tlbie_lock); + } + + return ret; +} + +/* + * Update the page protection bits. Intended to be used to create + * guard pages for kernel data structures on pages which are bolted + * in the HPT. Assumes pages being operated on will not be stolen. + * Does not work on large pages. + * + * No need to lock here because we should be the only user. + */ +static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) +{ + unsigned long vsid, va, vpn, flags; + long slot; + HPTE *hptep; + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + vsid = get_kernel_vsid(ea); + va = (vsid << 28) | (ea & 0x0fffffff); + vpn = va >> PAGE_SHIFT; + + slot = native_hpte_find(vpn); + if (slot == -1) + panic("could not find page to bolt\n"); + hptep = htab_data.htab + slot; + + set_pp_bit(newpp, hptep); + + /* Ensure it is out of the tlb too */ + if (lock_tlbie) + spin_lock_irqsave(&native_tlbie_lock, flags); + tlbie(va, 0); + if (lock_tlbie) + spin_unlock_irqrestore(&native_tlbie_lock, flags); +} + +static void native_hpte_invalidate(unsigned long slot, unsigned long va, + int large, int local) +{ + HPTE *hptep = htab_data.htab + slot; + Hpte_dword0 dw0; + unsigned long avpn = va >> 23; + unsigned long flags; + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (large) + avpn &= ~0x1UL; + + local_irq_save(flags); + native_lock_hpte(hptep); + + dw0 = hptep->dw0.dw0; + + /* Even if we miss, we need to invalidate the TLB */ + if ((dw0.avpn != avpn) || !dw0.v) { + native_unlock_hpte(hptep); + } else { + /* Invalidate the hpte. NOTE: this also unlocks it */ + hptep->dw0.dword0 = 0; + } + + /* Invalidate the tlb */ + if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + tlbiel(va); + } else { + if (lock_tlbie) + spin_lock(&native_tlbie_lock); + tlbie(va, large); + if (lock_tlbie) + spin_unlock(&native_tlbie_lock); + } + local_irq_restore(flags); +} + +static void native_flush_hash_range(unsigned long context, + unsigned long number, int local) +{ + unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn; + int i, j; + HPTE *hptep; + Hpte_dword0 dw0; + struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + + /* XXX fix for large ptes */ + unsigned long large = 0; + + local_irq_save(flags); + + j = 0; + for (i = 0; i < number; i++) { + if ((batch->addr[i] >= USER_START) && + (batch->addr[i] <= USER_END)) + vsid = get_vsid(context, batch->addr[i]); + else + vsid = get_kernel_vsid(batch->addr[i]); + + va = (vsid << 28) | (batch->addr[i] & 0x0fffffff); + batch->vaddr[j] = va; + if (large) + vpn = va >> HPAGE_SHIFT; + else + vpn = va >> PAGE_SHIFT; + hash = hpt_hash(vpn, large); + secondary = (pte_val(batch->pte[i]) & _PAGE_SECONDARY) >> 15; + if (secondary) + hash = ~hash; + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + slot += (pte_val(batch->pte[i]) & _PAGE_GROUP_IX) >> 12; + + hptep = htab_data.htab + slot; + + avpn = va >> 23; + if (large) + avpn &= ~0x1UL; + + native_lock_hpte(hptep); + + dw0 = hptep->dw0.dw0; + + /* Even if we miss, we need to invalidate the TLB */ + if ((dw0.avpn != avpn) || !dw0.v) { + native_unlock_hpte(hptep); + } else { + /* Invalidate the hpte. NOTE: this also unlocks it */ + hptep->dw0.dword0 = 0; + } + + j++; + } + + if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + asm volatile("ptesync":::"memory"); + + for (i = 0; i < j; i++) + __tlbiel(batch->vaddr[i]); + + asm volatile("ptesync":::"memory"); + } else { + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) + spin_lock(&native_tlbie_lock); + + asm volatile("ptesync":::"memory"); + + for (i = 0; i < j; i++) + __tlbie(batch->vaddr[i], 0); + + asm volatile("eieio; tlbsync; ptesync":::"memory"); + + if (lock_tlbie) + spin_unlock(&native_tlbie_lock); + } + + local_irq_restore(flags); +} + +void hpte_init_native(void) +{ +#ifdef CONFIG_PPC_PSERIES + struct device_node *root; + const char *model; +#endif /* CONFIG_PPC_PSERIES */ + + ppc_md.hpte_invalidate = native_hpte_invalidate; + ppc_md.hpte_updatepp = native_hpte_updatepp; + ppc_md.hpte_updateboltedpp = native_hpte_updateboltedpp; + ppc_md.hpte_insert = native_hpte_insert; + ppc_md.hpte_remove = native_hpte_remove; + +#ifdef CONFIG_PPC_PSERIES + /* Disable TLB batching on nighthawk */ + root = of_find_node_by_path("/"); + if (root) { + model = get_property(root, "model", NULL); + if (!strcmp(model, "CHRP IBM,9076-N81")) { + of_node_put(root); + goto bail; + } + of_node_put(root); + } +#endif /* CONFIG_PPC_PSERIES */ + + ppc_md.flush_hash_range = native_flush_hash_range; + bail: + htab_finish_init(); +} diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index f40565840..3a8a61380 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c @@ -18,6 +18,8 @@ * 2 of the License, or (at your option) any later version. */ +#undef DEBUG + #include #include #include @@ -28,6 +30,7 @@ #include #include #include +#include #include #include @@ -50,6 +53,12 @@ #include #include +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + /* * Note: pte --> Linux PTE * HPTE --> PowerPC Hashed Page Table Entry @@ -62,9 +71,9 @@ * */ -#ifdef CONFIG_PMAC_DART +#ifdef CONFIG_U3_DART extern unsigned long dart_tablebase; -#endif /* CONFIG_PMAC_DART */ +#endif /* CONFIG_U3_DART */ HTAB htab_data = {NULL, 0, 0, 0, 0}; @@ -80,7 +89,7 @@ static inline void loop_forever(void) ; } -#ifdef CONFIG_PPC_PSERIES +#ifdef CONFIG_PPC_MULTIPLATFORM static inline void create_pte_mapping(unsigned long start, unsigned long end, unsigned long mode, int large) { @@ -99,7 +108,7 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end, int ret; if (large) - vpn = va >> LARGE_PAGE_SHIFT; + vpn = va >> HPAGE_SHIFT; else vpn = va >> PAGE_SHIFT; @@ -107,12 +116,14 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end, hpteg = ((hash & htab_data.htab_hash_mask)*HPTES_PER_GROUP); - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) +#ifdef CONFIG_PPC_PSERIES + if (systemcfg->platform & PLATFORM_LPAR) ret = pSeries_lpar_hpte_insert(hpteg, va, virt_to_abs(addr) >> PAGE_SHIFT, 0, mode, 1, large); else - ret = pSeries_hpte_insert(hpteg, va, +#endif /* CONFIG_PPC_PSERIES */ + ret = native_hpte_insert(hpteg, va, virt_to_abs(addr) >> PAGE_SHIFT, 0, mode, 1, large); @@ -130,6 +141,8 @@ void __init htab_initialize(void) unsigned long mode_rw; int i, use_largepages = 0; + DBG(" -> htab_initialize()\n"); + /* * Calculate the required size of the htab. We want the number of * PTEGs to equal one half the number of real pages. @@ -146,12 +159,19 @@ void __init htab_initialize(void) htab_data.htab_num_ptegs = pteg_count; htab_data.htab_hash_mask = pteg_count - 1; - if (systemcfg->platform == PLATFORM_PSERIES || - systemcfg->platform == PLATFORM_POWERMAC) { + if (systemcfg->platform & PLATFORM_LPAR) { + /* Using a hypervisor which owns the htab */ + htab_data.htab = NULL; + _SDR1 = 0; + } else { /* Find storage for the HPT. Must be contiguous in * the absolute address space. */ table = lmb_alloc(htab_size_bytes, htab_size_bytes); + + DBG("Hash table allocated at %lx, size: %lx\n", table, + htab_size_bytes); + if ( !table ) { ppc64_terminate_msg(0x20, "hpt space"); loop_forever(); @@ -163,10 +183,6 @@ void __init htab_initialize(void) /* Initialize the HPT with no entries */ memset((void *)table, 0, htab_size_bytes); - } else { - /* Using a hypervisor which owns the htab */ - htab_data.htab = NULL; - _SDR1 = 0; } mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; @@ -178,14 +194,16 @@ void __init htab_initialize(void) if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) use_largepages = 1; - /* add all physical memory to the bootmem map */ + /* create bolted the linear mapping in the hash table */ for (i=0; i < lmb.memory.cnt; i++) { unsigned long base, size; base = lmb.memory.region[i].physbase + KERNELBASE; size = lmb.memory.region[i].size; -#ifdef CONFIG_PMAC_DART + DBG("creating mapping for region: %lx : %lx\n", base, size); + +#ifdef CONFIG_U3_DART /* Do not map the DART space. Fortunately, it will be aligned * in such a way that it will not cross two lmb regions and will * fit within a single 16Mb page. @@ -193,6 +211,8 @@ void __init htab_initialize(void) * only use 2Mb of that space. We will use more of it later for * AGP GART. We have to use a full 16Mb large page. */ + DBG("DART base: %lx\n", dart_tablebase); + if (dart_tablebase != 0 && dart_tablebase >= base && dart_tablebase < (base + size)) { if (base != dart_tablebase) @@ -203,13 +223,14 @@ void __init htab_initialize(void) mode_rw, use_largepages); continue; } -#endif /* CONFIG_PMAC_DART */ +#endif /* CONFIG_U3_DART */ create_pte_mapping(base, base + size, mode_rw, use_largepages); } + DBG(" <- htab_initialize()\n"); } #undef KB #undef MB -#endif +#endif /* CONFIG_PPC_MULTIPLATFORM */ /* * Called by asm hashtable.S for doing lazy icache flush @@ -236,14 +257,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; @@ -255,24 +273,24 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) int local = 0; cpumask_t tmp; - /* Check for invalid addresses. */ - if (!IS_VALID_EA(ea)) - return 1; - switch (REGION_ID(ea)) { case USER_REGION_ID: user_region = 1; mm = current->mm; - if (mm == NULL) + if ((ea > USER_END) || (! mm)) return 1; vsid = get_vsid(mm->context.id, ea); break; case IO_REGION_ID: + if (ea > IMALLOC_END) + return 1; mm = &ioremap_mm; vsid = get_kernel_vsid(ea); break; case VMALLOC_REGION_ID: + if (ea > VMALLOC_END) + return 1; mm = &init_mm; vsid = get_kernel_vsid(ea); break; @@ -334,7 +352,7 @@ void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte, va = (vsid << 28) | (ea & 0x0fffffff); if (large) - vpn = va >> LARGE_PAGE_SHIFT; + vpn = va >> HPAGE_SHIFT; else vpn = va >> PAGE_SHIFT; hash = hpt_hash(vpn, large); @@ -371,6 +389,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/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index b704e00d2..f9d47ac8f 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -527,6 +527,108 @@ full_search: return -ENOMEM; } +/* + * This mmap-allocator allocates new areas top-down from below the + * stack's low limit (the base): + * + * Because we have an exclusive hugepage region which lies within the + * normal user address space, we have to take special measures to make + * non-huge mmap()s evade the hugepage reserved regions. + */ +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) + && !is_hugepage_only_range(addr,len)) + 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 { +hugepage_recheck: + if (touches_hugepage_low_range(addr, len)) { + addr = (addr & ((~0) << SID_SHIFT)) - len; + goto hugepage_recheck; + } else if (touches_hugepage_high_range(addr, len)) { + addr = TASK_HPAGE_BASE - len; + } + + /* + * 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; +} + static unsigned long htlb_get_low_area(unsigned long len, u16 segmask) { unsigned long addr = 0; @@ -751,7 +853,7 @@ static void flush_hash_hugepage(mm_context_t context, unsigned long ea, vsid = get_vsid(context.id, ea); va = (vsid << 28) | (ea & 0x0fffffff); - vpn = va >> LARGE_PAGE_SHIFT; + vpn = va >> HPAGE_SHIFT; hash = hpt_hash(vpn, 1); if (hugepte_val(pte) & _HUGEPAGE_SECONDARY) hash = ~hash; diff --git a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c index 2399f3fcb..9d92b0d9c 100644 --- a/arch/ppc64/mm/imalloc.c +++ b/arch/ppc64/mm/imalloc.c @@ -37,33 +37,51 @@ static int get_free_im_addr(unsigned long size, unsigned long *im_addr) return 0; } +/* Return whether the region described by v_addr and size is a subset + * of the region described by parent + */ +static inline int im_region_is_subset(unsigned long v_addr, unsigned long size, + struct vm_struct *parent) +{ + return (int) (v_addr >= (unsigned long) parent->addr && + v_addr < (unsigned long) parent->addr + parent->size && + size < parent->size); +} + +/* Return whether the region described by v_addr and size is a superset + * of the region described by child + */ +static int im_region_is_superset(unsigned long v_addr, unsigned long size, + struct vm_struct *child) +{ + struct vm_struct parent; + + parent.addr = (void *) v_addr; + parent.size = size; + + return im_region_is_subset((unsigned long) child->addr, child->size, + &parent); +} + /* Return whether the region described by v_addr and size overlaps - * the region described by vm. Overlapping regions meet the + * the region described by vm. Overlapping regions meet the * following conditions: * 1) The regions share some part of the address space * 2) The regions aren't identical - * 3) The first region is not a subset of the second + * 3) Neither region is a subset of the other */ -static inline int im_region_overlaps(unsigned long v_addr, unsigned long size, +static int im_region_overlaps(unsigned long v_addr, unsigned long size, struct vm_struct *vm) { + if (im_region_is_superset(v_addr, size, vm)) + return 0; + return (v_addr + size > (unsigned long) vm->addr + vm->size && v_addr < (unsigned long) vm->addr + vm->size) || (v_addr < (unsigned long) vm->addr && v_addr + size > (unsigned long) vm->addr); } -/* Return whether the region described by v_addr and size is a subset - * of the region described by vm - */ -static inline int im_region_is_subset(unsigned long v_addr, unsigned long size, - struct vm_struct *vm) -{ - return (int) (v_addr >= (unsigned long) vm->addr && - v_addr < (unsigned long) vm->addr + vm->size && - size < vm->size); -} - /* Determine imalloc status of region described by v_addr and size. * Can return one of the following: * IM_REGION_UNUSED - Entire region is unallocated in imalloc space. @@ -73,28 +91,37 @@ static inline int im_region_is_subset(unsigned long v_addr, unsigned long size, * IM_REGION_EXISTS - Exact region already allocated in imalloc space. * vm will be assigned to a ptr to the existing imlist * member. - * IM_REGION_OVERLAPS - A portion of the region is already allocated in - * imalloc space. + * IM_REGION_OVERLAPS - Region overlaps an allocated region in imalloc space. + * IM_REGION_SUPERSET - Region is a superset of a region that is already + * allocated in imalloc space. */ -static int im_region_status(unsigned long v_addr, unsigned long size, +static int im_region_status(unsigned long v_addr, unsigned long size, struct vm_struct **vm) { struct vm_struct *tmp; - for (tmp = imlist; tmp; tmp = tmp->next) - if (v_addr < (unsigned long) tmp->addr + tmp->size) + for (tmp = imlist; tmp; tmp = tmp->next) + if (v_addr < (unsigned long) tmp->addr + tmp->size) break; - + if (tmp) { if (im_region_overlaps(v_addr, size, tmp)) return IM_REGION_OVERLAP; *vm = tmp; - if (im_region_is_subset(v_addr, size, tmp)) + if (im_region_is_subset(v_addr, size, tmp)) { + /* Return with tmp pointing to superset */ return IM_REGION_SUBSET; - else if (v_addr == (unsigned long) tmp->addr && - size == tmp->size) + } + if (im_region_is_superset(v_addr, size, tmp)) { + /* Return with tmp pointing to first subset */ + return IM_REGION_SUPERSET; + } + else if (v_addr == (unsigned long) tmp->addr && + size == tmp->size) { + /* Return with tmp pointing to exact region */ return IM_REGION_EXISTS; + } } *vm = NULL; @@ -208,6 +235,10 @@ static struct vm_struct * __im_get_area(unsigned long req_addr, tmp = split_im_region(req_addr, size, tmp); break; case IM_REGION_EXISTS: + /* Return requested region */ + break; + case IM_REGION_SUPERSET: + /* Return first existing subset of requested region */ break; default: printk(KERN_ERR "%s() unexpected imalloc region status\n", diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index 99d923868..cf0c57a7d 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -62,8 +63,6 @@ #include #include - -struct mmu_context_queue_t mmu_context_queue; int mem_init_done; unsigned long ioremap_bot = IMALLOC_BASE; static unsigned long phbs_io_bot = PHBS_IO_BASE; @@ -85,7 +84,6 @@ unsigned long __max_memory; /* info on what we think the IO hole is */ unsigned long io_hole_start; unsigned long io_hole_size; -unsigned long top_of_ram; void show_mem(void) { @@ -118,18 +116,18 @@ void show_mem(void) #ifdef CONFIG_PPC_ISERIES -void *ioremap(unsigned long addr, unsigned long size) +void __iomem *ioremap(unsigned long addr, unsigned long size) { - return (void *)addr; + return (void __iomem *)addr; } -extern void *__ioremap(unsigned long addr, unsigned long size, +extern void __iomem *__ioremap(unsigned long addr, unsigned long size, unsigned long flags) { - return (void *)addr; + return (void __iomem *)addr; } -void iounmap(void *addr) +void iounmap(volatile void __iomem *addr) { return; } @@ -183,7 +181,7 @@ static void map_io_page(unsigned long ea, unsigned long pa, int flags) } -static void * __ioremap_com(unsigned long addr, unsigned long pa, +static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, unsigned long ea, unsigned long size, unsigned long flags) { @@ -198,20 +196,17 @@ static void * __ioremap_com(unsigned long addr, unsigned long pa, map_io_page(ea+i, pa+i, flags); } - return (void *) (ea + (addr & ~PAGE_MASK)); + return (void __iomem *) (ea + (addr & ~PAGE_MASK)); } -void * +void __iomem * ioremap(unsigned long addr, unsigned long size) { - void *ret = __ioremap(addr, size, _PAGE_NO_CACHE); - if(mem_init_done) - return eeh_ioremap(addr, ret); /* may remap the addr */ - return ret; + return __ioremap(addr, size, _PAGE_NO_CACHE); } -void * +void __iomem * __ioremap(unsigned long addr, unsigned long size, unsigned long flags) { unsigned long pa, ea; @@ -354,19 +349,18 @@ static void unmap_im_area_pmd(pgd_t *dir, unsigned long address, * * XXX what about calls before mem_init_done (ie python_countermeasures()) */ -void iounmap(void *addr) +void iounmap(volatile void __iomem *token) { unsigned long address, start, end, size; struct mm_struct *mm; pgd_t *dir; + void *addr; if (!mem_init_done) { return; } - /* addr could be in EEH or IO region, map it to IO region regardless. - */ - addr = (void *) (IO_TOKEN_TO_ADDR(addr) & PAGE_MASK); + addr = (void *) ((unsigned long __force) token & PAGE_MASK); if ((size = im_free(addr)) == 0) { return; @@ -392,27 +386,55 @@ void iounmap(void *addr) return; } -int iounmap_explicit(void *addr, unsigned long size) +static int iounmap_subset_regions(unsigned long addr, unsigned long size) { struct vm_struct *area; + + /* Check whether subsets of this region exist */ + area = im_get_area(addr, size, IM_REGION_SUPERSET); + if (area == NULL) + return 1; + + while (area) { + iounmap((void __iomem *) area->addr); + area = im_get_area(addr, size, + IM_REGION_SUPERSET); + } + + return 0; +} + +int iounmap_explicit(volatile void __iomem *start, unsigned long size) +{ + struct vm_struct *area; + unsigned long addr; + int rc; - /* addr could be in EEH or IO region, map it to IO region regardless. - */ - addr = (void *) (IO_TOKEN_TO_ADDR(addr) & PAGE_MASK); + addr = (unsigned long __force) start & PAGE_MASK; /* Verify that the region either exists or is a subset of an existing * region. In the latter case, split the parent region to create * the exact region */ - area = im_get_area((unsigned long) addr, size, + area = im_get_area(addr, size, IM_REGION_EXISTS | IM_REGION_SUBSET); if (area == NULL) { - printk(KERN_ERR "%s() cannot unmap nonexistent range 0x%lx\n", - __FUNCTION__, (unsigned long) addr); - return 1; + /* Determine whether subset regions exist. If so, unmap */ + rc = iounmap_subset_regions(addr, size); + if (rc) { + printk(KERN_ERR + "%s() cannot unmap nonexistent range 0x%lx\n", + __FUNCTION__, addr); + return 1; + } + } else { + iounmap((void __iomem *) area->addr); } - + /* + * FIXME! This can't be right: iounmap(area->addr); + * Maybe it should be "iounmap(area);" + */ return 0; } @@ -447,41 +469,81 @@ void free_initrd_mem(unsigned long start, unsigned long end) } #endif +static spinlock_t mmu_context_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_IDR(mmu_context_idr); + +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + int index; + int err; + +again: + if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&mmu_context_lock); + err = idr_get_new(&mmu_context_idr, NULL, &index); + spin_unlock(&mmu_context_lock); + + if (err == -EAGAIN) + goto again; + else if (err) + return err; + + if (index > MAX_CONTEXT) { + idr_remove(&mmu_context_idr, index); + return -ENOMEM; + } + + mm->context.id = index; + + return 0; +} + +void destroy_context(struct mm_struct *mm) +{ + spin_lock(&mmu_context_lock); + idr_remove(&mmu_context_idr, mm->context.id); + spin_unlock(&mmu_context_lock); + + mm->context.id = NO_CONTEXT; +} + +static int __init mmu_context_init(void) +{ + int index; + + /* Reserve the first (invalid) context*/ + idr_pre_get(&mmu_context_idr, GFP_KERNEL); + idr_get_new(&mmu_context_idr, NULL, &index); + BUG_ON(0 != index); + + return 0; +} +arch_initcall(mmu_context_init); + /* * Do very early mm setup. */ void __init mm_init_ppc64(void) { +#ifndef CONFIG_PPC_ISERIES unsigned long i; +#endif ppc64_boot_msg(0x100, "MM Init"); - /* Reserve all contexts < FIRST_USER_CONTEXT for kernel use. - * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT) - * are stored on a stack/queue for easy allocation and deallocation. - */ - mmu_context_queue.lock = SPIN_LOCK_UNLOCKED; - mmu_context_queue.head = 0; - mmu_context_queue.tail = NUM_USER_CONTEXT-1; - mmu_context_queue.size = NUM_USER_CONTEXT; - for (i = 0; i < NUM_USER_CONTEXT; i++) - mmu_context_queue.elements[i] = i + FIRST_USER_CONTEXT; - /* This is the story of the IO hole... please, keep seated, * unfortunately, we are out of oxygen masks at the moment. * So we need some rough way to tell where your big IO hole * is. On pmac, it's between 2G and 4G, on POWER3, it's around * that area as well, on POWER4 we don't have one, etc... - * We need that to implement something approx. decent for - * page_is_ram() so that /dev/mem doesn't map cacheable IO space - * when XFree resquest some IO regions witout using O_SYNC, we - * also need that as a "hint" when sizing the TCE table on POWER3 + * We need that as a "hint" when sizing the TCE table on POWER3 * So far, the simplest way that seem work well enough for us it * to just assume that the first discontinuity in our physical * RAM layout is the IO hole. That may not be correct in the future * (and isn't on iSeries but then we don't care ;) */ - top_of_ram = lmb_end_of_DRAM(); #ifndef CONFIG_PPC_ISERIES for (i = 1; i < lmb.memory.cnt; i++) { @@ -504,22 +566,32 @@ void __init mm_init_ppc64(void) ppc64_boot_msg(0x100, "MM Init Done"); } - /* * This is called by /dev/mem to know if a given address has to * be mapped non-cacheable or not */ -int page_is_ram(unsigned long physaddr) +int page_is_ram(unsigned long pfn) { -#ifdef CONFIG_PPC_ISERIES - return 1; + int i; + unsigned long paddr = (pfn << PAGE_SHIFT); + + for (i=0; i < lmb.memory.cnt; i++) { + unsigned long base; + +#ifdef CONFIG_MSCHUNKS + base = lmb.memory.region[i].physbase; +#else + base = lmb.memory.region[i].base; #endif - if (physaddr >= top_of_ram) - return 0; - return io_hole_start == 0 || physaddr < io_hole_start || - physaddr >= (io_hole_start + io_hole_size); -} + if ((paddr >= base) && + (paddr < (base + lmb.memory.region[i].size))) { + return 1; + } + } + return 0; +} +EXPORT_SYMBOL(page_is_ram); /* * Initialize the bootmem system and give it all the memory we @@ -573,6 +645,7 @@ void __init paging_init(void) unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; unsigned long total_ram = lmb_phys_mem_size(); + unsigned long top_of_ram = lmb_end_of_DRAM(); printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", top_of_ram, total_ram); @@ -587,7 +660,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; } @@ -622,59 +695,53 @@ module_init(setup_kcore); void __init mem_init(void) { -#ifndef CONFIG_DISCONTIGMEM - unsigned long addr; +#ifdef CONFIG_DISCONTIGMEM + int nid; #endif - int codepages = 0; - int datapages = 0; - int initpages = 0; + pg_data_t *pgdat; + unsigned long i; + struct page *page; + unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; num_physpages = max_low_pfn; /* RAM is assumed contiguous */ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); #ifdef CONFIG_DISCONTIGMEM -{ - int nid; - for (nid = 0; nid < numnodes; nid++) { - if (node_data[nid].node_spanned_pages != 0) { + if (NODE_DATA(nid)->node_spanned_pages != 0) { printk("freeing bootmem node %x\n", nid); totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); } } - - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), - initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); -} #else max_mapnr = num_physpages; - totalram_pages += free_all_bootmem(); +#endif - for (addr = KERNELBASE; addr < (unsigned long)__va(lmb_end_of_DRAM()); - addr += PAGE_SIZE) { - if (!PageReserved(virt_to_page(addr))) - continue; - if (addr < (unsigned long)_etext) - codepages++; - - else if (addr >= (unsigned long)__init_begin - && addr < (unsigned long)__init_end) - initpages++; - else if (addr < klimit) - datapages++; + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + page = pgdat->node_mem_map + i; + if (PageReserved(page)) + reservedpages++; + } } - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), - initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); -#endif + codesize = (unsigned long)&_etext - (unsigned long)&_stext; + initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; + datasize = (unsigned long)&_edata - (unsigned long)&__init_end; + bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; + + printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " + "%luk reserved, %luk data, %luk bss, %luk init)\n", + (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + bsssize >> 10, + initsize >> 10); + mem_init_done = 1; #ifdef CONFIG_PPC_ISERIES diff --git a/arch/ppc64/mm/mmap.c b/arch/ppc64/mm/mmap.c index 5ebf68668..f90dd1f7a 100644 --- a/arch/ppc64/mm/mmap.c +++ b/arch/ppc64/mm/mmap.c @@ -54,13 +54,13 @@ static inline int mmap_is_legacy(void) */ if (!test_thread_flag(TIF_32BIT)) return 1; - - if (current->personality & ADDR_COMPAT_LAYOUT) + + if (current->personality & ADDR_COMPAT_LAYOUT) return 1; - + if (current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) return 1; - + return sysctl_legacy_va_layout; } @@ -81,7 +81,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm) } else { mm->mmap_base = mmap_base(); mm->get_unmapped_area = arch_get_unmapped_area_topdown; - mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; mm->unmap_area = arch_unmap_area_topdown; } } diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c index eb3313694..977140f78 100644 --- a/arch/ppc64/mm/numa.c +++ b/arch/ppc64/mm/numa.c @@ -18,11 +18,10 @@ #include #include -#if 1 -#define dbg(args...) printk(KERN_INFO args) -#else -#define dbg(args...) -#endif +static int numa_enabled = 1; + +static int numa_debug; +#define dbg(args...) if (numa_debug) { printk(KERN_INFO args); } #ifdef DEBUG_NUMA #define ARRAY_INITIALISER -1 @@ -36,10 +35,19 @@ char *numa_memory_lookup_table; cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; int nr_cpus_in_node[MAX_NUMNODES] = { [0 ... (MAX_NUMNODES -1)] = 0}; -struct pglist_data node_data[MAX_NUMNODES]; -bootmem_data_t plat_node_bdata[MAX_NUMNODES]; +struct pglist_data *node_data[MAX_NUMNODES]; +bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; static unsigned long node0_io_hole_size; +/* + * We need somewhere to store start/span for each node until we have + * allocated the real node_data structures. + */ +static struct { + unsigned long node_start_pfn; + unsigned long node_spanned_pages; +} init_node_data[MAX_NUMNODES] __initdata; + EXPORT_SYMBOL(node_data); EXPORT_SYMBOL(numa_cpu_lookup_table); EXPORT_SYMBOL(numa_memory_lookup_table); @@ -48,7 +56,6 @@ EXPORT_SYMBOL(nr_cpus_in_node); static inline void map_cpu_to_node(int cpu, int node) { - dbg("cpu %d maps to domain %d\n", cpu, node); numa_cpu_lookup_table[cpu] = node; if (!(cpu_isset(cpu, numa_cpumask_lookup_table[node]))) { cpu_set(cpu, numa_cpumask_lookup_table[node]); @@ -107,8 +114,8 @@ static int of_node_numa_domain(struct device_node *device, int depth) if (tmp && (tmp[0] >= depth)) { numa_domain = tmp[depth]; } else { - printk(KERN_ERR "WARNING: no NUMA information for " - "%s\n", device->full_name); + dbg("WARNING: no NUMA information for %s\n", + device->full_name); numa_domain = 0; } return numa_domain; @@ -137,11 +144,8 @@ static int find_min_common_depth(void) rtas_root = of_find_node_by_path("/rtas"); - if (!rtas_root) { - printk(KERN_ERR "WARNING: %s() could not find rtas root\n", - __FUNCTION__); + if (!rtas_root) return -1; - } /* * this property is 2 32-bit integers, each representing a level of @@ -155,8 +159,8 @@ static int find_min_common_depth(void) if ((len >= 1) && ref_points) { depth = ref_points[1]; } else { - printk(KERN_ERR "WARNING: could not find NUMA " - "associativity reference point\n"); + dbg("WARNING: could not find NUMA " + "associativity reference point\n"); depth = -1; } of_node_put(rtas_root); @@ -187,20 +191,21 @@ static int __init parse_numa_properties(void) long entries = lmb_end_of_DRAM() >> MEMORY_INCREMENT_SHIFT; unsigned long i; - if (strstr(saved_command_line, "numa=off")) { + if (numa_enabled == 0) { printk(KERN_WARNING "NUMA disabled by user\n"); return -1; } numa_memory_lookup_table = (char *)abs_to_virt(lmb_alloc(entries * sizeof(char), 1)); + memset(numa_memory_lookup_table, 0, entries * sizeof(char)); for (i = 0; i < entries ; i++) numa_memory_lookup_table[i] = ARRAY_INITIALISER; depth = find_min_common_depth(); - printk(KERN_INFO "NUMA associativity depth for CPU/Memory: %d\n", depth); + dbg("NUMA associativity depth for CPU/Memory: %d\n", depth); if (depth < 0) return depth; @@ -225,8 +230,7 @@ static int __init parse_numa_properties(void) numa_domain = 0; } } else { - printk(KERN_ERR "WARNING: no NUMA information for " - "cpu %ld\n", i); + dbg("WARNING: no NUMA information for cpu %ld\n", i); numa_domain = 0; } @@ -281,22 +285,22 @@ new_range: * this simple case and complain if there is a gap in * memory */ - if (node_data[numa_domain].node_spanned_pages) { + if (init_node_data[numa_domain].node_spanned_pages) { unsigned long shouldstart = - node_data[numa_domain].node_start_pfn + - node_data[numa_domain].node_spanned_pages; + init_node_data[numa_domain].node_start_pfn + + init_node_data[numa_domain].node_spanned_pages; if (shouldstart != (start / PAGE_SIZE)) { - printk(KERN_ERR "Hole in node, disabling " - "region start %lx length %lx\n", - start, size); + printk(KERN_ERR "WARNING: Hole in node, " + "disabling region start %lx " + "length %lx\n", start, size); continue; } - node_data[numa_domain].node_spanned_pages += + init_node_data[numa_domain].node_spanned_pages += size / PAGE_SIZE; } else { - node_data[numa_domain].node_start_pfn = + init_node_data[numa_domain].node_start_pfn = start / PAGE_SIZE; - node_data[numa_domain].node_spanned_pages = + init_node_data[numa_domain].node_spanned_pages = size / PAGE_SIZE; } @@ -304,9 +308,6 @@ new_range: numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = numa_domain; - dbg("memory region %lx to %lx maps to domain %d\n", - start, start+size, numa_domain); - ranges--; if (ranges) goto new_range; @@ -332,6 +333,7 @@ static void __init setup_nonnuma(void) long entries = top_of_ram >> MEMORY_INCREMENT_SHIFT; numa_memory_lookup_table = (char *)abs_to_virt(lmb_alloc(entries * sizeof(char), 1)); + memset(numa_memory_lookup_table, 0, entries * sizeof(char)); for (i = 0; i < entries ; i++) numa_memory_lookup_table[i] = ARRAY_INITIALISER; } @@ -341,8 +343,8 @@ static void __init setup_nonnuma(void) node_set_online(0); - node_data[0].node_start_pfn = 0; - node_data[0].node_spanned_pages = lmb_end_of_DRAM() / PAGE_SIZE; + init_node_data[0].node_start_pfn = 0; + init_node_data[0].node_spanned_pages = lmb_end_of_DRAM() / PAGE_SIZE; for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT) numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0; @@ -350,6 +352,108 @@ static void __init setup_nonnuma(void) node0_io_hole_size = top_of_ram - total_ram; } +static void __init dump_numa_topology(void) +{ + unsigned int node; + unsigned int cpu, count; + + for (node = 0; node < MAX_NUMNODES; node++) { + if (!node_online(node)) + continue; + + printk(KERN_INFO "Node %d CPUs:", node); + + count = 0; + /* + * If we used a CPU iterator here we would miss printing + * the holes in the cpumap. + */ + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) { + if (count == 0) + printk(" %u", cpu); + ++count; + } else { + if (count > 1) + printk("-%u", cpu - 1); + count = 0; + } + } + + if (count > 1) + printk("-%u", NR_CPUS - 1); + printk("\n"); + } + + for (node = 0; node < MAX_NUMNODES; node++) { + unsigned long i; + + if (!node_online(node)) + continue; + + printk(KERN_INFO "Node %d Memory:", node); + + count = 0; + + for (i = 0; i < lmb_end_of_DRAM(); i += MEMORY_INCREMENT) { + if (numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] == node) { + if (count == 0) + printk(" 0x%lx", i); + ++count; + } else { + if (count > 0) + printk("-0x%lx", i); + count = 0; + } + } + + if (count > 0) + printk("-0x%lx", i); + printk("\n"); + } +} + +/* + * Allocate some memory, satisfying the lmb or bootmem allocator where + * required. nid is the preferred node and end is the physical address of + * the highest address in the node. + * + * Returns the physical address of the memory. + */ +static unsigned long careful_allocation(int nid, unsigned long size, + unsigned long align, unsigned long end) +{ + unsigned long ret = lmb_alloc_base(size, align, end); + + /* retry over all memory */ + if (!ret) + ret = lmb_alloc_base(size, align, lmb_end_of_DRAM()); + + if (!ret) + panic("numa.c: cannot allocate %lu bytes on node %d", + size, nid); + + /* + * If the memory came from a previously allocated node, we must + * retry with the bootmem allocator. + */ + if (pa_to_nid(ret) < nid) { + nid = pa_to_nid(ret); + ret = (unsigned long)__alloc_bootmem_node(NODE_DATA(nid), + size, align, 0); + + if (!ret) + panic("numa.c: cannot allocate %lu bytes on node %d", + size, nid); + + ret = virt_to_abs(ret); + + dbg("alloc_bootmem %lx %lx\n", ret, size); + } + + return ret; +} + void __init do_init_bootmem(void) { int nid; @@ -360,6 +464,8 @@ void __init do_init_bootmem(void) if (parse_numa_properties()) setup_nonnuma(); + else + dump_numa_topology(); for (nid = 0; nid < numnodes; nid++) { unsigned long start_paddr, end_paddr; @@ -367,24 +473,38 @@ void __init do_init_bootmem(void) unsigned long bootmem_paddr; unsigned long bootmap_pages; - if (node_data[nid].node_spanned_pages == 0) - continue; + start_paddr = init_node_data[nid].node_start_pfn * PAGE_SIZE; + end_paddr = start_paddr + (init_node_data[nid].node_spanned_pages * PAGE_SIZE); - start_paddr = node_data[nid].node_start_pfn * PAGE_SIZE; - end_paddr = start_paddr + - (node_data[nid].node_spanned_pages * PAGE_SIZE); + /* Allocate the node structure node local if possible */ + NODE_DATA(nid) = (struct pglist_data *)careful_allocation(nid, + sizeof(struct pglist_data), + SMP_CACHE_BYTES, end_paddr); + NODE_DATA(nid) = abs_to_virt(NODE_DATA(nid)); + memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); - dbg("node %d\n", nid); - dbg("start_paddr = %lx\n", start_paddr); - dbg("end_paddr = %lx\n", end_paddr); + dbg("node %d\n", nid); + dbg("NODE_DATA() = %p\n", NODE_DATA(nid)); NODE_DATA(nid)->bdata = &plat_node_bdata[nid]; + NODE_DATA(nid)->node_start_pfn = + init_node_data[nid].node_start_pfn; + NODE_DATA(nid)->node_spanned_pages = + init_node_data[nid].node_spanned_pages; + + if (init_node_data[nid].node_spanned_pages == 0) + continue; + + dbg("start_paddr = %lx\n", start_paddr); + dbg("end_paddr = %lx\n", end_paddr); bootmap_pages = bootmem_bootmap_pages((end_paddr - start_paddr) >> PAGE_SHIFT); - dbg("bootmap_pages = %lx\n", bootmap_pages); - bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT, + bootmem_paddr = careful_allocation(nid, + bootmap_pages << PAGE_SHIFT, PAGE_SIZE, end_paddr); + memset(abs_to_virt(bootmem_paddr), 0, + bootmap_pages << PAGE_SHIFT); dbg("bootmap_paddr = %lx\n", bootmem_paddr); init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT, @@ -442,7 +562,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)); @@ -463,17 +582,22 @@ void __init paging_init(void) dbg("free_area_init node %d %lx %lx (hole: %lx)\n", nid, zones_size[ZONE_DMA], start_pfn, zholes_size[ZONE_DMA]); - /* - * Give this empty node a dummy struct page to avoid - * us from trying to allocate a node local mem_map - * in free_area_init_node (which will fail). - */ - if (!node_data[nid].node_spanned_pages) - 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); + free_area_init_node(nid, NODE_DATA(nid), zones_size, + start_pfn, zholes_size); } } + +static int __init early_numa(char *p) +{ + if (!p) + return 0; + + if (strstr(p, "off")) + numa_enabled = 0; + + if (strstr(p, "debug")) + numa_debug = 1; + + return 0; +} +early_param("numa", early_numa); diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c index bc6125804..7424d8d24 100644 --- a/arch/ppc64/mm/slb.c +++ b/arch/ppc64/mm/slb.c @@ -24,32 +24,55 @@ extern void slb_allocate(unsigned long ea); +static inline unsigned long mk_esid_data(unsigned long ea, unsigned long slot) +{ + return (ea & ESID_MASK) | SLB_ESID_V | slot; +} + +static inline unsigned long mk_vsid_data(unsigned long ea, unsigned long flags) +{ + return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags; +} + static inline void create_slbe(unsigned long ea, unsigned long vsid, unsigned long flags, unsigned long entry) { - ea = (ea & ESID_MASK) | SLB_ESID_V | entry; - vsid = (vsid << SLB_VSID_SHIFT) | flags; asm volatile("slbmte %0,%1" : - : "r" (vsid), "r" (ea) + : "r" (mk_vsid_data(ea, flags)), + "r" (mk_esid_data(ea, entry)) : "memory" ); } -static void slb_add_bolted(void) +static void slb_flush_and_rebolt(void) { -#ifndef CONFIG_PPC_ISERIES - WARN_ON(!irqs_disabled()); - /* If you change this make sure you change SLB_NUM_BOLTED - * appropriately too */ + * appropriately too. */ + unsigned long ksp_flags = SLB_VSID_KERNEL; + unsigned long ksp_esid_data; - /* Slot 1 - first VMALLOC segment - * Since modules end up there it gets hit very heavily. - */ - create_slbe(VMALLOCBASE, get_kernel_vsid(VMALLOCBASE), - SLB_VSID_KERNEL, 1); + WARN_ON(!irqs_disabled()); - asm volatile("isync":::"memory"); -#endif + if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + ksp_flags |= SLB_VSID_L; + + ksp_esid_data = mk_esid_data(get_paca()->kstack, 2); + if ((ksp_esid_data & ESID_MASK) == KERNELBASE) + ksp_esid_data &= ~SLB_ESID_V; + + /* We need to do this all in asm, so we're sure we don't touch + * the stack between the slbia and rebolting it. */ + asm volatile("isync\n" + "slbia\n" + /* Slot 1 - first VMALLOC segment */ + "slbmte %0,%1\n" + /* Slot 2 - kernel stack */ + "slbmte %2,%3\n" + "isync" + :: "r"(mk_vsid_data(VMALLOCBASE, SLB_VSID_KERNEL)), + "r"(mk_esid_data(VMALLOCBASE, 1)), + "r"(mk_vsid_data(ksp_esid_data, ksp_flags)), + "r"(ksp_esid_data) + : "memory"); } /* Flush all user entries from the segment table of the current processor. */ @@ -71,8 +94,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) } asm volatile("isync" : : : "memory"); } else { - asm volatile("isync; slbia; isync" : : : "memory"); - slb_add_bolted(); + slb_flush_and_rebolt(); } /* Workaround POWER5 < DD2.1 issue */ @@ -115,22 +137,27 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) void slb_initialize(void) { -#ifdef CONFIG_PPC_ISERIES - asm volatile("isync; slbia; isync":::"memory"); -#else + /* On iSeries the bolted entries have already been set up by + * the hypervisor from the lparMap data in head.S */ +#ifndef CONFIG_PPC_ISERIES unsigned long flags = SLB_VSID_KERNEL; - /* Invalidate the entire SLB (even slot 0) & all the ERATS */ - if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) - flags |= SLB_VSID_L; + /* Invalidate the entire SLB (even slot 0) & all the ERATS */ + if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + flags |= SLB_VSID_L; - asm volatile("isync":::"memory"); - asm volatile("slbmte %0,%0"::"r" (0) : "memory"); + asm volatile("isync":::"memory"); + asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); - create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE), - flags, 0); - + create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE), flags, 0); + create_slbe(VMALLOCBASE, get_kernel_vsid(KERNELBASE), + SLB_VSID_KERNEL, 1); + /* We don't bolt the stack for the time being - we're in boot, + * so the stack is in the bolted segment. By the time it goes + * elsewhere, we'll call _switch() which will bolt in the new + * one. */ + asm volatile("isync":::"memory"); #endif - slb_add_bolted(); + get_paca()->stab_rr = SLB_NUM_BOLTED; } diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S index 4b3dfe091..8379d678f 100644 --- a/arch/ppc64/mm/slb_low.S +++ b/arch/ppc64/mm/slb_low.S @@ -37,8 +37,21 @@ _GLOBAL(slb_allocate) * a free slot first but that took too long. Unfortunately we * dont have any LRU information to help us choose a slot. */ +#ifdef CONFIG_PPC_ISERIES + /* + * On iSeries, the "bolted" stack segment can be cast out on + * shared processor switch so we need to check for a miss on + * it and restore it to the right slot. + */ + ld r9,PACAKSAVE(r13) + clrrdi r9,r9,28 + clrrdi r11,r3,28 + li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ + cmpld r9,r11 + beq 3f +#endif /* CONFIG_PPC_ISERIES */ + ld r10,PACASTABRR(r13) -3: addi r10,r10,1 /* use a cpu feature mask if we ever change our slb size */ cmpldi r10,SLB_NUM_ENTRIES @@ -46,55 +59,28 @@ _GLOBAL(slb_allocate) blt+ 4f li r10,SLB_NUM_BOLTED - /* - * Never cast out the segment for our kernel stack. Since we - * dont invalidate the ERAT we could have a valid translation - * for the kernel stack during the first part of exception exit - * which gets invalidated due to a tlbie from another cpu at a - * non recoverable point (after setting srr0/1) - Anton - */ -4: slbmfee r11,r10 - srdi r11,r11,27 - /* - * Use paca->ksave as the value of the kernel stack pointer, - * because this is valid at all times. - * The >> 27 (rather than >> 28) is so that the LSB is the - * valid bit - this way we check valid and ESID in one compare. - * In order to completely close the tiny race in the context - * switch (between updating r1 and updating paca->ksave), - * we check against both r1 and paca->ksave. - */ - srdi r9,r1,27 - ori r9,r9,1 /* mangle SP for later compare */ - cmpd r11,r9 - beq- 3b - ld r9,PACAKSAVE(r13) - srdi r9,r9,27 - ori r9,r9,1 - cmpd r11,r9 - beq- 3b - +4: std r10,PACASTABRR(r13) - +3: /* r3 = faulting address, r10 = entry */ srdi r9,r3,60 /* get region */ srdi r3,r3,28 /* get esid */ cmpldi cr7,r9,0xc /* cmp KERNELBASE for later use */ - /* r9 = region, r3 = esid, cr7 = <>KERNELBASE */ - - rldicr. r11,r3,32,16 - bne- 8f /* invalid ea bits set */ - addi r11,r9,-1 - cmpldi r11,0xb - blt- 8f /* invalid region */ + rldimi r10,r3,28,0 /* r10= ESID<<28 | entry */ + oris r10,r10,SLB_ESID_V@h /* r10 |= SLB_ESID_V */ - /* r9 = region, r3 = esid, r10 = entry, cr7 = <>KERNELBASE */ + /* r3 = esid, r10 = esid_data, cr7 = <>KERNELBASE */ blt cr7,0f /* user or kernel? */ - /* kernel address */ + /* kernel address: proto-VSID = ESID */ + /* WARNING - MAGIC: we don't use the VSID 0xfffffffff, but + * this code will generate the protoVSID 0xfffffffff for the + * top segment. That's ok, the scramble below will translate + * it to VSID 0, which is reserved as a bad VSID - one which + * will never have any pages in it. */ li r11,SLB_VSID_KERNEL BEGIN_FTR_SECTION bne cr7,9f @@ -102,8 +88,12 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) b 9f -0: /* user address */ +0: /* user address: proto-VSID = context<<15 | ESID */ li r11,SLB_VSID_USER + + srdi. r9,r3,13 + bne- 8f /* invalid ea bits set */ + #ifdef CONFIG_HUGETLB_PAGE BEGIN_FTR_SECTION /* check against the hugepage ranges */ @@ -125,33 +115,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) #endif /* CONFIG_HUGETLB_PAGE */ 6: ld r9,PACACONTEXTID(r13) + rldimi r3,r9,USER_ESID_BITS,0 -9: /* r9 = "context", r3 = esid, r11 = flags, r10 = entry */ - - rldimi r9,r3,15,0 /* r9= VSID ordinal */ - -7: rldimi r10,r3,28,0 /* r10= ESID<<28 | entry */ - oris r10,r10,SLB_ESID_V@h /* r10 |= SLB_ESID_V */ - - /* r9 = ordinal, r3 = esid, r11 = flags, r10 = esid_data */ - - li r3,VSID_RANDOMIZER@higher - sldi r3,r3,32 - oris r3,r3,VSID_RANDOMIZER@h - ori r3,r3,VSID_RANDOMIZER@l - - mulld r9,r3,r9 /* r9 = ordinal * VSID_RANDOMIZER */ - clrldi r9,r9,28 /* r9 &= VSID_MASK */ - sldi r9,r9,SLB_VSID_SHIFT /* r9 <<= SLB_VSID_SHIFT */ - or r9,r9,r11 /* r9 |= flags */ +9: /* r3 = protovsid, r11 = flags, r10 = esid_data, cr7 = <>KERNELBASE */ + ASM_VSID_SCRAMBLE(r3,r9) - /* r9 = vsid_data, r10 = esid_data, cr7 = <>KERNELBASE */ + rldimi r11,r3,SLB_VSID_SHIFT,16 /* combine VSID and flags */ /* * No need for an isync before or after this slbmte. The exception * we enter with and the rfid we exit with are context synchronizing. */ - slbmte r9,r10 + slbmte r11,r10 bgelr cr7 /* we're done for kernel addresses */ @@ -174,6 +149,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) blr 8: /* invalid EA */ - li r9,0 /* 0 VSID ordinal -> BAD_VSID */ + li r3,0 /* BAD_VSID */ li r11,SLB_VSID_USER /* flags don't much matter */ - b 7b + b 9b diff --git a/arch/ppc64/mm/stab.c b/arch/ppc64/mm/stab.c new file mode 100644 index 000000000..9b4fe8ac1 --- /dev/null +++ b/arch/ppc64/mm/stab.c @@ -0,0 +1,240 @@ +/* + * PowerPC64 Segment Translation Support. + * + * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com + * Copyright (c) 2001 Dave Engebretsen + * + * Copyright (C) 2002 Anton Blanchard , IBM + * + * 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 +#include +#include +#include +#include +#include +#include + +/* Both the segment table and SLB code uses the following cache */ +#define NR_STAB_CACHE_ENTRIES 8 +DEFINE_PER_CPU(long, stab_cache_ptr); +DEFINE_PER_CPU(long, stab_cache[NR_STAB_CACHE_ENTRIES]); + +/* + * Create a segment table entry for the given esid/vsid pair. + */ +static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) +{ + unsigned long esid_data, vsid_data; + unsigned long entry, group, old_esid, castout_entry, i; + unsigned int global_entry; + struct stab_entry *ste, *castout_ste; + unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE; + + vsid_data = vsid << STE_VSID_SHIFT; + esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V; + if (! kernel_segment) + esid_data |= STE_ESID_KS; + + /* Search the primary group first. */ + global_entry = (esid & 0x1f) << 3; + ste = (struct stab_entry *)(stab | ((esid & 0x1f) << 7)); + + /* Find an empty entry, if one exists. */ + for (group = 0; group < 2; group++) { + for (entry = 0; entry < 8; entry++, ste++) { + if (!(ste->esid_data & STE_ESID_V)) { + ste->vsid_data = vsid_data; + asm volatile("eieio":::"memory"); + ste->esid_data = esid_data; + return (global_entry | entry); + } + } + /* Now search the secondary group. */ + global_entry = ((~esid) & 0x1f) << 3; + ste = (struct stab_entry *)(stab | (((~esid) & 0x1f) << 7)); + } + + /* + * Could not find empty entry, pick one with a round robin selection. + * Search all entries in the two groups. + */ + castout_entry = get_paca()->stab_rr; + for (i = 0; i < 16; i++) { + if (castout_entry < 8) { + global_entry = (esid & 0x1f) << 3; + ste = (struct stab_entry *)(stab | ((esid & 0x1f) << 7)); + castout_ste = ste + castout_entry; + } else { + global_entry = ((~esid) & 0x1f) << 3; + ste = (struct stab_entry *)(stab | (((~esid) & 0x1f) << 7)); + castout_ste = ste + (castout_entry - 8); + } + + /* Dont cast out the first kernel segment */ + if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE) + break; + + castout_entry = (castout_entry + 1) & 0xf; + } + + get_paca()->stab_rr = (castout_entry + 1) & 0xf; + + /* Modify the old entry to the new value. */ + + /* Force previous translations to complete. DRENG */ + asm volatile("isync" : : : "memory"); + + old_esid = castout_ste->esid_data >> SID_SHIFT; + castout_ste->esid_data = 0; /* Invalidate old entry */ + + asm volatile("sync" : : : "memory"); /* Order update */ + + castout_ste->vsid_data = vsid_data; + asm volatile("eieio" : : : "memory"); /* Order update */ + castout_ste->esid_data = esid_data; + + asm volatile("slbie %0" : : "r" (old_esid << SID_SHIFT)); + /* Ensure completion of slbie */ + asm volatile("sync" : : : "memory"); + + return (global_entry | (castout_entry & 0x7)); +} + +/* + * Allocate a segment table entry for the given ea and mm + */ +static int __ste_allocate(unsigned long ea, struct mm_struct *mm) +{ + unsigned long vsid; + unsigned char stab_entry; + unsigned long offset; + + /* Kernel or user address? */ + if (ea >= KERNELBASE) { + vsid = get_kernel_vsid(ea); + } else { + if ((ea >= TASK_SIZE_USER64) || (! mm)) + return 1; + + vsid = get_vsid(mm->context.id, ea); + } + + stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid); + + if (ea < KERNELBASE) { + offset = __get_cpu_var(stab_cache_ptr); + if (offset < NR_STAB_CACHE_ENTRIES) + __get_cpu_var(stab_cache[offset++]) = stab_entry; + else + offset = NR_STAB_CACHE_ENTRIES+1; + __get_cpu_var(stab_cache_ptr) = offset; + + /* Order update */ + asm volatile("sync":::"memory"); + } + + return 0; +} + +int ste_allocate(unsigned long ea) +{ + return __ste_allocate(ea, current->mm); +} + +/* + * Do the segment table work for a context switch: flush all user + * entries from the table, then preload some probably useful entries + * for the new task + */ +void switch_stab(struct task_struct *tsk, struct mm_struct *mm) +{ + struct stab_entry *stab = (struct stab_entry *) get_paca()->stab_addr; + struct stab_entry *ste; + unsigned long offset = __get_cpu_var(stab_cache_ptr); + unsigned long pc = KSTK_EIP(tsk); + unsigned long stack = KSTK_ESP(tsk); + unsigned long unmapped_base; + + /* Force previous translations to complete. DRENG */ + asm volatile("isync" : : : "memory"); + + if (offset <= NR_STAB_CACHE_ENTRIES) { + int i; + + for (i = 0; i < offset; i++) { + ste = stab + __get_cpu_var(stab_cache[i]); + ste->esid_data = 0; /* invalidate entry */ + } + } else { + unsigned long entry; + + /* Invalidate all entries. */ + ste = stab; + + /* Never flush the first entry. */ + ste += 1; + for (entry = 1; + entry < (PAGE_SIZE / sizeof(struct stab_entry)); + entry++, ste++) { + unsigned long ea; + ea = ste->esid_data & ESID_MASK; + if (ea < KERNELBASE) { + ste->esid_data = 0; + } + } + } + + asm volatile("sync; slbia; sync":::"memory"); + + __get_cpu_var(stab_cache_ptr) = 0; + + /* Now preload some entries for the new task */ + if (test_tsk_thread_flag(tsk, TIF_32BIT)) + unmapped_base = TASK_UNMAPPED_BASE_USER32; + else + unmapped_base = TASK_UNMAPPED_BASE_USER64; + + __ste_allocate(pc, mm); + + if (GET_ESID(pc) == GET_ESID(stack)) + return; + + __ste_allocate(stack, mm); + + if ((GET_ESID(pc) == GET_ESID(unmapped_base)) + || (GET_ESID(stack) == GET_ESID(unmapped_base))) + return; + + __ste_allocate(unmapped_base, mm); + + /* Order update */ + asm volatile("sync" : : : "memory"); +} + +extern void slb_initialize(void); + +/* + * Build an entry for the base kernel segment and put it into + * the segment table or SLB. All other segment table or SLB + * entries are faulted in. + */ +void stab_initialize(unsigned long stab) +{ + unsigned long vsid = get_kernel_vsid(KERNELBASE); + + if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { + slb_initialize(); + } else { + asm volatile("isync; slbia; isync":::"memory"); + make_ste(stab, GET_ESID(KERNELBASE), vsid); + + /* Order update */ + asm volatile("sync":::"memory"); + } +} diff --git a/arch/ppc64/mm/tlb.c b/arch/ppc64/mm/tlb.c index 8825e14cb..aa2d76ca4 100644 --- a/arch/ppc64/mm/tlb.c +++ b/arch/ppc64/mm/tlb.c @@ -26,10 +26,10 @@ #include #include #include +#include #include #include #include -#include #include DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c index 391e9afba..bd0dcd2e8 100644 --- a/arch/ppc64/oprofile/common.c +++ b/arch/ppc64/oprofile/common.c @@ -52,17 +52,10 @@ static int op_ppc64_setup(void) static void op_ppc64_shutdown(void) { - /* - * We need to be sure we have cleared all pending exceptions before - * removing the interrupt handler. For the moment we play it safe and - * leave it in - */ -#if 0 mb(); /* Remove our interrupt handler. We may be removing this module. */ perf_irq = save_perf_irq; -#endif } static void op_ppc64_cpu_start(void *dummy) @@ -90,6 +83,14 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) { int i; + /* + * There is one mmcr0, mmcr1 and mmcra for setting the events for + * all of the counters. + */ + oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); + oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); + oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); + for (i = 0; i < model->num_counters; ++i) { struct dentry *dir; char buf[3]; @@ -112,6 +113,10 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); + /* Default to tracing both kernel and user */ + sys.enable_kernel = 1; + sys.enable_user = 1; + return 0; } @@ -128,7 +133,7 @@ int __init oprofile_arch_init(struct oprofile_operations **ops) { unsigned int pvr; - pvr = _get_PVR(); + pvr = mfspr(SPRN_PVR); switch (PVR_VER(pvr)) { case PV_630: diff --git a/arch/ppc64/oprofile/op_impl.h b/arch/ppc64/oprofile/op_impl.h index aa9c8af60..c936c5ce6 100644 --- a/arch/ppc64/oprofile/op_impl.h +++ b/arch/ppc64/oprofile/op_impl.h @@ -19,6 +19,12 @@ /* freeze counters. set to 1 on a perfmon exception */ #define MMCR0_FC (1UL << (31 - 0)) +/* freeze in supervisor state */ +#define MMCR0_KERNEL_DISABLE (1UL << (31 - 1)) + +/* freeze in problem state */ +#define MMCR0_PROBLEM_DISABLE (1UL << (31 - 2)) + /* freeze counters while MSR mark = 1 */ #define MMCR0_FCM1 (1UL << (31 - 3)) @@ -28,15 +34,15 @@ /* freeze counters on enabled condition or event */ #define MMCR0_FCECE (1UL << (31 - 6)) -/* performance monitor alert has occurred, set to 0 after handling exception */ -#define MMCR0_PMAO (1UL << (31 - 24)) - /* PMC1 count enable*/ #define MMCR0_PMC1INTCONTROL (1UL << (31 - 16)) /* PMCn count enable*/ #define MMCR0_PMCNINTCONTROL (1UL << (31 - 17)) +/* performance monitor alert has occurred, set to 0 after handling exception */ +#define MMCR0_PMAO (1UL << (31 - 24)) + /* state of MSR HV when SIAR set */ #define MMCRA_SIHV (1UL << (63 - 35)) @@ -60,6 +66,9 @@ struct op_counter_config { /* System-wide configuration as set via oprofilefs. */ struct op_system_config { + unsigned long mmcr0; + unsigned long mmcr1; + unsigned long mmcra; unsigned long enable_kernel; unsigned long enable_user; }; diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c index 8a0e7a867..b2a512cdb 100644 --- a/arch/ppc64/oprofile/op_model_power4.c +++ b/arch/ppc64/oprofile/op_model_power4.c @@ -17,7 +17,7 @@ #include #include -#define dbg(args...) printk(args) +#define dbg(args...) #include "op_impl.h" @@ -27,6 +27,11 @@ static int num_counters; static int oprofile_running; static int mmcra_has_sihv; +/* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */ +static u32 mmcr0_val; +static u64 mmcr1_val; +static u32 mmcra_val; + static void power4_reg_setup(struct op_counter_config *ctr, struct op_system_config *sys, int num_ctrs) @@ -45,18 +50,36 @@ static void power4_reg_setup(struct op_counter_config *ctr, if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA_SIHV) mmcra_has_sihv = 1; + /* + * The performance counter event settings are given in the mmcr0, + * mmcr1 and mmcra values passed from the user in the + * op_system_config structure (sys variable). + */ + mmcr0_val = sys->mmcr0; + mmcr1_val = sys->mmcr1; + mmcra_val = sys->mmcra; + for (i = 0; i < num_counters; ++i) reset_value[i] = 0x80000000UL - ctr[i].count; - /* XXX setup user and kernel profiling */ + /* setup user and kernel profiling */ + if (sys->enable_kernel) + mmcr0_val &= ~MMCR0_KERNEL_DISABLE; + else + mmcr0_val |= MMCR0_KERNEL_DISABLE; + + if (sys->enable_user) + mmcr0_val &= ~MMCR0_PROBLEM_DISABLE; + else + mmcr0_val |= MMCR0_PROBLEM_DISABLE; } extern void ppc64_enable_pmcs(void); static void power4_cpu_setup(void *unused) { - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - unsigned long mmcra = mfspr(SPRN_MMCRA); + unsigned int mmcr0 = mmcr0_val; + unsigned long mmcra = mmcra_val; ppc64_enable_pmcs(); @@ -68,6 +91,8 @@ static void power4_cpu_setup(void *unused) mmcr0 |= MMCR0_PMC1INTCONTROL|MMCR0_PMCNINTCONTROL; mtspr(SPRN_MMCR0, mmcr0); + mtspr(SPRN_MMCR1, mmcr1_val); + mmcra |= MMCRA_SAMPLE_ENABLE; mtspr(SPRN_MMCRA, mmcra); diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c index 21ceb0b7c..251fdef43 100644 --- a/arch/ppc64/oprofile/op_model_rs64.c +++ b/arch/ppc64/oprofile/op_model_rs64.c @@ -15,14 +15,14 @@ #include #include -#define dbg(args...) printk(args) +#define dbg(args...) #include "op_impl.h" static void ctrl_write(unsigned int i, unsigned int val) { - unsigned int tmp; - unsigned long shift, mask; + unsigned int tmp = 0; + unsigned long shift = 0, mask = 0; dbg("ctrl_write %d %x\n", i, val); diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index d84ac32fa..6ef0b1ec3 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -252,30 +252,28 @@ extern inline void sync(void) static inline void disable_surveillance(void) { -#ifndef CONFIG_PPC_ISERIES +#ifdef CONFIG_PPC_PSERIES /* Since this can't be a module, args should end up below 4GB. */ static struct rtas_args args; - if (systemcfg->platform & PLATFORM_PSERIES) { - /* - * At this point we have got all the cpus we can into - * xmon, so there is hopefully no other cpu calling RTAS - * at the moment, even though we don't take rtas.lock. - * If we did try to take rtas.lock there would be a - * real possibility of deadlock. - */ - args.token = rtas_token("set-indicator"); - if (args.token == RTAS_UNKNOWN_SERVICE) - return; - args.nargs = 3; - args.nret = 1; - args.rets = &args.args[3]; - args.args[0] = SURVEILLANCE_TOKEN; - args.args[1] = 0; - args.args[2] = 0; - enter_rtas(__pa(&args)); - } -#endif + /* + * At this point we have got all the cpus we can into + * xmon, so there is hopefully no other cpu calling RTAS + * at the moment, even though we don't take rtas.lock. + * If we did try to take rtas.lock there would be a + * real possibility of deadlock. + */ + args.token = rtas_token("set-indicator"); + if (args.token == RTAS_UNKNOWN_SERVICE) + return; + args.nargs = 3; + args.nret = 1; + args.rets = &args.args[3]; + args.args[0] = SURVEILLANCE_TOKEN; + args.args[1] = 0; + args.args[2] = 0; + enter_rtas(__pa(&args)); +#endif /* CONFIG_PPC_PSERIES */ } #ifdef CONFIG_SMP @@ -2059,7 +2057,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr) { int nr, dotted; unsigned long first_adr; - unsigned long inst, last_inst; + unsigned long inst, last_inst = 0; unsigned char val[4]; dotted = 0; diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index ce8cb18b9..ab50e5c44 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -48,34 +48,6 @@ config ARCH_S390_31 depends on ARCH_S390X = 'n' default y -choice - prompt "Processor type" - default MARCH_G5 - -config MARCH_G5 - bool "S/390 model G5 and G6" - depends on ARCH_S390_31 - help - Select this to build a 31 bit kernel that works - on all S/390 and zSeries machines. - -config MARCH_Z900 - bool "IBM eServer zSeries model z800 and z900" - help - Select this to optimize for zSeries machines. This - will enable some optimizations that are not available - on older 31 bit only CPUs. - -config MARCH_Z990 - bool "IBM eServer zSeries model z890 and z990" - help - Select this enable optimizations for model z890/z990. - This will be slightly faster but does not work on - older machines such as the z900. - -endchoice - - config SMP bool "Symmetric multi-processing support" ---help--- @@ -121,7 +93,7 @@ config MATHEMU depends on MARCH_G5 help This option is required for IEEE compliant floating point arithmetic - on older S/390 machines. Say Y unless you know your machine doesn't + on older S/390 machines. Say Y unless you know your machine doesn't need this. config S390_SUPPORT @@ -150,13 +122,112 @@ config BINFMT_ELF32 This allows you to run 32-bit Linux/ELF binaries on your zSeries in 64 bit mode. Everybody wants this; say Y. +comment "Code generation options" + +choice + prompt "Processor type" + default MARCH_G5 + +config MARCH_G5 + bool "S/390 model G5 and G6" + depends on ARCH_S390_31 + help + Select this to build a 31 bit kernel that works + on all S/390 and zSeries machines. + +config MARCH_Z900 + bool "IBM eServer zSeries model z800 and z900" + help + Select this to optimize for zSeries machines. This + will enable some optimizations that are not available + on older 31 bit only CPUs. + +config MARCH_Z990 + bool "IBM eServer zSeries model z890 and z990" + help + Select this enable optimizations for model z890/z990. + This will be slightly faster but does not work on + older machines such as the z900. + +endchoice + +config PACK_STACK + bool "Pack kernel stack" + help + This option enables the compiler option -mkernel-backchain if it + is available. If the option is available the compiler supports + the new stack layout which dramatically reduces the minimum stack + frame size. With an old compiler a non-leaf function needs a + minimum of 96 bytes on 31 bit and 160 bytes on 64 bit. With + -mkernel-backchain the minimum size drops to 16 byte on 31 bit + and 24 byte on 64 bit. + + Say Y if you are unsure. + +config SMALL_STACK + bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" + depends on PACK_STACK + help + If you say Y here and the compiler supports the -mkernel-backchain + option the kernel will use a smaller kernel stack size. For 31 bit + the reduced size is 4kb instead of 8kb and for 64 bit it is 8kb + instead of 16kb. This allows to run more thread on a system and + reduces the pressure on the memory management for higher order + page allocations. + + Say N if you are unsure. + + +config CHECK_STACK + bool "Detect kernel stack overflow" + help + This option enables the compiler option -mstack-guard and + -mstack-size if they are available. If the compiler supports them + it will emit additional code to each function prolog to trigger + an illegal operation if the kernel stack is about to overflow. + + Say N if you are unsure. + +config STACK_GUARD + int "Size of the guard area (128-1024)" + range 128 1024 + depends on CHECK_STACK + default "256" + help + This allows you to specify the size of the guard area at the lower + end of the kernel stack. If the kernel stack points into the guard + area on function entry an illegal operation is triggered. The size + needs to be a power of 2. Please keep in mind that the size of an + interrupt frame is 184 bytes for 31 bit and 328 bytes on 64 bit. + The minimum size for the stack guard should be 256 for 31 bit and + 512 for 64 bit. + +config WARN_STACK + bool "Emit compiler warnings for function with broken stack usage" + help + This option enables the compiler options -mwarn-framesize and + -mwarn-dynamicstack. If the compiler supports these options it + will generate warnings for function which either use alloca or + create a stack frame bigger then CONFIG_WARN_STACK_SIZE. + + Say N if you are unsure. + +config WARN_STACK_SIZE + int "Maximum frame size considered safe (128-2048)" + range 128 2048 + depends on WARN_STACK + default "256" + help + This allows you to specify the maximum frame size a function may + have without the compiler complaining about it. + comment "I/O subsystem configuration" config MACHCHK_WARNING bool "Process warning machine checks" help Select this option if you want the machine check handler on IBM S/390 or - zSeries to process warning machine checks (e.g. on power failures). + zSeries to process warning machine checks (e.g. on power failures). If unsure, say "Y". config QDIO @@ -388,64 +459,10 @@ source "fs/Kconfig" source "arch/s390/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config KALLSYMS - bool "Load all symbols for debugging/kksymoops" - depends on DEBUG_KERNEL - help - Say Y here to let the kernel print out symbolic crash information and - symbolic stack backtraces. This increases the size of the kernel - somewhat, as all symbols have to be loaded into the kernel image. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -endmenu +source "arch/s390/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug new file mode 100644 index 000000000..f53b6d530 --- /dev/null +++ b/arch/s390/Kconfig.debug @@ -0,0 +1,5 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +endmenu diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 68c1a72b0..6d2c7ebc4 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -18,6 +18,7 @@ LDFLAGS := -m elf_s390 CFLAGS += -m31 AFLAGS += -m31 UTS_MACHINE := s390 +STACK_SIZE := 8192 endif ifdef CONFIG_ARCH_S390X @@ -26,16 +27,37 @@ MODFLAGS += -fpic -D__PIC__ CFLAGS += -m64 AFLAGS += -m64 UTS_MACHINE := s390x +STACK_SIZE := 16384 endif -cflags-$(CONFIG_MARCH_G5) += $(call check_gcc,-march=g5,) -cflags-$(CONFIG_MARCH_Z900) += $(call check_gcc,-march=z900,) -cflags-$(CONFIG_MARCH_Z990) += $(call check_gcc,-march=z990,) +cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5) +cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) +cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) + +ifeq ($(call cc-option-yn,-mkernel-backchain),y) +cflags-$(CONFIG_PACK_STACK) += -mkernel-backchain -D__PACK_STACK +aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK +cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK +aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK +ifdef CONFIG_SMALL_STACK +STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) ) +endif +endif + +ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y) +cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE) +cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD) +endif + +ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) +cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack +cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE) +endif -CFLAGS += $(cflags-y) -CFLAGS += $(call check_gcc,-finline-limit=10000,) +CFLAGS += -mbackchain $(cflags-y) +CFLAGS += $(call cc-option,-finline-limit=10000) CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare -CFLAGS += -mbackchain +AFLAGS += $(aflags-y) OBJCOPYFLAGS := -O binary LDFLAGS_vmlinux := -e start diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index a21e30846..462ee9a84 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -102,8 +102,12 @@ static inline void appldata_debug_print(struct appldata_mem_data *mem_data) */ static void appldata_get_mem_data(void *data) { - struct sysinfo val; - struct page_state ps; + /* + * don't put large structures on the stack, we are + * serialized through the appldata_ops_lock and can use static + */ + static struct sysinfo val; + static struct page_state ps; struct appldata_mem_data *mem_data; mem_data = data; diff --git a/arch/s390/defconfig b/arch/s390/defconfig index d4cd42c3e..55def7d33 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3 +# Fri Oct 8 19:17:35 2004 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -15,6 +17,7 @@ CONFIG_CLEAN_COMPILE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set @@ -36,6 +39,8 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -56,14 +61,22 @@ CONFIG_KMOD=y # CONFIG_ARCH_S390X is not set # CONFIG_64BIT is not set CONFIG_ARCH_S390_31=y -CONFIG_MARCH_G5=y -# CONFIG_MARCH_Z900 is not set -# CONFIG_MARCH_Z990 is not set CONFIG_SMP=y CONFIG_NR_CPUS=32 # CONFIG_HOTPLUG_CPU is not set CONFIG_MATHEMU=y +# +# Code generation options +# +CONFIG_MARCH_G5=y +# CONFIG_MARCH_Z900 is not set +# CONFIG_MARCH_Z990 is not set +CONFIG_PACK_STACK=y +# CONFIG_SMALL_STACK is not set +# CONFIG_CHECK_STACK is not set +# CONFIG_WARN_STACK is not set + # # I/O subsystem configuration # @@ -130,9 +143,7 @@ CONFIG_SCSI_FC_ATTRS=y # # SCSI low-level drivers # -# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_DEBUG is not set CONFIG_ZFCP=y CONFIG_CCW=y @@ -154,7 +165,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_XPRAM=m # CONFIG_DCSSBLK is not set CONFIG_DASD=y -# CONFIG_DASD_PROFILE is not set +CONFIG_DASD_PROFILE=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y CONFIG_DASD_DIAG=y @@ -168,6 +179,7 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=m # CONFIG_MD_RAID6 is not set CONFIG_MD_MULTIPATH=m @@ -236,11 +248,13 @@ CONFIG_IP_MULTICAST=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set CONFIG_XFRM=y @@ -419,7 +433,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 @@ -443,6 +456,7 @@ CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -486,8 +500,8 @@ CONFIG_MSDOS_PARTITION=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_INFO is not set # # Security options @@ -506,16 +520,18 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_SHA1_Z990 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_DES_Z990 is not set # 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/Makefile b/arch/s390/kernel/Makefile index 892b7e1b0..a19cb59ed 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -6,11 +6,11 @@ EXTRA_AFLAGS := -traditional obj-y := bitmap.o traps.o time.o process.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o profile.o + semaphore.o s390_ext.o debug.o profile.o irq.o extra-$(CONFIG_ARCH_S390_31) += head.o extra-$(CONFIG_ARCH_S390X) += head64.o -extra-y += init_task.o vmlinux.lds.s +extra-y += init_task.o vmlinux.lds obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index ce2b03578..7537972ac 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -39,5 +39,9 @@ int main(void) DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),); DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),); DEFINE(__PT_SIZE, sizeof(struct pt_regs),); + BLANK(); + DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),); + DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),); + DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),); return 0; } diff --git a/arch/s390/kernel/compat_exec.c b/arch/s390/kernel/compat_exec.c index 595c43a89..b4049a3dd 100644 --- a/arch/s390/kernel/compat_exec.c +++ b/arch/s390/kernel/compat_exec.c @@ -69,7 +69,7 @@ int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack) mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + mm->stack_vm = mm->total_vm = vma_pages(mpnt); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 5685c5feb..5c0a63aff 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, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index e8c8b2fe7..f29bcb856 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -118,10 +118,10 @@ int copy_siginfo_from_user32(siginfo_t *to, siginfo_t32 __user *from) err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); - if (from->si_code < 0) + if (to->si_code < 0) err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { - switch (from->si_code >> 16) { + switch (to->si_code >> 16) { case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __get_user(to->si_int, &from->si_int); @@ -218,14 +218,17 @@ sys32_sigaction(int sig, const struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; + unsigned long sa_handler, sa_restorer; int ret; if (act) { compat_old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler) || - __get_user((unsigned long)new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(sa_handler, &act->sa_handler) || + __get_user(sa_restorer, &act->sa_restorer)) return -EFAULT; + new_ka.sa.sa_handler = (__sighandler_t) sa_handler; + new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); @@ -234,9 +237,11 @@ sys32_sigaction(int sig, const struct old_sigaction32 __user *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { + sa_handler = (unsigned long) old_ka.sa.sa_handler; + sa_restorer = (unsigned long) old_ka.sa.sa_restorer; if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user((unsigned long)old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(sa_handler, &oact->sa_handler) || + __put_user(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); @@ -253,6 +258,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction new_ka, old_ka; + unsigned long sa_handler; int ret; compat_sigset_t set32; @@ -261,7 +267,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, return -EINVAL; if (act) { - ret = get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler); + ret = get_user(sa_handler, &act->sa_handler); ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); switch (_NSIG_WORDS) { @@ -278,6 +284,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, if (ret) return -EFAULT; + new_ka.sa.sa_handler = (__sighandler_t) sa_handler; } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); @@ -311,17 +318,19 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, struct pt_regs *regs) { stack_t kss, koss; + unsigned long ss_sp; int ret, err = 0; mm_segment_t old_fs = get_fs(); if (uss) { if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) return -EFAULT; - err |= __get_user((unsigned long) kss.ss_sp, &uss->ss_sp); + err |= __get_user(ss_sp, &uss->ss_sp); err |= __get_user(kss.ss_size, &uss->ss_size); err |= __get_user(kss.ss_flags, &uss->ss_flags); if (err) return -EFAULT; + kss.ss_sp = (void *) ss_sp; } set_fs (KERNEL_DS); @@ -333,7 +342,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, if (!ret && uoss) { if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) return -EFAULT; - err |= __put_user((unsigned long) koss.ss_sp, &uoss->ss_sp); + ss_sp = (unsigned long) koss.ss_sp; + err |= __put_user(ss_sp, &uoss->ss_sp); err |= __put_user(koss.ss_size, &uoss->ss_size); err |= __put_user(koss.ss_flags, &uoss->ss_flags); if (err) @@ -552,9 +562,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 +612,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 +620,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 = ¤t->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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index f1e538c9d..8669d6c3e 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -24,7 +24,6 @@ #include -#define MIN(a,b) (((a)<(b))?(a):(b)) #define DEBUG_PROLOG_ENTRY -1 /* typedefs */ @@ -435,7 +434,7 @@ static ssize_t debug_output(struct file *file, /* file descriptor */ while(count < len){ size = debug_format_entry(p_info); - size = MIN((len - count), (size - entry_offset)); + size = min((len - count), (size - entry_offset)); if(size){ if (copy_to_user(user_buf + count, @@ -723,7 +722,7 @@ debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); debug_finish_entry(id, active, level, 0); spin_unlock_irqrestore(&id->lock, flags); @@ -744,7 +743,7 @@ debug_entry_t *debug_exception_common(debug_info_t * id, int level, spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); debug_finish_entry(id, active, level, 1); spin_unlock_irqrestore(&id->lock, flags); @@ -789,7 +788,7 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id, curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active); va_start(ap,string); curr_event->string=string; - for(idx=0;idxbuf_size / sizeof(long))-1));idx++) + for(idx=0;idxbuf_size / sizeof(long))-1);idx++) curr_event->args[idx]=va_arg(ap,long); va_end(ap); debug_finish_entry(id, active, level, 0); @@ -821,7 +820,7 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id, curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active); va_start(ap,string); curr_event->string=string; - for(idx=0;idxbuf_size / sizeof(long))-1));idx++) + for(idx=0;idxbuf_size / sizeof(long))-1);idx++) curr_event->args[idx]=va_arg(ap,long); va_end(ap); debug_finish_entry(id, active, level, 1); @@ -1157,7 +1156,7 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, } /* number of arguments used for sprintf (without the format string) */ - num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + num_used_args = min(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c index 52d5a78b5..bb0f97313 100644 --- a/arch/s390/kernel/ebcdic.c +++ b/arch/s390/kernel/ebcdic.c @@ -391,10 +391,10 @@ __u8 _ebc_toupper[256] = 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); +EXPORT_SYMBOL(_ascebc_500); +EXPORT_SYMBOL(_ebcasc_500); +EXPORT_SYMBOL(_ascebc); +EXPORT_SYMBOL(_ebcasc); +EXPORT_SYMBOL(_ebc_tolower); +EXPORT_SYMBOL(_ebc_toupper); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1f87bf29c..06312d09c 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -19,6 +19,7 @@ #include #include #include +#include /* * Stack layout for the system_call stack entry. @@ -52,6 +53,9 @@ _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) +STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER +STACK_SIZE = 1 << STACK_SHIFT + #define BASED(name) name-system_call(%r13) /* @@ -86,10 +90,16 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) bnz BASED(1f) 0: l %r14,__LC_ASYNC_STACK # are we already on the async stack ? slr %r14,%r15 - sra %r14,13 + sra %r14,STACK_SHIFT be BASED(2f) 1: l %r15,__LC_ASYNC_STACK .endif +#ifdef CONFIG_CHECK_STACK + b BASED(3f) +2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + bz BASED(stack_overflow) +3: +#endif 2: s %r15,BASED(.Lc_spsize) # make room for registers & psw mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack la %r12,\psworg @@ -99,7 +109,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) st %r12,SP_ILC(%r15) mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack la %r12,0 - st %r12,0(%r15) # clear back chain + st %r12,__SF_BACKCHAIN(%r15) # clear back chain .endm .macro RESTORE_ALL sync @@ -124,46 +134,22 @@ __switch_to: __switch_to_base: tm __THREAD_per(%r3),0xe8 # new process is using per ? bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine - stctl %c9,%c11,24(%r15) # We are using per stuff - clc __THREAD_per(12,%r3),24(%r15) + stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff + clc __THREAD_per(12,%r3),__SF_EMPTY(%r15) be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: - stm %r6,%r15,24(%r15) # store __switch_to registers of prev task + stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp - lm %r6,%r15,24(%r15) # load __switch_to registers of next task + lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task st %r3,__LC_CURRENT # __LC_CURRENT = current task struct l %r3,__THREAD_info(%r3) # load thread_info from task struct st %r3,__LC_THREAD_INFO - ahi %r3,8192 + ahi %r3,STACK_SIZE st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack br %r14 -/* - * do_softirq calling function. We want to run the softirq functions on the - * asynchronous interrupt stack. - */ - .global do_call_softirq -do_call_softirq: - stnsm 24(%r15),0xfc - stm %r12,%r15,28(%r15) - lr %r12,%r15 - basr %r13,0 -do_call_base: - l %r0,__LC_ASYNC_STACK - slr %r0,%r15 - sra %r0,13 - be 0f-do_call_base(%r13) - l %r15,__LC_ASYNC_STACK -0: sl %r15,.Lc_overhead-do_call_base(%r13) - st %r12,0(%r15) # store backchain - l %r1,.Ldo_softirq-do_call_base(%r13) - basr %r14,%r1 - lm %r12,%r15,28(%r12) - ssm 24(%r15) - br %r14 - __critical_start: /* * SVC interrupt handler routine. System calls are synchronous events and @@ -304,9 +290,12 @@ sysc_tracenogo: ret_from_fork: l %r13,__LC_SVC_NEW_PSW+4 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct - l %r1,BASED(.Lschedtail) + tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? + bo BASED(0f) + st %r15,SP_R15(%r15) # store stack pointer for new kthread +0: l %r1,BASED(.Lschedtail) basr %r14,%r1 - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts b BASED(sysc_return) # @@ -457,7 +446,7 @@ pgm_svcper: mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts b BASED(sysc_do_svc) /* @@ -493,16 +482,16 @@ io_preempt: l %r1,SP_R15(%r15) s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(4,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 io_resume_loop: tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bno BASED(io_leave) mvc __TI_precount(4,%r9),BASED(.Lc_pactive) - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts l %r1,BASED(.Lschedule) basr %r14,%r1 # call schedule - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts xc __TI_precount(4,%r9),__TI_precount(%r9) b BASED(io_resume_loop) #endif @@ -514,7 +503,7 @@ io_work: l %r1,__LC_KERNEL_STACK s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(4,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 # # One of the work bits is on. Find out which one. @@ -532,9 +521,9 @@ io_work_loop: # io_reschedule: l %r1,BASED(.Lschedule) - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts basr %r14,%r1 # call scheduler - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts tm __TI_flags+3(%r9),_TIF_WORK_INT bz BASED(io_leave) # there is no work to do b BASED(io_work_loop) @@ -543,12 +532,12 @@ io_reschedule: # _TIF_SIGPENDING is set, call do_signal # io_sigpending: - stosm 24(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset l %r1,BASED(.Ldo_signal) basr %r14,%r1 # call do_signal - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts b BASED(io_leave) # out of here, do NOT recheck /* @@ -589,8 +578,8 @@ restart_int_handler: l %r15,__LC_SAVE_AREA+60 # load ksp lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs lam %a0,%a15,__LC_AREGS_SAVE_AREA - stosm 0(%r15),0x04 # now we can turn dat on - lm %r6,%r15,24(%r15) # load registers from clone + lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone + stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on basr %r14,0 l %r14,restart_addr-.(%r14) br %r14 # branch to start_secondary @@ -611,6 +600,31 @@ restart_crash: restart_go: #endif +#ifdef CONFIG_CHECK_STACK +/* + * The synchronous or the asynchronous stack overflowed. We are dead. + * No need to properly save the registers, we are going to panic anyway. + * Setup a pt_regs so that show_trace can provide a good call trace. + */ +stack_overflow: + l %r15,__LC_PANIC_STACK # change to panic stack + sl %r15,BASED(.Lc_spsize) + mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack + stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack + la %r1,__LC_SAVE_AREA + ch %r12,BASED(.L0x020) # old psw addr == __LC_SVC_OLD_PSW ? + be BASED(0f) + ch %r12,BASED(.L0x028) # old psw addr == __LC_PGM_OLD_PSW ? + be BASED(0f) + la %r1,__LC_SAVE_AREA+16 +0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain + l %r1,BASED(1f) # branch to kernel_stack_overflow + la %r2,SP_PTREGS(%r15) # load pt_regs + br %r1 +1: .long kernel_stack_overflow +#endif + cleanup_table_system_call: .long system_call + 0x80000000, sysc_do_svc + 0x80000000 cleanup_table_sysc_return: @@ -695,7 +709,6 @@ cleanup_sysc_leave_lpsw: .Ldo_IRQ: .long do_IRQ .Ldo_extint: .long do_extint .Ldo_signal: .long do_signal -.Ldo_softirq: .long do_softirq .Lhandle_per: .long do_single_step .Ljump_table: .long pgm_check_table .Lschedule: .long schedule diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 54190092b..10056f2b1 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -19,6 +19,7 @@ #include #include #include +#include /* * Stack layout for the system_call stack entry. @@ -48,6 +49,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE +STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER +STACK_SIZE = 1 << STACK_SHIFT + _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) @@ -85,10 +89,16 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) jnz 1f 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? slgr %r14,%r15 - srag %r14,%r14,14 + srag %r14,%r14,STACK_SHIFT jz 2f 1: lg %r15,__LC_ASYNC_STACK # load async stack .endif +#ifdef CONFIG_CHECK_STACK + j 3f +2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + jz stack_overflow +3: +#endif 2: aghi %r15,-SP_SIZE # make room for registers & psw mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack la %r12,\psworg @@ -98,7 +108,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) st %r12,SP_ILC(%r15) mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack la %r12,0 - stg %r12,0(%r15) + stg %r12,__SF_BACKCHAIN(%r15) .endm .macro RESTORE_ALL sync @@ -121,43 +131,22 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) __switch_to: tm __THREAD_per+4(%r3),0xe8 # is the new process using per ? jz __switch_to_noper # if not we're fine - stctg %c9,%c11,48(%r15) # We are using per stuff - clc __THREAD_per(24,%r3),48(%r15) + stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff + clc __THREAD_per(24,%r3),__SF_EMPTY(%r15) je __switch_to_noper # we got away without bashing TLB's lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: - stmg %r6,%r15,48(%r15) # store __switch_to registers of prev task + stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp - lmg %r6,%r15,48(%r15) # load __switch_to registers of next task + lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct lg %r3,__THREAD_info(%r3) # load thread_info from task struct stg %r3,__LC_THREAD_INFO - aghi %r3,16384 + aghi %r3,STACK_SIZE stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack br %r14 -/* - * do_softirq calling function. We want to run the softirq functions on the - * asynchronous interrupt stack. - */ - .global do_call_softirq -do_call_softirq: - stnsm 48(%r15),0xfc - stmg %r12,%r15,56(%r15) - lgr %r12,%r15 - lg %r0,__LC_ASYNC_STACK - slgr %r0,%r15 - srag %r0,%r0,14 - je 0f - lg %r15,__LC_ASYNC_STACK -0: aghi %r15,-STACK_FRAME_OVERHEAD - stg %r12,0(%r15) # store back chain - brasl %r14,do_softirq - lmg %r12,%r15,56(%r12) - ssm 48(%r15) - br %r14 - __critical_start: /* * SVC interrupt handler routine. System calls are synchronous events and @@ -304,7 +293,10 @@ sysc_tracenogo: ret_from_fork: lg %r13,__LC_SVC_NEW_PSW+8 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - brasl %r14,schedule_tail + tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? + jo 0f + stg %r15,SP_R15(%r15) # store stack pointer for new kthread +0: brasl %r14,schedule_tail stosm 24(%r15),0x03 # reenable interrupts j sysc_return @@ -504,7 +496,7 @@ pgm_svcper: mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - stosm 48(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts j sysc_do_svc /* @@ -539,16 +531,16 @@ io_preempt: lg %r1,SP_R15(%r15) aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(8,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 io_resume_loop: tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jno io_leave larl %r1,.Lc_pactive mvc __TI_precount(4,%r9),0(%r1) - stosm 48(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts brasl %r14,schedule # call schedule - stnsm 48(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts xc __TI_precount(4,%r9),__TI_precount(%r9) j io_resume_loop #endif @@ -560,7 +552,7 @@ io_work: lg %r1,__LC_KERNEL_STACK aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc 0(8,%r1),0(%r1) # clear back chain + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 # # One of the work bits is on. Find out which one. @@ -577,23 +569,23 @@ io_work_loop: # _TIF_NEED_RESCHED is set, call schedule # io_reschedule: - stosm 48(%r15),0x03 # reenable interrupts - brasl %r14,schedule # call scheduler - stnsm 48(%r15),0xfc # disable I/O and ext. interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + brasl %r14,schedule # call scheduler + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts tm __TI_flags+7(%r9),_TIF_WORK_INT - jz io_leave # there is no work to do + jz io_leave # there is no work to do j io_work_loop # # _TIF_SIGPENDING is set, call do_signal # io_sigpending: - stosm 48(%r15),0x03 # reenable interrupts - la %r2,SP_PTREGS(%r15) # load pt_regs - slgr %r3,%r3 # clear *oldset - brasl %r14,do_signal # call do_signal - stnsm 48(%r15),0xfc # disable I/O and ext. interrupts - j sysc_leave # out of here, do NOT recheck + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + la %r2,SP_PTREGS(%r15) # load pt_regs + slgr %r3,%r3 # clear *oldset + brasl %r14,do_signal # call do_signal + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + j sysc_leave # out of here, do NOT recheck /* * External interrupt handler routine @@ -631,8 +623,8 @@ restart_int_handler: lctlg %c0,%c15,0(%r10) # get new ctl regs lghi %r10,__LC_AREGS_SAVE_AREA lam %a0,%a15,0(%r10) - stosm 0(%r15),0x04 # now we can turn dat on - lmg %r6,%r15,48(%r15) # load registers from clone + lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone + stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on jg start_secondary #else /* @@ -649,6 +641,29 @@ restart_crash: restart_go: #endif +#ifdef CONFIG_CHECK_STACK +/* + * The synchronous or the asynchronous stack overflowed. We are dead. + * No need to properly save the registers, we are going to panic anyway. + * Setup a pt_regs so that show_trace can provide a good call trace. + */ +stack_overflow: + lg %r15,__LC_PANIC_STACK # change to panic stack + aghi %r1,-SP_SIZE + mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack + stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack + la %r1,__LC_SAVE_AREA + chi %r12,__LC_SVC_OLD_PSW + je 0f + chi %r12,__LC_PGM_OLD_PSW + je 0f + la %r1,__LC_SAVE_AREA+16 +0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack + xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain + la %r2,SP_PTREGS(%r15) # load pt_regs + jg kernel_stack_overflow +#endif + cleanup_table_system_call: .quad system_call, sysc_do_svc cleanup_table_sysc_return: diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index fb295b79f..b804c55bd 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifndef CONFIG_IPL .org 0 @@ -741,10 +743,10 @@ _stext: basr %r13,0 # get base # l %r15,.Linittu-.LPG2(%r13) mvc __LC_CURRENT(4),__TI_task(%r15) - ahi %r15,8192 # init_task_union + 8192 + ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE st %r15,__LC_KERNEL_STACK # set end of kernel stack ahi %r15,-96 - xc 0(4,%r15),0(%r15) # set backchain to zero + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain # check control registers stctl %c0,%c15,0(%r15) diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index e32a8e90f..8366793bc 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifndef CONFIG_IPL .org 0 @@ -741,10 +743,10 @@ _stext: basr %r13,0 # get base larl %r15,init_thread_union lg %r14,__TI_task(%r15) # cache current in lowcore stg %r14,__LC_CURRENT - aghi %r15,16384 # init_task_union + 16384 + aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE stg %r15,__LC_KERNEL_STACK # set end of kernel stack aghi %r15,-160 - xc 0(8,%r15),0(%r15) # set backchain to zero + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain # check control registers stctg %c0,%c15,0(%r15) diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c new file mode 100644 index 000000000..79a422247 --- /dev/null +++ b/arch/s390/kernel/irq.c @@ -0,0 +1,99 @@ +/* + * arch/s390/kernel/irq.c + * + * S390 version + * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * + * This file contains interrupt related functions. + */ + +#include +#include +#include +#include +#include +#include + +/* + * show_interrupts is needed by /proc/interrupts. + */ +int show_interrupts(struct seq_file *p, void *v) +{ + static const char *intrclass_names[] = { "EXT", "I/O", }; + int i = *(loff_t *) v, j; + + if (i == 0) { + seq_puts(p, " "); + for (j=0; j> (PAGE_SHIFT + THREAD_ORDER)) != 0) { + /* Need to switch to the async. stack. */ + new -= STACK_FRAME_OVERHEAD; + ((struct stack_frame *) new)->back_chain = old; + + asm volatile(" la 15,0(%0)\n" + " basr 14,%2\n" + " la 15,0(%1)\n" + : : "a" (new), "a" (old), + "a" (__do_softirq) + : "0", "1", "2", "3", "4", "5", + "cc", "memory" ); + } else + /* We are already on the async stack. */ + __do_softirq(); + } + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(do_softirq); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 73cb6baeb..5d56e77c7 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -58,14 +58,11 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); */ unsigned long thread_saved_pc(struct task_struct *tsk) { - unsigned long bc; + struct stack_frame *sf; - bc = *((unsigned long *) tsk->thread.ksp); -#ifndef CONFIG_ARCH_S390X - return *((unsigned long *) (bc+56)); -#else - return *((unsigned long *) (bc+112)); -#endif + sf = (struct stack_frame *) tsk->thread.ksp; + sf = (struct stack_frame *) sf->back_chain; + return sf->gprs[8]; } /* @@ -186,41 +183,20 @@ void show_regs(struct pt_regs *regs) extern void kernel_thread_starter(void); -#ifndef CONFIG_ARCH_S390X - __asm__(".align 4\n" "kernel_thread_starter:\n" - " l 15,0(8)\n" - " sr 15,7\n" - " stosm 24(15),3\n" - " lr 2,10\n" + " la 2,0(10)\n" " basr 14,9\n" - " sr 2,2\n" + " la 2,0\n" " br 11\n"); -#else /* CONFIG_ARCH_S390X */ - -__asm__(".align 4\n" - "kernel_thread_starter:\n" - " lg 15,0(8)\n" - " sgr 15,7\n" - " stosm 48(15),3\n" - " lgr 2,10\n" - " basr 14,9\n" - " sgr 2,2\n" - " br 11\n"); - -#endif /* CONFIG_ARCH_S390X */ - int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); - regs.psw.mask = PSW_KERNEL_BITS; + regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE; - regs.gprs[7] = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); - regs.gprs[8] = __LC_KERNEL_STACK; regs.gprs[9] = (unsigned long) fn; regs.gprs[10] = (unsigned long) arg; regs.gprs[11] = (unsigned long) do_exit; @@ -253,20 +229,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, unsigned long unused, struct task_struct * p, struct pt_regs * regs) { - struct stack_frame + struct fake_frame { - unsigned long back_chain; - unsigned long eos; - unsigned long glue1; - unsigned long glue2; - unsigned long scratch[2]; - unsigned long gprs[10]; /* gprs 6 -15 */ - unsigned int fprs[4]; /* fpr 4 and 6 */ - unsigned int empty[4]; + struct stack_frame sf; struct pt_regs childregs; } *frame; - frame = ((struct stack_frame *) + frame = ((struct fake_frame *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; p->thread.ksp = (unsigned long) frame; p->set_child_tid = p->clear_child_tid = NULL; @@ -274,13 +243,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, frame->childregs = *regs; frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ frame->childregs.gprs[15] = new_stackp; - frame->back_chain = frame->eos = 0; + frame->sf.back_chain = 0; /* new return point is ret_from_fork */ - frame->gprs[8] = (unsigned long) ret_from_fork; + frame->sf.gprs[8] = (unsigned long) ret_from_fork; /* fake return stack for resume(), don't go back to schedule */ - frame->gprs[9] = (unsigned long) frame; + frame->sf.gprs[9] = (unsigned long) frame; /* Save access registers to new thread structure. */ save_access_regs(&p->thread.acrs[0]); @@ -336,7 +305,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, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } @@ -423,30 +392,26 @@ void dump_thread(struct pt_regs * regs, struct user * dump) unsigned long get_wchan(struct task_struct *p) { - unsigned long r14, r15, bc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) + struct stack_frame *sf, *low, *high; + unsigned long return_address; + int count; + + if (!p || p == current || p->state == TASK_RUNNING || !p->thread_info) return 0; - stack_page = (unsigned long) p->thread_info; - r15 = p->thread.ksp; - if (!stack_page || r15 < stack_page || - r15 >= THREAD_SIZE - sizeof(unsigned long) + stack_page) + low = (struct stack_frame *) p->thread_info; + high = (struct stack_frame *) + ((unsigned long) p->thread_info + THREAD_SIZE) - 1; + sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN); + if (sf <= low || sf > high) return 0; - bc = (*(unsigned long *) r15) & PSW_ADDR_INSN; - do { - if (bc < stack_page || - bc >= THREAD_SIZE - sizeof(unsigned long) + stack_page) + for (count = 0; count < 16; count++) { + sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN); + if (sf <= low || sf > high) return 0; -#ifndef CONFIG_ARCH_S390X - r14 = (*(unsigned long *) (bc+56)) & PSW_ADDR_INSN; -#else - r14 = *(unsigned long *) (bc+112); -#endif - if (!in_sched_functions(r14)) - return r14; - bc = (*(unsigned long *) bc) & PSW_ADDR_INSN; - } while (count++ < 16); + return_address = sf->gprs[8] & PSW_ADDR_INSN; + if (!in_sched_functions(return_address)) + return return_address; + } return 0; } diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c index f219748d7..7ba777eec 100644 --- a/arch/s390/kernel/profile.c +++ b/arch/s390/kernel/profile.c @@ -6,52 +6,15 @@ * */ #include +#include static struct proc_dir_entry * root_irq_dir; -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, - const char __user *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - void init_irq_proc(void) { - struct proc_dir_entry *entry; - /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); } diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index c00e5e328..b61490bd1 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 43afd32f8..1a5ba047e 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -23,16 +23,18 @@ /* * memory management */ -EXPORT_SYMBOL_NOVERS(_oi_bitmap); -EXPORT_SYMBOL_NOVERS(_ni_bitmap); -EXPORT_SYMBOL_NOVERS(_zb_findmap); -EXPORT_SYMBOL_NOVERS(_sb_findmap); -EXPORT_SYMBOL_NOVERS(__copy_from_user_asm); -EXPORT_SYMBOL_NOVERS(__copy_to_user_asm); -EXPORT_SYMBOL_NOVERS(__clear_user_asm); -EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); -EXPORT_SYMBOL_NOVERS(__strnlen_user_asm); +EXPORT_SYMBOL(_oi_bitmap); +EXPORT_SYMBOL(_ni_bitmap); +EXPORT_SYMBOL(_zb_findmap); +EXPORT_SYMBOL(_sb_findmap); +EXPORT_SYMBOL(__copy_from_user_asm); +EXPORT_SYMBOL(__copy_to_user_asm); +EXPORT_SYMBOL(__copy_in_user_asm); +EXPORT_SYMBOL(__clear_user_asm); +EXPORT_SYMBOL(__strncpy_from_user_asm); +EXPORT_SYMBOL(__strnlen_user_asm); EXPORT_SYMBOL(diag10); +EXPORT_SYMBOL(default_storage_key); /* * semaphore ops @@ -60,6 +62,5 @@ EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_devno); EXPORT_SYMBOL(console_irq); -EXPORT_SYMBOL_NOVERS(do_call_softirq); EXPORT_SYMBOL(sys_wait4); EXPORT_SYMBOL(cpcmd); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index a50891ce0..1324fc6ce 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -53,6 +53,7 @@ unsigned int console_devno = -1; unsigned int console_irq = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; +unsigned int default_storage_key = 0; struct { unsigned long addr, size, type; } memory_chunk[MEMORY_CHUNKS] = { { 0 } }; @@ -503,6 +504,10 @@ void __init setup_arch(char **cmdline_p) lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->async_stack = (unsigned long) __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; +#ifdef CONFIG_CHECK_STACK + lc->panic_stack = (unsigned long) + __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; +#endif lc->current_task = (unsigned long) init_thread_union.thread_info.task; lc->thread_info = (unsigned long) &init_thread_union; #ifdef CONFIG_ARCH_S390X @@ -604,49 +609,3 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -/* - * show_interrupts is needed by /proc/interrupts. - */ - -static const char *intrclass_names[] = { - "EXT", - "I/O", -}; - -int show_interrupts(struct seq_file *p, void *v) -{ - int i = *(loff_t *) v, j; - - if (i == 0) { - seq_puts(p, " "); - for (j=0; jsa.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 = ¤t->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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->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 eb8a5161a..b5c09d144 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(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM | CLONE_IDLETASK, 0, ®s, 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; } @@ -643,6 +637,7 @@ __cpu_up(unsigned int cpu) { struct task_struct *idle; struct _lowcore *cpu_lowcore; + struct stack_frame *sf; sigp_ccode ccode; int curr_cpu; @@ -666,9 +661,14 @@ __cpu_up(unsigned int cpu) idle = current_set[cpu]; cpu_lowcore = lowcore_ptr[cpu]; - cpu_lowcore->save_area[15] = idle->thread.ksp; cpu_lowcore->kernel_stack = (unsigned long) idle->thread_info + (THREAD_SIZE); + sf = (struct stack_frame *) (cpu_lowcore->kernel_stack + - sizeof(struct pt_regs) + - sizeof(struct stack_frame)); + memset(sf, 0, sizeof(struct stack_frame)); + sf->gprs[9] = (unsigned long) sf; + cpu_lowcore->save_area[15] = (unsigned long) sf; __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15); __asm__ __volatile__("stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) @@ -747,7 +747,7 @@ cpu_die(void) void __init smp_prepare_cpus(unsigned int max_cpus) { - unsigned long async_stack; + unsigned long stack; unsigned int cpu; int i; @@ -767,12 +767,18 @@ void __init smp_prepare_cpus(unsigned int max_cpus) lowcore_ptr[i] = (struct _lowcore *) __get_free_pages(GFP_KERNEL|GFP_DMA, sizeof(void*) == 8 ? 1 : 0); - async_stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER); - if (lowcore_ptr[i] == NULL || async_stack == 0ULL) + stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER); + if (lowcore_ptr[i] == NULL || stack == 0ULL) panic("smp_boot_cpus failed to allocate memory\n"); *(lowcore_ptr[i]) = S390_lowcore; - lowcore_ptr[i]->async_stack = async_stack + (ASYNC_SIZE); + lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE); +#ifdef CONFIG_CHECK_STACK + stack = __get_free_pages(GFP_KERNEL,0); + if (stack == 0ULL) + panic("smp_boot_cpus failed to allocate memory\n"); + lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE); +#endif } set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 12f46a65a..8f2794216 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -174,47 +174,7 @@ __calculate_ticks(__u64 elapsed) #ifdef CONFIG_PROFILING -extern char _stext, _etext; - -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void s390_do_profile(struct pt_regs * regs) -{ - unsigned long eip; - extern cpumask_t prof_cpu_mask; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - eip = instruction_pointer(regs); - - /* - * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. - * (default is all CPUs.) - */ - if (!cpu_isset(smp_processor_id(), prof_cpu_mask)) - return; - - eip -= (unsigned long) &_stext; - eip >>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (eip > prof_len-1) - eip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[eip]); -} +#define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) #else #define s390_do_profile(regs) do { ; } while(0) #endif /* CONFIG_PROFILING */ diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 6614d4be1..e67ee2702 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -67,54 +67,93 @@ extern pgm_check_handler_t do_monitor_call; #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) #ifndef CONFIG_ARCH_S390X -#define RET_ADDR 56 #define FOURLONG "%08lx %08lx %08lx %08lx\n" static int kstack_depth_to_print = 12; - #else /* CONFIG_ARCH_S390X */ -#define RET_ADDR 112 #define FOURLONG "%016lx %016lx %016lx %016lx\n" static int kstack_depth_to_print = 20; - #endif /* CONFIG_ARCH_S390X */ -void show_trace(struct task_struct *task, unsigned long * stack) +/* + * For show_trace we have tree different stack to consider: + * - the panic stack which is used if the kernel stack has overflown + * - the asynchronous interrupt stack (cpu related) + * - the synchronous kernel stack (process related) + * The stack trace can start at any of the three stack and can potentially + * touch all of them. The order is: panic stack, async stack, sync stack. + */ +static unsigned long +__show_trace(unsigned long sp, unsigned long low, unsigned long high) { - unsigned long backchain, low_addr, high_addr, ret_addr; + struct stack_frame *sf; + struct pt_regs *regs; - if (!stack) - stack = (task == NULL) ? *stack_pointer : &(task->thread.ksp); + while (1) { + sp = sp & PSW_ADDR_INSN; + if (sp < low || sp > high - sizeof(*sf)) + return sp; + sf = (struct stack_frame *) sp; + printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); + print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN); + /* Follow the backchain. */ + while (1) { + low = sp; + sp = sf->back_chain & PSW_ADDR_INSN; + if (!sp) + break; + if (sp <= low || sp > high - sizeof(*sf)) + return sp; + sf = (struct stack_frame *) sp; + printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); + print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN); + } + /* Zero backchain detected, check for interrupt frame. */ + sp = (unsigned long) (sf + 1); + if (sp <= low || sp > high - sizeof(*regs)) + return sp; + regs = (struct pt_regs *) sp; + printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN); + print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN); + low = sp; + sp = regs->gprs[15]; + } +} +void show_trace(struct task_struct *task, unsigned long * stack) +{ + register unsigned long __r15 asm ("15"); + unsigned long sp; + + sp = (unsigned long) stack; + if (!sp) + sp = task ? task->thread.ksp : __r15; printk("Call Trace:\n"); - low_addr = ((unsigned long) stack) & PSW_ADDR_INSN; - high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE; - /* Skip the first frame (biased stack) */ - backchain = *((unsigned long *) low_addr) & PSW_ADDR_INSN; - /* Print up to 8 lines */ - while (backchain > low_addr && backchain <= high_addr) { - ret_addr = *((unsigned long *) (backchain+RET_ADDR)) & PSW_ADDR_INSN; - printk(" [<%016lx>] ", ret_addr); - print_symbol("%s\n", ret_addr); - low_addr = backchain; - backchain = *((unsigned long *) backchain) & PSW_ADDR_INSN; - } +#ifdef CONFIG_CHECK_STACK + sp = __show_trace(sp, S390_lowcore.panic_stack - 4096, + S390_lowcore.panic_stack); +#endif + sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE, + S390_lowcore.async_stack); + if (task) + __show_trace(sp, (unsigned long) task->thread_info, + (unsigned long) task->thread_info + THREAD_SIZE); + else + __show_trace(sp, S390_lowcore.thread_info, + S390_lowcore.thread_info + THREAD_SIZE); printk("\n"); } void show_stack(struct task_struct *task, unsigned long *sp) { + register unsigned long * __r15 asm ("15"); unsigned long *stack; int i; // debugging aid: "show_stack(NULL);" prints the // back trace for this cpu. - if (!sp) { - if (task) - sp = (unsigned long *) task->thread.ksp; - else - sp = *stack_pointer; - } + if (!sp) + sp = task ? (unsigned long *) task->thread.ksp : __r15; stack = sp; for (i = 0; i < kstack_depth_to_print; i++) { @@ -591,6 +630,11 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) } } +asmlinkage void kernel_stack_overflow(struct pt_regs * regs) +{ + die("Kernel stack overflow", regs, 0); + panic("Corrupt kernel stack, can't continue."); +} /* init is done in lowcore.S and head.S */ diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index b4534b286..89fdb3808 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -24,6 +24,7 @@ SECTIONS .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x0700 @@ -78,9 +79,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 d9ccdbdc2..02d2179e4 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -21,7 +21,7 @@ #include #include -#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/lib/string.c b/arch/s390/lib/string.c index 966af7c52..9cf22aa48 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -46,7 +46,7 @@ size_t strlen(const char *s) { return __strend(s) - s; } -EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL(strlen); /** * strnlen - Find the length of a length-limited string @@ -59,7 +59,7 @@ size_t strnlen(const char * s, size_t n) { return __strnend(s, n) - s; } -EXPORT_SYMBOL_NOVERS(strnlen); +EXPORT_SYMBOL(strnlen); /** * strcpy - Copy a %NUL terminated string @@ -79,7 +79,7 @@ char *strcpy(char *dest, const char *src) : "cc", "memory" ); return ret; } -EXPORT_SYMBOL_NOVERS(strcpy); +EXPORT_SYMBOL(strcpy); /** * strlcpy - Copy a %NUL terminated string into a sized buffer @@ -103,7 +103,7 @@ size_t strlcpy(char *dest, const char *src, size_t size) } return ret; } -EXPORT_SYMBOL_NOVERS(strlcpy); +EXPORT_SYMBOL(strlcpy); /** * strncpy - Copy a length-limited, %NUL-terminated string @@ -121,7 +121,7 @@ char *strncpy(char *dest, const char *src, size_t n) __builtin_memcpy(dest, src, len); return dest; } -EXPORT_SYMBOL_NOVERS(strncpy); +EXPORT_SYMBOL(strncpy); /** * strcat - Append one %NUL-terminated string to another @@ -144,7 +144,7 @@ char *strcat(char *dest, const char *src) : "d" (r0), "0" (0UL) : "cc", "memory" ); return ret; } -EXPORT_SYMBOL_NOVERS(strcat); +EXPORT_SYMBOL(strcat); /** * strlcat - Append a length-limited, %NUL-terminated string to another @@ -168,7 +168,7 @@ size_t strlcat(char *dest, const char *src, size_t n) } return res; } -EXPORT_SYMBOL_NOVERS(strlcat); +EXPORT_SYMBOL(strlcat); /** * strncat - Append a length-limited, %NUL-terminated string to another @@ -190,7 +190,7 @@ char *strncat(char *dest, const char *src, size_t n) __builtin_memcpy(p, src, len); return dest; } -EXPORT_SYMBOL_NOVERS(strncat); +EXPORT_SYMBOL(strncat); /** * strcmp - Compare two strings @@ -217,7 +217,7 @@ int strcmp(const char *cs, const char *ct) : : "cc" ); return ret; } -EXPORT_SYMBOL_NOVERS(strcmp); +EXPORT_SYMBOL(strcmp); /** * strrchr - Find the last occurrence of a character in a string @@ -235,7 +235,7 @@ char * strrchr(const char * s, int c) } while (--len > 0); return 0; } -EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL(strrchr); /** * strstr - Find the first substring in a %NUL terminated string @@ -269,7 +269,7 @@ char * strstr(const char * s1,const char * s2) } return 0; } -EXPORT_SYMBOL_NOVERS(strstr); +EXPORT_SYMBOL(strstr); /** * memchr - Find a character in an area of memory. @@ -293,7 +293,7 @@ void *memchr(const void *s, int c, size_t n) : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); return (void *) ret; } -EXPORT_SYMBOL_NOVERS(memchr); +EXPORT_SYMBOL(memchr); /** * memcmp - Compare two areas of memory @@ -319,7 +319,7 @@ int memcmp(const void *cs, const void *ct, size_t n) ret = *(char *) r2 - *(char *) r4; return ret; } -EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL(memcmp); /** * memscan - Find a character in an area of memory. @@ -340,7 +340,7 @@ void *memscan(void *s, int c, size_t n) : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); return (void *) ret; } -EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL(memscan); /** * memcpy - Copy one area of memory to another @@ -354,7 +354,7 @@ void *memcpy(void *dest, const void *src, size_t n) { return __builtin_memcpy(dest, src, n); } -EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL(memcpy); /** * bcopy - Copy one area of memory to another @@ -369,7 +369,7 @@ void bcopy(const void *srcp, void *destp, size_t n) { __builtin_memcpy(destp, srcp, n); } -EXPORT_SYMBOL_NOVERS(bcopy); +EXPORT_SYMBOL(bcopy); /** * memset - Fill a region of memory with the given value @@ -393,4 +393,4 @@ void *memset(void *s, int c, size_t n) } while (--n > 0); return s; } -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memset); diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index f8583caa6..aa9a42b6e 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/fault.c b/arch/s390/mm/fault.c index 8b2dda883..d6bd3d429 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -25,11 +25,11 @@ #include #include #include +#include #include #include #include -#include #ifndef CONFIG_ARCH_S390X #define __FAIL_ADDR_MASK 0x7ffff000 @@ -126,8 +126,8 @@ static inline int check_user_space(struct pt_regs *regs, int error_code) * Send SIGSEGV to task. This is an external routine * to keep the stack usage of do_page_fault small. */ -static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, - int si_code, unsigned long address) +static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, + int si_code, unsigned long address) { struct siginfo si; @@ -282,7 +282,7 @@ bad_area: if (regs->psw.mask & PSW_MASK_PSTATE) { tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; - force_sigsegv(regs, error_code, si_code, address); + do_sigsegv(regs, error_code, si_code, address); return; } diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index ce61d06ca..de30f48e5 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -194,7 +194,7 @@ endchoice choice prompt "Processor subtype" - + config CPU_SUBTYPE_SH7604 bool "SH7604" depends on CPU_SH2 @@ -301,7 +301,7 @@ config MEMORY_START ---help--- Computers built with Hitachi SuperH processors always map the ROM starting at address zero. But the processor - does not specify the range that RAM takes. + does not specify the range that RAM takes. The physical memory (RAM) start address will be automatically set to 08000000, unless you selected one of the following @@ -339,7 +339,7 @@ config MEMORY_SET # If none of the above have set memory start/size, ask the user. config MEMORY_OVERRIDE bool "Override default load address and memory size" - + # XXX: break these out into the board-specific configs below config CF_ENABLER bool "Compact Flash Enabler support" @@ -522,7 +522,7 @@ config SH_STORE_QUEUES help Selecting this option will enable an in-kernel API for manipulating the store queues integrated in the SH-4 processors. - + config SMP bool "Symmetric multi-processing support" ---help--- @@ -711,7 +711,6 @@ source "drivers/pci/hotplug/Kconfig" endmenu - menu "Executable file formats" source "fs/Kconfig.binfmt" @@ -742,161 +741,10 @@ source "fs/Kconfig" source "arch/sh/oprofile/Kconfig" -menu "Kernel hacking" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config SH_STANDARD_BIOS - bool "Use LinuxSH standard BIOS" - help - Say Y here if your target has the gdb-sh-stub - package from www.m17n.org (or any conforming standard LinuxSH BIOS) - in FLASH or EPROM. The kernel will use standard BIOS calls during - boot for various housekeeping tasks (including calls to read and - write characters to a system console, get a MAC address from an - on-board Ethernet interface, and shut down the hardware). Note this - does not work with machines with an existing operating system in - mask ROM and no flash (WindowsCE machines fall in this category). - If unsure, say N. - -config EARLY_SCIF_CONSOLE - bool "Use early SCIF console" - depends on CPU_SH4 - -config EARLY_PRINTK - bool "Early printk support" - depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE - help - Say Y here to redirect kernel printk messages to the serial port - used by the SH-IPL bootloader, starting very early in the boot - process and ending when the kernel's serial console is initialised. - This option is only useful porting the kernel to a new machine, - when the kernel may crash or hang before the serial console is - initialised. If unsure, say N. - -config KGDB - bool "Include KGDB kernel debugger" - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -menu "KGDB configuration options" - depends on KGDB - -config MORE_COMPILE_OPTIONS - bool "Add any additional compile options" - help - If you want to add additional CFLAGS to the kernel build, enable this - option and then enter what you would like to add in the next question. - Note however that -g is already appended with the selection of KGDB. - -config COMPILE_OPTIONS - string "Additional compile arguments" - depends on MORE_COMPILE_OPTIONS - -config KGDB_NMI - bool "Enter KGDB on NMI" - default n - -config KGDB_THREAD - bool "Include KGDB thread support" - default y - -config SH_KGDB_CONSOLE - bool "Console messages through GDB" - default n - -config KGDB_SYSRQ - bool "Allow SysRq 'G' to enter KGDB" - default y - -config KGDB_KERNEL_ASSERTS - bool "Include KGDB kernel assertions" - default n - -comment "Serial port setup" - -config KGDB_DEFPORT - int "Port number (ttySCn)" - default "1" - -config KGDB_DEFBAUD - int "Baud rate" - default "115200" - -choice - prompt "Parity" - depends on KGDB - default KGDB_DEFPARITY_N - -config KGDB_DEFPARITY_N - bool "None" - -config KGDB_DEFPARITY_E - bool "Even" - -config KGDB_DEFPARITY_O - bool "Odd" - -endchoice - -choice - prompt "Data bits" - depends on KGDB - default KGDB_DEFBITS_8 - -config KGDB_DEFBITS_8 - bool "8" - -config KGDB_DEFBITS_7 - bool "7" - -endchoice - -endmenu - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - default y if KGDB - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - -endmenu +source "arch/sh/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug new file mode 100644 index 000000000..3fab181da --- /dev/null +++ b/arch/sh/Kconfig.debug @@ -0,0 +1,124 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config SH_STANDARD_BIOS + bool "Use LinuxSH standard BIOS" + help + Say Y here if your target has the gdb-sh-stub + package from www.m17n.org (or any conforming standard LinuxSH BIOS) + in FLASH or EPROM. The kernel will use standard BIOS calls during + boot for various housekeeping tasks (including calls to read and + write characters to a system console, get a MAC address from an + on-board Ethernet interface, and shut down the hardware). Note this + does not work with machines with an existing operating system in + mask ROM and no flash (WindowsCE machines fall in this category). + If unsure, say N. + +config EARLY_SCIF_CONSOLE + bool "Use early SCIF console" + depends on CPU_SH4 + +config EARLY_PRINTK + bool "Early printk support" + depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE + help + Say Y here to redirect kernel printk messages to the serial port + used by the SH-IPL bootloader, starting very early in the boot + process and ending when the kernel's serial console is initialised. + This option is only useful porting the kernel to a new machine, + when the kernel may crash or hang before the serial console is + initialised. If unsure, say N. + +config KGDB + bool "Include KGDB kernel debugger" + help + Include in-kernel hooks for kgdb, the Linux kernel source level + debugger. See for more information. + Unless you are intending to debug the kernel, say N here. + +menu "KGDB configuration options" + depends on KGDB + +config MORE_COMPILE_OPTIONS + bool "Add any additional compile options" + help + If you want to add additional CFLAGS to the kernel build, enable this + option and then enter what you would like to add in the next question. + Note however that -g is already appended with the selection of KGDB. + +config COMPILE_OPTIONS + string "Additional compile arguments" + depends on MORE_COMPILE_OPTIONS + +config KGDB_NMI + bool "Enter KGDB on NMI" + default n + +config KGDB_THREAD + bool "Include KGDB thread support" + default y + +config SH_KGDB_CONSOLE + bool "Console messages through GDB" + default n + +config KGDB_SYSRQ + bool "Allow SysRq 'G' to enter KGDB" + default y + +config KGDB_KERNEL_ASSERTS + bool "Include KGDB kernel assertions" + default n + +comment "Serial port setup" + +config KGDB_DEFPORT + int "Port number (ttySCn)" + default "1" + +config KGDB_DEFBAUD + int "Baud rate" + default "115200" + +choice + prompt "Parity" + depends on KGDB + default KGDB_DEFPARITY_N + +config KGDB_DEFPARITY_N + bool "None" + +config KGDB_DEFPARITY_E + bool "Even" + +config KGDB_DEFPARITY_O + bool "Odd" + +endchoice + +choice + prompt "Data bits" + depends on KGDB + default KGDB_DEFBITS_8 + +config KGDB_DEFBITS_8 + bool "8" + +config KGDB_DEFBITS_7 + bool "7" + +endchoice + +endmenu + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + default y if KGDB + help + If you say Y here the resulting kernel image will be slightly larger + and slower, but it will give very useful debugging information. + If you don't debug the kernel, you can say N, but we may not be able + to solve problems without frame pointers. + +endmenu diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 7e0087146..5d2c028d9 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -31,7 +31,7 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml cflags-$(CONFIG_CPU_SH2) += -m2 cflags-$(CONFIG_CPU_SH3) += -m3 cflags-$(CONFIG_CPU_SH4) += -m4 \ - $(call check_gcc,-mno-implicit-fp,-m4-nofpu) + $(call cc-option,-mno-implicit-fp,-m4-nofpu) cflags-$(CONFIG_SH_DSP) += -Wa,-dsp cflags-$(CONFIG_SH_KGDB) += -g @@ -122,7 +122,7 @@ drivers-$(CONFIG_OPROFILE) += arch/sh/oprofile/ boot := arch/sh/boot -AFLAGS_vmlinux.lds.o := -traditional +CPPFLAGS_vmlinux.lds := -traditional prepare: target_links diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c index c9bbd72b4..ba3a65439 100644 --- a/arch/sh/boards/mpc1211/pci.c +++ b/arch/sh/boards/mpc1211/pci.c @@ -176,14 +176,7 @@ static void __devinit quirk_ali_ide_ports(struct pci_dev *dev) dev->resource[4].end = 0xf00f; dev->resource[4].flags = IORESOURCE_IO; } - - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, - PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports); char * __devinit pcibios_setup(char *str) { diff --git a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c index 54020ebbb..276fa11ee 100644 --- a/arch/sh/boards/overdrive/galileo.c +++ b/arch/sh/boards/overdrive/galileo.c @@ -455,13 +455,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d) } } } - - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); void __init pcibios_init(void) { diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile index 05ca14dfa..75a6876bf 100644 --- a/arch/sh/boot/compressed/Makefile +++ b/arch/sh/boot/compressed/Makefile @@ -22,7 +22,7 @@ CONFIG_MEMORY_START ?= 0x0c000000 CONFIG_BOOT_LINK_OFFSET ?= 0x00800000 IMAGE_OFFSET := $(shell printf "0x%8x" $$[0x80000000+$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)]) -LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds.s +LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE $(call if_changed,ld) diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c index aa5e24a65..d07572bfc 100644 --- a/arch/sh/drivers/pci/fixups-dreamcast.c +++ b/arch/sh/drivers/pci/fixups-dreamcast.c @@ -47,11 +47,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev) } } -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, - PCI_ANY_ID, gapspci_fixup_resources }, - { 0, } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources); void __init pcibios_fixup_bus(struct pci_bus *bus) { diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index b2bb72972..1a5a883ad 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -177,16 +177,9 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d) } } } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); #endif -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { -#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, -#endif - { 0 } -}; - /* * Called after each bus is probed, but before its children * are examined. diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c index 29e7bf619..4be02f627 100644 --- a/arch/sh/drivers/pci/pci-st40.c +++ b/arch/sh/drivers/pci/pci-st40.c @@ -160,13 +160,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d) } } } - - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); int __init st40pci_init(unsigned memStart, unsigned memSize) { diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index d36bd9410..8b819698d 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the Linux/SuperH kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o setup.o time.o sys_sh.o semaphore.o \ diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index d78503dd2..73ec3365d 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -137,14 +137,16 @@ unlock: int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 8ba6dd300..c9a43c8df 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, ®s, 0, + return do_fork(clone_flags, newsp, ®s, 0, (int __user *)parent_tidptr, (int __user *)child_tidptr); } diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 42868fca4..5e5cdd7f2 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -87,7 +86,7 @@ EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__const_udelay); -#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name) +#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) /* These symbols are generated by the compiler itself */ DECLARE_EXPORT(__udivsi3); diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index ccee2eca5..fc5ef9960 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 adb8eae9f..6ff83edf8 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -98,19 +97,12 @@ void __devinit smp_prepare_boot_cpu(void) int __cpu_up(unsigned int cpu) { struct task_struct *tsk; - struct pt_regs regs; - memset(®s, 0, sizeof(struct pt_regs)); - tsk = copy_process(CLONE_VM | CLONE_IDLETASK, 0, ®s, 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/time.c b/arch/sh/kernel/time.c index 3bcdf4ca4..75ed2b870 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -250,36 +251,6 @@ EXPORT_SYMBOL(do_settimeofday); /* last time the RTC clock got updated */ static long last_rtc_update; -/* Profiling definitions */ -extern unsigned long prof_cpu_mask; -extern unsigned int * prof_buffer; -extern unsigned long prof_len; -extern unsigned long prof_shift; -extern char _stext; - -static inline void sh_do_profile(unsigned long pc) -{ - /* Don't profile cpu_idle.. */ - if (!prof_buffer || !current->pid) - return; - - if (pc >= 0xa0000000UL && pc < 0xc0000000UL) - pc -= 0x20000000; - - pc -= (unsigned long)&_stext; - pc >>= prof_shift; - - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -287,9 +258,7 @@ static inline void sh_do_profile(unsigned long pc) static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_timer(regs); - - if (!user_mode(regs)) - sh_do_profile(regs->pc); + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_HEARTBEAT if (sh_mv.mv_heartbeat != NULL) diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 923980741..51bdc1cf7 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -23,6 +23,7 @@ SECTIONS .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x0009 @@ -75,9 +76,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/fault-nommu.c b/arch/sh/mm/fault-nommu.c index e757b2c18..34d4e0c68 100644 --- a/arch/sh/mm/fault-nommu.c +++ b/arch/sh/mm/fault-nommu.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 43a9e2689..7abba2161 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 7b49b6976..030008e1f 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/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 318d1a529..4bffcf59c 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 4b7a0bcdc..115b1b6be 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig index 0ac5d418e..551ba9a20 100644 --- a/arch/sh64/Kconfig +++ b/arch/sh64/Kconfig @@ -263,58 +263,10 @@ source "fs/Kconfig" source "arch/sh64/oprofile/Kconfig" -menu "Kernel hacking" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in Documentation/sysrq.txt. Don't say Y unless - you really know what this hack does. - -config EARLY_PRINTK - bool "Early SCIF console support" - -config DEBUG_KERNEL_WITH_GDB_STUB - bool "GDB Stub kernel debug" - -config SH64_PROC_TLB - bool "Debug: report TLB fill/purge activity through /proc/tlb" - depends on PROC_FS - -config SH64_PROC_ASIDS - bool "Debug: report ASIDs through /proc/asids" - depends on PROC_FS - -config SH64_SR_WATCH - bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" - -config SH_ALPHANUMERIC - bool "Enable debug outputs to on-board alphanumeric display" - -config SH_NO_BSS_INIT - bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - default y if KGDB - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. - -endmenu +source "arch/sh64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug new file mode 100644 index 000000000..530b3c650 --- /dev/null +++ b/arch/sh64/Kconfig.debug @@ -0,0 +1,37 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config EARLY_PRINTK + bool "Early SCIF console support" + +config DEBUG_KERNEL_WITH_GDB_STUB + bool "GDB Stub kernel debug" + +config SH64_PROC_TLB + bool "Debug: report TLB fill/purge activity through /proc/tlb" + depends on PROC_FS + +config SH64_PROC_ASIDS + bool "Debug: report ASIDs through /proc/asids" + depends on PROC_FS + +config SH64_SR_WATCH + bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" + +config SH_ALPHANUMERIC + bool "Enable debug outputs to on-board alphanumeric display" + +config SH_NO_BSS_INIT + bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + default y if KGDB + help + If you say Y here the resulting kernel image will be slightly larger + and slower, but it will give very useful debugging information. + If you don't debug the kernel, you can say N, but we may not be able + to solve problems without frame pointers. + +endmenu diff --git a/arch/sh64/boot/compressed/Makefile b/arch/sh64/boot/compressed/Makefile index 3f6cbf017..9cd216718 100644 --- a/arch/sh64/boot/compressed/Makefile +++ b/arch/sh64/boot/compressed/Makefile @@ -12,7 +12,7 @@ # targets := vmlinux vmlinux.bin vmlinux.bin.gz \ - head.o misc.o cache.o piggy.o vmlinux.lds.o + head.o misc.o cache.o piggy.o vmlinux.lds EXTRA_AFLAGS := -traditional @@ -25,7 +25,7 @@ OBJECTS := $(obj)/head.o $(obj)/misc.o $(obj)/cache.o ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[$(CONFIG_MEMORY_START)+0x400000+0x10000]) LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \ - -T $(obj)/../../kernel/vmlinux.lds.s \ + -T $(obj)/../../kernel/vmlinux.lds \ --no-warn-mismatch $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE @@ -41,6 +41,6 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh64-linux -T OBJCOPYFLAGS += -R .empty_zero_page -$(obj)/piggy.o: $(obj)/vmlinux.lds.s $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(obj)/vmlinux.lds $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) diff --git a/arch/sh64/kernel/irq.c b/arch/sh64/kernel/irq.c index bcf6385db..7d0f422e1 100644 --- a/arch/sh64/kernel/irq.c +++ b/arch/sh64/kernel/irq.c @@ -148,6 +148,7 @@ asmlinkage void do_NMI(unsigned long vector_num, struct pt_regs * regs) int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status; + int ret; status = 1; /* Force the "do bottom halves" bit */ @@ -155,8 +156,9 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c index c2b4f00e2..842a24373 100644 --- a/arch/sh64/kernel/pci_sh5.c +++ b/arch/sh64/kernel/pci_sh5.c @@ -48,12 +48,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d) } } } - -/* Add future fixups here... */ -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, - { 0 } -}; +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); char * __init pcibios_setup(char *str) { diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c index f9e82274e..13cec3579 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); } /* @@ -901,7 +901,7 @@ unsigned long get_wchan(struct task_struct *p) */ pc = thread_saved_pc(p); -#if CONFIG_FRAME_POINTER +#ifdef CONFIG_FRAME_POINTER if (in_sh64_switch_to(pc)) { sh64_switch_to_fp = (long) p->thread.sp; /* r14 is saved at offset 4 in the sh64_switch_to frame */ diff --git a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c index 887e89a45..c48bc4a27 100644 --- a/arch/sh64/kernel/ptrace.c +++ b/arch/sh64/kernel/ptrace.c @@ -311,11 +311,8 @@ asmlinkage void syscall_trace(void) if (!(tsk->ptrace & PT_PTRACED)) return; - tsk->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - tsk->state = TASK_STOPPED; - notify_parent(tsk, 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 * for normal use. strace only continues with a signal if the diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c index 80712f1ef..36cd5de95 100644 --- a/arch/sh64/kernel/sh_ksyms.c +++ b/arch/sh64/kernel/sh_ksyms.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -59,17 +58,17 @@ EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL_NOVERS(__down); -EXPORT_SYMBOL_NOVERS(__down_trylock); -EXPORT_SYMBOL_NOVERS(__up); -EXPORT_SYMBOL_NOVERS(__put_user_asm_l); -EXPORT_SYMBOL_NOVERS(__get_user_asm_l); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__put_user_asm_l); +EXPORT_SYMBOL(__get_user_asm_l); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(flush_dcache_page); @@ -78,7 +77,7 @@ EXPORT_SYMBOL(flush_dcache_page); extern void __sdivsi3(void); extern void __muldi3(void); extern void __udivsi3(void); -EXPORT_SYMBOL_NOVERS(__sdivsi3); -EXPORT_SYMBOL_NOVERS(__muldi3); -EXPORT_SYMBOL_NOVERS(__udivsi3); +EXPORT_SYMBOL(__sdivsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__udivsi3); diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c index 376b8998b..a848fbdb1 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/time.c b/arch/sh64/kernel/time.c index 128bd22af..b3738ed37 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -298,37 +298,6 @@ static int set_rtc_time(unsigned long nowtime) /* last time the RTC clock got updated */ static long last_rtc_update = 0; -static inline void sh64_do_profile(struct pt_regs *regs) -{ - extern int _stext; - unsigned long pc; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - /* Don't profile cpu_idle.. */ - if (!prof_buffer || !current->pid) - return; - - pc = instruction_pointer(regs); - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - /* - * Don't ignore out-of-bounds PC values silently, put them into the - * last histogram slot, so if present, they will show up as a sharp - * peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - - /* We could just be sloppy and not lock against a re-entry on this - increment, but the profiling code won't always be linked in anyway. */ - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -340,8 +309,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg ctc_last_interrupt = (unsigned long) current_ctc; do_timer(regs); - - sh64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_HEARTBEAT { diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S index a3fba816b..7d9f7a633 100644 --- a/arch/sh64/kernel/vmlinux.lds.S +++ b/arch/sh64/kernel/vmlinux.lds.S @@ -59,6 +59,7 @@ SECTIONS *(.text64) *(.text..SHmedia32) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) #ifdef CONFIG_LITTLE_ENDIAN @@ -106,9 +107,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/fault.c b/arch/sh64/mm/fault.c index b5ab4a88c..d1190b415 100644 --- a/arch/sh64/mm/fault.c +++ b/arch/sh64/mm/fault.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include /* required by inline asm statements */ diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c index 17cdeb425..09cd9c879 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/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c index a69f7751c..69f686c88 100644 --- a/arch/sh64/mm/tlbmiss.c +++ b/arch/sh64/mm/tlbmiss.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include /* required by inline asm statements */ diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 7d0688aa6..3d978f461 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -23,8 +23,7 @@ config GENERIC_ISA_DMA source "init/Kconfig" - -menu "General setup" +menu "General machine setup" config VT bool @@ -217,8 +216,8 @@ config SUN_PM bool default y help - Enable power management and CPU standby features on supported - SPARC platforms. + Enable power management and CPU standby features on supported + SPARC platforms. config SUN4 bool "Support for SUN4 machines (disables SUN4[CDM] support)" @@ -380,81 +379,10 @@ source "drivers/usb/Kconfig" source "drivers/char/watchdog/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_STACK_USAGE - bool "Enable stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This options enables additional error checking for high memory - systems. Disable for production systems. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - depends on DEBUG_KERNEL - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" - depends on DEBUG_KERNEL - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -endmenu +source "arch/sparc/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug new file mode 100644 index 000000000..120f6b529 --- /dev/null +++ b/arch/sparc/Kconfig.debug @@ -0,0 +1,14 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +endmenu diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 15fcf89e1..7b3bbaf08 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -13,7 +13,7 @@ AS := $(AS) -32 LDFLAGS := -m elf32_sparc -CHECK := $(CHECK) -D__sparc__=1 +CHECKFLAGS += -D__sparc__ #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index b19cc8689..b36508431 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -7,28 +7,52 @@ ROOT_IMG := /usr/src/root.img ELFTOAOUT := elftoaout -host-progs := piggyback btfixupprep -targets := tftpboot.img btfix.o btfix.s image +hostprogs-y := piggyback btfixupprep +targets := tftpboot.img btfix.o btfix.S image quiet_cmd_elftoaout = ELFTOAOUT $@ cmd_elftoaout = $(ELFTOAOUT) $(obj)/image -o $@ -quiet_cmd_piggy = PIGGY $@ +quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $@ $(obj)/System.map $(ROOT_IMG) -quiet_cmd_btfix = BTFIX $@ +quiet_cmd_btfix = BTFIX $@ cmd_btfix = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@ +quiet_cmd_sysmap = SYSMAP $(obj)/System.map + cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap +quiet_cmd_image = LD $@ + cmd_image = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) -o $@ + +define rule_image + $(if $($(quiet)cmd_image), \ + echo ' $($(quiet)cmd_image)' &&) \ + $(cmd_image); \ + $(if $($(quiet)cmd_sysmap), \ + echo ' $($(quiet)cmd_sysmap)' &&) \ + $(cmd_sysmap) $@ $(obj)/System.map; \ + if [ $$? -ne 0 ]; then \ + rm -f $@; \ + /bin/false; \ + fi; \ + echo 'cmd_$@ := $(cmd_image)' > $(@D)/.$(@F).cmd +endef BTOBJS := $(HEAD_Y) $(INIT_Y) BTLIBS := $(CORE_Y) $(LIBS_Y) $(DRIVERS_Y) $(NET_Y) -LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds.s $(BTOBJS) --start-group $(BTLIBS) --end-group $(kallsyms.o) +LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds $(BTOBJS) \ + --start-group $(BTLIBS) --end-group \ + $(kallsyms.o) $(obj)/btfix.o -# Actual linking +# Link the final image including btfixup'ed symbols. +# This is a replacement for the link done in the top-level Makefile. +# Note: No dependency on the prerequisite files since that would require +# make to try check if they are updated - and due to changes +# in gcc options (path for example) this would result in +# these files being recompiled for each build. $(obj)/image: $(obj)/btfix.o FORCE - $(call if_changed,ld) - $(NM) $@ | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > $(obj)/System.map + $(call if_changed_rule,image) $(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE $(call if_changed,elftoaout) $(call if_changed,piggy) -$(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE +$(obj)/btfix.S: $(obj)/btfixupprep vmlinux FORCE $(call if_changed,btfix) diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index fcf149e00..3d22ba2af 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds EXTRA_AFLAGS := -ansi diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 14a4b9593..624e2a6ed 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -858,7 +858,7 @@ vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7 vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG .globl invalid_segment_patch1, invalid_segment_patch2 - .globl num_context_patch1, num_context_patch2 + .globl num_context_patch1 .globl vac_linesize_patch, vac_hwflush_patch1 .globl vac_hwflush_patch2 diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index af81a999f..fc31de66b 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -23,6 +23,6 @@ EXPORT_SYMBOL(init_task); * in etrap.S which assumes it. */ union thread_union init_thread_union - __attribute__((section (".text,#alloc"))) + __attribute__((section (".text\"\n\t#"))) __attribute__((aligned (THREAD_SIZE))) = { INIT_THREAD_INFO(init_task) }; diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index cfabf35ee..4e0ed320d 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index bc52cd482..c982473d1 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -36,10 +36,6 @@ #include -struct pci_fixup pcibios_fixups[] = { - { 0 } -}; - unsigned int pcic_pin_to_irq(unsigned int pin, char *name); /* diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 4ff019336..1dc918135 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/ptrace.c b/arch/sparc/kernel/ptrace.c index d838bd8f6..589652ea0 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -614,12 +614,9 @@ asmlinkage void syscall_trace(void) return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - current->state = TASK_STOPPED; current->thread.flags ^= MAGIC_CONSTANT; - 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 * for normal use. strace only continues with a signal if the diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 7bc43b4c0..55352ed85 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 28edf9319..276860da5 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(¤t->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); } @@ -635,6 +635,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 4. signal handler */ regs->pc = (unsigned long) ka->sa.sa_handler; @@ -662,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 @@ -719,6 +720,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); @@ -744,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 */ @@ -874,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) @@ -887,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) @@ -928,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 */ @@ -1016,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 @@ -1034,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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -1075,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; /* @@ -1094,15 +1092,12 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, if (!oldset) oldset = ¤t->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 = ¤t->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/smp.c b/arch/sparc/kernel/smp.c index 46591a15e..f11dd14db 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index fdaacfa47..7282bc3ee 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -214,6 +213,10 @@ EXPORT_SYMBOL(pci_dma_sync_single_for_cpu); EXPORT_SYMBOL(pci_dma_sync_single_for_device); EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu); EXPORT_SYMBOL(pci_dma_sync_sg_for_device); +EXPORT_SYMBOL(pci_map_sg); +EXPORT_SYMBOL(pci_unmap_sg); +EXPORT_SYMBOL(pci_map_page); +EXPORT_SYMBOL(pci_unmap_page); /* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */ EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(iounmap); @@ -298,6 +301,9 @@ EXPORT_SYMBOL(csum_partial); /* Cache flushing. */ EXPORT_SYMBOL(sparc_flush_page_to_ram); +/* For when serial stuff is built as modules. */ +EXPORT_SYMBOL(sun_do_break); + EXPORT_SYMBOL(__ret_efault); EXPORT_SYMBOL(memcmp); diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 9f659c2f4..1de4c8a39 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -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++) ; @@ -418,8 +409,6 @@ void smp4d_message_pass(int target, int msg, unsigned long data, int wait) panic("Bogon SMP message pass."); } -extern void sparc_do_profile(unsigned long pc, unsigned long o7); - void smp4d_percpu_timer_interrupt(struct pt_regs *regs) { int cpu = hard_smp4d_processor_id(); @@ -437,8 +426,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) show_leds(cpu); } - if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + profile_tick(CPU_PROFILING, regs); if(!--prof_counter(cpu)) { int user = user_mode(regs); diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index f2fc64edc..100433e05 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #define IRQ_RESCHEDULE 13 @@ -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); @@ -400,16 +391,13 @@ void smp4m_cross_call_irq(void) ccall_info.processors_out[i] = 1; } -extern void sparc_do_profile(unsigned long pc, unsigned long o7); - void smp4m_percpu_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); clear_profile_irq(cpu); - if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + profile_tick(CPU_PROFILING, regs); if(!--prof_counter(cpu)) { int user = user_mode(regs); diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index fd452a6d3..288a0b44b 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -74,7 +74,7 @@ sys_call_table: /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink -/*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall +/*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .long sys_ni_syscall, sys_ni_syscall, sys_ni_syscall #ifdef CONFIG_SUNOS_EMUL diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index bdec61be6..60507d394 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -79,38 +79,26 @@ struct intersil *intersil_clock; #endif -static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; - -/* 32-bit Sparc specific profiling function. */ -void sparc_do_profile(unsigned long pc, unsigned long o7) +unsigned long profile_pc(struct pt_regs *regs) { - if(prof_buffer && current->pid) { - extern int _stext; - extern int __copy_user_begin, __copy_user_end; - extern int __atomic_begin, __atomic_end; - extern int __bzero_begin, __bzero_end; - extern int __bitops_begin, __bitops_end; - - if ((pc >= (unsigned long) &__copy_user_begin && - pc < (unsigned long) &__copy_user_end) || - (pc >= (unsigned long) &__atomic_begin && - pc < (unsigned long) &__atomic_end) || - (pc >= (unsigned long) &__bzero_begin && - pc < (unsigned long) &__bzero_end) || - (pc >= (unsigned long) &__bitops_begin && - pc < (unsigned long) &__bitops_end)) - pc = o7; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - spin_lock(&ticker_lock); - if(pc < prof_len) - prof_buffer[pc]++; - else - prof_buffer[prof_len - 1]++; - spin_unlock(&ticker_lock); - } + extern char __copy_user_begin[], __copy_user_end[]; + extern char __atomic_begin[], __atomic_end[]; + extern char __bzero_begin[], __bzero_end[]; + extern char __bitops_begin[], __bitops_end[]; + + unsigned long pc = regs->pc; + + if (in_lock_functions(pc) || + (pc >= (unsigned long) __copy_user_begin && + pc < (unsigned long) __copy_user_end) || + (pc >= (unsigned long) __atomic_begin && + pc < (unsigned long) __atomic_end) || + (pc >= (unsigned long) __bzero_begin && + pc < (unsigned long) __bzero_end) || + (pc >= (unsigned long) __bitops_begin && + pc < (unsigned long) __bitops_end)) + pc = regs->u_regs[UREG_RETPC]; + return pc; } __volatile__ unsigned int *master_l10_counter; @@ -129,8 +117,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) static long last_rtc_update; #ifndef CONFIG_SMP - if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + profile_tick(CPU_PROFILING, regs); #endif /* Protect counter clear so that do_gettimeoffset works */ diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 8d4bbfaf3..38938d2e6 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -13,6 +13,7 @@ SECTIONS { *(.text) SCHED_TEXT + LOCK_TEXT *(.gnu.warning) } =0 _etext = .; @@ -46,9 +47,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 c18475eaa..d5593b5d2 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 b56b67b45..fd85c7b01 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -379,7 +379,7 @@ extern unsigned long invalid_segment_patch1, invalid_segment_patch1_ff; extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff; extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff; extern unsigned long num_context_patch1, num_context_patch1_16; -extern unsigned long num_context_patch2, num_context_patch2_16; +extern unsigned long num_context_patch2_16; extern unsigned long vac_linesize_patch, vac_linesize_patch_32; extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on; extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on; @@ -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/Kconfig b/arch/sparc64/Kconfig index 604428879..0bad2767c 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -12,10 +12,13 @@ config MMU bool default y -source "init/Kconfig" +config TIME_INTERPOLATION + bool + default y +source "init/Kconfig" -menu "General setup" +menu "General machine setup" config BBC_I2C tristate "UltraSPARC-III bootbus i2c controller driver" @@ -549,7 +552,6 @@ config UNIX98_PTY_COUNT endmenu - menu "XFree86 DRI support" config DRM @@ -604,113 +606,10 @@ source "drivers/char/watchdog/Kconfig" source "arch/sparc64/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_STACK_USAGE - bool "Enable stack utilization instrumentation" - depends on DEBUG_KERNEL - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_SPINLOCK_SLEEP - bool "Sleep-inside-spinlock checking" - depends DEBUG_KERNEL - help - If you say Y here, various routines which may sleep will become very - noisy if they are called with a spinlock held. - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" - depends on DEBUG_KERNEL - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -config DEBUG_DCFLUSH - bool "D-cache flush debugging" - depends on DEBUG_KERNEL - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config STACK_DEBUG - depends on DEBUG_KERNEL - bool "Stack Overflow Detection Support" - -config DEBUG_BOOTMEM - depends on DEBUG_KERNEL - bool "Debug BOOTMEM initialization" - -# We have a custom atomic_dec_and_lock() implementation but it's not -# compatible with spinlock debugging so we need to fall back on -# the generic version in that case. -config HAVE_DEC_LOCK - bool - depends on SMP && !DEBUG_SPINLOCK - default y - -config MCOUNT - bool - depends on STACK_DEBUG - default y - -config FRAME_POINTER - bool - depends on MCOUNT - default y - -endmenu +source "arch/sparc64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug new file mode 100644 index 000000000..cd8d39fb9 --- /dev/null +++ b/arch/sparc64/Kconfig.debug @@ -0,0 +1,54 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +config DEBUG_DCFLUSH + bool "D-cache flush debugging" + depends on DEBUG_KERNEL + +config STACK_DEBUG + depends on DEBUG_KERNEL + bool "Stack Overflow Detection Support" + +config DEBUG_BOOTMEM + depends on DEBUG_KERNEL + bool "Debug BOOTMEM initialization" + +# We have a custom atomic_dec_and_lock() implementation but it's not +# compatible with spinlock debugging so we need to fall back on +# the generic version in that case. +config HAVE_DEC_LOCK + bool + depends on SMP && !DEBUG_SPINLOCK + default y + +config MCOUNT + bool + depends on STACK_DEBUG + default y + +config FRAME_POINTER + bool + depends on MCOUNT + default y + +endmenu diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index fc57c40c2..58d4c91ca 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -8,16 +8,16 @@ # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) # -CHECK := $(CHECK) -D__sparc__=1 -D__sparc_v9__=1 +CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -AFLAGS_vmlinux.lds.o += -Usparc +CPPFLAGS_vmlinux.lds += -Usparc CC := $(shell if $(CC) -m64 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo $(CC); else echo sparc64-linux-gcc; fi ) -NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) +NEW_GCC := $(call cc-option-yn, -m64 -mcmodel=medlow) NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; ) -INLINE_LIMIT := $(shell if $(CC) -m64 -finline-limit=100000 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) +INLINE_LIMIT := $(call cc-option-yn, -m64 -finline-limit=100000) export NEW_GCC diff --git a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile index 5eb14ff1c..6968a6da5 100644 --- a/arch/sparc64/boot/Makefile +++ b/arch/sparc64/boot/Makefile @@ -7,7 +7,7 @@ ROOT_IMG := /usr/src/root.img ELFTOAOUT := elftoaout -host-progs := piggyback +hostprogs-y := piggyback targets := image tftpboot.img vmlinux.aout quiet_cmd_elftoaout = ELF2AOUT $@ diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 7fa2d47a6..1b2f3c2cb 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,8 +1,11 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3 +# Sun Oct 3 14:28:53 2004 # CONFIG_64BIT=y CONFIG_MMU=y +CONFIG_TIME_INTERPOLATION=y # # Code maturity level options @@ -13,6 +16,7 @@ CONFIG_CLEAN_COMPILE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -33,6 +37,8 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -46,7 +52,7 @@ CONFIG_KMOD=y CONFIG_STOP_MACHINE=y # -# General setup +# General machine setup # CONFIG_BBC_I2C=m CONFIG_VT=y @@ -65,6 +71,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 +125,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 +161,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 +224,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 # @@ -251,7 +259,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_IDEDMA_ONLYDISK=y -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set CONFIG_BLK_DEV_ALI15X3=y # CONFIG_WDC_ALI15X3 is not set @@ -328,7 +335,8 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000 # CONFIG_AIC79XX_DEBUG_ENABLE is not set CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA_SVW=m CONFIG_SCSI_ATA_PIIX=m @@ -353,9 +361,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set -CONFIG_SCSI_IPR=m -# CONFIG_SCSI_IPR_TRACE is not set -# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR is not set CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y @@ -398,6 +404,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 @@ -412,7 +419,6 @@ CONFIG_DM_ZERO=m # CONFIG_FUSION=m CONFIG_FUSION_MAX_SGE=40 -CONFIG_FUSION_ISENSE=m CONFIG_FUSION_CTL=m CONFIG_FUSION_LAN=m @@ -475,6 +481,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 +521,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 @@ -523,6 +531,8 @@ CONFIG_BRIDGE_NETFILTER=y # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_CT_ACCT=y +CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m CONFIG_IP_NF_TFTP=m @@ -548,8 +558,15 @@ CONFIG_IP_NF_MATCH_STATE=m CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_OWNER=m CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_REALM=m +CONFIG_IP_NF_MATCH_SCTP=m +CONFIG_IP_NF_MATCH_COMMENT=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m @@ -568,18 +585,13 @@ CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_CLASSIFY=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_COMPAT_IPFWADM=m -CONFIG_IP_NF_TARGET_NOTRACK=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_MATCH_REALM=m # # IPv6: Netfilter Configuration @@ -599,6 +611,7 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_AHESP=m CONFIG_IP6_NF_MATCH_LENGTH=m CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_PHYSDEV=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_MANGLE=m @@ -704,6 +717,8 @@ CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y # # Network testing @@ -880,6 +895,7 @@ CONFIG_NS83820=m CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m CONFIG_R8169=m +CONFIG_R8169_NAPI=y CONFIG_SK98LIN=m CONFIG_TIGON3=m @@ -1064,6 +1080,7 @@ CONFIG_SERIO_I8042=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PARKBD is not set CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m # # Input Device Drivers @@ -1095,6 +1112,7 @@ CONFIG_I2C_CHARDEV=m # CONFIG_I2C_ALGOBIT=y CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m # # I2C Hardware Bus support @@ -1119,6 +1137,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 @@ -1140,6 +1159,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 @@ -1262,6 +1282,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 @@ -1473,6 +1494,7 @@ CONFIG_SND_VIRMIDI=m CONFIG_SND_AC97_CODEC=m CONFIG_SND_ALI5451=m CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m CONFIG_SND_AU8810=m CONFIG_SND_AU8820=m CONFIG_SND_AU8830=m @@ -1512,6 +1534,7 @@ CONFIG_SND_VX222=m # ALSA USB devices # # CONFIG_SND_USB_AUDIO is not set +CONFIG_SND_USB_USX2Y=m # # ALSA Sparc devices @@ -1531,6 +1554,7 @@ CONFIG_USB=y CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -1596,7 +1620,6 @@ CONFIG_USB_HPUSBSCSI=m # CONFIG_USB_IBMCAM is not set # CONFIG_USB_KONICAWC is not set # CONFIG_USB_OV511 is not set -CONFIG_USB_PWC=m # CONFIG_USB_SE401 is not set CONFIG_USB_SN9C102=m # CONFIG_USB_STV680 is not set @@ -1733,14 +1756,15 @@ 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_KPROBES=y +# CONFIG_DEBUG_DCFLUSH is not set # CONFIG_STACK_DEBUG is not set # CONFIG_DEBUG_BOOTMEM is not set CONFIG_HAVE_DEC_LOCK=y @@ -1761,6 +1785,7 @@ CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 2caca47d8..093281bdf 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -5,7 +5,7 @@ EXTRA_AFLAGS := -ansi EXTRA_CFLAGS := -Werror -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ traps.o devices.o auxio.o \ @@ -22,6 +22,7 @@ obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o +obj-$(CONFIG_KPROBES) += kprobes.o ifdef CONFIG_SUNOS_EMUL obj-y += sys_sunos32.o sunos_ioctl32.o diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index 24ecb1075..11672d2d3 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -17,7 +17,7 @@ #include /* This cannot be static, as it is referenced in entry.S */ -unsigned long auxio_register = 0UL; +void __iomem *auxio_register = 0UL; enum auxio_type { AUXIO_TYPE_NODEV, @@ -30,7 +30,7 @@ static spinlock_t auxio_lock = SPIN_LOCK_UNLOCKED; static void __auxio_sbus_set(u8 bits_on, u8 bits_off) { - if(auxio_register) { + if (auxio_register) { unsigned char regval; unsigned long flags; unsigned char newval; @@ -49,7 +49,7 @@ static void __auxio_sbus_set(u8 bits_on, u8 bits_off) static void __auxio_ebus_set(u8 bits_on, u8 bits_off) { - if(auxio_register) { + if (auxio_register) { unsigned char regval; unsigned long flags; unsigned char newval; @@ -126,7 +126,8 @@ found_sdev: if (sdev) { auxio_devtype = AUXIO_TYPE_SBUS; auxio_register = sbus_ioremap(&sdev->resource[0], 0, - sdev->reg_addrs[0].reg_size, "auxiliaryIO"); + sdev->reg_addrs[0].reg_size, + "auxiliaryIO"); } #ifdef CONFIG_PCI else { @@ -142,7 +143,7 @@ found_sdev: ebus_done: if (edev) { auxio_devtype = AUXIO_TYPE_EBUS; - auxio_register = (unsigned long) + auxio_register = ioremap(edev->resource[0].start, sizeof(u32)); } } diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index a28046203..fb3e3b780 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -27,12 +27,12 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; #define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ do { unsigned int *dest = &(__elf_regs[0]); \ struct pt_regs *src = (__pt_regs); \ - unsigned int *sp; \ + unsigned int __user *sp; \ int i; \ for(i = 0; i < 16; i++) \ dest[i] = (unsigned int) src->u_regs[i];\ /* Don't try this at home kids... */ \ - sp = (unsigned int *) (src->u_regs[14] & \ + sp = (unsigned int __user *) (src->u_regs[14] & \ 0x00000000fffffffc); \ for(i = 0; i < 16; i++) \ __get_user(dest[i+16], &sp[i]); \ diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 2296525af..97cf912f0 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c @@ -72,7 +72,7 @@ struct mctrl_info { struct obp_mem_layout layout_prop; int layout_size; - void *regs; + void __iomem *regs; u64 timing_control1; u64 timing_control2; diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 9468eacdc..d50b755c7 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -17,7 +17,8 @@ #define TASK_REGOFF (THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ) #define ETRAP_PSTATE1 (PSTATE_RMO | PSTATE_PRIV) -#define ETRAP_PSTATE2 (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE) +#define ETRAP_PSTATE2 \ + (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE) /* * On entry, %g7 is return address - 0x4. @@ -27,91 +28,91 @@ .text .align 64 .globl etrap, etrap_irq, etraptl1 -etrap: rdpr %pil, %g2 ! Single Group +etrap: rdpr %pil, %g2 etrap_irq: - rdpr %tstate, %g1 ! Single Group - sllx %g2, 20, %g3 ! IEU0 Group - andcc %g1, TSTATE_PRIV, %g0 ! IEU1 - or %g1, %g3, %g1 ! IEU0 Group - bne,pn %xcc, 1f ! CTI - sub %sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2 ! IEU1 - wrpr %g0, 7, %cleanwin ! Single Group+4bubbles - - sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group - sethi %hi(TSTATE_PEF), %g3 ! IEU1 - or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group - and %g1, %g3, %g3 ! IEU1 - brnz,pn %g3, 1f ! CTI+IEU1 Group - add %g6, %g2, %g2 ! IEU0 - wr %g0, 0, %fprs ! Single Group+4bubbles -1: rdpr %tpc, %g3 ! Single Group - - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] ! Store Group - rdpr %tnpc, %g1 ! Single Group - stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] ! Store Group - rd %y, %g3 ! Single Group+4bubbles - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] ! Store Group - st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] ! Store Group - save %g2, -STACK_BIAS, %sp ! Ordering here is critical ! Single Group - mov %g6, %l6 ! IEU0 Group - - bne,pn %xcc, 3f ! CTI - mov PRIMARY_CONTEXT, %l4 ! IEU1 - rdpr %canrestore, %g3 ! Single Group+4bubbles - rdpr %wstate, %g2 ! Single Group+4bubbles - wrpr %g0, 0, %canrestore ! Single Group+4bubbles - sll %g2, 3, %g2 ! IEU0 Group - mov 1, %l5 ! IEU1 - stb %l5, [%l6 + TI_FPDEPTH] ! Store - - wrpr %g3, 0, %otherwin ! Single Group+4bubbles - wrpr %g2, 0, %wstate ! Single Group+4bubbles - stxa %g0, [%l4] ASI_DMMU ! Store Group - flush %l6 ! Single Group+9bubbles - wr %g0, ASI_AIUS, %asi ! Single Group+4bubbles -2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles - mov %g4, %l4 ! IEU1 - mov %g5, %l5 ! IEU0 Group - - mov %g7, %l2 ! IEU1 - wrpr %g0, ETRAP_PSTATE1, %pstate ! Single Group+4bubbles - stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] ! Store Group - stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] ! Store Group - stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] ! Store Group - stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] ! Store Group - stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] ! Store Group - stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] ! Store Group - - stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] ! Store Group - stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] ! Store Group - stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] ! Store Group - stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] ! Store Group - stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] ! Store Group - stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] ! Store Group - stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] ! Store Group - - stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] ! Store Group - stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] ! Store Group - wrpr %g0, ETRAP_PSTATE2, %pstate ! Single Group+4bubbles - mov %l6, %g6 ! IEU0 - jmpl %l2 + 0x4, %g0 ! CTI Group - ldx [%g6 + TI_TASK], %g4 ! Load + rdpr %tstate, %g1 + sllx %g2, 20, %g3 + andcc %g1, TSTATE_PRIV, %g0 + or %g1, %g3, %g1 + bne,pn %xcc, 1f + sub %sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2 + wrpr %g0, 7, %cleanwin + + sethi %hi(TASK_REGOFF), %g2 + sethi %hi(TSTATE_PEF), %g3 + or %g2, %lo(TASK_REGOFF), %g2 + and %g1, %g3, %g3 + brnz,pn %g3, 1f + add %g6, %g2, %g2 + wr %g0, 0, %fprs +1: rdpr %tpc, %g3 + + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] + rdpr %tnpc, %g1 + stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] + rd %y, %g3 + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] + st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] + save %g2, -STACK_BIAS, %sp ! Ordering here is critical + mov %g6, %l6 + + bne,pn %xcc, 3f + mov PRIMARY_CONTEXT, %l4 + rdpr %canrestore, %g3 + rdpr %wstate, %g2 + wrpr %g0, 0, %canrestore + sll %g2, 3, %g2 + mov 1, %l5 + stb %l5, [%l6 + TI_FPDEPTH] + + wrpr %g3, 0, %otherwin + wrpr %g2, 0, %wstate + stxa %g0, [%l4] ASI_DMMU + flush %l6 + wr %g0, ASI_AIUS, %asi +2: wrpr %g0, 0x0, %tl + mov %g4, %l4 + mov %g5, %l5 + + mov %g7, %l2 + wrpr %g0, ETRAP_PSTATE1, %pstate + stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] + stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] + stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] + stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] + stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] + stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] + + stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] + stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] + stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] + stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] + stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] + stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] + stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] + + stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] + stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] + wrpr %g0, ETRAP_PSTATE2, %pstate + mov %l6, %g6 + jmpl %l2 + 0x4, %g0 + ldx [%g6 + TI_TASK], %g4 nop nop nop -3: ldub [%l6 + TI_FPDEPTH], %l5 ! Load Group - add %l6, TI_FPSAVED + 1, %l4 ! IEU0 - srl %l5, 1, %l3 ! IEU0 Group - add %l5, 2, %l5 ! IEU1 - stb %l5, [%l6 + TI_FPDEPTH] ! Store - ba,pt %xcc, 2b ! CTI - stb %g0, [%l4 + %l3] ! Store Group +3: ldub [%l6 + TI_FPDEPTH], %l5 + add %l6, TI_FPSAVED + 1, %l4 + srl %l5, 1, %l3 + add %l5, 2, %l5 + stb %l5, [%l6 + TI_FPDEPTH] + ba,pt %xcc, 2b + stb %g0, [%l4 + %l3] nop etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. - * We place this right after pt_regs on the trap stack. The layout - * is: + * We place this right after pt_regs on the trap stack. + * The layout is: * 0x00 TL1's TSTATE * 0x08 TL1's TPC * 0x10 TL1's TNPC @@ -166,81 +167,81 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. wrpr %g1, %tl stx %g1, [%g2 + STACK_BIAS + 0x80] - rdpr %tstate, %g1 ! Single Group+4bubbles - sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 - ba,pt %xcc, 1b ! CTI Group - andcc %g1, TSTATE_PRIV, %g0 ! IEU0 + rdpr %tstate, %g1 + sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 + ba,pt %xcc, 1b + andcc %g1, TSTATE_PRIV, %g0 .align 64 .globl scetrap -scetrap: rdpr %pil, %g2 ! Single Group - rdpr %tstate, %g1 ! Single Group - sllx %g2, 20, %g3 ! IEU0 Group - andcc %g1, TSTATE_PRIV, %g0 ! IEU1 - or %g1, %g3, %g1 ! IEU0 Group - bne,pn %xcc, 1f ! CTI - sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2 ! IEU1 - wrpr %g0, 7, %cleanwin ! Single Group+4bubbles - - sllx %g1, 51, %g3 ! IEU0 Group - sethi %hi(TASK_REGOFF), %g2 ! IEU1 - or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group - brlz,pn %g3, 1f ! CTI+IEU1 - add %g6, %g2, %g2 ! IEU0 Group - wr %g0, 0, %fprs ! Single Group+4bubbles -1: rdpr %tpc, %g3 ! Single Group - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] ! Store Group - - rdpr %tnpc, %g1 ! Single Group - stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] ! Store Group - stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] ! Store Group - save %g2, -STACK_BIAS, %sp ! Ordering here is critical ! Single Group - mov %g6, %l6 ! IEU0 Group - bne,pn %xcc, 2f ! CTI - mov ASI_P, %l7 ! IEU1 - rdpr %canrestore, %g3 ! Single Group+4bubbles - - rdpr %wstate, %g2 ! Single Group+4bubbles - wrpr %g0, 0, %canrestore ! Single Group+4bubbles - sll %g2, 3, %g2 ! IEU0 Group - mov PRIMARY_CONTEXT, %l4 ! IEU1 - wrpr %g3, 0, %otherwin ! Single Group+4bubbles - wrpr %g2, 0, %wstate ! Single Group+4bubbles - stxa %g0, [%l4] ASI_DMMU ! Store - flush %l6 ! Single Group+9bubbles - - mov ASI_AIUS, %l7 ! IEU0 Group -2: mov %g4, %l4 ! IEU1 - mov %g5, %l5 ! IEU0 Group - add %g7, 0x4, %l2 ! IEU1 - wrpr %g0, ETRAP_PSTATE1, %pstate ! Single Group+4bubbles - stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] ! Store Group - stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] ! Store Group - sllx %l7, 24, %l7 ! IEU0 - - stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] ! Store Group - rdpr %cwp, %l0 ! Single Group - stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] ! Store Group - stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] ! Store Group - stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] ! Store Group - stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] ! Store Group - or %l7, %l0, %l7 ! IEU0 - sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 ! IEU1 - - or %l7, %l0, %l7 ! IEU0 Group - wrpr %l2, %tnpc ! Single Group+4bubbles - wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate ! Single Group+4bubbles - stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] ! Store Group - stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] ! Store Group - stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] ! Store Group - stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] ! Store Group - stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] ! Store Group - - stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] ! Store Group - stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] ! Store Group - mov %l6, %g6 ! IEU1 - stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] ! Store Group - ldx [%g6 + TI_TASK], %g4 ! Load Group +scetrap: rdpr %pil, %g2 + rdpr %tstate, %g1 + sllx %g2, 20, %g3 + andcc %g1, TSTATE_PRIV, %g0 + or %g1, %g3, %g1 + bne,pn %xcc, 1f + sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2 + wrpr %g0, 7, %cleanwin + + sllx %g1, 51, %g3 + sethi %hi(TASK_REGOFF), %g2 + or %g2, %lo(TASK_REGOFF), %g2 + brlz,pn %g3, 1f + add %g6, %g2, %g2 + wr %g0, 0, %fprs +1: rdpr %tpc, %g3 + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] + + rdpr %tnpc, %g1 + stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] + stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] + save %g2, -STACK_BIAS, %sp ! Ordering here is critical + mov %g6, %l6 + bne,pn %xcc, 2f + mov ASI_P, %l7 + rdpr %canrestore, %g3 + + rdpr %wstate, %g2 + wrpr %g0, 0, %canrestore + sll %g2, 3, %g2 + mov PRIMARY_CONTEXT, %l4 + wrpr %g3, 0, %otherwin + wrpr %g2, 0, %wstate + stxa %g0, [%l4] ASI_DMMU + flush %l6 + + mov ASI_AIUS, %l7 +2: mov %g4, %l4 + mov %g5, %l5 + add %g7, 0x4, %l2 + wrpr %g0, ETRAP_PSTATE1, %pstate + stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] + stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] + sllx %l7, 24, %l7 + + stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] + rdpr %cwp, %l0 + stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] + stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] + stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] + stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] + or %l7, %l0, %l7 + sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 + + or %l7, %l0, %l7 + wrpr %l2, %tnpc + wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate + stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] + stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] + stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] + stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] + stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] + + stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] + stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] + mov %l6, %g6 + stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] + ldx [%g6 + TI_TASK], %g4 done nop nop diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 01c8869a7..4a286a800 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -50,6 +50,7 @@ bootup_user_stack: */ .global root_flags, ram_flags, root_dev .global sparc_ramdisk_image, sparc_ramdisk_size + .global sparc_ramdisk_image64 .ascii "HdrS" .word LINUX_VERSION_CODE @@ -60,7 +61,7 @@ bootup_user_stack: * 0x0202 : Supports kernel params string * 0x0201 : Supports reboot_command */ - .half 0x0300 /* HdrS version */ + .half 0x0301 /* HdrS version */ root_flags: .half 1 @@ -74,6 +75,8 @@ sparc_ramdisk_size: .word 0 .xword reboot_command .xword bootstr_info +sparc_ramdisk_image64: + .xword 0 .word _end /* We must be careful, 32-bit OpenBOOT will get confused if it diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index d52b84291..3162b2ed1 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -791,16 +790,24 @@ void handler_irq(int irq, struct pt_regs *regs) #endif if ((flags & IBF_MULTI) == 0) { struct irqaction *ap = bp->irq_info; - ap->handler(__irq(bp), ap->dev_id, regs); - random |= ap->flags & SA_SAMPLE_RANDOM; + int ret; + + ret = ap->handler(__irq(bp), ap->dev_id, regs); + if (ret == IRQ_HANDLED) + random |= ap->flags; } else { void **vector = (void **)bp->irq_info; int ent; for (ent = 0; ent < 4; ent++) { struct irqaction *ap = vector[ent]; if (ap != NULL) { - ap->handler(__irq(bp), ap->dev_id, regs); - random |= ap->flags & SA_SAMPLE_RANDOM; + int ret; + + ret = ap->handler(__irq(bp), + ap->dev_id, + regs); + if (ret == IRQ_HANDLED) + random |= ap->flags; } } } @@ -813,8 +820,9 @@ void handler_irq(int irq, struct pt_regs *regs) } #endif upa_writel(ICLR_IDLE, bp->iclr); + /* Test and add entropy */ - if (random) + if (random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); } } else diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c new file mode 100644 index 000000000..bc5cc1d17 --- /dev/null +++ b/arch/sparc64/kernel/kprobes.c @@ -0,0 +1,373 @@ +/* arch/sparc64/kernel/kprobes.c + * + * Copyright (C) 2004 David S. Miller + */ + +#include +#include +#include + +#include +#include + +/* We do not have hardware single-stepping on sparc64. + * So we implement software single-stepping with breakpoint + * traps. The top-level scheme is similar to that used + * in the x86 kprobes implementation. + * + * In the kprobe->insn[] array we store the original + * instruction at index zero and a break instruction at + * index one. + * + * When we hit a kprobe we: + * - Run the pre-handler + * - Remember "regs->tnpc" and interrupt level stored in + * "regs->tstate" so we can restore them later + * - Disable PIL interrupts + * - Set regs->tpc to point to kprobe->insn[0] + * - Set regs->tnpc to point to kprobe->insn[1] + * - Mark that we are actively in a kprobe + * + * At this point we wait for the second breakpoint at + * kprobe->insn[1] to hit. When it does we: + * - Run the post-handler + * - Set regs->tpc to "remembered" regs->tnpc stored above, + * restore the PIL interrupt level in "regs->tstate" as well + * - Make any adjustments necessary to regs->tnpc in order + * to handle relative branches correctly. See below. + * - Mark that we are no longer actively in a kprobe. + */ + +void arch_prepare_kprobe(struct kprobe *p) +{ + p->insn[0] = *p->addr; + p->insn[1] = BREAKPOINT_INSTRUCTION_2; +} + +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 + +static struct kprobe *current_kprobe; +static unsigned long current_kprobe_orig_tnpc; +static unsigned long current_kprobe_orig_tstate_pil; +static unsigned int kprobe_status; + +static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + current_kprobe_orig_tnpc = regs->tnpc; + current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); + regs->tstate |= TSTATE_PIL; + + regs->tpc = (unsigned long) &p->insn[0]; + regs->tnpc = (unsigned long) &p->insn[1]; +} + +static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) +{ + *p->addr = p->opcode; + flushi(p->addr); + + regs->tpc = (unsigned long) p->addr; + regs->tnpc = current_kprobe_orig_tnpc; + regs->tstate = ((regs->tstate & ~TSTATE_PIL) | + current_kprobe_orig_tstate_pil); +} + +static int kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + void *addr = (void *) regs->tpc; + int ret = 0; + + preempt_disable(); + + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + * Disarm the probe we just hit, and ignore it. + */ + p = get_kprobe(addr); + if (p) { + disarm_kprobe(p, regs); + ret = 1; + } else { + p = current_kprobe; + if (p->break_handler && p->break_handler(p, regs)) + goto ss_probe; + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) { + unlock_kprobes(); + if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) { + /* + * The breakpoint instruction was removed right + * after we hit it. Another cpu has removed + * either a probepoint or a debugger breakpoint + * at this address. In either case, no further + * handling of this interrupt is appropriate. + */ + ret = 1; + } + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + if (p->pre_handler(p, regs)) + return 1; + +ss_probe: + prepare_singlestep(p, regs); + kprobe_status = KPROBE_HIT_SS; + return 1; + +no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +/* If INSN is a relative control transfer instruction, + * return the corrected branch destination value. + * + * The original INSN location was REAL_PC, it actually + * executed at PC and produced destination address NPC. + */ +static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc, + unsigned long pc, unsigned long npc) +{ + /* Branch not taken, no mods necessary. */ + if (npc == pc + 0x4UL) + return real_pc + 0x4UL; + + /* The three cases are call, branch w/prediction, + * and traditional branch. + */ + if ((insn & 0xc0000000) == 0x40000000 || + (insn & 0xc1c00000) == 0x00400000 || + (insn & 0xc1c00000) == 0x00800000) { + /* The instruction did all the work for us + * already, just apply the offset to the correct + * instruction location. + */ + return (real_pc + (npc - pc)); + } + + return real_pc + 0x4UL; +} + +/* If INSN is an instruction which writes it's PC location + * into a destination register, fix that up. + */ +static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc) +{ + unsigned long *slot = NULL; + + /* Simplest cast is call, which always uses %o7 */ + if ((insn & 0xc0000000) == 0x40000000) { + slot = ®s->u_regs[UREG_I7]; + } + + /* Jmpl encodes the register inside of the opcode */ + if ((insn & 0xc1f80000) == 0x81c00000) { + unsigned long rd = ((insn >> 25) & 0x1f); + + if (rd <= 15) { + slot = ®s->u_regs[rd]; + } else { + /* Hard case, it goes onto the stack. */ + flushw_all(); + + rd -= 16; + slot = (unsigned long *) + (regs->u_regs[UREG_FP] + STACK_BIAS); + slot += rd; + } + } + if (slot != NULL) + *slot = real_pc; +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the breakpoint + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->insn. + * + * This function prepares to return from the post-single-step + * breakpoint trap. + */ +static void resume_execution(struct kprobe *p, struct pt_regs *regs) +{ + u32 insn = p->insn[0]; + + regs->tpc = current_kprobe_orig_tnpc; + regs->tnpc = relbranch_fixup(insn, + (unsigned long) p->addr, + (unsigned long) &p->insn[0], + regs->tnpc); + retpc_fixup(regs, insn, (unsigned long) p->addr); + + regs->tstate = ((regs->tstate & ~TSTATE_PIL) | + current_kprobe_orig_tstate_pil); +} + +static inline int post_kprobe_handler(struct pt_regs *regs) +{ + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) + current_kprobe->post_handler(current_kprobe, regs, 0); + + resume_execution(current_kprobe, regs); + + unlock_kprobes(); + preempt_enable_no_resched(); + + return 1; +} + +/* Interrupts disabled, kprobe_lock held. */ +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + resume_execution(current_kprobe, regs); + + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} + +/* + * Wrapper routine to for handling exceptions. + */ +int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, + void *data) +{ + struct die_args *args = (struct die_args *)data; + switch (val) { + case DIE_DEBUG: + if (kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_DEBUG_2: + if (post_kprobe_handler(args->regs)) + return NOTIFY_STOP; + break; + case DIE_GPF: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + case DIE_PAGE_FAULT: + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + return NOTIFY_STOP; + break; + default: + break; + } + return NOTIFY_DONE; +} + +asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs) +{ + BUG_ON(trap_level != 0x170 && trap_level != 0x171); + + if (user_mode(regs)) { + local_irq_enable(); + bad_trap(regs, trap_level); + return; + } + + /* trap_level == 0x170 --> ta 0x70 + * trap_level == 0x171 --> ta 0x71 + */ + if (notify_die((trap_level == 0x170) ? DIE_DEBUG : DIE_DEBUG_2, + (trap_level == 0x170) ? "debug" : "debug_2", + regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP) + bad_trap(regs, trap_level); +} + +/* Jprobes support. */ +static struct pt_regs jprobe_saved_regs; +static struct pt_regs *jprobe_saved_regs_location; +static struct sparc_stackf jprobe_saved_stack; + +int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + + jprobe_saved_regs_location = regs; + memcpy(&jprobe_saved_regs, regs, sizeof(*regs)); + + /* Save a whole stack frame, this gets arguments + * pushed onto the stack after using up all the + * arg registers. + */ + memcpy(&jprobe_saved_stack, + (char *) (regs->u_regs[UREG_FP] + STACK_BIAS), + sizeof(jprobe_saved_stack)); + + regs->tpc = (unsigned long) jp->entry; + regs->tnpc = ((unsigned long) jp->entry) + 0x4UL; + regs->tstate |= TSTATE_PIL; + + return 1; +} + +void jprobe_return(void) +{ + preempt_enable_no_resched(); + __asm__ __volatile__( + ".globl jprobe_return_trap_instruction\n" +"jprobe_return_trap_instruction:\n\t" + "ta 0x70"); +} + +extern void jprobe_return_trap_instruction(void); + +extern void __show_regs(struct pt_regs * regs); + +int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + u32 *addr = (u32 *) regs->tpc; + + if (addr == (u32 *) jprobe_return_trap_instruction) { + if (jprobe_saved_regs_location != regs) { + printk("JPROBE: Current regs (%p) does not match " + "saved regs (%p).\n", + regs, jprobe_saved_regs_location); + printk("JPROBE: Saved registers\n"); + __show_regs(jprobe_saved_regs_location); + printk("JPROBE: Current registers\n"); + __show_regs(regs); + BUG(); + } + /* Restore old register state. Do pt_regs + * first so that UREG_FP is the original one for + * the stack frame restore. + */ + memcpy(regs, &jprobe_saved_regs, sizeof(*regs)); + + memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS), + &jprobe_saved_stack, + sizeof(jprobe_saved_stack)); + + return 1; + } + return 0; +} diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 31cc686de..75032d0e2 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -41,7 +41,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, #else /* List of all PCI controllers found in the system. */ -spinlock_t pci_controller_lock = SPIN_LOCK_UNLOCKED; struct pci_controller_info *pci_controller_root = NULL; /* Each PCI controller found gets a unique index. */ @@ -298,12 +297,9 @@ static void __init pci_controller_probe(void) static void __init pci_scan_each_controller_bus(void) { struct pci_controller_info *p; - unsigned long flags; - spin_lock_irqsave(&pci_controller_lock, flags); for (p = pci_controller_root; p; p = p->next) p->scan_bus(p); - spin_unlock_irqrestore(&pci_controller_lock, flags); } /* Reorder the pci_dev chain, so that onboard devices come first @@ -351,10 +347,6 @@ static int __init pcibios_init(void) subsys_initcall(pcibios_init); -struct pci_fixup pcibios_fixups[] = { - { 0 } -}; - void pcibios_fixup_bus(struct pci_bus *pbus) { struct pci_pbm_info *pbm = pbus->sysdata; diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index fda652414..58310aace 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -15,18 +15,13 @@ */ void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; - - walk = walk->next; - while (walk != &pbus->devices) { - struct pci_dev *pdev = pci_dev_b(walk); + struct pci_dev *pdev; + list_for_each_entry(pdev, &pbus->devices, bus_list) { if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) { pbus->self = pdev; return; } - - walk = walk->next; } prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n"); @@ -217,31 +212,18 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, struct pci_pbm_info *pbm, int prom_node) { - struct list_head *walk = &pbus->devices; - - /* This loop is coded like this because the cookie - * fillin routine can delete devices from the tree. - */ - walk = walk->next; - while (walk != &pbus->devices) { - struct pci_dev *pdev = pci_dev_b(walk); - struct list_head *walk_next = walk->next; + struct pci_dev *pdev, *pdev_next; + struct pci_bus *this_pbus, *pbus_next; + /* This must be _safe because the cookie fillin + routine can delete devices from the tree. */ + list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list) pdev_cookie_fillin(pbm, pdev, prom_node); - walk = walk_next; - } - - walk = &pbus->children; - walk = walk->next; - while (walk != &pbus->children) { - struct pci_bus *this_pbus = pci_bus_b(walk); + list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) { struct pcidev_cookie *pcp = this_pbus->self->sysdata; - struct list_head *walk_next = walk->next; pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node); - - walk = walk_next; } } @@ -431,14 +413,14 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm, void __init pci_record_assignments(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_record_assignments(pbm, pci_dev_b(walk)); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_record_assignments(pbm, dev); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_record_assignments(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_record_assignments(pbm, bus); } /* Return non-zero if PDEV has implicit I/O resources even @@ -549,14 +531,14 @@ static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, void __init pci_assign_unassigned(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_assign_unassigned(pbm, pci_dev_b(walk)); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_assign_unassigned(pbm, dev); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_assign_unassigned(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_assign_unassigned(pbm, bus); } static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) @@ -797,14 +779,14 @@ have_irq: void __init pci_fixup_irq(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_fixup_irq(pci_dev_b(walk)); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_fixup_irq(dev); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_fixup_irq(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_fixup_irq(pbm, bus); } static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) @@ -897,7 +879,7 @@ static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk; + struct pci_dev *pdev; int all_are_66mhz; u16 status; @@ -906,11 +888,8 @@ void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, goto out; } - walk = &pbus->devices; all_are_66mhz = 1; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); - + list_for_each_entry(pdev, &pbus->devices, bus_list) { pci_read_config_word(pdev, PCI_STATUS, &status); if (!(status & PCI_STATUS_66MHZ)) { all_are_66mhz = 0; @@ -929,17 +908,17 @@ out: void pci_setup_busmastering(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *dev; + struct pci_bus *bus; int is_66mhz; is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) - pdev_setup_busmastering(pci_dev_b(walk), is_66mhz); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_setup_busmastering(dev, is_66mhz); - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_setup_busmastering(pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_setup_busmastering(pbm, bus); } void pci_register_legacy_regions(struct resource *io_res, @@ -987,10 +966,10 @@ void pci_scan_for_target_abort(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *pdev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &pbus->devices, bus_list) { u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -1005,19 +984,18 @@ void pci_scan_for_target_abort(struct pci_controller_info *p, } } - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_scan_for_target_abort(p, pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_scan_for_target_abort(p, pbm, bus); } void pci_scan_for_master_abort(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *pdev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &pbus->devices, bus_list) { u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -1031,19 +1009,18 @@ void pci_scan_for_master_abort(struct pci_controller_info *p, } } - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_scan_for_master_abort(p, pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_scan_for_master_abort(p, pbm, bus); } void pci_scan_for_parity_error(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct list_head *walk = &pbus->devices; + struct pci_dev *pdev; + struct pci_bus *bus; - for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &pbus->devices, bus_list) { u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -1058,7 +1035,6 @@ void pci_scan_for_parity_error(struct pci_controller_info *p, } } - walk = &pbus->children; - for (walk = walk->next; walk != &pbus->children; walk = walk->next) - pci_scan_for_parity_error(p, pbm, pci_bus_b(walk)); + list_for_each_entry(bus, &pbus->children, node) + pci_scan_for_parity_error(p, pbm, bus); } diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 302a0a2ce..6c3205962 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -11,7 +11,6 @@ #include #include -extern spinlock_t pci_controller_lock; extern struct pci_controller_info *pci_controller_root; extern int pci_num_controllers; diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index cca82a12e..94a52983c 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -56,6 +56,39 @@ static void __iommu_flushall(struct pci_iommu *iommu) } } +#define IOPTE_CONSISTENT(CTX) \ + (IOPTE_VALID | IOPTE_CACHE | \ + (((CTX) << 47) & IOPTE_CONTEXT)) + +#define IOPTE_STREAMING(CTX) \ + (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) + +/* Existing mappings are never marked invalid, instead they + * are pointed to a dummy page. + */ +#define IOPTE_IS_DUMMY(iommu, iopte) \ + ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) + +static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) +{ + unsigned long val = iopte_val(*iopte); + + val &= ~IOPTE_PAGE; + val |= iommu->dummy_page_pa; + + iopte_val(*iopte) = val; +} + +void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize) +{ + int i; + + tsbsize /= sizeof(iopte_t); + + for (i = 0; i < tsbsize; i++) + iopte_make_dummy(iommu, &iommu->page_table[i]); +} + static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) { iopte_t *iopte, *limit, *first; @@ -79,7 +112,7 @@ static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long n first = iopte; for (;;) { - if (iopte_val(*iopte) == 0UL) { + if (IOPTE_IS_DUMMY(iommu, iopte)) { if ((iopte + (1 << cnum)) >= limit) ent = 0; else @@ -142,12 +175,12 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); while (iopte > iommu->page_table) { iopte--; - if (!(iopte_val(*iopte) & IOPTE_VALID)) { + if (IOPTE_IS_DUMMY(iommu, iopte)) { unsigned long tmp = npages; while (--tmp) { iopte--; - if (iopte_val(*iopte) & IOPTE_VALID) + if (!IOPTE_IS_DUMMY(iommu, iopte)) break; } if (tmp == 0) { @@ -162,15 +195,6 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long return NULL; } -#define IOPTE_CONSISTENT(CTX) \ - (IOPTE_VALID | IOPTE_CACHE | \ - (((CTX) << 47) & IOPTE_CONTEXT)) - -#define IOPTE_STREAMING(CTX) \ - (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) - -#define IOPTE_INVALID 0UL - /* Allocate and map kernel buffer of size SIZE using consistent mode * DMA for PCI device PDEV. Return non-NULL cpu-side address if * successful and set *DMA_ADDRP to the PCI side dma address. @@ -261,7 +285,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ limit = (iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); while (walk < limit) { - if (iopte_val(*walk) != IOPTE_INVALID) + if (!IOPTE_IS_DUMMY(iommu, walk)) break; walk++; } @@ -280,7 +304,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; for (i = 0; i < npages; i++, iopte++) - iopte_val(*iopte) = IOPTE_INVALID; + iopte_make_dummy(iommu, iopte); if (iommu->iommu_ctxflush) { pci_iommu_write(iommu->iommu_ctxflush, ctx); @@ -376,7 +400,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int base = iommu->page_table + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU - if (iopte_val(*base) == IOPTE_INVALID) + if (IOPTE_IS_DUMMY(iommu, base)) printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", bus_addr, sz, __builtin_return_address(0)); #endif @@ -415,7 +439,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int } /* Step 2: Clear out first TSB entry. */ - iopte_val(*base) = IOPTE_INVALID; + iopte_make_dummy(iommu, base); free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); @@ -611,7 +635,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU - if (iopte_val(*base) == IOPTE_INVALID) + if (IOPTE_IS_DUMMY(iommu, base)) printk("pci_unmap_sg called on non-mapped region %016lx,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0)); #endif @@ -648,7 +672,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, } /* Step 2: Clear out first TSB entry. */ - iopte_val(*base) = IOPTE_INVALID; + iopte_make_dummy(iommu, base); free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index dc4d63084..2dacbd780 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1076,17 +1076,17 @@ static void __init psycho_register_error_handlers(struct pci_controller_info *p) * bits for each PBM. */ tmp = psycho_read(base + PSYCHO_PCIA_CTRL); - tmp |= (PSYCHO_PCICTRL_SBH_ERR | - PSYCHO_PCICTRL_SERR | - PSYCHO_PCICTRL_SBH_INT | + tmp |= (PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); + tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIA_CTRL, tmp); tmp = psycho_read(base + PSYCHO_PCIB_CTRL); - tmp |= (PSYCHO_PCICTRL_SBH_ERR | - PSYCHO_PCICTRL_SERR | - PSYCHO_PCICTRL_SBH_INT | + tmp |= (PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); + tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIB_CTRL, tmp); } @@ -1241,6 +1241,14 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. @@ -1254,7 +1262,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) iommu->page_table_sz_bits = 17; iommu->page_table_map_base = 0xc0000000; iommu->dma_addr_mask = 0xffffffff; - memset((char *)tsbbase, 0, IO_TSB_SIZE); + pci_iommu_table_init(iommu, IO_TSB_SIZE); /* We start with no consistent mappings. */ iommu->lowest_consistent_map = @@ -1479,22 +1487,18 @@ void __init psycho_init(int node, char *model_name) struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; struct pci_iommu *iommu; - unsigned long flags; u32 upa_portid; int is_pbm_a, err; upa_portid = prom_getintdefault(node, "upa-portid", 0xff); - spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { if (p->pbm_A.portid == upa_portid) { - spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); psycho_pbm_init(p, node, is_pbm_a); return; } } - spin_unlock_irqrestore(&pci_controller_lock, flags); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) { @@ -1510,10 +1514,8 @@ void __init psycho_init(int node, char *model_name) memset(iommu, 0, sizeof(*iommu)); p->pbm_A.iommu = p->pbm_B.iommu = iommu; - spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; - spin_unlock_irqrestore(&pci_controller_lock, flags); p->pbm_A.portid = upa_portid; p->pbm_B.portid = upa_portid; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 6a266a7bf..2bf247792 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1113,10 +1113,9 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource) static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) { - struct list_head *walk = &sabre_bus->devices; + struct pci_dev *pdev; - for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { - struct pci_dev *pdev = pci_dev_b(walk); + list_for_each_entry(pdev, &sabre_bus->devices, bus_list) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { @@ -1178,10 +1177,9 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) static void __init sabre_scan_bus(struct pci_controller_info *p) { static int once; - struct pci_bus *sabre_bus; + struct pci_bus *sabre_bus, *pbus; struct pci_pbm_info *pbm; struct pcidev_cookie *cookie; - struct list_head *walk; int sabres_scanned; /* The APB bridge speaks to the Sabre host PCI bridge @@ -1217,9 +1215,7 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) sabres_scanned = 0; - walk = &sabre_bus->children; - for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) { - struct pci_bus *pbus = pci_bus_b(walk); + list_for_each_entry(pbus, &sabre_bus->children, node) { if (pbus->number == p->pbm_A.pci_first_busno) { pbm = &p->pbm_A; @@ -1293,6 +1289,14 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); @@ -1301,7 +1305,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = dvma_offset; iommu->dma_addr_mask = dma_mask; - memset((char *)tsbbase, 0, PAGE_SIZE << order); + pci_iommu_table_init(iommu, PAGE_SIZE << order); sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); @@ -1546,7 +1550,6 @@ void __init sabre_init(int pnode, char *model_name) struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; struct pci_iommu *iommu; - unsigned long flags; int tsbsize, err; u32 busrange[2]; u32 vdma[2]; @@ -1594,10 +1597,8 @@ void __init sabre_init(int pnode, char *model_name) upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); - spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; - spin_unlock_irqrestore(&pci_controller_lock, flags); p->pbm_A.portid = upa_portid; p->pbm_B.portid = upa_portid; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index be6fa906a..f72da320b 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1171,7 +1171,7 @@ static void __init tomatillo_register_error_handlers(struct pci_controller_info prom_halt(); } bucket = __bucket(irq); - tmp = readl(bucket->imap); + tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); @@ -1309,7 +1309,7 @@ static void __init schizo_register_error_handlers(struct pci_controller_info *p) prom_halt(); } bucket = __bucket(irq); - tmp = readl(bucket->imap); + tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); @@ -1372,10 +1372,10 @@ static void __init schizo_register_error_handlers(struct pci_controller_info *p) SCHIZO_PCICTRL_RTRY_ERR | SCHIZO_PCICTRL_SBH_ERR | SCHIZO_PCICTRL_SERR | - SCHIZO_PCICTRL_SBH_INT | SCHIZO_PCICTRL_EEN); - err_no_mask = SCHIZO_PCICTRL_DTO_ERR; + err_no_mask = (SCHIZO_PCICTRL_DTO_ERR | + SCHIZO_PCICTRL_SBH_INT); /* Enable PCI Error interrupts and clear error * bits for each PBM. @@ -1766,6 +1766,14 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. @@ -1780,7 +1788,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = vdma[0]; iommu->dma_addr_mask = dma_mask; - memset((char *)tsbbase, 0, PAGE_SIZE << order); + pci_iommu_table_init(iommu, PAGE_SIZE << order); switch (tsbsize) { case 64: @@ -2073,13 +2081,11 @@ static void __init __schizo_init(int node, char *model_name, int chip_type) { struct pci_controller_info *p; struct pci_iommu *iommu; - unsigned long flags; int is_pbm_a; u32 portid; portid = prom_getintdefault(node, "portid", 0xff); - spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { struct pci_pbm_info *pbm; @@ -2091,13 +2097,11 @@ static void __init __schizo_init(int node, char *model_name, int chip_type) &p->pbm_B); if (portid_compare(pbm->portid, portid, chip_type)) { - spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); schizo_pbm_init(p, node, portid, chip_type); return; } } - spin_unlock_irqrestore(&pci_controller_lock, flags); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) { @@ -2122,10 +2126,8 @@ static void __init __schizo_init(int node, char *model_name, int chip_type) memset(iommu, 0, sizeof(*iommu)); p->pbm_B.iommu = iommu; - spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; - spin_unlock_irqrestore(&pci_controller_lock, flags); p->index = pci_num_controllers++; p->pbms_same_domain = 0; diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 006a562dc..52f14e399 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -27,7 +27,7 @@ int scons_pwroff = 1; #ifdef CONFIG_PCI -static unsigned long power_reg = 0UL; +static void __iomem *power_reg; static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); static int button_pressed; @@ -52,7 +52,7 @@ void machine_power_off(void) { if (!serial_console || scons_pwroff) { #ifdef CONFIG_PCI - if (power_reg != 0UL) { + if (power_reg) { /* Both register bits seem to have the * same effect, so until I figure out * what the difference is... @@ -130,8 +130,8 @@ void __init power_init(void) return; found: - power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4); - printk("power: Control reg at %016lx ... ", power_reg); + power_reg = ioremap(edev->resource[0].start, 0x4); + printk("power: Control reg at %p ... ", power_reg); poweroff_method = machine_halt; /* able to use the standard halt */ if (has_button_interrupt(edev)) { if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { @@ -141,8 +141,7 @@ found: printk("powerd running.\n"); if (request_irq(edev->irqs[0], - power_handler, SA_SHIRQ, "power", - (void *) power_reg) < 0) + power_handler, SA_SHIRQ, "power", NULL) < 0) printk("power: Error, cannot register IRQ handler.\n"); } else { printk("not using powerd.\n"); diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 145ce7c73..f3e3c657e 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/ptrace.c b/arch/sparc64/kernel/ptrace.c index 3e9aa09a9..fd73a3ab8 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -627,11 +627,8 @@ asmlinkage void syscall_trace(void) return; if (!(current->ptrace & PT_PTRACED)) return; - 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/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 438e373ce..51e762bcd 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index ba3fcb4b2..d81bfab51 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(¤t->sighand->siglock); return; segv: - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); } /* Checks if the fp is valid */ @@ -545,6 +545,12 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + /* The sigcontext is passed in this way because of how it + * is defined in GLIBC's /usr/include/bits/sigcontext.h + * for sparc64. It includes the 128 bytes of siginfo_t. + */ + regs->u_regs[UREG_I2] = (unsigned long) &sf->info; + /* 5. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); @@ -559,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, @@ -568,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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -609,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; @@ -626,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 = ¤t->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 a9a5b31a3..63d9cec39 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). @@ -76,9 +86,61 @@ struct new_signal_frame32 { __siginfo_fpu_t fpu_state; }; +struct siginfo32 { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE32]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t32 _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + sigval_t32 _sigval; + } _rt; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ + struct { + u32 _addr; /* faulting insn/memory ref. */ + int _trapno; + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +}; + struct rt_signal_frame32 { struct sparc_stackf32 ss; - siginfo_t32 info; + struct siginfo32 info; struct pt_regs32 regs; compat_sigset_t mask; /* __siginfo_fpu32_t * */ u32 fpu_save; @@ -95,11 +157,11 @@ struct rt_signal_frame32 { #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) -int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) +int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) { int err; - if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(struct siginfo32))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -119,7 +181,7 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) case __SI_TIMER >> 16: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user((u32)(u64)from->si_ptr, &to->si_ptr); + err |= __put_user(from->si_int, &to->si_int); break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); @@ -145,6 +207,22 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) return err; } +/* CAUTION: This is just a very minimalist implementation for the + * sake of compat_sys_rt_sigqueueinfo() + */ +int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from) +{ + if (!access_ok(VERIFY_WRITE, from, sizeof(struct siginfo32))) + return -EFAULT; + + if (copy_from_user(to, from, 3*sizeof(int)) || + copy_from_user(to->_sifields._pad, from->_sifields._pad, + SI_PAD_SIZE)) + return -EFAULT; + + return 0; +} + /* * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... @@ -299,8 +377,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 +413,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 +483,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 +530,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 +575,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) spin_unlock_irq(¤t->sighand->siglock); return; segv: - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } /* Checks if the fp is valid */ @@ -648,7 +736,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 +803,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); @@ -749,6 +840,7 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; @@ -795,7 +887,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 */ @@ -919,7 +1011,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, return; sigsegv: - do_exit(SIGSEGV); + force_sigsegv(signr, current); } asmlinkage int @@ -1070,7 +1162,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, @@ -1119,6 +1211,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); @@ -1157,6 +1251,7 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; @@ -1206,7 +1301,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, @@ -1225,8 +1320,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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -1266,21 +1359,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 = ¤t->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 abc65dc6d..f2bbaafd8 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -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); @@ -981,8 +974,6 @@ void smp_promstop_others(void) smp_cross_call(&xcall_promstop, 0, 0, 0); } -extern void sparc64_do_profile(struct pt_regs *regs); - #define prof_multiplier(__cpu) cpu_data(__cpu).multiplier #define prof_counter(__cpu) cpu_data(__cpu).counter @@ -1008,7 +999,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) } do { - sparc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); if (!--prof_counter(cpu)) { irq_enter(); diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 5eafadd28..3864b4b6e 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -74,8 +73,6 @@ extern void *__bzero(void *, size_t); extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); -extern int __strncmp(const char *, const char *, __kernel_size_t); -extern __kernel_size_t __strlen(const char *); extern __kernel_size_t strlen(const char *); extern void linux_sparc_syscall(void); extern void rtrap(void); @@ -144,7 +141,7 @@ EXPORT_SYMBOL(synchronize_irq); #if defined(CONFIG_MCOUNT) extern void _mcount(void); -EXPORT_SYMBOL_NOVERS(_mcount); +EXPORT_SYMBOL(_mcount); #endif /* CPU online map and active count. */ @@ -187,8 +184,6 @@ EXPORT_SYMBOL(atomic_dec_and_lock); EXPORT_SYMBOL(___test_and_set_bit); EXPORT_SYMBOL(___test_and_clear_bit); EXPORT_SYMBOL(___test_and_change_bit); -EXPORT_SYMBOL(___test_and_set_le_bit); -EXPORT_SYMBOL(___test_and_clear_le_bit); /* Bit searching */ EXPORT_SYMBOL(find_next_bit); @@ -295,7 +290,6 @@ EXPORT_SYMBOL(__prom_getchild); EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */ -EXPORT_SYMBOL(__strlen); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(__strlen_user); @@ -334,7 +328,6 @@ EXPORT_SYMBOL(sys_close); #endif /* Special internal versions of library functions. */ -EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(copy_user_page); @@ -342,8 +335,7 @@ EXPORT_SYMBOL(__bzero); EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); EXPORT_SYMBOL(__memcmp); -EXPORT_SYMBOL(__strncmp); -EXPORT_SYMBOL(__memmove); +EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(csum_partial); @@ -351,9 +343,12 @@ EXPORT_SYMBOL(csum_partial_copy_sparc64); EXPORT_SYMBOL(ip_fast_csum); /* Moving data to/from/in userspace. */ -EXPORT_SYMBOL(__copy_to_user); -EXPORT_SYMBOL(__copy_from_user); -EXPORT_SYMBOL(__copy_in_user); +EXPORT_SYMBOL(___copy_to_user); +EXPORT_SYMBOL(___copy_from_user); +EXPORT_SYMBOL(___copy_in_user); +EXPORT_SYMBOL(copy_to_user_fixup); +EXPORT_SYMBOL(copy_from_user_fixup); +EXPORT_SYMBOL(copy_in_user_fixup); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__bzero_noasi); @@ -367,17 +362,24 @@ EXPORT_SYMBOL(pfn_to_page); /* No version information on this, heavily used in inline asm, * and will always be 'void __ret_efault(void)'. */ -EXPORT_SYMBOL_NOVERS(__ret_efault); +EXPORT_SYMBOL(__ret_efault); /* No version information on these, as gcc produces such symbols. */ -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strncmp); + +/* Delay routines. */ +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__ndelay); +EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL(__delay); void VISenter(void); /* RAID code needs this */ -EXPORT_SYMBOL_NOVERS(VISenter); +EXPORT_SYMBOL(VISenter); /* for input/keybdev */ EXPORT_SYMBOL(sun_do_break); diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index 7a5d4f4e5..f978c13f5 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -120,7 +120,7 @@ SIGN1(sys32_setgroups, sys_setgroups, %o0) SIGN2(sys32_setpgid, sys_setpgid, %o0, %o1) SIGN3(sys32_setpriority, sys_setpriority, %o0, %o1, %o2) SIGN1(sys32_ssetmask, sys_ssetmask, %o0) -SIGN2(sys32_syslog, sys_syslog, %o0, %o1) +SIGN2(sys32_syslog, sys_syslog, %o0, %o2) SIGN1(sys32_umask, sys_umask, %o0) SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2) SIGN1(sys32_sendto, sys_sendto, %o0) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 56e277383..b81f15521 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1045,7 +1045,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, } asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, - siginfo_t32 __user *uinfo, + struct siginfo32 __user *uinfo, struct compat_timespec __user *uts, compat_size_t sigsetsize) { @@ -1130,15 +1130,15 @@ asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, } asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, - siginfo_t32 __user *uinfo) + struct siginfo32 __user *uinfo) { siginfo_t info; 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_to_kernel32(&info, uinfo)) return -EFAULT; + set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); set_fs (old_fs); @@ -1736,3 +1736,33 @@ sys32_timer_create(u32 clock, struct sigevent32 __user *se32, return err; } +asmlinkage long compat_sys_waitid(u32 which, u32 pid, + struct siginfo32 __user *uinfo, u32 options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + memset(&info, 0, sizeof(info)); + + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, + options, + uru ? (struct rusage __user *) &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru) { + ret = put_compat_rusage(&ru, uru); + if (ret) + return ret; + } + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); +} diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index a937ab707..8fe732b34 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -75,7 +75,7 @@ sys_call_table32: /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink - .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, sys_ni_syscall + .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall #endif /* CONFIG_COMPAT */ @@ -141,7 +141,7 @@ sys_call_table: /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink - .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall + .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index f961a0d3b..b50e16d49 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,18 @@ struct sparc64_tick_ops *tick_ops; #define TICK_PRIV_BIT (1UL << 63) +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return regs->u_regs[UREG_RETPC]; + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif + static void tick_disable_protection(void) { /* Set things up so user can access tick register for profiling @@ -418,7 +431,6 @@ static struct sparc64_tick_ops hbtick_operations = { unsigned long timer_tick_offset; unsigned long timer_tick_compare; -static unsigned long timer_ticks_per_usec_quotient; static unsigned long timer_ticks_per_nsec_quotient; #define TICK_SIZE (tick_nsec / 1000) @@ -441,28 +453,6 @@ static inline void timer_check_rtc(void) } } -void sparc64_do_profile(struct pt_regs *regs) -{ - unsigned long pc; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - pc = regs->tpc; - - pc -= (unsigned long) _stext; - pc >>= prof_shift; - - if(pc >= prof_len) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); -} - static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { unsigned long ticks, pstate; @@ -471,7 +461,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) do { #ifndef CONFIG_SMP - sparc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #endif do_timer(regs); @@ -920,10 +910,10 @@ try_isa_clock: } /* This is gets the master TICK_INT timer going. */ -static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +static unsigned long sparc64_init_timers(void) { - unsigned long pstate, clock; - int node, err; + unsigned long clock; + int node; #ifdef CONFIG_SMP extern void smp_tick_init(void); #endif @@ -956,6 +946,14 @@ static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struc smp_tick_init(); #endif + return clock; +} + +static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +{ + unsigned long pstate; + int err; + /* Register IRQ handler. */ err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC, "timer", NULL); @@ -981,8 +979,6 @@ static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struc : "r" (pstate)); local_irq_enable(); - - return clock; } struct freq_table { @@ -1034,18 +1030,27 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val static struct notifier_block sparc64_cpufreq_notifier_block = { .notifier_call = sparc64_cpufreq_notifier }; -#endif + +#endif /* CONFIG_CPU_FREQ */ + +static struct time_interpolator sparc64_cpu_interpolator = { + .source = TIME_SOURCE_CPU, + .shift = 16, +}; /* The quotient formula is taken from the IA64 port. */ -#define SPARC64_USEC_PER_CYC_SHIFT 30UL #define SPARC64_NSEC_PER_CYC_SHIFT 30UL void __init time_init(void) { - unsigned long clock = sparc64_init_timers(timer_interrupt); + unsigned long clock = sparc64_init_timers(); - timer_ticks_per_usec_quotient = - (((1000000UL << SPARC64_USEC_PER_CYC_SHIFT) + - (clock / 2)) / clock); + sparc64_cpu_interpolator.frequency = clock; + register_time_interpolator(&sparc64_cpu_interpolator); + + /* Now that the interpolator is registered, it is + * safe to start the timer ticking. + */ + sparc64_start_timers(timer_interrupt); timer_ticks_per_nsec_quotient = (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + @@ -1057,17 +1062,6 @@ void __init time_init(void) #endif } -static __inline__ unsigned long do_gettimeoffset(void) -{ - unsigned long ticks = tick_ops->get_tick(); - - ticks += timer_tick_offset; - ticks -= timer_tick_compare; - - return (ticks * timer_ticks_per_usec_quotient) - >> SPARC64_USEC_PER_CYC_SHIFT; -} - unsigned long long sched_clock(void) { unsigned long ticks = tick_ops->get_tick(); @@ -1076,100 +1070,6 @@ unsigned long long sched_clock(void) >> SPARC64_NSEC_PER_CYC_SHIFT; } -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - if (this_is_starfire) - return 0; - - write_seqlock_irq(&xtime_lock); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * made, and then undo it! - */ - nsec -= do_gettimeoffset() * 1000; - nsec -= (jiffies - wall_jiffies) * (NSEC_PER_SEC / HZ); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -/* Ok, my cute asm atomicity trick doesn't work anymore. - * There are just too many variables that need to be protected - * now (both members of xtime, wall_jiffies, et al.) - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long seq; - unsigned long usec, sec; - unsigned long max_ntp_tick = tick_usec - tickadj; - - do { - unsigned long lost; - - seq = read_seqbegin(&xtime_lock); - usec = do_gettimeoffset(); - lost = jiffies - wall_jiffies; - - /* - * If time_adjust is negative then NTP is slowing the clock - * so make sure not to go into next possible interval. - * Better to lose some accuracy than have time go backwards.. - */ - if (unlikely(time_adjust < 0)) { - usec = min(usec, max_ntp_tick); - - if (lost) - usec += lost * max_ntp_tick; - } - else if (unlikely(lost)) - usec += lost * tick_usec; - - sec = xtime.tv_sec; - - /* Believe it or not, this divide shows up on - * kernel profiles. The problem is that it is - * both 64-bit and signed. Happily, 32-bits - * of precision is all we really need and in - * doing so gcc ends up emitting a cheap multiply. - * - * XXX Why is tv_nsec 'long' and 'signed' in - * XXX the first place, can it even be negative? - */ - usec += ((unsigned int) xtime.tv_nsec / 1000U); - } while (read_seqretry(&xtime_lock, seq)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, chip_minutes; diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 473901974..7519f39c5 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -36,10 +36,24 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include #endif +struct notifier_block *sparc64die_chain; +static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED; + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&sparc64die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + return err; +} + /* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap * stack. It is found at (pt_regs + sizeof(pt_regs)) and the layout @@ -71,11 +85,20 @@ static void dump_tl1_traplog(struct tl1_traplog *p) } } -void bad_trap (struct pt_regs *regs, long lvl) +void do_call_debug(struct pt_regs *regs) +{ + notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); +} + +void bad_trap(struct pt_regs *regs, long lvl) { char buffer[32]; siginfo_t info; + if (notify_die(DIE_TRAP, "bad trap", regs, + 0, lvl, SIGTRAP) == NOTIFY_STOP) + return; + if (lvl < 0x100) { sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl); die_if_kernel(buffer, regs); @@ -84,7 +107,7 @@ void bad_trap (struct pt_regs *regs, long lvl) lvl -= 0x100; if (regs->tstate & TSTATE_PRIV) { sprintf(buffer, "Kernel bad sw trap %lx", lvl); - die_if_kernel (buffer, regs); + die_if_kernel(buffer, regs); } if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; @@ -98,10 +121,14 @@ void bad_trap (struct pt_regs *regs, long lvl) force_sig_info(SIGILL, &info, current); } -void bad_trap_tl1 (struct pt_regs *regs, long lvl) +void bad_trap_tl1(struct pt_regs *regs, long lvl) { char buffer[32]; + if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs, + 0, lvl, SIGTRAP) == NOTIFY_STOP) + return; + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); sprintf (buffer, "Bad trap %lx at tl>0", lvl); @@ -121,6 +148,10 @@ void instruction_access_exception(struct pt_regs *regs, { siginfo_t info; + if (notify_die(DIE_TRAP, "instruction access exception", regs, + 0, 0x8, SIGTRAP) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) { printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", sfsr, sfar); @@ -141,15 +172,23 @@ void instruction_access_exception(struct pt_regs *regs, void instruction_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { + if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs, + 0, 0x8, SIGTRAP) == NOTIFY_STOP) + return; + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); instruction_access_exception(regs, sfsr, sfar); } -void data_access_exception (struct pt_regs *regs, - unsigned long sfsr, unsigned long sfar) +void data_access_exception(struct pt_regs *regs, + unsigned long sfsr, unsigned long sfar) { siginfo_t info; + if (notify_die(DIE_TRAP, "data access exception", regs, + 0, 0x30, SIGTRAP) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) { /* Test if this comes from uaccess places. */ unsigned long fixup; @@ -220,6 +259,10 @@ void do_iae(struct pt_regs *regs) spitfire_clean_and_reenable_l1_caches(); + if (notify_die(DIE_TRAP, "instruction access exception", regs, + 0, 0x8, SIGTRAP) == NOTIFY_STOP) + return; + info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_OBJERR; @@ -230,6 +273,8 @@ void do_iae(struct pt_regs *regs) void do_dae(struct pt_regs *regs) { + siginfo_t info; + #ifdef CONFIG_PCI if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { spitfire_clean_and_reenable_l1_caches(); @@ -244,7 +289,18 @@ void do_dae(struct pt_regs *regs) return; } #endif - do_iae(regs); + spitfire_clean_and_reenable_l1_caches(); + + if (notify_die(DIE_TRAP, "data access exception", regs, + 0, 0x30, SIGTRAP) == NOTIFY_STOP) + return; + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_OBJERR; + info.si_addr = (void *)0; + info.si_trapno = 0; + force_sig_info(SIGBUS, &info, current); } static char ecc_syndrome_table[] = { @@ -1638,6 +1694,10 @@ void do_fpe_common(struct pt_regs *regs) void do_fpieee(struct pt_regs *regs) { + if (notify_die(DIE_TRAP, "fpu exception ieee", regs, + 0, 0x24, SIGFPE) == NOTIFY_STOP) + return; + do_fpe_common(regs); } @@ -1648,6 +1708,10 @@ void do_fpother(struct pt_regs *regs) struct fpustate *f = FPUSTATE; int ret = 0; + if (notify_die(DIE_TRAP, "fpu exception other", regs, + 0, 0x25, SIGFPE) == NOTIFY_STOP) + return; + switch ((current_thread_info()->xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ @@ -1663,6 +1727,10 @@ void do_tof(struct pt_regs *regs) { siginfo_t info; + if (notify_die(DIE_TRAP, "tagged arithmetic overflow", regs, + 0, 0x26, SIGEMT) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) die_if_kernel("Penguin overflow trap from kernel mode", regs); if (test_thread_flag(TIF_32BIT)) { @@ -1681,6 +1749,10 @@ void do_div0(struct pt_regs *regs) { siginfo_t info; + if (notify_die(DIE_TRAP, "integer division by zero", regs, + 0, 0x28, SIGFPE) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) die_if_kernel("TL0: Kernel divide by zero.", regs); if (test_thread_flag(TIF_32BIT)) { @@ -1771,6 +1843,37 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); +static inline int is_kernel_stack(struct task_struct *task, + struct reg_window *rw) +{ + unsigned long rw_addr = (unsigned long) rw; + unsigned long thread_base, thread_end; + + if (rw_addr < PAGE_OFFSET) { + if (task != &init_task) + return 0; + } + + thread_base = (unsigned long) task->thread_info; + thread_end = thread_base + sizeof(union thread_union); + if (rw_addr >= thread_base && + rw_addr < thread_end && + !(rw_addr & 0x7UL)) + return 1; + + return 0; +} + +static inline struct reg_window *kernel_stack_up(struct reg_window *rw) +{ + unsigned long fp = rw->ins[6]; + + if (!fp) + return NULL; + + return (struct reg_window *) (fp + STACK_BIAS); +} + void die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; @@ -1786,6 +1889,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) " \\__U_/\n"); printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter); + notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV); __asm__ __volatile__("flushw"); __show_regs(regs); if (regs->tstate & TSTATE_PRIV) { @@ -1795,17 +1899,14 @@ void die_if_kernel(char *str, struct pt_regs *regs) /* Stop the back trace when we hit userland or we * find some badly aligned kernel stack. */ - while (rw && - count++ < 30 && - (((unsigned long) rw) >= PAGE_OFFSET) && - (char *) rw < ((char *) current) - + sizeof (union thread_union) && - !(((unsigned long) rw) & 0x7)) { + while (rw && + count++ < 30&& + is_kernel_stack(current, rw)) { printk("Caller[%016lx]", rw->ins[7]); print_symbol(": %s", rw->ins[7]); printk("\n"); - rw = (struct reg_window *) - (rw->ins[6] + STACK_BIAS); + + rw = kernel_stack_up(rw); } instruction_dump ((unsigned int *) regs->tpc); } else { @@ -1834,6 +1935,10 @@ void do_illegal_instruction(struct pt_regs *regs) u32 insn; siginfo_t info; + if (notify_die(DIE_TRAP, "illegal instruction", regs, + 0, 0x10, SIGILL) == NOTIFY_STOP) + return; + if (tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); if (test_thread_flag(TIF_32BIT)) @@ -1859,6 +1964,10 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo { siginfo_t info; + if (notify_die(DIE_TRAP, "memory address unaligned", regs, + 0, 0x34, SIGSEGV) == NOTIFY_STOP) + return; + if (regs->tstate & TSTATE_PRIV) { extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, @@ -1881,6 +1990,10 @@ void do_privop(struct pt_regs *regs) { siginfo_t info; + if (notify_die(DIE_TRAP, "privileged operation", regs, + 0, 0x11, SIGILL) == NOTIFY_STOP) + return; + if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 40f7919aa..491bb3681 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -158,7 +158,7 @@ tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) tl0_linux64: LINUX_64BIT_SYSCALL_TRAP tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) -tl0_resv170: BTRAP(0x170) BTRAP(0x171) BTRAP(0x172) +tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) BTRAP(0x172) tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S index 8faeee09f..a710d38d1 100644 --- a/arch/sparc64/kernel/vmlinux.lds.S +++ b/arch/sparc64/kernel/vmlinux.lds.S @@ -16,6 +16,7 @@ SECTIONS { *(.text) SCHED_TEXT + LOCK_TEXT *(.gnu.warning) } =0 _etext = .; @@ -52,9 +53,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/lib/Makefile b/arch/sparc64/lib/Makefile index 2da5af9a1..7dd001f52 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -7,11 +7,12 @@ EXTRA_CFLAGS := -Werror lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ - VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ - U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o ipcsum.o rwsem.o xor.o splock.o \ - find_bit.o + VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ + VIScsumcopyusr.o VISsave.o atomic.o bitops.o \ + U1memcpy.o U1copy_from_user.o U1copy_to_user.o \ + U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ + copy_in_user.o user_fixup.o memmove.o \ + mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o iomap.o lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c index b64aee993..3008d536e 100644 --- a/arch/sparc64/lib/PeeCeeI.c +++ b/arch/sparc64/lib/PeeCeeI.c @@ -7,7 +7,7 @@ #include #include -void outsb(unsigned long addr, const void *src, unsigned long count) +void outsb(void __iomem *addr, const void *src, unsigned long count) { const u8 *p = src; @@ -15,7 +15,7 @@ void outsb(unsigned long addr, const void *src, unsigned long count) outb(*p++, addr); } -void outsw(unsigned long addr, const void *src, unsigned long count) +void outsw(void __iomem *addr, const void *src, unsigned long count) { if(count) { u16 *ps = (u16 *)src; @@ -44,7 +44,7 @@ void outsw(unsigned long addr, const void *src, unsigned long count) } } -void outsl(unsigned long addr, const void *src, unsigned long count) +void outsl(void __iomem *addr, const void *src, unsigned long count) { if(count) { if((((u64)src) & 0x3) == 0) { @@ -119,7 +119,7 @@ void outsl(unsigned long addr, const void *src, unsigned long count) } } -void insb(unsigned long addr, void *dst, unsigned long count) +void insb(void __iomem *addr, void *dst, unsigned long count) { if(count) { u32 *pi; @@ -144,7 +144,7 @@ void insb(unsigned long addr, void *dst, unsigned long count) } } -void insw(unsigned long addr, void *dst, unsigned long count) +void insw(void __iomem *addr, void *dst, unsigned long count) { if(count) { u16 *ps = dst; @@ -169,7 +169,7 @@ void insw(unsigned long addr, void *dst, unsigned long count) } } -void insl(unsigned long addr, void *dst, unsigned long count) +void insl(void __iomem *addr, void *dst, unsigned long count) { if(count) { if((((unsigned long)dst) & 0x3) == 0) { diff --git a/arch/sparc64/lib/U1copy_from_user.S b/arch/sparc64/lib/U1copy_from_user.S new file mode 100644 index 000000000..93146a81e --- /dev/null +++ b/arch/sparc64/lib/U1copy_from_user.S @@ -0,0 +1,33 @@ +/* U1copy_from_user.S: UltraSparc-I/II/IIi/IIe optimized copy from userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME ___copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest +#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_AIUS, dest +#define EX_RETVAL(x) 0 + + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ + +#include "U1memcpy.S" diff --git a/arch/sparc64/lib/U1copy_to_user.S b/arch/sparc64/lib/U1copy_to_user.S new file mode 100644 index 000000000..1fccc521e --- /dev/null +++ b/arch/sparc64/lib/U1copy_to_user.S @@ -0,0 +1,33 @@ +/* U1copy_to_user.S: UltraSparc-I/II/IIi/IIe optimized copy to userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME ___copy_to_user +#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS +#define EX_RETVAL(x) 0 + + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ + +#include "U1memcpy.S" diff --git a/arch/sparc64/lib/U1memcpy.S b/arch/sparc64/lib/U1memcpy.S new file mode 100644 index 000000000..06a5bd262 --- /dev/null +++ b/arch/sparc64/lib/U1memcpy.S @@ -0,0 +1,555 @@ +/* U1memcpy.S: UltraSPARC-I/II/IIi/IIe optimized memcpy. + * + * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#ifdef __KERNEL__ +#include +#include +#else +#define ASI_BLK_P 0xf0 +#define FPRS_FEF 0x04 +#ifdef MEMCPY_DEBUG +#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \ + clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0; +#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#else +#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs +#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#endif +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x +#endif + +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef LOAD_BLK +#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_P, dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef STORE_BLK +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_P +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME memcpy +#endif + +#ifndef PREAMBLE +#define PREAMBLE +#endif + +#ifndef XCC +#define XCC xcc +#endif + +#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + faligndata %f1, %f2, %f48; \ + faligndata %f2, %f3, %f50; \ + faligndata %f3, %f4, %f52; \ + faligndata %f4, %f5, %f54; \ + faligndata %f5, %f6, %f56; \ + faligndata %f6, %f7, %f58; \ + faligndata %f7, %f8, %f60; \ + faligndata %f8, %f9, %f62; + +#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \ + EX_LD(LOAD_BLK(%src, %fdest)); \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %src, 0x40, %src; \ + subcc %len, 0x40, %len; \ + be,pn %xcc, jmptgt; \ + add %dest, 0x40, %dest; \ + +#define LOOP_CHUNK1(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f0, f48, len, branch_dest) +#define LOOP_CHUNK2(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest) +#define LOOP_CHUNK3(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest) + +#define STORE_SYNC(dest, fsrc) \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %dest, 0x40, %dest; + +#define STORE_JUMP(dest, fsrc, target) \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %dest, 0x40, %dest; \ + ba,pt %xcc, target; + +#define FINISH_VISCHUNK(dest, f0, f1, left) \ + subcc %left, 8, %left;\ + bl,pn %xcc, 95f; \ + faligndata %f0, %f1, %f48; \ + EX_ST(STORE(std, %f48, %dest)); \ + add %dest, 8, %dest; + +#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ + subcc %left, 8, %left; \ + bl,pn %xcc, 95f; \ + fsrc1 %f0, %f1; + +#define UNEVEN_VISCHUNK(dest, f0, f1, left) \ + UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ + ba,a,pt %xcc, 93f; + + .register %g2,#scratch + .register %g3,#scratch + + .text + .align 64 + + .globl FUNC_NAME + .type FUNC_NAME,#function +FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ + PREAMBLE + mov %o0, %g5 + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + blu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + cmp %o2, (5 * 64) + blu,pt %XCC, 70f + andcc %o3, 0x7, %g0 + + /* Clobbers o5/g1/g2/g3/g7/icc/xcc. */ + VISEntry + + /* Is 'dst' already aligned on an 64-byte boundary? */ + andcc %o0, 0x3f, %g2 + be,pt %XCC, 2f + + /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number + * of bytes to copy to make 'dst' 64-byte aligned. We pre- + * subtract this from 'len'. + */ + sub %o0, %o1, %o4 + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 + andcc %g2, 0x7, %g1 + be,pt %icc, 2f + and %g2, 0x38, %g2 + +1: subcc %g1, 0x1, %g1 + EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) + EX_ST(STORE(stb, %o3, %o1 + %o4)) + bgu,pt %XCC, 1b + add %o1, 0x1, %o1 + + add %o1, %o4, %o0 + +2: cmp %g2, 0x0 + and %o1, 0x7, %g1 + be,pt %icc, 3f + alignaddr %o1, %g0, %o1 + + EX_LD(LOAD(ldd, %o1, %f4)) +1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f4, %f6, %f0 + EX_ST(STORE(std, %f0, %o0)) + be,pn %icc, 3f + add %o0, 0x8, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f6, %f4, %f0 + EX_ST(STORE(std, %f0, %o0)) + bne,pt %icc, 1b + add %o0, 0x8, %o0 + + /* Destination is 64-byte aligned. */ +3: + membar #LoadStore | #StoreStore | #StoreLoad + + subcc %o2, 0x40, %o4 + add %o1, %g1, %g1 + andncc %o4, (0x40 - 1), %o4 + srl %g1, 3, %g2 + sub %o2, %o4, %g3 + andn %o1, (0x40 - 1), %o1 + and %g2, 7, %g2 + andncc %g3, 0x7, %g3 + fmovd %f0, %f2 + sub %g3, 0x8, %g3 + sub %o2, %o4, %o2 + + add %g1, %o4, %g1 + subcc %o2, %g3, %o2 + + EX_LD(LOAD_BLK(%o1, %f0)) + add %o1, 0x40, %o1 + add %g1, %g3, %g1 + EX_LD(LOAD_BLK(%o1, %f16)) + add %o1, 0x40, %o1 + sub %o4, 0x80, %o4 + EX_LD(LOAD_BLK(%o1, %f32)) + add %o1, 0x40, %o1 + + /* There are 8 instances of the unrolled loop, + * one for each possible alignment of the + * source buffer. Each loop instance is 452 + * bytes. + */ + sll %g2, 3, %o3 + sub %o3, %g2, %o3 + sllx %o3, 4, %o3 + add %o3, %g2, %o3 + sllx %o3, 2, %g2 +1: rd %pc, %o3 + add %o3, %lo(1f - 1b), %o3 + jmpl %o3 + %g2, %g0 + nop + + .align 64 +1: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f0, %f2, %f48 +1: FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + STORE_JUMP(o0, f48, 40f) membar #Sync +2: FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + STORE_JUMP(o0, f48, 48f) membar #Sync +3: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + STORE_JUMP(o0, f48, 56f) membar #Sync + +1: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f2, %f4, %f48 +1: FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + STORE_JUMP(o0, f48, 41f) membar #Sync +2: FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + STORE_JUMP(o0, f48, 49f) membar #Sync +3: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + STORE_JUMP(o0, f48, 57f) membar #Sync + +1: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f4, %f6, %f48 +1: FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + STORE_JUMP(o0, f48, 42f) membar #Sync +2: FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + STORE_JUMP(o0, f48, 50f) membar #Sync +3: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + STORE_JUMP(o0, f48, 58f) membar #Sync + +1: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f6, %f8, %f48 +1: FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + STORE_JUMP(o0, f48, 43f) membar #Sync +2: FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + STORE_JUMP(o0, f48, 51f) membar #Sync +3: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + STORE_JUMP(o0, f48, 59f) membar #Sync + +1: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f8, %f10, %f48 +1: FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + STORE_JUMP(o0, f48, 44f) membar #Sync +2: FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + STORE_JUMP(o0, f48, 52f) membar #Sync +3: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + STORE_JUMP(o0, f48, 60f) membar #Sync + +1: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f10, %f12, %f48 +1: FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + STORE_JUMP(o0, f48, 45f) membar #Sync +2: FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + STORE_JUMP(o0, f48, 53f) membar #Sync +3: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + STORE_JUMP(o0, f48, 61f) membar #Sync + +1: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f12, %f14, %f48 +1: FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + STORE_JUMP(o0, f48, 46f) membar #Sync +2: FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + STORE_JUMP(o0, f48, 54f) membar #Sync +3: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + STORE_JUMP(o0, f48, 62f) membar #Sync + +1: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f14, %f16, %f48 +1: FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + STORE_JUMP(o0, f48, 47f) membar #Sync +2: FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + STORE_JUMP(o0, f48, 55f) membar #Sync +3: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + STORE_JUMP(o0, f48, 63f) membar #Sync + +40: FINISH_VISCHUNK(o0, f0, f2, g3) +41: FINISH_VISCHUNK(o0, f2, f4, g3) +42: FINISH_VISCHUNK(o0, f4, f6, g3) +43: FINISH_VISCHUNK(o0, f6, f8, g3) +44: FINISH_VISCHUNK(o0, f8, f10, g3) +45: FINISH_VISCHUNK(o0, f10, f12, g3) +46: FINISH_VISCHUNK(o0, f12, f14, g3) +47: UNEVEN_VISCHUNK(o0, f14, f0, g3) +48: FINISH_VISCHUNK(o0, f16, f18, g3) +49: FINISH_VISCHUNK(o0, f18, f20, g3) +50: FINISH_VISCHUNK(o0, f20, f22, g3) +51: FINISH_VISCHUNK(o0, f22, f24, g3) +52: FINISH_VISCHUNK(o0, f24, f26, g3) +53: FINISH_VISCHUNK(o0, f26, f28, g3) +54: FINISH_VISCHUNK(o0, f28, f30, g3) +55: UNEVEN_VISCHUNK(o0, f30, f0, g3) +56: FINISH_VISCHUNK(o0, f32, f34, g3) +57: FINISH_VISCHUNK(o0, f34, f36, g3) +58: FINISH_VISCHUNK(o0, f36, f38, g3) +59: FINISH_VISCHUNK(o0, f38, f40, g3) +60: FINISH_VISCHUNK(o0, f40, f42, g3) +61: FINISH_VISCHUNK(o0, f42, f44, g3) +62: FINISH_VISCHUNK(o0, f44, f46, g3) +63: UNEVEN_VISCHUNK_LAST(o0, f46, f0, g3) + +93: EX_LD(LOAD(ldd, %o1, %f2)) + add %o1, 8, %o1 + subcc %g3, 8, %g3 + faligndata %f0, %f2, %f8 + EX_ST(STORE(std, %f8, %o0)) + bl,pn %xcc, 95f + add %o0, 8, %o0 + EX_LD(LOAD(ldd, %o1, %f0)) + add %o1, 8, %o1 + subcc %g3, 8, %g3 + faligndata %f2, %f0, %f8 + EX_ST(STORE(std, %f8, %o0)) + bge,pt %xcc, 93b + add %o0, 8, %o0 + +95: brz,pt %o2, 2f + mov %g1, %o1 + +1: EX_LD(LOAD(ldub, %o1, %o3)) + add %o1, 1, %o1 + subcc %o2, 1, %o2 + EX_ST(STORE(stb, %o3, %o0)) + bne,pt %xcc, 1b + add %o0, 1, %o0 + +2: membar #StoreLoad | #StoreStore + VISExit + retl + mov EX_RETVAL(%g5), %o0 + + .align 64 +70: /* 16 < len <= (5 * 64) */ + bne,pn %XCC, 75f + sub %o0, %o1, %o3 + +72: andn %o2, 0xf, %o4 + and %o2, 0xf, %o2 +1: EX_LD(LOAD(ldx, %o1 + 0x00, %o5)) + EX_LD(LOAD(ldx, %o1 + 0x08, %g1)) + subcc %o4, 0x10, %o4 + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 + EX_ST(STORE(stx, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 +73: andcc %o2, 0x8, %g0 + be,pt %XCC, 1f + nop + EX_LD(LOAD(ldx, %o1, %o5)) + sub %o2, 0x8, %o2 + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 +1: andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + EX_LD(LOAD(lduw, %o1, %o5)) + sub %o2, 0x4, %o2 + EX_ST(STORE(stw, %o5, %o1 + %o3)) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop + +75: andcc %o0, 0x7, %g1 + sub %g1, 0x8, %g1 + be,pn %icc, 2f + sub %g0, %g1, %g1 + sub %o2, %g1, %o2 + +1: EX_LD(LOAD(ldub, %o1, %o5)) + subcc %g1, 1, %g1 + EX_ST(STORE(stb, %o5, %o1 + %o3)) + bgu,pt %icc, 1b + add %o1, 1, %o1 + +2: add %o1, %o3, %o0 + andcc %o1, 0x7, %g1 + bne,pt %icc, 8f + sll %g1, 3, %g1 + + cmp %o2, 16 + bgeu,pt %icc, 72b + nop + ba,a,pt %xcc, 73b + +8: mov 64, %o3 + andn %o1, 0x7, %o1 + EX_LD(LOAD(ldx, %o1, %g2)) + sub %o3, %g1, %o3 + andn %o2, 0x7, %o4 + sllx %g2, %g1, %g2 +1: EX_LD(LOAD(ldx, %o1 + 0x8, %g3)) + subcc %o4, 0x8, %o4 + add %o1, 0x8, %o1 + srlx %g3, %o3, %o5 + or %o5, %g2, %o5 + EX_ST(STORE(stx, %o5, %o0)) + add %o0, 0x8, %o0 + bgu,pt %icc, 1b + sllx %g3, %g1, %g2 + + srl %g1, 3, %g1 + andcc %o2, 0x7, %o2 + be,pn %icc, 85f + add %o1, %g1, %o1 + ba,pt %xcc, 90f + sub %o0, %o1, %o3 + + .align 64 +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +1: EX_LD(LOAD(lduw, %o1, %g1)) + subcc %o2, 4, %o2 + EX_ST(STORE(stw, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 4, %o1 + +85: retl + mov EX_RETVAL(%g5), %o0 + + .align 32 +90: EX_LD(LOAD(ldub, %o1, %g1)) + subcc %o2, 1, %o2 + EX_ST(STORE(stb, %g1, %o1 + %o3)) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + mov EX_RETVAL(%g5), %o0 + + .size FUNC_NAME, .-FUNC_NAME diff --git a/arch/sparc64/lib/U3copy_from_user.S b/arch/sparc64/lib/U3copy_from_user.S index 46b446b14..df600b667 100644 --- a/arch/sparc64/lib/U3copy_from_user.S +++ b/arch/sparc64/lib/U3copy_from_user.S @@ -3,410 +3,20 @@ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#include -#include -#include -#include - -#define XCC xcc - -#define EXNV_RAW(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: add %o1, %o3, %o0; \ - ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV4(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: add %o1, %o3, %o0; \ - a, b, %o1; \ - ba U3cfu_fixup; \ - add %o1, 4, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV8(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: add %o1, %o3, %o0; \ - a, b, %o1; \ - ba U3cfu_fixup; \ - add %o1, 8, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - add %o1, %o4, %o1; \ - ba U3cfu_fixup; \ - add %o1, 0x1c0, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - sll %g3, 6, %g3; \ - add %o1, 0x80, %o1; \ - ba U3cfu_fixup; \ - add %o1, %g3, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - add %o1, 0x40, %o1; \ - ba U3cfu_fixup; \ - add %o1, %g3, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; - - .register %g2,#scratch - .register %g3,#scratch - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - */ - - .text - .align 32 - - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ - - .globl U3copy_from_user -U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */ - cmp %o2, 0 - be,pn %XCC, 85f - or %o0, %o1, %o3 - cmp %o2, 16 - bleu,a,pn %XCC, 80f - or %o3, %o2, %o3 - - cmp %o2, 256 - blu,pt %XCC, 70f - andcc %o3, 0x7, %g0 - - ba,pt %xcc, 1f - andcc %o0, 0x3f, %g2 - - /* Here len >= 256 and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -1: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %XCC, 2f - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV_RAW(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - - bg,pt %XCC, 1b - stb %o3, [%o0 + -1] - -2: VISEntryHalf - and %o1, 0x7, %g1 - ba,pt %xcc, 1f - alignaddr %o1, %g0, %o1 - - .align 64 -1: - membar #StoreLoad | #StoreStore | #LoadStore - prefetcha [%o1 + 0x000] %asi, #one_read - prefetcha [%o1 + 0x040] %asi, #one_read - andn %o2, (0x40 - 1), %o4 - prefetcha [%o1 + 0x080] %asi, #one_read - prefetcha [%o1 + 0x0c0] %asi, #one_read - EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) - prefetcha [%o1 + 0x100] %asi, #one_read - EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) - prefetcha [%o1 + 0x140] %asi, #one_read - EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) - prefetcha [%o1 + 0x180] %asi, #one_read - faligndata %f0, %f2, %f16 - EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) - faligndata %f2, %f4, %f18 - EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) - faligndata %f4, %f6, %f20 - EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) - faligndata %f6, %f8, %f22 - - EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) - faligndata %f8, %f10, %f24 - EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) - faligndata %f10, %f12, %f26 - EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) - - sub %o4, 0x80, %o4 - add %o1, 0x40, %o1 - ba,pt %xcc, 1f - srl %o4, 6, %o3 - - .align 64 -1: - EX3(ldda [%o1 + 0x008] %asi, %f2) - faligndata %f12, %f14, %f28 - EX3(ldda [%o1 + 0x010] %asi, %f4) - faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - EX3(ldda [%o1 + 0x018] %asi, %f6) - faligndata %f0, %f2, %f16 - - EX3(ldda [%o1 + 0x020] %asi, %f8) - faligndata %f2, %f4, %f18 - EX3(ldda [%o1 + 0x028] %asi, %f10) - faligndata %f4, %f6, %f20 - EX3(ldda [%o1 + 0x030] %asi, %f12) - faligndata %f6, %f8, %f22 - EX3(ldda [%o1 + 0x038] %asi, %f14) - faligndata %f8, %f10, %f24 - - EX3(ldda [%o1 + 0x040] %asi, %f0) - prefetcha [%o1 + 0x180] %asi, #one_read - faligndata %f10, %f12, %f26 - subcc %o3, 0x01, %o3 - add %o1, 0x40, %o1 - bg,pt %XCC, 1b - add %o0, 0x40, %o0 - - /* Finally we copy the last full 64-byte block. */ - EX3(ldda [%o1 + 0x008] %asi, %f2) - faligndata %f12, %f14, %f28 - EX3(ldda [%o1 + 0x010] %asi, %f4) - faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - EX3(ldda [%o1 + 0x018] %asi, %f6) - faligndata %f0, %f2, %f16 - EX3(ldda [%o1 + 0x020] %asi, %f8) - faligndata %f2, %f4, %f18 - EX3(ldda [%o1 + 0x028] %asi, %f10) - faligndata %f4, %f6, %f20 - EX3(ldda [%o1 + 0x030] %asi, %f12) - faligndata %f6, %f8, %f22 - EX3(ldda [%o1 + 0x038] %asi, %f14) - faligndata %f8, %f10, %f24 - cmp %g1, 0 - be,pt %XCC, 1f - add %o0, 0x40, %o0 - EX4(ldda [%o1 + 0x040] %asi, %f0) -1: faligndata %f10, %f12, %f26 - faligndata %f12, %f14, %f28 - faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - add %o0, 0x40, %o0 - add %o1, 0x40, %o1 - - membar #Sync - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer. - */ - and %o2, 0x3f, %o2 - andcc %o2, 0x38, %g2 - be,pn %XCC, 10f - subcc %g2, 0x8, %g2 - be,pn %XCC, 10f - cmp %g1, 0 - - be,a,pt %XCC, 1f - EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) - -1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f0, %f2, %f8 - std %f8, [%o0 + 0x00] - be,pn %XCC, 10f - add %o0, 0x8, %o0 - EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f2, %f0, %f8 - std %f8, [%o0 + 0x00] - bne,pn %XCC, 1b - add %o0, 0x8, %o0 - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -10: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %XCC, 85f - sub %o0, %o1, %o3 - - andcc %g1, 0x7, %g0 - bne,pn %icc, 90f - andcc %o2, 0x8, %g0 - be,pt %icc, 1f - nop - EXNV(ldxa [%o1] %asi, %o5, add %o2, %g0) - stx %o5, [%o1 + %o3] - add %o1, 0x8, %o1 - -1: andcc %o2, 0x4, %g0 - be,pt %icc, 1f - nop - EXNV(lduwa [%o1] %asi, %o5, and %o2, 0x7) - stw %o5, [%o1 + %o3] - add %o1, 0x4, %o1 - -1: andcc %o2, 0x2, %g0 - be,pt %icc, 1f - nop - EXNV(lduha [%o1] %asi, %o5, and %o2, 0x3) - sth %o5, [%o1 + %o3] - add %o1, 0x2, %o1 - -1: andcc %o2, 0x1, %g0 - be,pt %icc, 85f - nop - EXNV(lduba [%o1] %asi, %o5, and %o2, 0x1) - ba,pt %xcc, 85f - stb %o5, [%o1 + %o3] - -70: /* 16 < len <= 64 */ - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - EXNV8(ldxa [%o1] %asi, %o5, add %o2, %o4) - stx %o5, [%o1 + %o3] - bgu,pt %XCC, 1b - add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 - be,pt %XCC, 1f - nop - sub %o2, 0x4, %o2 - EXNV4(lduwa [%o1] %asi, %o5, add %o2, %g0) - stw %o5, [%o1 + %o3] - add %o1, 0x4, %o1 -1: cmp %o2, 0 - be,pt %XCC, 85f - nop - ba,pt %xcc, 90f - nop - -80: /* 0 < len <= 16 */ - andcc %o3, 0x3, %g0 - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - -1: - subcc %o2, 4, %o2 - EXNV(lduwa [%o1] %asi, %g1, add %o2, %g0) - stw %g1, [%o1 + %o3] - bgu,pt %XCC, 1b - add %o1, 4, %o1 - -85: retl - clr %o0 - - .align 32 -90: - subcc %o2, 1, %o2 - EXNV(lduba [%o1] %asi, %g1, add %o2, %g0) - stb %g1, [%o1 + %o3] - bgu,pt %XCC, 90b - add %o1, 1, %o1 - retl - clr %o0 - -U3cfu_fixup: - /* Since this is copy_from_user(), zero out the rest of the - * kernel buffer. - */ - cmp %o1, 0 - ble,pn %icc, 2f - mov %o1, %g2 - -1: subcc %g2, 1, %g2 - stb %g0, [%o0] - bne,pt %icc, 1b - add %o0, 1, %o0 - -2: retl - mov %o1, %o0 +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME U3copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest +#define EX_RETVAL(x) 0 + +#include "U3memcpy.S" diff --git a/arch/sparc64/lib/U3copy_to_user.S b/arch/sparc64/lib/U3copy_to_user.S index 715227156..f337f22ed 100644 --- a/arch/sparc64/lib/U3copy_to_user.S +++ b/arch/sparc64/lib/U3copy_to_user.S @@ -1,415 +1,33 @@ -/* U3copy_to_user.S: UltraSparc-III optimized memcpy. +/* U3copy_to_user.S: UltraSparc-III optimized copy to userspace. * * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#include -#include -#include -#include - -#define XCC xcc - -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV2(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 1, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV3(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 4, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV4(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 8, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ .align 4; -#define EXBLK1(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - add %o4, 0x1c0, %o1; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - sll %o3, 6, %o3; \ - and %o2, (0x40 - 1), %o2; \ - add %o3, 0x80, %o1; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x80, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x40, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; - - .register %g2,#scratch - .register %g3,#scratch - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - */ - - .text - .align 32 - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ +#define FUNC_NAME U3copy_to_user +#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS +#define EX_RETVAL(x) 0 - .globl U3copy_to_user -U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */ /* Writing to %asi is _expensive_ so we hardcode it. * Reading %asi to check for KERNEL_DS is comparatively * cheap. */ - rd %asi, %g1 - cmp %g1, ASI_AIUS - bne,pn %icc, U3memcpy_user_stub - nop - - cmp %o2, 0 - be,pn %XCC, 85f - or %o0, %o1, %o3 - cmp %o2, 16 - bleu,a,pn %XCC, 80f - or %o3, %o2, %o3 - - cmp %o2, 256 - blu,pt %XCC, 70f - andcc %o3, 0x7, %g0 - - ba,pt %xcc, 1f - andcc %o0, 0x3f, %g2 - - /* Here len >= 256 and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -1: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %XCC, 2f - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - - bg,pt %XCC, 1b - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) - -2: VISEntryHalf - and %o1, 0x7, %g1 - ba,pt %xcc, 1f - alignaddr %o1, %g0, %o1 - - .align 64 -1: - membar #StoreLoad | #StoreStore | #LoadStore - prefetch [%o1 + 0x000], #one_read - prefetch [%o1 + 0x040], #one_read - andn %o2, (0x40 - 1), %o4 - prefetch [%o1 + 0x080], #one_read - prefetch [%o1 + 0x0c0], #one_read - ldd [%o1 + 0x000], %f0 - prefetch [%o1 + 0x100], #one_read - ldd [%o1 + 0x008], %f2 - prefetch [%o1 + 0x140], #one_read - ldd [%o1 + 0x010], %f4 - prefetch [%o1 + 0x180], #one_read - faligndata %f0, %f2, %f16 - ldd [%o1 + 0x018], %f6 - faligndata %f2, %f4, %f18 - ldd [%o1 + 0x020], %f8 - faligndata %f4, %f6, %f20 - ldd [%o1 + 0x028], %f10 - faligndata %f6, %f8, %f22 - - ldd [%o1 + 0x030], %f12 - faligndata %f8, %f10, %f24 - ldd [%o1 + 0x038], %f14 - faligndata %f10, %f12, %f26 - ldd [%o1 + 0x040], %f0 - - sub %o4, 0x80, %o4 - add %o1, 0x40, %o1 - ba,pt %xcc, 1f - srl %o4, 6, %o3 - - .align 64 -1: - ldd [%o1 + 0x008], %f2 - faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 - faligndata %f14, %f0, %f30 - EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) - ldd [%o1 + 0x018], %f6 - faligndata %f0, %f2, %f16 - - ldd [%o1 + 0x020], %f8 - faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 - faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 - faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 - faligndata %f8, %f10, %f24 - - ldd [%o1 + 0x040], %f0 - prefetch [%o1 + 0x180], #one_read - faligndata %f10, %f12, %f26 - subcc %o3, 0x01, %o3 - add %o1, 0x40, %o1 - bg,pt %XCC, 1b - add %o0, 0x40, %o0 - - /* Finally we copy the last full 64-byte block. */ - ldd [%o1 + 0x008], %f2 - faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 - faligndata %f14, %f0, %f30 - EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) - ldd [%o1 + 0x018], %f6 - faligndata %f0, %f2, %f16 - ldd [%o1 + 0x020], %f8 - faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 - faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 - faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 - faligndata %f8, %f10, %f24 - cmp %g1, 0 - be,pt %XCC, 1f - add %o0, 0x40, %o0 - ldd [%o1 + 0x040], %f0 -1: faligndata %f10, %f12, %f26 - faligndata %f12, %f14, %f28 - faligndata %f14, %f0, %f30 - EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) - add %o0, 0x40, %o0 - add %o1, 0x40, %o1 - - membar #Sync - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer. - */ - and %o2, 0x3f, %o2 - andcc %o2, 0x38, %g2 - be,pn %XCC, 2f - subcc %g2, 0x8, %g2 - be,pn %XCC, 2f - cmp %g1, 0 - - be,a,pt %XCC, 1f - ldd [%o1 + 0x00], %f0 - -1: ldd [%o1 + 0x08], %f2 - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f0, %f2, %f8 - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) - be,pn %XCC, 2f - add %o0, 0x8, %o0 - ldd [%o1 + 0x08], %f0 - add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 - subcc %g2, 0x8, %g2 - faligndata %f2, %f0, %f8 - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) - bne,pn %XCC, 1b - add %o0, 0x8, %o0 - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -2: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %XCC, 85f - sub %o0, %o1, %o3 - - andcc %g1, 0x7, %g0 - bne,pn %icc, 90f - andcc %o2, 0x8, %g0 - be,pt %icc, 1f - nop - ldx [%o1], %o5 - EXNV(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - add %o1, 0x8, %o1 - -1: andcc %o2, 0x4, %g0 - be,pt %icc, 1f - nop - lduw [%o1], %o5 - EXNV(stwa %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x7) - add %o1, 0x4, %o1 - -1: andcc %o2, 0x2, %g0 - be,pt %icc, 1f - nop - lduh [%o1], %o5 - EXNV(stha %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x3) - add %o1, 0x2, %o1 - -1: andcc %o2, 0x1, %g0 - be,pt %icc, 85f - nop - ldub [%o1], %o5 - ba,pt %xcc, 85f - EXNV(stba %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x1) - -70: /* 16 < len <= 64 */ - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - ldx [%o1], %o5 - EXNV4(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %o4) - bgu,pt %XCC, 1b - add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 - be,pt %XCC, 1f - nop - sub %o2, 0x4, %o2 - lduw [%o1], %o5 - EXNV3(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - add %o1, 0x4, %o1 -1: cmp %o2, 0 - be,pt %XCC, 85f - nop - ba,pt %xcc, 90f - nop - -80: /* 0 < len <= 16 */ - andcc %o3, 0x3, %g0 - bne,pn %XCC, 90f - sub %o0, %o1, %o3 - -1: - subcc %o2, 4, %o2 - lduw [%o1], %g1 - EXNV3(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - bgu,pt %XCC, 1b - add %o1, 4, %o1 - -85: retl - clr %o0 +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ - .align 32 -90: - subcc %o2, 1, %o2 - ldub [%o1], %g1 - EXNV2(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) - bgu,pt %XCC, 90b - add %o1, 1, %o1 - retl - clr %o0 +#include "U3memcpy.S" diff --git a/arch/sparc64/lib/U3memcpy.S b/arch/sparc64/lib/U3memcpy.S index e9982deef..5cde95446 100644 --- a/arch/sparc64/lib/U3memcpy.S +++ b/arch/sparc64/lib/U3memcpy.S @@ -6,14 +6,50 @@ #ifdef __KERNEL__ #include #include -#include -#include #else #define ASI_BLK_P 0xf0 #define FPRS_FEF 0x04 +#ifdef MEMCPY_DEBUG +#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \ + clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0; +#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#else #define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs #endif +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x +#endif + +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef STORE_BLK +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_P +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME U3memcpy +#endif + +#ifndef PREAMBLE +#define PREAMBLE +#endif #ifndef XCC #define XCC xcc @@ -33,7 +69,7 @@ */ .text - .align 32 + .align 64 /* The cheetah's flexible spine, oversized liver, enlarged heart, * slender muscular body, and claws make it the swiftest hunter @@ -41,137 +77,158 @@ * of up to 2.4GB per second. */ - .globl U3memcpy -U3memcpy: /* %o0=dst, %o1=src, %o2=len */ + .globl FUNC_NAME + .type FUNC_NAME,#function +FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ + PREAMBLE mov %o0, %g5 cmp %o2, 0 be,pn %XCC, 85f or %o0, %o1, %o3 cmp %o2, 16 - bleu,a,pn %XCC, 70f + blu,a,pn %XCC, 80f or %o3, %o2, %o3 - cmp %o2, 256 - blu,pt %XCC, 80f + cmp %o2, (3 * 64) + blu,pt %XCC, 70f andcc %o3, 0x7, %g0 - ba,pt %xcc, 1f - andcc %o0, 0x3f, %g2 - - /* Here len >= 256 and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. + /* Clobbers o5/g1/g2/g3/g7/icc/xcc. We must preserve + * o5 from here until we hit VISExitHalf. */ - .align 64 -1: + VISEntryHalf + /* Is 'dst' already aligned on an 64-byte boundary? */ + andcc %o0, 0x3f, %g2 be,pt %XCC, 2f /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number * of bytes to copy to make 'dst' 64-byte aligned. We pre- * subtract this from 'len'. */ - sub %g2, 0x40, %g2 + sub %o0, %o1, %o4 + sub %g2, 0x40, %g2 sub %g0, %g2, %g2 sub %o2, %g2, %o2 + andcc %g2, 0x7, %g1 + be,pt %icc, 2f + and %g2, 0x38, %g2 - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 +1: subcc %g1, 0x1, %g1 + EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) + EX_ST(STORE(stb, %o3, %o1 + %o4)) + bgu,pt %XCC, 1b + add %o1, 0x1, %o1 - bg,pt %XCC, 1b - stb %o3, [%o0 + -1] + add %o1, %o4, %o0 -2: VISEntryHalf +2: cmp %g2, 0x0 and %o1, 0x7, %g1 - ba,pt %xcc, 1f + be,pt %icc, 3f alignaddr %o1, %g0, %o1 - .align 64 -1: - membar #StoreLoad | #StoreStore | #LoadStore - prefetch [%o1 + 0x000], #one_read - prefetch [%o1 + 0x040], #one_read + EX_LD(LOAD(ldd, %o1, %f4)) +1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f4, %f6, %f0 + EX_ST(STORE(std, %f0, %o0)) + be,pn %icc, 3f + add %o0, 0x8, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f6, %f4, %f2 + EX_ST(STORE(std, %f2, %o0)) + bne,pt %icc, 1b + add %o0, 0x8, %o0 + +3: LOAD(prefetch, %o1 + 0x000, #one_read) + LOAD(prefetch, %o1 + 0x040, #one_read) andn %o2, (0x40 - 1), %o4 - prefetch [%o1 + 0x080], #one_read - prefetch [%o1 + 0x0c0], #one_read - ldd [%o1 + 0x000], %f0 - prefetch [%o1 + 0x100], #one_read - ldd [%o1 + 0x008], %f2 - prefetch [%o1 + 0x140], #one_read - ldd [%o1 + 0x010], %f4 - prefetch [%o1 + 0x180], #one_read + LOAD(prefetch, %o1 + 0x080, #one_read) + LOAD(prefetch, %o1 + 0x0c0, #one_read) + LOAD(prefetch, %o1 + 0x100, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x000, %f0)) + LOAD(prefetch, %o1 + 0x140, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) + LOAD(prefetch, %o1 + 0x180, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) + LOAD(prefetch, %o1 + 0x1c0, #one_read) faligndata %f0, %f2, %f16 - ldd [%o1 + 0x018], %f6 + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) faligndata %f2, %f4, %f18 - ldd [%o1 + 0x020], %f8 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) faligndata %f4, %f6, %f20 - ldd [%o1 + 0x028], %f10 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) faligndata %f6, %f8, %f22 - ldd [%o1 + 0x030], %f12 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) faligndata %f8, %f10, %f24 - ldd [%o1 + 0x038], %f14 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) faligndata %f10, %f12, %f26 - ldd [%o1 + 0x040], %f0 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) - sub %o4, 0x80, %o4 + subcc %o4, 0x80, %o4 add %o1, 0x40, %o1 - ba,pt %xcc, 1f + bgu,pt %XCC, 1f srl %o4, 6, %o3 + ba,pt %xcc, 2f + nop .align 64 1: - ldd [%o1 + 0x008], %f2 + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - ldd [%o1 + 0x018], %f6 + EX_ST(STORE_BLK(%f16, %o0)) + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) faligndata %f0, %f2, %f16 + add %o0, 0x40, %o0 - ldd [%o1 + 0x020], %f8 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) + subcc %o3, 0x01, %o3 faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 - faligndata %f8, %f10, %f24 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) - ldd [%o1 + 0x040], %f0 - prefetch [%o1 + 0x180], #one_read + faligndata %f8, %f10, %f24 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) + LOAD(prefetch, %o1 + 0x1c0, #one_read) faligndata %f10, %f12, %f26 - subcc %o3, 0x01, %o3 - add %o1, 0x40, %o1 bg,pt %XCC, 1b - add %o0, 0x40, %o0 + add %o1, 0x40, %o1 /* Finally we copy the last full 64-byte block. */ - ldd [%o1 + 0x008], %f2 +2: + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) faligndata %f12, %f14, %f28 - ldd [%o1 + 0x010], %f4 + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P - ldd [%o1 + 0x018], %f6 + EX_ST(STORE_BLK(%f16, %o0)) + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) faligndata %f0, %f2, %f16 - ldd [%o1 + 0x020], %f8 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) faligndata %f2, %f4, %f18 - ldd [%o1 + 0x028], %f10 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) faligndata %f4, %f6, %f20 - ldd [%o1 + 0x030], %f12 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) faligndata %f6, %f8, %f22 - ldd [%o1 + 0x038], %f14 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) faligndata %f8, %f10, %f24 cmp %g1, 0 be,pt %XCC, 1f add %o0, 0x40, %o0 - ldd [%o1 + 0x040], %f0 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) 1: faligndata %f10, %f12, %f26 faligndata %f12, %f14, %f28 faligndata %f14, %f0, %f30 - stda %f16, [%o0] ASI_BLK_P + EX_ST(STORE_BLK(%f16, %o0)) add %o0, 0x40, %o0 add %o1, 0x40, %o1 membar #Sync @@ -189,23 +246,22 @@ U3memcpy: /* %o0=dst, %o1=src, %o2=len */ be,pn %XCC, 2f cmp %g1, 0 + sub %o2, %g2, %o2 be,a,pt %XCC, 1f - ldd [%o1 + 0x00], %f0 + EX_LD(LOAD(ldd, %o1 + 0x00, %f0)) -1: ldd [%o1 + 0x08], %f2 +1: EX_LD(LOAD(ldd, %o1 + 0x08, %f2)) add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 subcc %g2, 0x8, %g2 faligndata %f0, %f2, %f8 - std %f8, [%o0 + 0x00] + EX_ST(STORE(std, %f8, %o0)) be,pn %XCC, 2f add %o0, 0x8, %o0 - ldd [%o1 + 0x08], %f0 + EX_LD(LOAD(ldd, %o1 + 0x08, %f0)) add %o1, 0x8, %o1 - sub %o2, 0x8, %o2 subcc %g2, 0x8, %g2 faligndata %f2, %f0, %f8 - std %f8, [%o0 + 0x00] + EX_ST(STORE(std, %f8, %o0)) bne,pn %XCC, 1b add %o0, 0x8, %o0 @@ -225,48 +281,60 @@ U3memcpy: /* %o0=dst, %o1=src, %o2=len */ andcc %o2, 0x8, %g0 be,pt %icc, 1f nop - ldx [%o1], %o5 - stx %o5, [%o1 + %o3] + EX_LD(LOAD(ldx, %o1, %o5)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) add %o1, 0x8, %o1 1: andcc %o2, 0x4, %g0 be,pt %icc, 1f nop - lduw [%o1], %o5 - stw %o5, [%o1 + %o3] + EX_LD(LOAD(lduw, %o1, %o5)) + EX_ST(STORE(stw, %o5, %o1 + %o3)) add %o1, 0x4, %o1 1: andcc %o2, 0x2, %g0 be,pt %icc, 1f nop - lduh [%o1], %o5 - sth %o5, [%o1 + %o3] + EX_LD(LOAD(lduh, %o1, %o5)) + EX_ST(STORE(sth, %o5, %o1 + %o3)) add %o1, 0x2, %o1 1: andcc %o2, 0x1, %g0 be,pt %icc, 85f nop - ldub [%o1], %o5 + EX_LD(LOAD(ldub, %o1, %o5)) ba,pt %xcc, 85f - stb %o5, [%o1 + %o3] + EX_ST(STORE(stb, %o5, %o1 + %o3)) + .align 64 70: /* 16 < len <= 64 */ - bne,pn %XCC, 90f + bne,pn %XCC, 75f sub %o0, %o1, %o3 - andn %o2, 0x7, %o4 - and %o2, 0x7, %o2 -1: subcc %o4, 0x8, %o4 - ldx [%o1], %o5 - stx %o5, [%o1 + %o3] +72: + andn %o2, 0xf, %o4 + and %o2, 0xf, %o2 +1: subcc %o4, 0x10, %o4 + EX_LD(LOAD(ldx, %o1 + 0x00, %o5)) + EX_LD(LOAD(ldx, %o1 + 0x08, %g1)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 + EX_ST(STORE(stx, %g1, %o1 + %o3)) bgu,pt %XCC, 1b add %o1, 0x8, %o1 - andcc %o2, 0x4, %g0 +73: andcc %o2, 0x8, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x8, %o2 + EX_LD(LOAD(ldx, %o1, %o5)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 +1: andcc %o2, 0x4, %g0 be,pt %XCC, 1f nop sub %o2, 0x4, %o2 - lduw [%o1], %o5 - stw %o5, [%o1 + %o3] + EX_LD(LOAD(lduw, %o1, %o5)) + EX_ST(STORE(stw, %o5, %o1 + %o3)) add %o1, 0x4, %o1 1: cmp %o2, 0 be,pt %XCC, 85f @@ -274,6 +342,53 @@ U3memcpy: /* %o0=dst, %o1=src, %o2=len */ ba,pt %xcc, 90f nop +75: + andcc %o0, 0x7, %g1 + sub %g1, 0x8, %g1 + be,pn %icc, 2f + sub %g0, %g1, %g1 + sub %o2, %g1, %o2 + +1: subcc %g1, 1, %g1 + EX_LD(LOAD(ldub, %o1, %o5)) + EX_ST(STORE(stb, %o5, %o1 + %o3)) + bgu,pt %icc, 1b + add %o1, 1, %o1 + +2: add %o1, %o3, %o0 + andcc %o1, 0x7, %g1 + bne,pt %icc, 8f + sll %g1, 3, %g1 + + cmp %o2, 16 + bgeu,pt %icc, 72b + nop + ba,a,pt %xcc, 73b + +8: mov 64, %o3 + andn %o1, 0x7, %o1 + EX_LD(LOAD(ldx, %o1, %g2)) + sub %o3, %g1, %o3 + andn %o2, 0x7, %o4 + sllx %g2, %g1, %g2 +1: EX_LD(LOAD(ldx, %o1 + 0x8, %g3)) + subcc %o4, 0x8, %o4 + add %o1, 0x8, %o1 + srlx %g3, %o3, %o5 + or %o5, %g2, %o5 + EX_ST(STORE(stx, %o5, %o0)) + add %o0, 0x8, %o0 + bgu,pt %icc, 1b + sllx %g3, %g1, %g2 + + srl %g1, 3, %g1 + andcc %o2, 0x7, %o2 + be,pn %icc, 85f + add %o1, %g1, %o1 + ba,pt %xcc, 90f + sub %o0, %o1, %o3 + + .align 64 80: /* 0 < len <= 16 */ andcc %o3, 0x3, %g0 bne,pn %XCC, 90f @@ -281,34 +396,22 @@ U3memcpy: /* %o0=dst, %o1=src, %o2=len */ 1: subcc %o2, 4, %o2 - lduw [%o1], %g1 - stw %g1, [%o1 + %o3] + EX_LD(LOAD(lduw, %o1, %g1)) + EX_ST(STORE(stw, %g1, %o1 + %o3)) bgu,pt %XCC, 1b add %o1, 4, %o1 85: retl - mov %g5, %o0 + mov EX_RETVAL(%g5), %o0 - .align 32 + .align 32 90: subcc %o2, 1, %o2 - ldub [%o1], %g1 - stb %g1, [%o1 + %o3] + EX_LD(LOAD(ldub, %o1, %g1)) + EX_ST(STORE(stb, %g1, %o1 + %o3)) bgu,pt %XCC, 90b add %o1, 1, %o1 retl - mov %g5, %o0 + mov EX_RETVAL(%g5), %o0 - /* Act like copy_{to,in}_user(), ie. return zero instead - * of original destination pointer. This is invoked when - * copy_{to,in}_user() finds that %asi is kernel space. - */ - .globl U3memcpy_user_stub -U3memcpy_user_stub: - save %sp, -192, %sp - mov %i0, %o0 - mov %i1, %o1 - call U3memcpy - mov %i2, %o2 - ret - restore %g0, %g0, %o0 + .size FUNC_NAME, .-FUNC_NAME diff --git a/arch/sparc64/lib/U3patch.S b/arch/sparc64/lib/U3patch.S new file mode 100644 index 000000000..e2b6c5e4b --- /dev/null +++ b/arch/sparc64/lib/U3patch.S @@ -0,0 +1,32 @@ +/* U3patch.S: Patch Ultra-I routines with Ultra-III variant. + * + * Copyright (C) 2004 David S. Miller + */ + +#define BRANCH_ALWAYS 0x10680000 +#define NOP 0x01000000 +#define ULTRA3_DO_PATCH(OLD, NEW) \ + sethi %hi(NEW), %g1; \ + or %g1, %lo(NEW), %g1; \ + sethi %hi(OLD), %g2; \ + or %g2, %lo(OLD), %g2; \ + sub %g1, %g2, %g1; \ + sethi %hi(BRANCH_ALWAYS), %g3; \ + srl %g1, 2, %g1; \ + or %g3, %lo(BRANCH_ALWAYS), %g3; \ + or %g3, %g1, %g3; \ + stw %g3, [%g2]; \ + sethi %hi(NOP), %g3; \ + or %g3, %lo(NOP), %g3; \ + stw %g3, [%g2 + 0x4]; \ + flush %g2; + + .globl cheetah_patch_copyops + .type cheetah_patch_copyops,#function +cheetah_patch_copyops: + ULTRA3_DO_PATCH(memcpy, U3memcpy) + ULTRA3_DO_PATCH(___copy_from_user, U3copy_from_user) + ULTRA3_DO_PATCH(___copy_to_user, U3copy_to_user) + retl + nop + .size cheetah_patch_copyops,.-cheetah_patch_copyops diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S index a0d6d8ac3..26463d8a4 100644 --- a/arch/sparc64/lib/atomic.S +++ b/arch/sparc64/lib/atomic.S @@ -10,6 +10,7 @@ .align 64 .globl __atomic_add + .type __atomic_add,#function __atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ lduw [%o1], %g5 add %g5, %o0, %g7 @@ -19,8 +20,10 @@ __atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ membar #StoreLoad | #StoreStore retl add %g7, %o0, %o0 + .size __atomic_add, .-__atomic_add .globl __atomic_sub + .type __atomic_sub,#function __atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */ lduw [%o1], %g5 sub %g5, %o0, %g7 @@ -30,8 +33,10 @@ __atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */ membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 + .size __atomic_sub, .-__atomic_sub .globl __atomic64_add + .type __atomic64_add,#function __atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ ldx [%o1], %g5 add %g5, %o0, %g7 @@ -41,8 +46,10 @@ __atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ membar #StoreLoad | #StoreStore retl add %g7, %o0, %o0 + .size __atomic64_add, .-__atomic64_add .globl __atomic64_sub + .type __atomic64_sub,#function __atomic64_sub: /* %o0 = increment, %o1 = atomic_ptr */ ldx [%o1], %g5 sub %g5, %o0, %g7 @@ -52,4 +59,4 @@ __atomic64_sub: /* %o0 = increment, %o1 = atomic_ptr */ membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 - + .size __atomic64_sub, .-__atomic64_sub diff --git a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S index 0c2aacc83..c1e370068 100644 --- a/arch/sparc64/lib/bitops.S +++ b/arch/sparc64/lib/bitops.S @@ -9,6 +9,7 @@ .text .align 64 .globl ___test_and_set_bit + .type ___test_and_set_bit,#function ___test_and_set_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 @@ -26,8 +27,10 @@ ___test_and_set_bit: /* %o0=nr, %o1=addr */ ldx [%o1], %g7 2: retl membar #StoreLoad | #StoreStore + .size ___test_and_set_bit, .-___test_and_set_bit .globl ___test_and_clear_bit + .type ___test_and_clear_bit,#function ___test_and_clear_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 @@ -45,8 +48,10 @@ ___test_and_clear_bit: /* %o0=nr, %o1=addr */ ldx [%o1], %g7 2: retl membar #StoreLoad | #StoreStore + .size ___test_and_clear_bit, .-___test_and_clear_bit .globl ___test_and_change_bit + .type ___test_and_change_bit,#function ___test_and_change_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 @@ -64,41 +69,4 @@ ___test_and_change_bit: /* %o0=nr, %o1=addr */ 2: retl membar #StoreLoad | #StoreStore nop - - .globl ___test_and_set_le_bit -___test_and_set_le_bit: /* %o0=nr, %o1=addr */ - srlx %o0, 5, %g1 - mov 1, %g5 - sllx %g1, 2, %g3 - and %o0, 31, %g2 - sllx %g5, %g2, %g5 - add %o1, %g3, %o1 - lduwa [%o1] ASI_PL, %g7 -1: andcc %g7, %g5, %o0 - bne,pn %icc, 2f - xor %g7, %g5, %g1 - casa [%o1] ASI_PL, %g7, %g1 - cmp %g7, %g1 - bne,a,pn %icc, 1b - lduwa [%o1] ASI_PL, %g7 -2: retl - membar #StoreLoad | #StoreStore - - .globl ___test_and_clear_le_bit -___test_and_clear_le_bit: /* %o0=nr, %o1=addr */ - srlx %o0, 5, %g1 - mov 1, %g5 - sllx %g1, 2, %g3 - and %o0, 31, %g2 - sllx %g5, %g2, %g5 - add %o1, %g3, %o1 - lduwa [%o1] ASI_PL, %g7 -1: andcc %g7, %g5, %o0 - be,pn %icc, 2f - xor %g7, %g5, %g1 - casa [%o1] ASI_PL, %g7, %g1 - cmp %g7, %g1 - bne,a,pn %icc, 1b - lduwa [%o1] ASI_PL, %g7 -2: retl - membar #StoreLoad | #StoreStore + .size ___test_and_change_bit, .-___test_and_change_bit diff --git a/arch/sparc64/lib/copy_in_user.S b/arch/sparc64/lib/copy_in_user.S new file mode 100644 index 000000000..816076c0b --- /dev/null +++ b/arch/sparc64/lib/copy_in_user.S @@ -0,0 +1,119 @@ +/* copy_in_user.S: Copy from userspace to userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#include + +#define XCC xcc + +#define EX(x,y) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + + .register %g2,#scratch + .register %g3,#scratch + + .text + .align 32 + + /* Don't try to get too fancy here, just nice and + * simple. This is predominantly used for well aligned + * small copies in the compat layer. It is also used + * to copy register windows around during thread cloning. + */ + + .globl ___copy_in_user + .type ___copy_in_user,#function +___copy_in_user: /* %o0=dst, %o1=src, %o2=len */ + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ + rd %asi, %g1 + cmp %g1, ASI_AIUS + bne,pn %icc, memcpy_user_stub + nop + + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + /* 16 < len <= 64 */ + andcc %o3, 0x7, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + EX(ldxa [%o1] %asi, %o5) + EX(stxa %o5, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + EX(lduwa [%o1] %asi, %o5) + EX(stwa %o5, [%o1 + %o3] ASI_AIUS) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop + +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +82: + subcc %o2, 4, %o2 + EX(lduwa [%o1] %asi, %g1) + EX(stwa %g1, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 82b + add %o1, 4, %o1 + +85: retl + clr %o0 + + .align 32 +90: + subcc %o2, 1, %o2 + EX(lduba [%o1] %asi, %g1) + EX(stba %g1, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + clr %o0 + + .size ___copy_in_user, .-___copy_in_user + + /* Act like copy_{to,in}_user(), ie. return zero instead + * of original destination pointer. This is invoked when + * copy_{to,in}_user() finds that %asi is kernel space. + */ + .globl memcpy_user_stub + .type memcpy_user_stub,#function +memcpy_user_stub: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + call memcpy + mov %i2, %o2 + ret + restore %g0, %g0, %o0 + .size memcpy_user_stub, .-memcpy_user_stub diff --git a/arch/sparc64/lib/copy_page.S b/arch/sparc64/lib/copy_page.S index 862eefb17..23ebf2c97 100644 --- a/arch/sparc64/lib/copy_page.S +++ b/arch/sparc64/lib/copy_page.S @@ -45,6 +45,7 @@ .align 32 .globl copy_user_page + .type copy_user_page,#function copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ lduw [%g6 + TI_PRE_COUNT], %o4 sethi %uhi(PAGE_OFFSET), %g2 @@ -237,3 +238,5 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ retl stw %o4, [%g6 + TI_PRE_COUNT] + + .size copy_user_page, .-copy_user_page diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c index 9e083e27d..9fb4dedc8 100644 --- a/arch/sparc64/lib/debuglocks.c +++ b/arch/sparc64/lib/debuglocks.c @@ -84,7 +84,7 @@ again: put_cpu(); } -int _spin_trylock(spinlock_t *lock) +int _do_spin_trylock(spinlock_t *lock) { unsigned long val, caller; int cpu = get_cpu(); diff --git a/arch/sparc64/lib/delay.c b/arch/sparc64/lib/delay.c new file mode 100644 index 000000000..f55f528a7 --- /dev/null +++ b/arch/sparc64/lib/delay.c @@ -0,0 +1,49 @@ +/* delay.c: Delay loops for sparc64 + * + * Copyright (C) 2004 David S. Miller + * + * Based heavily upon x86 variant which is: + * Copyright (C) 1993 Linus Torvalds + * Copyright (C) 1997 Martin Mares + */ + +#include + +void __delay(unsigned long loops) +{ + __asm__ __volatile__( +" b,pt %%xcc, 1f\n" +" cmp %0, 0\n" +" .align 32\n" +"1:\n" +" bne,pt %%xcc, 1b\n" +" subcc %0, 1, %0\n" + : "=&r" (loops) + : "0" (loops) + : "cc"); +} + +/* We used to multiply by HZ after shifting down by 32 bits + * but that runs into problems for higher values of HZ and + * slow cpus. + */ +void __const_udelay(unsigned long n) +{ + n *= 4; + + n *= (cpu_data(smp_processor_id()).udelay_val * (HZ/4)); + n >>= 32; + + __delay(n + 1); +} + +void __udelay(unsigned long n) +{ + __const_udelay(n * 0x10c7UL); +} + + +void __ndelay(unsigned long n) +{ + __const_udelay(n * 0x5UL); +} diff --git a/arch/sparc64/lib/iomap.c b/arch/sparc64/lib/iomap.c new file mode 100644 index 000000000..ac556db06 --- /dev/null +++ b/arch/sparc64/lib/iomap.c @@ -0,0 +1,48 @@ +/* + * Implement the sparc64 iomap interfaces + */ +#include +#include +#include + +/* Create a virtual mapping cookie for an IO port range */ +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return (void __iomem *) (unsigned long) port; +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem * addr) +{ + /* nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); diff --git a/arch/sparc64/lib/ipcsum.S b/arch/sparc64/lib/ipcsum.S index e7d349fac..58ca5b9a8 100644 --- a/arch/sparc64/lib/ipcsum.S +++ b/arch/sparc64/lib/ipcsum.S @@ -1,6 +1,7 @@ .text - .align 32 - .globl ip_fast_csum + .align 32 + .globl ip_fast_csum + .type ip_fast_csum,#function ip_fast_csum: /* %o0 = iph, %o1 = ihl */ sub %o1, 4, %g7 lduw [%o0 + 0x00], %o2 @@ -30,3 +31,4 @@ ip_fast_csum: /* %o0 = iph, %o1 = ihl */ set 0xffff, %o1 retl and %o2, %o1, %o0 + .size ip_fast_csum, .-ip_fast_csum diff --git a/arch/sparc64/lib/memmove.S b/arch/sparc64/lib/memmove.S new file mode 100644 index 000000000..ca8781d0b --- /dev/null +++ b/arch/sparc64/lib/memmove.S @@ -0,0 +1,33 @@ +/* memmove.S: Simple memmove implementation. + * + * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + + .text + .align 32 + .globl memmove + .type memmove,#function +memmove: + mov %o0, %g1 + cmp %o0, %o1 + blu,pt %xcc, memcpy + sub %o0, %o1, %g5 + add %o1, %o2, %g3 + cmp %g3, %o0 + bleu,pt %xcc, memcpy + add %o1, %o2, %g5 + add %o0, %o2, %o5 + + sub %g5, 1, %o1 + sub %o5, 1, %o0 +1: ldub [%o1], %g5 + subcc %o2, 1, %o2 + sub %o1, 1, %o1 + stb %g5, [%o0] + bne,pt %icc, 1b + sub %o0, 1, %o0 + + retl + mov %g1, %o0 + .size memmove, .-memmove diff --git a/arch/sparc64/lib/strlen.S b/arch/sparc64/lib/strlen.S index 55527f639..066ec1ed7 100644 --- a/arch/sparc64/lib/strlen.S +++ b/arch/sparc64/lib/strlen.S @@ -9,9 +9,9 @@ #define HI_MAGIC 0x80808080 .align 32 - .global strlen, __strlen + .globl strlen + .type strlen,#function strlen: -__strlen: mov %o0, %o1 andcc %o0, 3, %g0 be,pt %icc, 9f @@ -76,3 +76,5 @@ __strlen: 13: retl mov 2, %o0 + + .size strlen, .-strlen diff --git a/arch/sparc64/lib/strncmp.S b/arch/sparc64/lib/strncmp.S index 474ba7296..6f14f53db 100644 --- a/arch/sparc64/lib/strncmp.S +++ b/arch/sparc64/lib/strncmp.S @@ -7,9 +7,9 @@ #include .text - .align 4 - .global __strncmp, strncmp -__strncmp: + .align 32 + .globl strncmp + .type strncmp,#function strncmp: brlez,pn %o2, 3f lduba [%o0] (ASI_PNF), %o3 @@ -29,3 +29,4 @@ strncmp: 3: retl clr %o0 + .size strncmp, .-strncmp diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S index 9abb371e4..93d600a31 100644 --- a/arch/sparc64/lib/strncpy_from_user.S +++ b/arch/sparc64/lib/strncpy_from_user.S @@ -12,7 +12,7 @@ 0: .xword 0x0101010101010101 .text - .align 4 + .align 32 /* Must return: * @@ -31,6 +31,7 @@ */ .globl __strncpy_from_user + .type __strncpy_from_user,#function __strncpy_from_user: /* %o0=dest, %o1=src, %o2=count */ sethi %hi(0b), %o5 ! IEU0 Group @@ -122,6 +123,7 @@ __strncpy_from_user: mov %o2, %o0 2: retl add %o2, %o3, %o0 + .size __strncpy_from_user, .-__strncpy_from_user .section .fixup,#alloc,#execinstr .align 4 diff --git a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c new file mode 100644 index 000000000..58ec56050 --- /dev/null +++ b/arch/sparc64/lib/user_fixup.c @@ -0,0 +1,68 @@ +/* user_fixup.c: Fix up user copy faults. + * + * Copyright (C) 2004 David S. Miller + */ + +#include +#include +#include +#include +#include + +/* Calculating the exact fault address when using + * block loads and stores can be very complicated. + * Instead of trying to be clever and handling all + * of the cases, just fix things up simply here. + */ + +unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) +{ + char *dst = to; + const char __user *src = from; + + while (size--) { + if (__get_user(*dst, src)) + break; + dst++; + src++; + } + + if (size) + memset(dst, 0, size); + + return size; +} + +unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) +{ + char __user *dst = to; + const char *src = from; + + while (size--) { + if (__put_user(*src, dst)) + break; + dst++; + src++; + } + + return size; +} + +unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) +{ + char __user *dst = to; + char __user *src = from; + + while (size--) { + char tmp; + + if (__get_user(tmp, src)) + break; + if (__put_user(tmp, dst)) + break; + dst++; + src++; + } + + return size; +} diff --git a/arch/sparc64/lib/xor.S b/arch/sparc64/lib/xor.S index 8eeba353d..f748fd6bb 100644 --- a/arch/sparc64/lib/xor.S +++ b/arch/sparc64/lib/xor.S @@ -18,8 +18,9 @@ * !(len & 127) && len >= 256 */ .text - .globl xor_vis_2 - .type xor_vis_2,@function + .align 32 + .globl xor_vis_2 + .type xor_vis_2,#function xor_vis_2: rd %fprs, %o5 andcc %o5, FPRS_FEF|FPRS_DU, %g0 @@ -87,11 +88,10 @@ xor_vis_2: wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_2, .-xor_vis_2 + .size xor_vis_2, .-xor_vis_2 - - .globl xor_vis_3 - .type xor_vis_3,@function + .globl xor_vis_3 + .type xor_vis_3,#function xor_vis_3: rd %fprs, %o5 andcc %o5, FPRS_FEF|FPRS_DU, %g0 @@ -156,11 +156,10 @@ xor_vis_3: wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_3, .-xor_vis_3 - + .size xor_vis_3, .-xor_vis_3 - .globl xor_vis_4 - .type xor_vis_4,@function + .globl xor_vis_4 + .type xor_vis_4,#function xor_vis_4: rd %fprs, %o5 andcc %o5, FPRS_FEF|FPRS_DU, %g0 @@ -244,11 +243,10 @@ xor_vis_4: wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_4, .-xor_vis_4 - + .size xor_vis_4, .-xor_vis_4 - .globl xor_vis_5 - .type xor_vis_5,@function + .globl xor_vis_5 + .type xor_vis_5,#function xor_vis_5: mov %o5, %g5 rd %fprs, %o5 @@ -353,4 +351,4 @@ xor_vis_5: wr %g1, %g0, %asi retl wr %g0, 0, %fprs - .size xor_vis_5, .-xor_vis_5 + .size xor_vis_5, .-xor_vis_5 diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 49c3dd29a..63b989f3f 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -27,6 +27,7 @@ #include #include #include +#include #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) @@ -147,6 +148,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk, printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", (tsk->mm ? (unsigned long) tsk->mm->pgd : (unsigned long) tsk->active_mm->pgd)); + if (notify_die(DIE_GPF, "general protection fault", regs, + 0, 0, SIGSEGV) == NOTIFY_STOP) + return; die_if_kernel("Oops", regs); } @@ -318,8 +322,13 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs) int si_code, fault_code; unsigned long address; - si_code = SEGV_MAPERR; fault_code = get_thread_fault_code(); + + if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, + fault_code, 0, SIGSEGV) == NOTIFY_STOP) + return; + + si_code = SEGV_MAPERR; address = current_thread_info()->fault_address; if ((fault_code & FAULT_CODE_ITLB) && diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 60308cead..a82492650 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -68,6 +68,7 @@ unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; extern char _start[], _end[]; /* Initial ramdisk setup */ +extern unsigned long sparc_ramdisk_image64; extern unsigned int sparc_ramdisk_image; extern unsigned int sparc_ramdisk_size; @@ -1279,10 +1280,12 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) #ifdef CONFIG_BLK_DEV_INITRD /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ - if (sparc_ramdisk_image) { - if (sparc_ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE) - sparc_ramdisk_image -= KERNBASE; - initrd_start = sparc_ramdisk_image + phys_base; + if (sparc_ramdisk_image || sparc_ramdisk_image64) { + unsigned long ramdisk_image = sparc_ramdisk_image ? + sparc_ramdisk_image : sparc_ramdisk_image64; + if (ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE) + ramdisk_image -= KERNBASE; + initrd_start = ramdisk_image + phys_base; initrd_end = initrd_start + sparc_ramdisk_size; if (initrd_end > end_of_phys_memory) { printk(KERN_CRIT "initrd extends beyond end of memory " @@ -1325,6 +1328,10 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) size = initrd_end - initrd_start; /* Resert the initrd image area. */ +#ifdef CONFIG_DEBUG_BOOTMEM + prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n", + initrd_start, initrd_end); +#endif reserve_bootmem(initrd_start, size); *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -1377,7 +1384,7 @@ void __init paging_init(void) if ((real_end > ((unsigned long)KERNBASE + 0x400000))) bigkernel = 1; #ifdef CONFIG_BLK_DEV_INITRD - if (sparc_ramdisk_image) + if (sparc_ramdisk_image || sparc_ramdisk_image64) real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size)); #endif @@ -1502,7 +1509,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/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 4a3db02e1..15b4cfe07 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -137,21 +137,34 @@ asmlinkage int solaris_brk(u32 brk) return sunos_brk(brk); } -#define set_utsfield(to, from, dotchop, countfrom) { \ - char *p; \ - int i, len = (countfrom) ? \ - ((sizeof(to) > sizeof(from) ? \ - sizeof(from) : sizeof(to))) : sizeof(to); \ - if (copy_to_user(to, from, len)) \ - return -EFAULT; \ - if (dotchop) \ - for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \ - else \ - i = len - 1; \ - if (__put_user('\0', (char __user *)((to)+i))) \ - return -EFAULT; \ +static int __set_utsfield(char __user *to, int to_size, + const char *from, int from_size, + int dotchop, int countfrom) +{ + int len = countfrom ? (to_size > from_size ? + from_size : to_size) : to_size; + int off; + + if (copy_to_user(to, from, len)) + return -EFAULT; + + off = len < to_size? len: len - 1; + if (dotchop) { + const char *p = strnchr(from, len, '.'); + if (p) off = p - from; + } + + if (__put_user('\0', to + off)) + return -EFAULT; + + return 0; } +#define set_utsfield(to, from, dotchop, countfrom) \ + __set_utsfield((to), sizeof(to), \ + (from), sizeof(from), \ + (dotchop), (countfrom)) + struct sol_uname { char sysname[9]; char nodename[9]; @@ -219,17 +232,20 @@ static char *serial(char *buffer) asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) { struct sol_uname __user *v = A(buf); + int err; + switch (which) { case 0: /* old uname */ /* Let's cheat */ - set_utsfield(v->sysname, "SunOS", 1, 0); + err = set_utsfield(v->sysname, "SunOS", 1, 0); down_read(&uts_sem); - set_utsfield(v->nodename, system_utsname.nodename, 1, 1); + err |= set_utsfield(v->nodename, system_utsname.nodename, + 1, 1); up_read(&uts_sem); - set_utsfield(v->release, "2.6", 0, 0); - set_utsfield(v->version, "Generic", 0, 0); - set_utsfield(v->machine, machine(), 0, 0); - return 0; + err |= set_utsfield(v->release, "2.6", 0, 0); + err |= set_utsfield(v->version, "Generic", 0, 0); + err |= set_utsfield(v->machine, machine(), 0, 0); + return (err ? -EFAULT : 0); case 2: /* ustat */ return -ENOSYS; case 3: /* fusers */ @@ -242,15 +258,18 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) asmlinkage int solaris_utsname(u32 buf) { struct sol_utsname __user *v = A(buf); + int err; + /* Why should we not lie a bit? */ down_read(&uts_sem); - set_utsfield(v->sysname, "SunOS", 0, 0); - set_utsfield(v->nodename, system_utsname.nodename, 1, 1); - set_utsfield(v->release, "5.6", 0, 0); - set_utsfield(v->version, "Generic", 0, 0); - set_utsfield(v->machine, machine(), 0, 0); + err = set_utsfield(v->sysname, "SunOS", 0, 0); + err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1); + err |= set_utsfield(v->release, "5.6", 0, 0); + err |= set_utsfield(v->version, "Generic", 0, 0); + err |= set_utsfield(v->machine, machine(), 0, 0); up_read(&uts_sem); - return 0; + + return (err ? -EFAULT : 0); } #define SI_SYSNAME 1 /* return name of operating system */ diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 47fbaf3f4..78b22b893 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -34,7 +34,7 @@ config MODE_TT help This option controls whether tracing thread support is compiled into UML. Normally, this should be set to Y. If you intend to - use only skas mode (and the host has the skas patch applied to it), + use only skas mode (and the host has the skas patch applied to it), then it is OK to say N here. config STATIC_LINK @@ -45,7 +45,7 @@ config STATIC_LINK If CONFIG_MODE_TT is disabled, then this option gives you the ability to force a static link of UML. Normally, if only skas mode is built in to UML, it will be linked as a shared binary. This is inconvenient - for use in a chroot jail. So, if you intend to run UML inside a + for use in a chroot jail. So, if you intend to run UML inside a chroot, and you disable CONFIG_MODE_TT, you probably want to say Y here. @@ -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 + . + source "fs/Kconfig.binfmt" @@ -82,9 +96,22 @@ config HOSTFS For more information, see . - If you'd like to be able to work with files stored on the host, + 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" @@ -102,15 +129,12 @@ config MCONSOLE It is safe to say 'Y' here. -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on MCONSOLE - config HOST_2G_2G bool "2G/2G host address space split" -config UML_SMP +config SMP bool "Symmetric multi-processing support" + default n help This option enables UML SMP support. UML implements virtual SMP by allowing as many processes to run simultaneously on the host as @@ -119,13 +143,8 @@ config UML_SMP will appear to be running simultaneously. If the host is a multiprocessor, then UML processes may run simultaneously, depending on the host scheduler. - CONFIG_SMP will be set to whatever this option is set to. It is safe to leave this unchanged. -config SMP - bool - default UML_SMP - config NR_CPUS int "Maximum number of CPUs (2-32)" range 2 32 @@ -140,11 +159,11 @@ config NEST_LEVEL in. Normally, this is zero, meaning that it will run directly on the host. Setting it to one will build a UML that can run inside a UML that is running on the host. Generally, if you intend this UML to run - inside another UML, set CONFIG_NEST_LEVEL to one more than the host + inside another UML, set CONFIG_NEST_LEVEL to one more than the host UML. - Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to - greater than one, then the guest UML should have its CONFIG_NEST_LEVEL + Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to + greater than one, then the guest UML should have its CONFIG_NEST_LEVEL set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. Only change this if you are running nested UMLs. @@ -159,6 +178,7 @@ config KERNEL_HALF_GIGS config HIGHMEM bool "Highmem support" + depends on BROKEN config KERNEL_STACK_ORDER int "Kernel stack size order" @@ -168,6 +188,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" @@ -195,6 +226,7 @@ source "crypto/Kconfig" source "lib/Kconfig" menu "SCSI support" +depends on BROKEN config SCSI tristate "SCSI support" @@ -211,61 +243,8 @@ endmenu source "drivers/md/Kconfig" -source "drivers/mtd/Kconfig" - - -menu "Kernel hacking" - -config DEBUG_SLAB - bool "Debug memory allocations" - -config DEBUG_SPINLOCK - bool "Debug spinlocks usage" - -config DEBUG_INFO - bool "Enable kernel debugging symbols" - help - When this is enabled, the User-Mode Linux binary will include - debugging symbols. This enlarges the binary by a few megabytes, - but aids in tracking down kernel problems in UML. It is required - if you intend to do any kernel development. - - If you're truly short on disk space or don't expect to report any - bugs back to the UML developers, say N, otherwise say Y. - -config FRAME_POINTER - bool - default y if DEBUG_INFO - -config PT_PROXY - bool "Enable ptrace proxy" - depends on XTERM_CHAN && DEBUG_INFO - -config GPROF - bool "Enable gprof support" - depends on DEBUG_INFO - help - This allows profiling of a User-Mode Linux kernel with the gprof - utility. - - See for more - details. - - If you're involved in UML kernel development and want to use gprof, - say Y. If you're unsure, say N. - -config GCOV - bool "Enable gcov support" - depends on DEBUG_INFO - help - This option allows developers to retrieve coverage data from a UML - session. - - See for more - details. - - If you're involved in UML kernel development and want to use gcov, - say Y. If you're unsure, say N. - -endmenu +if BROKEN + source "drivers/mtd/Kconfig" +endif +source "arch/um/Kconfig.debug" diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug new file mode 100644 index 000000000..a2d58306d --- /dev/null +++ b/arch/um/Kconfig.debug @@ -0,0 +1,43 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FRAME_POINTER + bool + default y if DEBUG_INFO + +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" + depends on DEBUG_INFO + help + This allows profiling of a User-Mode Linux kernel with the gprof + utility. + + See for more + details. + + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. + +config GCOV + bool "Enable gcov support" + depends on DEBUG_INFO + help + This option allows developers to retrieve coverage data from a UML + session. + + See for more + details. + + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. + +endmenu diff --git a/arch/um/Kconfig_block b/arch/um/Kconfig_block index fba53d9bb..8f2ba090c 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" @@ -50,6 +54,7 @@ config BLK_DEV_INITRD config MMAPPER tristate "Example IO memory driver" + depends on BROKEN help The User-Mode Linux port can provide support for IO Memory emulation with this option. This allows a host file to be diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char index a21cbbc7e..09f47388c 100644 --- a/arch/um/Kconfig_char +++ b/arch/um/Kconfig_char @@ -72,6 +72,10 @@ config XTERM_CHAN well, since UML's gdb currently requires an xterm. It is safe to say 'Y' here. +config NOCONFIG_CHAN + bool + default !(XTERM_CHAN && TTY_CHAN && PTY_CHAN && PORT_CHAN && FD_CHAN && NULL_CHAN) + config CON_ZERO_CHAN string "Default main console channel initialization" default "fd:0,fd:1" @@ -108,11 +112,55 @@ 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/. 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 WATCHDOG bool "Watchdog Timer Support" diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net index 443a74bd6..1c2f9a70d 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 @@ -135,7 +135,7 @@ config UML_NET_MCAST config UML_NET_PCAP bool "pcap transport" - depends on UML_NET + depends on UML_NET && BROKEN help The pcap transport makes a pcap packet stream on the host look like an ethernet device inside UML. This is useful for making @@ -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 bb7d3f6ba..0406c1a90 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -5,35 +5,25 @@ ARCH_DIR = arch/um OS := $(shell uname -s) +#We require it or things break. +SHELL := /bin/bash -# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE) -# The way the toplevel Makefile is written EXTRAVERSION is not supposed -# to be changed outside the toplevel Makefile, but recalculating MODLIB is -# a sufficient workaround until we no longer need architecture dependent -# EXTRAVERSION... -MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) +filechk_gen_header = $< -ifeq ($(CONFIG_DEBUG_INFO),y) -CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -endif - -core-y += $(ARCH_DIR)/kernel/ \ - $(ARCH_DIR)/drivers/ \ +core-y += $(ARCH_DIR)/kernel/ \ + $(ARCH_DIR)/drivers/ \ $(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) - MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas @@ -41,9 +31,11 @@ ifneq ($(MAKEFILE-y),) include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) endif -EXTRAVERSION := $(EXTRAVERSION)-1um +ARCH_INCLUDE := -I$(ARCH_DIR)/include +SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) -ARCH_INCLUDE = -I$(ARCH_DIR)/include +include $(ARCH_DIR)/Makefile-$(SUBARCH) +include $(ARCH_DIR)/Makefile-os-$(OS) # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common @@ -52,32 +44,32 @@ 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 cc-option,-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) : $(ARCH_DIR)/include/skas_ptregs.h endif -include/linux/version.h: arch/$(ARCH)/Makefile - -$(ARCH_DIR)/vmlinux.lds.S : - touch $@ - -prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) - -LDFLAGS_vmlinux = -r - -vmlinux: $(ARCH_DIR)/main.o +prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \ + $(ARCH_DIR)/kernel/vmlinux.lds.S # These aren't in Makefile-tt because they are needed in the !CONFIG_MODE_TT + # CONFIG_MODE_SKAS + CONFIG_STATIC_LINK case. LINK_TT = -static -LD_SCRIPT_TT := uml.lds.s +LD_SCRIPT_TT := uml.lds.S ifeq ($(CONFIG_STATIC_LINK),y) LINK-y += $(LINK_TT) @@ -98,82 +90,99 @@ 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)) ] ) -AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \ - -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ - -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE) - -AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum - -LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) +ifndef START + START = $$(($(TOP_ADDR) - $(SIZE))) +endif -$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE - $(call if_changed_dep,as_s_S) +CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \ + -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ + -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ + -DKERNEL_STACK_SIZE=$(STACK_SIZE)) -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 +CFLAGS_vmlinux = $(LINK-y) $(LINK_WRAPS) +define cmd_vmlinux__ + $(CC) $(CFLAGS_vmlinux) -o $@ \ + -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \ + -Wl,--start-group $(vmlinux-main) -Wl,--end-group \ + -L/usr/lib -lutil \ + $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^) +endef 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 -CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \ - $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS) +#When cleaning we don't include .config, so we don't include +#TT or skas makefiles and don't clean skas_ptregs.h. +CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ + $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h -$(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)) $(ARCH_DIR)/os 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' \ + @: + +archclean: + $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util + @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 +#We need to re-preprocess this when the symlink dest changes. +#So we touch it. +$(ARCH_DIR)/kernel/vmlinux.lds.S: FORCE + @echo ' SYMLINK $@' + $(Q)ln -sf $(LD_SCRIPT-y) $@ + $(Q)touch $@ $(SYMLINK_HEADERS): - cd $(TOPDIR)/$(dir $@) ; \ + @echo ' SYMLINK $@' + $(Q)cd $(TOPDIR)/$(dir $@) ; \ ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) include/asm-um/arch: - cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch + @echo ' SYMLINK $@' + $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch $(ARCH_DIR)/include/sysdep: - cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep + @echo ' SYMLINK $@' + $(Q)cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep $(ARCH_DIR)/os: - cd $(ARCH_DIR) && ln -sf os-$(OS) os + @echo ' SYMLINK $@' + $(Q)cd $(ARCH_DIR) && ln -sf os-$(OS) os + +# Generated files +define filechk_umlconfig + sed 's/ CONFIG/ UML_CONFIG/' +endef + +$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h + $(call filechk,umlconfig) + +$(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)/include/uml-config.h : - sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ +$(ARCH_DIR)/include/skas_ptregs.h: $(ARCH_DIR)/kernel/skas/util/mk_ptregs + $(call filechk,gen_header) -$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task - $< > $@ +$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants: $(ARCH_DIR)/util \ + FORCE ; -$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants - $< > $@ +$(ARCH_DIR)/kernel/skas/util/mk_ptregs: $(ARCH_DIR)/kernel/skas/util FORCE ; -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ - $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/util: scripts_basic $(SYS_DIR)/sc.h FORCE + $(Q)$(MAKE) $(build)=$@ -$(ARCH_DIR)/util: FORCE - @$(call descend,$@,) +$(ARCH_DIR)/kernel/skas/util: scripts_basic FORCE + $(Q)$(MAKE) $(build)=$@ export SUBARCH USER_CFLAGS OS diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index 3bd90fbdb..9a6cf6e5b 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -1,37 +1,45 @@ ifeq ($(CONFIG_HOST_2G_2G), y) -TOP_ADDR = 0x80000000 +TOP_ADDR := 0x80000000 else -TOP_ADDR = 0xc0000000 +TOP_ADDR := 0xc0000000 +endif + +ifeq ($(CONFIG_MODE_SKAS),y) + ifneq ($(CONFIG_MODE_TT),y) + START := 0x8048000 + endif endif CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) -ELF_ARCH = $(SUBARCH) -ELF_FORMAT = elf32-$(SUBARCH) + +ifneq ($(CONFIG_GPROF),y) +ARCH_CFLAGS += -DUM_FASTCALL +endif + +ELF_ARCH := $(SUBARCH) +ELF_FORMAT := elf32-$(SUBARCH) OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_BLOB := --format binary --oformat elf32-i386 -SYS_DIR := $(ARCH_DIR)/include/sysdep-i386 SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util -SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h +SYS_HEADERS := $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h prepare: $(SYS_HEADERS) $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc - $< > $@ + $(call filechk,gen_header) $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread - $< > $@ + $(call filechk,gen_header) -$(SYS_UTIL_DIR)/mk_sc: FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_sc: scripts_basic 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: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ -$(SYS_UTIL_DIR): include/asm FORCE - @$(call descend,$@,) +$(SYS_UTIL_DIR): scripts_basic include/asm FORCE + $(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 b9dfec5f7..fb3050ff9 100644 --- a/arch/um/Makefile-skas +++ b/arch/um/Makefile-skas @@ -9,12 +9,9 @@ CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage CFLAGS-$(CONFIG_GPROF) += $(PROFILE) LINK-$(CONFIG_GPROF) += $(PROFILE) -MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include +MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/kernel/skas/include LINK_SKAS = -Wl,-rpath,/lib -LD_SCRIPT_SKAS = dyn.lds.s +LD_SCRIPT_SKAS = dyn.lds.S -GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h - -$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : - $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h +GEN_HEADERS += $(ARCH_DIR)/include/skas_ptregs.h diff --git a/arch/um/Makefile-tt b/arch/um/Makefile-tt index 8d58a3083..eed367d9c 100644 --- a/arch/um/Makefile-tt +++ b/arch/um/Makefile-tt @@ -3,5 +3,4 @@ # Licensed under the GPL # -MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/tt/include - +MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/kernel/tt/include diff --git a/arch/um/config.release b/arch/um/config.release index 6d32bc20c..fc68bcb92 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 412d006b9..84547f12f 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -1,47 +1,79 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc2-mm1 +# Thu Sep 16 23:44:48 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_LOCALVERSION="" +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_KOBJECT_UEVENT=y +# 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_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM 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 +90,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 +102,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 +112,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 +122,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 +133,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 +142,25 @@ 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_INET_TUNNEL 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 +172,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 +201,130 @@ 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 + +# +# Caches +# +# CONFIG_CACHEFS is not set + +# +# 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 +332,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 +361,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 +380,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Security options # +# CONFIG_KEYS is not set # CONFIG_SECURITY is not set # @@ -311,33 +391,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 +420,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 +469,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 8ea9ada4a..127bb4d07 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 9e45a082e..7a8d75086 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "chan_kern.h" @@ -16,7 +17,9 @@ #include "irq_user.h" #include "sigio.h" #include "line.h" +#include "os.h" +#ifdef CONFIG_NOCONFIG_CHAN static void *not_configged_init(char *str, int device, struct chan_opts *opts) { printk(KERN_ERR "Using a channel type which is configured out of " @@ -85,6 +88,55 @@ static struct chan_ops not_configged_ops = { .free = not_configged_free, .winch = 0, }; +#endif /* CONFIG_NOCONFIG_CHAN */ + +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); +} + +/* XXX Trivial wrapper around os_write_file */ + +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) { @@ -265,6 +317,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 +477,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 +533,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 714bace49..8a5180a77 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 #include #include -#include #include #include #include @@ -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 index d875d0435..19517312a 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -13,22 +13,22 @@ #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, +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, +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, +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 bitmap_offset, unsigned long *bitmap_len_out, int *data_offset_out); #endif diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h new file mode 100644 index 000000000..ce251f083 --- /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 index 014c2c853..d3fad2486 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -27,20 +27,20 @@ struct cow_header_v1 { #define PATH_LEN_V2 MAXPATHLEN struct cow_header_v2 { - unsigned long magic; - unsigned long version; + __u32 magic; + __u32 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 +/* 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 - +/* 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 @@ -90,15 +90,15 @@ union cow_header { #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, +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) / + *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; *data_offset_out *= sectorsize; } @@ -117,7 +117,7 @@ static int absolutize(char *to, int size, char *from) int remaining; if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { - cow_printf("absolutize : unable to get cwd - errno = %d\n", + cow_printf("absolutize : unable to get cwd - errno = %d\n", errno); return(-1); } @@ -126,7 +126,7 @@ static int absolutize(char *to, int size, char *from) *slash = '\0'; if(chdir(from)){ *slash = '/'; - cow_printf("absolutize : Can't cd to '%s' - " + cow_printf("absolutize : Can't cd to '%s' - " "errno = %d\n", from, errno); return(-1); } @@ -158,7 +158,7 @@ static int absolutize(char *to, int size, char *from) return(0); } -int write_cow_header(char *cow_file, int fd, char *backing_file, +int write_cow_header(char *cow_file, int fd, char *backing_file, int sectorsize, int alignment, long long *size) { struct cow_header_v3 *header; @@ -183,12 +183,12 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, 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, + "limited to %d characters\n", backing_file, sizeof(header->backing_file) - 1); goto out_free; } - if(absolutize(header->backing_file, sizeof(header->backing_file), + if(absolutize(header->backing_file, sizeof(header->backing_file), backing_file)) goto out_free; @@ -234,10 +234,10 @@ int file_reader(__u64 offset, char *buf, int len, void *arg) /* 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 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; @@ -310,7 +310,7 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, } else { cow_printf("read_cow_header - invalid COW version\n"); - goto out; + goto out; } err = -ENOMEM; *backing_file_out = cow_strdup(file); @@ -326,18 +326,18 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, } int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, - int alignment, int *bitmap_offset_out, + 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, + err = write_cow_header(cow_file, fd, backing_file, sectorsize, alignment, &size); - if(err) + 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); @@ -349,9 +349,9 @@ int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, goto out; } - /* does not really matter how much we write it is just to set EOF + /* 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 + * to zero without having to allocate it */ err = cow_write_file(fd, &zero, sizeof(zero)); if(err != sizeof(zero)){ diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index de71aec2d..cf15b4a8b 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 4ac314c1a..1c6daad92 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "user.h" #include "user_util.h" #include "chan_user.h" @@ -35,7 +36,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); @@ -44,10 +46,16 @@ void *fd_init(char *str, int device, struct chan_opts *opts) int fd_open(int input, int output, int primary, void *d, char **dev_out) { struct fd_chan *data = d; + int err; if(data->raw && isatty(data->fd)){ - tcgetattr(data->fd, &data->tt); - raw(data->fd, 0); + CATCH_EINTR(err = tcgetattr(data->fd, &data->tt)); + if(err) + return(err); + + err = raw(data->fd); + if(err) + return(err); } sprintf(data->str, "%d", data->fd); *dev_out = data->str; @@ -57,9 +65,13 @@ int fd_open(int input, int output, int primary, void *d, char **dev_out) void fd_close(int fd, void *d) { struct fd_chan *data = d; + int err; if(data->raw && isatty(fd)){ - tcsetattr(fd, TCSAFLUSH, &data->tt); + CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); + if(err) + printk("Failed to restore terminal state - " + "errno = %d\n", -err); data->raw = 0; } } diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index cbbf41b5f..d934181b8 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 b512783a4..d5742783e 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=\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=\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=\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=\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,56 @@ 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 err; #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); + + err = os_read_file(state->fd, kbuf, count); + if(err < 0) + goto out; + + if(copy_to_user(buffer, kbuf, err)) + err = -EFAULT; + + out: + kfree(kbuf); + return(err); } 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 err; #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); + + err = -EFAULT; + if(copy_from_user(kbuf, buffer, count)) + goto out; + + err = os_write_file(state->fd, kbuf, count); + if(err < 0) + goto out; + *ppos += err; + + out: + kfree(kbuf); + return(err); } static unsigned int hostaudio_poll(struct file *file, @@ -86,12 +139,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 err; #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; + } + + err = 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(err); } static int hostaudio_open(struct inode *inode, struct file *file) @@ -105,17 +189,19 @@ static int hostaudio_open(struct inode *inode, struct file *file) #endif state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); - if(state == NULL) return(-ENOMEM); + if(state == NULL) + return(-ENOMEM); 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){ kfree(state); return(ret); } + state->fd = ret; file->private_data = state; return(0); } @@ -123,16 +209,15 @@ 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); + os_close_file(state->fd); kfree(state); - return(ret); + return(0); } /* /dev/mixer file operations */ @@ -146,7 +231,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,9 +250,11 @@ 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); } @@ -179,16 +266,15 @@ 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); + os_close_file(state->fd); kfree(state); - return(ret); + return(0); } @@ -225,7 +311,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/line.c b/arch/um/drivers/line.c index 92efc73ca..c6b77fccd 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); @@ -56,10 +73,11 @@ static void buffer_data(struct line *line, const char *buf, int len) else { memcpy(line->tail, buf, end); buf += end; - len -= end; - memcpy(line->buffer, buf, len); - line->tail = line->buffer + len; + memcpy(line->buffer, buf, len - end); + line->tail = line->buffer + len - end; } + + return(len); } static int flush_buffer(struct line *line) @@ -95,7 +113,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 +122,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 +137,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 +192,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,20 +324,20 @@ 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; } init++; if((n >= 0) && (n >= num)){ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", - n, num); - return(1); + n, num - 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 +351,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 +365,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 +376,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 +388,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 +398,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 +415,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 +438,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 +459,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 +492,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 +520,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 +559,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 58e5db630..0fe1d9fa9 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 b12cb189d..9076c0603 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) @@ -47,27 +51,26 @@ static struct notifier_block reboot_notifier = { LIST_HEAD(mc_requests); -void mc_work_proc(void *unused) +static void mc_work_proc(void *unused) { struct mconsole_entry *req; unsigned long flags; - int done; - do { + while(!list_empty(&mc_requests)){ local_save_flags(flags); req = list_entry(mc_requests.next, struct mconsole_entry, list); list_del(&req->list); - done = list_empty(&mc_requests); local_irq_restore(flags); req->request.cmd->handler(&req->request); kfree(req); - } while(!done); + } } DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mconsole_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { int fd; struct mconsole_entry *new; @@ -75,9 +78,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 { @@ -86,8 +90,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } } - if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); + 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 = - Add a new device to UML; - same syntax as command line - config - Query the configuration of a device - remove - Remove a device from UML - sysrq - 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 = - Add a new device to UML; \n\ + same syntax as command line \n\ + config - Query the configuration of a device \n\ + remove - Remove a device from UML \n\ + sysrq - 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 - make UML enter into the kernel log\n\ + proc - returns the contents of the UML's /proc/\n\ " void mconsole_help(struct mc_request *req) @@ -279,8 +374,8 @@ void mconsole_sysrq(struct mc_request *req) ptr += strlen("sysrq"); while(isspace(*ptr)) ptr++; - handle_sysrq(*ptr, ¤t->thread.regs, NULL); mconsole_reply(req, "", 0, 0); + handle_sysrq(*ptr, ¤t->thread.regs, NULL); } #else void mconsole_sysrq(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 11b09a96f..fe5afb132 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 628d8f804..1862691b9 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 a52b79dfd..c686a39ea 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -19,6 +19,8 @@ #include "linux/inetdevice.h" #include "linux/ctype.h" #include "linux/bootmem.h" +#include "linux/ethtool.h" +#include "asm/uaccess.h" #include "user_util.h" #include "kern_util.h" #include "net_kern.h" @@ -26,6 +28,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 +40,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 +65,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 +87,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) @@ -124,6 +129,13 @@ static int uml_net_open(struct net_device *dev) spin_lock(&opened_lock); list_add(&lp->list, &opened); spin_unlock(&opened_lock); + + /* clear buffer - it can happen that the host side of the interface + * is full when we get here. In this case, new data is never queued, + * SIGIOs never arrive, and the net never works. + */ + while((err = uml_net_rx(dev)) > 0) ; + out: spin_unlock(&lp->lock); return(err); @@ -237,7 +249,30 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu) static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return(-EINVAL); + static const struct ethtool_drvinfo info = { + .cmd = ETHTOOL_GDRVINFO, + .driver = "uml virtual ethernet", + .version = "42", + }; + void *useraddr; + u32 ethcmd; + + switch (cmd) { + case SIOCETHTOOL: + useraddr = ifr->ifr_data; + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + default: + return -EOPNOTSUPP; + } + default: + return -EINVAL; + } } void uml_net_user_timer_expire(unsigned long _conn) @@ -250,37 +285,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 +294,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 +336,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 +362,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 +617,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 75a83e9e1..2e4e1d49f 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 d361554eb..66b2fbe3d 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -5,7 +5,6 @@ #include #include -#include #include "chan_user.h" #include "os.h" diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 3c4463019..4044053cd 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 7a37cf6a2..1e8592ec1 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, @@ -74,12 +76,17 @@ void port_free(void *d) int port_open(int input, int output, int primary, void *d, char **dev_out) { struct port_chan *data = d; - int fd; + int fd, err; fd = port_wait(data->kernel_data); if((fd >= 0) && data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } *dev_out = data->dev; return(fd); @@ -90,7 +97,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 +137,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 +164,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 +177,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 +198,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 027405386..c4634b500 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -7,12 +7,12 @@ #include #include #include -#include #include #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 }); @@ -37,15 +38,21 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; char *dev; - int fd; + int fd, err; - if((fd = get_pty()) < 0){ + fd = get_pty(); + if(fd < 0){ printk("open_pts : Failed to open pts\n"); return(-errno); } if(data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } dev = ptsname(fd); @@ -57,29 +64,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); } } } @@ -89,13 +94,19 @@ int getmaster(char *line) int pty_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; - int fd; + int fd, err; char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; fd = getmaster(dev); - if(fd < 0) return(-errno); + if(fd < 0) + return(-errno); + + if(data->raw){ + err = raw(fd); + if(err) + return(err); + } - if(data->raw) raw(fd, 0); if(data->announce) (*data->announce)(dev, data->dev); sprintf(data->dev_name, "%s", dev); diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 782cf522b..3d8d4ca36 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -4,11 +4,9 @@ #include #include #include -#include -#include +#include #include #include -#include #include #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 cbdbb65c3..c322515c7 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include #include #include #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 826a77c8c..4a3586f0d 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 3ae795edf..54e6a57c8 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -17,8 +17,8 @@ #include "linux/init.h" #include "linux/interrupt.h" #include "linux/slab.h" +#include "linux/hardirq.h" #include "asm/current.h" -#include "asm/hardirq.h" #include "asm/irq.h" #include "stdio_console.h" #include "line.h" @@ -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,52 +189,53 @@ int stdio_init(void) return(0); } -__initcall(stdio_init); +late_initcall(stdio_init); -static void console_write(struct console *console, const char *string, +static void uml_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 *uml_console_device(struct console *c, int *index) { *index = c->index; return console_driver; } -static int console_setup(struct console *co, char *options) +static int uml_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: uml_console_write, + device: uml_console_device, + setup: uml_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 e9eb9e362..dd008aa8f 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #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 }); @@ -41,13 +41,18 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts) int tty_open(int input, int output, int primary, void *d, char **dev_out) { struct tty_chan *data = d; - int fd; + int fd, err; fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); if(fd < 0) return(fd); if(data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } *dev_out = data->dev; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0c3890b3e..53fba09ad 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, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1); 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; } @@ -343,14 +396,13 @@ int thread_fd = -1; */ int intr_count = 0; -static void ubd_finish(struct request *req, int error) +/* call ubd_finish if you need to serialize */ +static void __ubd_finish(struct request *req, int error) { int nsect; if(error){ - spin_lock(&ubd_io_lock); end_request(req, 0); - spin_unlock(&ubd_io_lock); return; } nsect = req->current_nr_sectors; @@ -359,41 +411,57 @@ static void ubd_finish(struct request *req, int error) req->errors = 0; req->nr_sectors -= nsect; req->current_nr_sectors = 0; - spin_lock(&ubd_io_lock); end_request(req, 1); +} + +static inline void ubd_finish(struct request *req, int error) +{ + spin_lock(&ubd_io_lock); + __ubd_finish(req, error); spin_unlock(&ubd_io_lock); } +/* Called without ubd_io_lock held */ 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 +485,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 +501,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 +529,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 +559,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 +598,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 +650,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 +693,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]; @@ -667,9 +754,7 @@ int ubd_init(void) return -1; } - 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); @@ -688,9 +773,11 @@ int ubd_driver_init(void){ unsigned long stack; int err; + /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/ if(global_openflags.s){ - printk(KERN_INFO "ubd : Synchronous mode\n"); - return(0); + printk(KERN_INFO "ubd: Synchronous mode\n"); + /* Letting ubd=sync be like using ubd#s= instead of ubd#= is + * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), @@ -699,12 +786,13 @@ int ubd_driver_init(void){ printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); + io_pid = -1; return(0); } 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 +802,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,91 +831,211 @@ 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) +{ + __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) { - int i, update_bitmap, sector = req->offset >> 9; + __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); } +/* Called with ubd_io_lock held */ 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); - spin_lock(&ubd_io_lock); end_request(req, 0); - spin_unlock(&ubd_io_lock); 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); } +/* Called with ubd_io_lock held */ static void do_ubd_request(request_queue_t *q) { struct io_thread_req io_req; @@ -841,18 +1043,17 @@ static void do_ubd_request(request_queue_t *q) int err, n; if(thread_fd == -1){ - while(!list_empty(&q->queue_head)){ - req = elv_next_request(q); + while((req = elv_next_request(q)) != NULL){ err = prepare_request(req, &io_req); if(!err){ do_io(&io_req); - ubd_finish(req, io_req.error); + __ubd_finish(req, io_req.error); } } } else { - if(do_ubd || list_empty(&q->queue_head)) return; - req = elv_next_request(q); + if(do_ubd || (req = elv_next_request(q)) == NULL) + return; err = prepare_request(req, &io_req); if(!err){ do_ubd = ubd_handler; @@ -870,7 +1071,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, { struct hd_geometry *loc = (struct hd_geometry *) arg; struct ubd *dev = inode->i_bdev->bd_disk->private_data; - int err; struct hd_driveid ubd_id = { .cyls = 0, .heads = 128, @@ -885,35 +1085,9 @@ 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: - if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || (inode->i_bdev->bd_contains != inode->i_bdev)) - return(-EINVAL); - return(0); - - case HDIO_GET_UNMASKINTR: - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - return(0); - - case HDIO_GET_MULTCOUNT: - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - return(0); - - case HDIO_SET_MULTCOUNT: - if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if(inode->i_bdev->bd_contains != inode->i_bdev) - return(-EINVAL); - return(0); - case HDIO_GET_IDENTITY: ubd_id.cyls = dev->size / (128 * 32 * 512); if(copy_to_user((char *) arg, (char *) &ubd_id, @@ -935,6 +1109,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 93b6f3e90..882d2f7c1 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -11,11 +11,8 @@ #include #include #include -#include #include -#include #include -#include #include #include #include "asm/types.h" @@ -24,146 +21,30 @@ #include "user.h" #include "ubd_user.h" #include "os.h" +#include "cow.h" #include #include -#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, - §orsize, bitmap_offset_out); + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, + &size, §orsize, &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); + } - if(stat64(file, &buf) < 0) return(0); - return(S_ISDIR(buf.st_mode)); + 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); + } + + 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,20 @@ 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); + err = -errno; + 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 59c4ba89f..f417b3b66 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -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, @@ -83,6 +83,7 @@ __uml_setup("xterm=", xterm_setup, " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); +/* XXX This badly needs some cleaning up in the error paths */ int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; @@ -93,7 +94,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 +107,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,20 +129,32 @@ 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; } - tcgetattr(new, &data->tt); - if(data->raw) raw(new, 0); + CATCH_EINTR(err = tcgetattr(new, &data->tt)); + if(err){ + new = err; + goto out; + } + + if(data->raw){ + err = raw(new); + if(err){ + new = err; + goto out; + } + } data->pid = pid; *dev_out = NULL; @@ -160,7 +173,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 1b4683fe3..a94813fce 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/include/2_5compat.h b/arch/um/include/2_5compat.h index 6d36d9c30..abdb015a4 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/irq_kern.h b/arch/um/include/irq_kern.h index 4bcb829d7..3af52a634 100644 --- a/arch/um/include/irq_kern.h +++ b/arch/um/include/irq_kern.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -9,7 +9,7 @@ #include "linux/interrupt.h" extern int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *, + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id); diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h index 087bd39d0..0df4076ac 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h @@ -14,6 +14,7 @@ extern void free_irq_by_irq_and_dev(int irq, void *dev_id); extern void free_irq_by_fd(int fd); extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); +extern int deactivate_all_fds(void); extern void forward_interrupts(int pid); extern void init_irq_signals(int on_sigstack); extern void forward_ipi(int fd, int pid); diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 09e76a308..eace6b208 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 e9783dc16..31911329f 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 7eea2fac0..9fbe3083f 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 bad6b30b8..10c46c389 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 index b39f03d94..cb7e196d3 100644 --- a/arch/um/include/mem_kern.h +++ b/arch/um/include/mem_kern.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index d80ac354b..f530ac3f8 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 b9b1f0c1d..8c4011265 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,48 @@ 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_clear_fd_async(int fd); 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 +160,13 @@ 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); +extern unsigned long long os_usecs(void); #endif diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h index adaea4d5a..b075e543d 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 7cd983d88..cfb5fb4f5 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 d1ca652a7..bb6b343f1 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" /* @@ -102,7 +103,8 @@ static inline unsigned short ip_fast_csum(unsigned char * iph, are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl) - : "1" (iph), "2" (ihl)); + : "1" (iph), "2" (ihl) + : "memory"); return(sum); } diff --git a/arch/um/include/sysdep-i386/frame_user.h b/arch/um/include/sysdep-i386/frame_user.h index b4065b235..13faf079a 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 26c70cf8b..887fdb61e 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 08d7c1323..47687dcf2 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(®s->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/time_user.h b/arch/um/include/time_user.h index 9ddb749f7..6793a2fcd 100644 --- a/arch/um/include/time_user.h +++ b/arch/um/include/time_user.h @@ -11,6 +11,7 @@ extern void switch_timers(int to_real); extern void set_interval(int timer_type); extern void idle_sleep(int secs); extern void enable_timer(void); +extern void disable_timer(void); extern unsigned long time_lock(void); extern void time_unlock(unsigned long); diff --git a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h index b28beaf58..9bac59c4c 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 41afa3a8f..c9b3574c6 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 6f009be0f..57ee9e261 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 e87b8fcb0..ab089d7a7 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -8,14 +8,14 @@ #include "sysdep/ptrace.h" +#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR)) + extern int mode_tt; 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 +59,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); @@ -76,7 +74,6 @@ extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); extern void do_longjmp(void *p, int val); -extern void suspend_new_thread(int fd); extern int detach(int pid, int sig); extern int attach(int pid); extern void kill_child_dead(int pid); @@ -86,11 +83,15 @@ 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 setjmp_wrapper(void (*proc)(void *, void *), ...); +extern int raw(int fd); + #endif /* diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 0f13dd4c7..9fa9711ec 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -3,15 +3,16 @@ # Licensed under the GPL # -extra-y := vmlinux.lds.s +extra-y := vmlinux.lds +clean-files := vmlinux.lds.S 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 +25,19 @@ 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 frame.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)) +CFLAGS_frame.o := -fno-omit-frame-pointer $(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() { $$_ =~ s/CONFIG/$$config/; print $$_ }' - -$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config - $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@ - -$(obj)/config.o : $(obj)/config.c - -clean: - rm -f config.c - for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done - -modules: - -fastdep: + $(CC) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) -c -o $@ $< -dep: +QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' -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 f6c96b955..c062cbfe3 100644 --- a/arch/um/kernel/config.c.in +++ b/arch/um/kernel/config.c.in @@ -7,9 +7,7 @@ #include #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/dyn.lds.S b/arch/um/kernel/dyn.lds.S new file mode 100644 index 000000000..ee1642119 --- /dev/null +++ b/arch/um/kernel/dyn.lds.S @@ -0,0 +1,171 @@ +#include + +OUTPUT_FORMAT(ELF_FORMAT) +OUTPUT_ARCH(ELF_ARCH) +ENTRY(_start) +jiffies = jiffies_64; + +SECTIONS +{ + . = START + SIZEOF_HEADERS; + .interp : { *(.interp) } + __binary_start = .; + . = ALIGN(4096); /* Init code and data */ + _stext = .; + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + + . = ALIGN(4096); + + /* Read-only sections, merged into text segment: */ + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : { + *(.text) + SCHED_TEXT + *(.stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : { + KEEP (*(.fini)) + } =0x90909090 + + .kstrtab : { *(.kstrtab) } + + #include "asm/common.lds.S" + + init.data : { *(.init.data) } + + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + .preinit_array : { *(.preinit_array) } + .init_array : { *(.init_array) } + .fini_array : { *(.fini_array) } + .data : { + . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ + *(.data.init_task) + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + } + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index a6be6b542..a5f21283d 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, ¤t->thread.regs); if (error == 0){ current->ptrace &= ~PT_DTRACE; diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c index d8993f293..4b349f207 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 9ff437466..809002dad 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 5c4b27942..0e3d409d9 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -7,12 +7,12 @@ #include #include #include -#include #include #include #include #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, @@ -116,10 +132,12 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, return(-errno); } if(stack_out == NULL){ - pid = waitpid(pid, &status, 0); - if(pid < 0) + CATCH_EINTR(pid = waitpid(pid, &status, 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); @@ -133,7 +151,7 @@ int helper_wait(int pid, int block) { int ret; - ret = waitpid(pid, NULL, WNOHANG); + CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); if(ret < 0){ printk("helper_wait : waitpid failed, errno = %d\n", errno); return(-errno); diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index be82cafe9..cd7c85be0 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 944c734ca..57d5b41db 100644 --- a/arch/um/kernel/initrd_user.c +++ b/arch/um/kernel/initrd_user.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #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 0e968bb11..2b8250955 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -18,9 +18,10 @@ #include "linux/proc_fs.h" #include "linux/init.h" #include "linux/seq_file.h" +#include "linux/profile.h" +#include "linux/hardirq.h" #include "asm/irq.h" #include "asm/hw_irq.h" -#include "asm/hardirq.h" #include "asm/atomic.h" #include "asm/signal.h" #include "asm/system.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; jtypename); - 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; } /* @@ -155,13 +147,16 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ + int ret, retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; + retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -169,7 +164,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, local_irq_disable(); - return status; + return retval; } /* @@ -282,13 +277,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 +379,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,16 +427,22 @@ 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); } +EXPORT_SYMBOL(um_request_irq); +EXPORT_SYMBOL(reactivate_fd); /* this was setup_x86_irq but it seems pretty generic */ int setup_irq(unsigned int irq, struct irqaction * new) @@ -474,7 +474,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 +587,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 +602,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; @@ -610,30 +615,6 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, return full_count; } -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data, new_value; - unsigned long full_count = count, err; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -662,24 +643,15 @@ static void register_irq_proc (unsigned int irq) smp_affinity_entry[irq] = entry; } -/* Read and written as a long */ -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - void __init init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 57fe9bb72..38e66ac84 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -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); @@ -364,36 +364,47 @@ void deactivate_fd(int fd, int irqnum) irq_unlock(flags); } -void forward_ipi(int fd, int pid) +int deactivate_all_fds(void) { - 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); - } + struct irq_fd *irq; + int err; + + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_clear_fd_async(irq->fd); + if(err) + return(err); } + + return(0); +} + +void forward_ipi(int fd, int pid) +{ + 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 1f82ad73a..a867e18c6 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 +#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,67 @@ 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(uml_strdup); + +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. */ @@ -75,10 +109,10 @@ EXPORT_SYMBOL(sys_wait4); /* required for SMP */ extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); -EXPORT_SYMBOL_NOVERS(__write_lock_failed); +EXPORT_SYMBOL(__write_lock_failed); extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); -EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(__read_lock_failed); #endif @@ -90,3 +124,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/kernel/main.c b/arch/um/kernel/main.c new file mode 100644 index 000000000..e1fd2c583 --- /dev/null +++ b/arch/um/kernel/main.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "mem_user.h" +#include "signal_user.h" +#include "user.h" +#include "init.h" +#include "mode.h" +#include "choose-mode.h" +#include "uml-config.h" + +/* 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; + +/* Set in main */ +char *linux_prog; + +#define PGD_BOUND (4 * 1024 * 1024) +#define STACKSIZE (8 * 1024 * 1024) +#define THREAD_NAME_LEN (256) + +static void set_stklim(void) +{ + struct rlimit lim; + + if(getrlimit(RLIMIT_STACK, &lim) < 0){ + perror("getrlimit"); + exit(1); + } + if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){ + lim.rlim_cur = STACKSIZE; + if(setrlimit(RLIMIT_STACK, &lim) < 0){ + perror("setrlimit"); + exit(1); + } + } + stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); +} + +static __init void do_uml_initcalls(void) +{ + initcall_t *call; + + call = &__uml_initcall_start; + while (call < &__uml_initcall_end){; + (*call)(); + call++; + } +} + +static void last_ditch_exit(int sig) +{ + CHOOSE_MODE(kmalloc_ok = 0, (void) 0); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + uml_cleanup(); + exit(1); +} + +extern int uml_exitcode; + +int main(int argc, char **argv, char **envp) +{ + char **new_argv; + sigset_t mask; + int ret, i; + + /* Enable all signals except SIGIO - in some environments, we can + * enter with some signals blocked + */ + + sigemptyset(&mask); + sigaddset(&mask, SIGIO); + if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){ + perror("sigprocmask"); + exit(1); + } + +#ifdef UML_CONFIG_MODE_TT + /* 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' + }; + + 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(); + + new_argv = malloc((argc + 1) * sizeof(char *)); + if(new_argv == NULL){ + perror("Mallocing argv"); + exit(1); + } + for(i=0;i= uml_physmem) && (addr < high_physmem)){ + if(CAN_KMALLOC()) + kfree(ptr); + } + else if((addr >= start_vm) && (addr < end_vm)){ + if(CAN_KMALLOC()) + vfree(ptr); + } + else __real_free(ptr); +} + +/* + * 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/mem.c b/arch/um/kernel/mem.c index 84a895c2a..09add571c 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(®ions_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(®ions_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> 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), + ¤t->thread.fault_addr, + ¤t->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=\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), - ¤t->thread.fault_addr, - ¤t->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 d90345b5f..ec15ba43d 100644 --- a/arch/um/kernel/mem_user.c +++ b/arch/um/kernel/mem_user.c @@ -34,10 +34,9 @@ #include #include #include -#include #include #include -#include +#include #include #include #include "kern_util.h" @@ -47,105 +46,147 @@ #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, size; 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; + } + + err = os_stat_fd(fd, &buf); + if(err < 0){ + os_print_error(err, "parse_iomem - cannot stat_fd file"); + goto out_close; } - if(fstat(fd, &buf) < 0) { - printk("parse_iomem - cannot fstat file, errno = %d\n", errno); - return(1); + + new = malloc(sizeof(*new)); + if(new == NULL){ + perror("Couldn't allocate iomem_region struct"); + goto out_close; } - add_iomem(driver, fd, buf.st_size); + + size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = 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 +194,20 @@ __uml_setup("iomem=", parse_iomem, " Configure as an IO memory region named .\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 index d0e0f50dc..3253bc0e3 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -1,13 +1,14 @@ -/* +/* * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #include "linux/mm.h" -#include "linux/ghash.h" +#include "linux/rbtree.h" #include "linux/slab.h" #include "linux/vmalloc.h" #include "linux/bootmem.h" +#include "linux/module.h" #include "asm/types.h" #include "asm/pgtable.h" #include "kern_util.h" @@ -19,36 +20,8 @@ #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; + struct rb_node rb; int fd; __u64 offset; void *virt; @@ -56,21 +29,48 @@ struct phys_desc { struct list_head list; }; -struct virtmem_table virtmem_hash; +static struct rb_root phys_mappings = RB_ROOT; -static int virt_cmp(void *virt1, void *virt2) +static struct rb_node **find_rb(void *virt) { - return(virt1 != virt2); + struct rb_node **n = &phys_mappings.rb_node; + struct phys_desc *d; + + while(*n != NULL){ + d = rb_entry(*n, struct phys_desc, rb); + if(d->virt == virt) + return(n); + + if(d->virt > virt) + n = &(*n)->rb_left; + else + n = &(*n)->rb_right; + } + + return(n); } -static int virt_hash(void *virt) +static struct phys_desc *find_phys_mapping(void *virt) { - unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT; - return(addr % PHYS_HASHSIZE); + struct rb_node **n = find_rb(virt); + + if(*n == NULL) + return(NULL); + + return(rb_entry(*n, struct phys_desc, rb)); } -DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp, - virt_hash); +static void insert_phys_mapping(struct phys_desc *desc) +{ + struct rb_node **n = find_rb(desc->virt); + + if(*n != NULL) + panic("Physical remapping for %p already present", + desc->virt); + + rb_link_node(&desc->rb, (*n)->rb_parent, n); + rb_insert_color(&desc->rb, &phys_mappings); +} LIST_HEAD(descriptor_mappings); @@ -106,7 +106,7 @@ static struct desc_mapping *descriptor_mapping(int fd) if(desc == NULL) return(NULL); - *desc = ((struct desc_mapping) + *desc = ((struct desc_mapping) { .fd = fd, .list = LIST_HEAD_INIT(desc->list), .pages = LIST_HEAD_INIT(desc->pages) }); @@ -127,7 +127,8 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) return(-ENOMEM); phys = __pa(virt); - if(find_virtmem_hash(&virtmem_hash, virt) != NULL) + desc = find_phys_mapping(virt); + if(desc != NULL) panic("Address 0x%p is already substituted\n", virt); err = -ENOMEM; @@ -135,14 +136,13 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) if(desc == NULL) goto out; - *desc = ((struct phys_desc) - { .virt_ptrs = { NULL, NULL }, - .fd = fd, + *desc = ((struct phys_desc) + { .fd = fd, .offset = offset, .virt = virt, .phys = __pa(virt), .list = LIST_HEAD_INIT(desc->list) }); - insert_virtmem_hash(&virtmem_hash, desc); + insert_phys_mapping(desc); list_add(&desc->list, &fd_maps->pages); @@ -151,7 +151,7 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) if(!err) goto out; - remove_virtmem_hash(&virtmem_hash, desc); + rb_erase(&desc->rb, &phys_mappings); kfree(desc); out: return(err); @@ -164,7 +164,7 @@ static void remove_mapping(struct phys_desc *desc) void *virt = desc->virt; int err; - remove_virtmem_hash(&virtmem_hash, desc); + rb_erase(&desc->rb, &phys_mappings); list_del(&desc->list); kfree(desc); @@ -179,7 +179,7 @@ int physmem_remove_mapping(void *virt) struct phys_desc *desc; virt = (void *) ((unsigned long) virt & PAGE_MASK); - desc = find_virtmem_hash(&virtmem_hash, virt); + desc = find_phys_mapping(virt); if(desc == NULL) return(0); @@ -221,6 +221,10 @@ void physmem_forget_descriptor(int fd) kfree(desc); } +EXPORT_SYMBOL(physmem_forget_descriptor); +EXPORT_SYMBOL(physmem_remove_mapping); +EXPORT_SYMBOL(physmem_subst_mapping); + void arch_free_page(struct page *page, int order) { void *virt; @@ -234,7 +238,9 @@ void arch_free_page(struct page *page, int order) int is_remapped(void *virt) { - return(find_virtmem_hash(&virtmem_hash, virt) != NULL); + struct phys_desc *desc = find_phys_mapping(virt); + + return(desc != NULL); } /* Changed during early boot */ @@ -273,7 +279,7 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) if(kmalloc_ok){ map = kmalloc(total_len, GFP_KERNEL); - if(map == NULL) + if(map == NULL) map = vmalloc(total_len); } else map = alloc_bootmem_low_pages(total_len); @@ -322,12 +328,12 @@ static unsigned long kmem_top = 0; unsigned long get_kmem_end(void) { - if(kmem_top == 0) + 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, +void map_memory(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x) { __u64 offset; @@ -335,9 +341,14 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, fd = phys_mapping(phys, &offset); err = os_map_memory((void *) virt, fd, offset, len, r, w, x); - if(err) + if(err) { + if(err == -ENOMEM) + printk("try increasing the host's " + "/proc/sys/vm/max_map_count to /4096\n"); 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) @@ -353,7 +364,7 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, physmem_fd = create_mem_file(len + highmem); offset = uml_reserved - uml_physmem; - err = os_map_memory((void *) uml_reserved, physmem_fd, offset, + err = os_map_memory((void *) uml_reserved, physmem_fd, offset, len - offset, 1, 1, 0); if(err < 0){ os_print_error(err, "Mapping memory"); @@ -367,8 +378,7 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, int phys_mapping(unsigned long phys, __u64 *offset_out) { - struct phys_desc *desc = find_virtmem_hash(&virtmem_hash, - __va(phys & PAGE_MASK)); + struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK)); int fd = -1; if(desc != NULL){ @@ -381,9 +391,9 @@ int phys_mapping(unsigned long phys, __u64 *offset_out) } else if(phys < __pa(end_iomem)){ struct iomem_region *region = iomem_regions; - + while(region != NULL){ - if((phys >= region->phys) && + if((phys >= region->phys) && (phys < region->phys + region->size)){ fd = region->fd; *offset_out = phys - region->phys; @@ -419,7 +429,7 @@ __uml_setup("mem=", uml_mem_setup, 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; @@ -437,7 +447,7 @@ int setup_iomem(void) int err; while(region != NULL){ - err = os_map_memory((void *) iomem_start, region->fd, 0, + 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, " diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 4c3aa4535..4468f2440 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -9,18 +9,17 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include #include +#include #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -47,7 +46,7 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) int flags = 0, pages; if(sig_stack != NULL){ - pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; + pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); set_sigstack(sig_stack, pages * page_size()); flags = SA_ONSTACK; } @@ -71,8 +70,7 @@ void init_new_thread_signals(int altstack) set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 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); + flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); signal(SIGHUP, SIG_IGN); init_irq_signals(altstack); @@ -122,24 +120,19 @@ 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(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) - panic("outer trampoline didn't exit with SIGKILL"); - - return(arg.pid); -} + if(new_pid < 0) + return(new_pid); -void suspend_new_thread(int fd) -{ - char c; + CATCH_EINTR(err = waitpid(new_pid, &status, 0)); + if(err < 0) + panic("Waiting for outer trampoline failed - errno = %d", + errno); - os_stop_process(os_getpid()); + if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) + panic("outer trampoline didn't exit with SIGKILL, " + "status = %d", status); - if(read(fd, &c, sizeof(c)) != sizeof(c)) - panic("read failed in suspend_new_thread"); + return(arg.pid); } static int ptrace_child(void *arg) @@ -168,7 +161,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 +178,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 +186,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, ®s) < 0) + panic("check_ptrace : failed to read child " + "registers, errno = %d", errno); + regs.orig_eax = pid; + if (ptrace(PTRACE_SETREGS, pid, 0, ®s) < 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 +258,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,15 +278,16 @@ 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) { - jmp_buf buf; + sigjmp_buf buf; int n; *jmp_ptr = &buf; - n = setjmp(buf); + n = sigsetjmp(buf, 1); if(n != 0) return(n); (*fn)(arg); @@ -273,7 +327,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 e17600a9b..d2efcff92 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,13 +157,15 @@ 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) { p->thread = (struct thread_struct) INIT_THREAD; - p->thread.kernel_stack = - (unsigned long) p->thread_info + 2 * PAGE_SIZE; return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, clone_flags, sp, stack_top, p, regs)); } @@ -190,7 +192,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 +301,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); @@ -318,8 +325,7 @@ int user_context(unsigned long sp) unsigned long stack; stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); - stack += 2 * PAGE_SIZE; - return(stack != current->thread.kernel_stack); + return(stack != (unsigned long) current_thread); } extern void remove_umid_dir(void); @@ -367,10 +373,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 +396,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 c68c937f6..40912d18c 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; @@ -292,7 +287,7 @@ int sys_ptrace(long request, long pid, long addr, long data) } #endif default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: @@ -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 3e4ab2963..207f89d74 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 02272e623..fbffae415 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio_kern.c @@ -6,26 +6,33 @@ #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) +static 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) { - if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, + int err; + + err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", - NULL)){ - printk("write_sigio_irq : um_request_irq failed\n"); + NULL); + if(err){ + printk("write_sigio_irq : um_request_irq failed, err = %d\n", + err); return(-1); } sigio_irq_fd = fd; diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index b5ce13d55..82d19b451 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -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,14 @@ 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); + /* Not now, but complain so we now where we failed. */ + err = raw(master); + 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 +87,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 +102,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 +130,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 +192,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 +208,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 +242,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 +261,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 +359,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 +389,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 +402,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 6e13847ed..23aefcbea 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 = ¤t->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 = ¤t->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 = ¤t->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(¤t->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(¤t->thread.regs)); - void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); + void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); + void __user *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); spin_lock_irq(¤t->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(¤t->thread.regs)); - void *fp; + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct ucontext __user *uc = sp_to_uc(sp); int sig_size = _NSIG_WORDS * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -266,7 +294,6 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext)); copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, &signal_frame_si.common.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c index 52cfd60a1..74a69e491 100644 --- a/arch/um/kernel/signal_user.c +++ b/arch/um/kernel/signal_user.c @@ -80,6 +80,12 @@ void unblock_signals(void) change_signals(SIG_UNBLOCK); } +/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled + * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to + * be able to profile all of UML, not just the non-critical sections. If + * profiling is not thread-safe, then that is not my problem. We can disable + * profiling when SMP is enabled in that case. + */ #define SIGIO_BIT 0 #define SIGVTALRM_BIT 1 @@ -114,6 +120,11 @@ int set_signals(int enable) sigaddset(&mask, SIGVTALRM); sigaddset(&mask, SIGALRM); } + + /* This is safe - sigprocmask is guaranteed to copy locally the + * value of new_set, do his work and then, at the end, write to + * old_set. + */ if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) panic("Failed to enable signals"); ret = enable_mask(&mask); diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 72c79956f..37d3f7e97 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,22 +3,14 @@ # Licensed under the GPL # -obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ +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)/ + +subdir-y := util 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 - $(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 c9942b6fc..d50633a70 100644 --- a/arch/um/kernel/skas/exec_user.c +++ b/arch/um/kernel/skas/exec_user.c @@ -11,6 +11,7 @@ #include #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 7516206cc..285edc50a 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 f5c5268cc..be043e8f7 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 d9614f6cd..0bbc97540 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 d28c4b1de..0d6f30bf7 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 d163090c0..cfcfa0d60 100644 --- a/arch/um/kernel/skas/mem_user.c +++ b/arch/um/kernel/skas/mem_user.c @@ -7,6 +7,7 @@ #include #include #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 5911cdd0c..6cb9a6d02 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 cb91f8cd1..cb748f85d 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -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,45 +187,66 @@ 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)) { - jmp_buf switch_buf, fork_buf; + unsigned long flags; + sigjmp_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(); } void thread_wait(void *sw, void *fb) { - jmp_buf buf, **switch_buf = sw, *fork_buf; + sigjmp_buf buf, **switch_buf = sw, *fork_buf; *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,42 +286,43 @@ 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) { - jmp_buf my_buf, **me_ptr = me, *next_buf = next; + sigjmp_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; +static sigjmp_buf initial_jmpbuf; /* XXX Make these percpu */ static void (*cb_proc)(void *arg); static void *cb_arg; -static jmp_buf *cb_back; +static sigjmp_buf *cb_back; int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) { - jmp_buf **switch_buf = switch_buf_ptr; + sigjmp_buf **switch_buf = switch_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) @@ -297,15 +347,15 @@ void remove_sigstack(void) void initial_thread_cb_skas(void (*proc)(void *), void *arg) { - jmp_buf here; + sigjmp_buf here; cb_proc = proc; cb_arg = 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,40 +366,21 @@ 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); -} - -int new_mm(int from) -{ - struct proc_mm_op copy; - int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); - - if(fd < 0) - return(-errno); - - if(from != -1){ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = from } } ); - n = os_write_file(fd, ©, sizeof(copy)); - if(n != sizeof(copy)) - printk("new_mm : /proc/mm copy_segments failed, " - "errno = %d\n", errno); - } - return(fd); + siglongjmp(initial_jmpbuf, 4); } 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 +388,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 128146c80..5418f0862 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" @@ -16,6 +22,62 @@ #include "frame.h" #include "kern.h" #include "mode.h" +#include "proc_mm.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) { @@ -61,11 +123,13 @@ void new_thread_handler(int sig) thread_wait(¤t->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, ¤t->thread.exec_buf); if(n == 1) userspace(¤t->thread.regs.regs); @@ -93,11 +157,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(¤t->thread.regs.regs); } @@ -128,15 +192,36 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, handler = new_thread_handler; } - new_thread((void *) p->thread.kernel_stack, - &p->thread.mode.skas.switch_buf, + new_thread(p->thread_info, &p->thread.mode.skas.switch_buf, &p->thread.mode.skas.fork_buf, handler); return(0); } +int new_mm(int from) +{ + struct proc_mm_op copy; + int n, fd; + + fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); + if(fd < 0) + return(fd); + + if(from != -1){ + copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, + .u = + { .copy_segments = from } } ); + n = os_write_file(fd, ©, sizeof(copy)); + if(n != sizeof(copy)) + printk("new_mm : /proc/mm copy_segments failed, " + "err = %d\n", -n); + } + + return(fd); +} + 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,27 +245,29 @@ static int start_kernel_proc(void *unused) int start_uml_skas(void) { - start_userspace(); + start_userspace(0); capture_signal_stack(); init_new_thread_signals(1); - idle_timer(); + uml_idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; - return(start_idle_thread((void *) init_task.thread.kernel_stack, + return(start_idle_thread(init_task.thread_info, &init_task.thread.mode.skas.switch_buf, &init_task.thread.mode.skas.fork_buf)); } 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 2ad8271c6..3eeea057c 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 5f340e102..b015d1960 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 bc837a77e..1d7eca5a8 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 caccb772b..34fd5f94e 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/tlb.c b/arch/um/kernel/skas/tlb.c index ed3d6bcd5..02e3e06bb 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -77,7 +77,7 @@ void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end) int updated = 0, err; mm = &init_mm; - for(addr = start_vm; addr < end_vm;){ + for(addr = start; addr < end;){ pgd = pgd_offset(mm, addr); pmd = pmd_offset(pgd, addr); if(pmd_present(*pmd)){ diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 0906f65b8..96593709a 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 */ @@ -19,8 +19,10 @@ void sig_handler_common_skas(int sig, void *sc_ptr) struct skas_regs *r; struct signal_info *info; int save_errno = errno; + int save_user; r = &TASK_REGS(get_current())->skas; + save_user = r->is_user; r->is_user = 0; r->fault_addr = SC_FAULT_ADDR(sc); r->fault_type = SC_FAULT_TYPE(sc); @@ -33,16 +35,13 @@ void sig_handler_common_skas(int sig, void *sc_ptr) (*info->handler)(sig, (union uml_pt_regs *) r); errno = save_errno; + r->is_user = save_user; } -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 index ea82f19b2..77048cd67 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -12,8 +12,9 @@ #include "asm/pgtable.h" #include "asm/uaccess.h" #include "kern_util.h" +#include "user_util.h" -extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, +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) @@ -25,7 +26,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) int dummy_code; if(IS_ERR(phys) || (is_write && !pte_write(pte))){ - err = handle_page_fault(virt, 0, is_write, 0, &dummy_code); + err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); if(err) return(0); phys = um_virt_to_phys(current, virt, NULL); @@ -33,7 +34,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) return((unsigned long) phys); } -static int do_op(unsigned long addr, int len, int is_write, +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; @@ -51,37 +52,67 @@ static int do_op(unsigned long addr, int len, int is_write, 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) +static void do_buffer_op(void *jmpbuf, void *arg_ptr) { + va_list args = *((va_list *) arg_ptr); + unsigned long addr = va_arg(args, unsigned long); + int len = va_arg(args, int); + int is_write = va_arg(args, int); + int (*op)(unsigned long, int, void *) = va_arg(args, void *); + void *arg = va_arg(args, void *); + int *res = va_arg(args, int *); int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); int remain = len, n; + current->thread.fault_catcher = jmpbuf; n = do_op(addr, size, is_write, op, arg); - if(n != 0) - return(n < 0 ? remain : 0); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } addr += size; remain -= size; - if(remain == 0) - return(0); + if(remain == 0){ + *res = 0; + goto out; + } while(addr < ((addr + remain) & PAGE_MASK)){ n = do_op(addr, PAGE_SIZE, is_write, op, arg); - if(n != 0) - return(n < 0 ? remain : 0); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } addr += PAGE_SIZE; remain -= PAGE_SIZE; } - if(remain == 0) - return(0); + if(remain == 0){ + *res = 0; + goto out; + } n = do_op(addr, remain, is_write, op, arg); if(n != 0) - return(n < 0 ? remain : 0); - return(0); + *res = (n < 0 ? remain : 0); + else *res = 0; + out: + current->thread.fault_catcher = NULL; +} + +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int faulted, res; + + faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, + &res); + if(!faulted) + return(res); + + return(addr + len - (unsigned long) current->thread.fault_addr); } static int copy_chunk_from_user(unsigned long from, int len, void *arg) @@ -135,7 +166,7 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) n = strnlen(to, len); *to_ptr += n; - if(n < len) + if(n < len) return(1); return(0); } @@ -153,7 +184,7 @@ int strncpy_from_user_skas(char *dst, const char *src, int count) if(!access_ok_skas(VERIFY_READ, src, 1)) return(-EFAULT); - n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, + n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, &ptr); if(n != 0) return(-EFAULT); @@ -178,7 +209,7 @@ int clear_user_skas(void *mem, int len) return(0); } - return(access_ok_skas(VERIFY_WRITE, mem, len) ? + return(access_ok_skas(VERIFY_WRITE, mem, len) ? buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len); } diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile index e62dc253e..a26e0c34a 100644 --- a/arch/um/kernel/skas/util/Makefile +++ b/arch/um/kernel/skas/util/Makefile @@ -1,10 +1,2 @@ -all: mk_ptregs - -mk_ptregs : mk_ptregs.o - $(CC) -o mk_ptregs mk_ptregs.o - -mk_ptregs.o : mk_ptregs.c - $(CC) -c $< - -clean : - $(RM) -f mk_ptregs *.o *~ +hostprogs-y := mk_ptregs +always := $(hostprogs-y) diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c index 658791017..116f74d2c 100644 --- a/arch/um/kernel/skas/util/mk_ptregs.c +++ b/arch/um/kernel/skas/util/mk_ptregs.c @@ -1,3 +1,4 @@ +#include #include #include diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index b8158556c..b5e66b291 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 @@ -12,10 +18,10 @@ #include "linux/threads.h" #include "linux/interrupt.h" #include "linux/err.h" +#include "linux/hardirq.h" #include "asm/smp.h" #include "asm/processor.h" #include "asm/spinlock.h" -#include "asm/hardirq.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" @@ -23,9 +29,11 @@ #include "os.h" /* CPU online map, set by smp_boot_cpus */ -unsigned long cpu_online_map = cpumask_of_cpu(0); +cpumask_t cpu_online_map = CPU_MASK_NONE; +cpumask_t cpu_possible_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(cpu_possible_map); /* Per CPU bogomips and other parameters * The only piece used here is the ipi pipe, which is set before SMP is @@ -33,14 +41,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 +55,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 +107,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 +126,21 @@ void smp_prepare_cpus(unsigned int maxcpus) { struct task_struct *idle; unsigned long waittime; - int err, cpu; + int err, cpu, me = smp_processor_id(); + int i; + + for (i = 0; i < ncpus; ++i) + cpu_set(i, cpu_possible_map); - 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 +152,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 +188,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 +248,9 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, info = _info; for (i=0;ithread_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 77a7d922e..314925365 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,49 @@ #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 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 +63,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 2af5fc2e5..6d0912b99 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,23 @@ 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); -} - -long sys_clone(unsigned long clone_flags, unsigned long newsp) -{ - struct task_struct *p; - - current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); - 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 +127,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 +214,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 +263,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(¤t->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 b43c21466..80b84700f 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 3fd42081d..b1674bc13 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 6f0d7573e..96691a0df 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -4,24 +4,33 @@ */ #include +#include #include #include #include #include #include -#include "linux/module.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 + */ +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) @@ -44,6 +53,15 @@ void enable_timer(void) errno); } +void disable_timer(void) +{ + struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); + if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || + (setitimer(ITIMER_REAL, &disable, NULL) < 0)) + printk("disnable_timer - setitimer failed, errno = %d\n", + errno); +} + void switch_timers(int to_real) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); @@ -66,7 +84,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 +94,23 @@ void idle_timer(void) set_interval(ITIMER_REAL); } +extern int do_posix_clock_monotonic_gettime(struct timespec *tp); + void time_init(void) { + struct timespec now; + 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 +123,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 +139,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 752fd03f2..5ce566882 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -20,6 +20,7 @@ #include "user_util.h" #include "time_user.h" #include "mode.h" +#include "os.h" u64 jiffies_64; @@ -30,22 +31,63 @@ 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_usecs; +#ifdef CONFIG_UML_REAL_TIME_CLOCK +static long long delta; /* Deviation per interval */ +#endif + +#define MILLION 1000000 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 + /* We've had 1 tick */ + unsigned long long usecs = os_usecs(); - if(!timer_irq_inited) return; - missed_ticks[cpu] = 0; - while(ticks--) do_IRQ(TIMER_IRQ, regs); + delta += usecs - prev_usecs; + prev_usecs = usecs; + + /* Protect against the host clock being set backwards */ + if(delta < 0) + delta = 0; + + ticks += (delta * HZ) / MILLION; + delta -= (ticks * MILLION) / HZ; +#else + ticks = 1; +#endif + } + else { + prev_usecs = os_usecs(); + first_tick = 1; + } + + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } void boot_timer_handler(int sig) @@ -58,12 +100,15 @@ void boot_timer_handler(int sig) do_timer(®s); } -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 +126,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; } @@ -110,7 +155,7 @@ void __udelay(um_udelay_t usecs) { int i, n; - n = (loops_per_jiffy * HZ * usecs) / 1000000; + n = (loops_per_jiffy * HZ * usecs) / MILLION; for(i=0;ithread_info->cpu == 0) + if(current_thread->cpu == 0) timer_irq(regs); } @@ -136,6 +183,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 +198,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 +208,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 7925dc459..cba33ef6d 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 63812e597..d12eac64a 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -5,11 +5,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -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); @@ -121,9 +127,9 @@ void alarm_handler(int sig, struct sigcontext sc) void do_longjmp(void *b, int val) { - jmp_buf *buf = b; + sigjmp_buf *buf = b; - longjmp(*buf, val); + siglongjmp(*buf, val); } /* diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 439688b0d..33416e889 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 afd94713d..065b504a6 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -14,9 +14,11 @@ #include "kern_util.h" #include "irq_user.h" #include "time_user.h" +#include "signal_user.h" #include "mem_user.h" #include "os.h" #include "tlb.h" +#include "mode.h" static int exec_tramp(void *sig_stack) { @@ -38,8 +40,7 @@ void flush_thread_tt(void) do_exit(SIGKILL); } - new_pid = start_fork_tramp((void *) current->thread.kernel_stack, - stack, 0, exec_tramp); + new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp); if(new_pid < 0){ printk(KERN_ERR "flush_thread : new thread failed, errno = %d\n", @@ -47,17 +48,19 @@ 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()); + change_sig(SIGUSR1, 1); + change_sig(SIGUSR1, 0); 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 35d108266..6d5fa825a 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 83d94abb9..1a64e753e 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 42425a225..7399836cb 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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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 0c39b2663..34090b8d2 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 e10db3f1f..308526745 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 7a2f330a3..6224afcd8 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -28,7 +28,7 @@ void *switch_to_tt(void *prev, void *next, void *last) { - struct task_struct *from, *to; + struct task_struct *from, *to, *prev_sched; unsigned long flags; int err, vtalrm, alrm, prof, cpu; char 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)) @@ -72,6 +72,18 @@ void *switch_to_tt(void *prev, void *next, void *last) if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); + /* If the process that we have just scheduled away from has exited, + * then it needs to be killed here. The reason is that, even though + * it will kill itself when it next runs, that may be too late. Its + * stack will be freed, possibly before then, and if that happens, + * we have a use-after-free situation. So, it gets killed here + * in case it has not already killed itself. + */ + prev_sched = current->thread.prev_sched; + if((prev_sched->state == TASK_ZOMBIE) || + (prev_sched->state == TASK_DEAD)) + os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); + /* This works around a nasty race with 'jail'. If we are switching * between two threads of a threaded app and the incoming process * runs before the outgoing process reaches the read, and it makes @@ -104,50 +116,92 @@ 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 suspend_new_thread(int fd) +{ + int err; + char c; + + os_stop_process(os_getpid()); + err = os_read_file(fd, &c, sizeof(c)); + if(err != sizeof(c)) + panic("read failed in suspend_new_thread, err = %d", -err); } 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(¤t->thread.regs.regs) = (void *) (&sig + 1); + disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | + (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); + SC_SIGMASK(UPT_SC(¤t->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, ¤t->thread.exec_buf)) do_exit(0); + + /* XXX No set_user_mode here because a newly execed process will + * immediately segfault on its non-existent IP, coming straight back + * to the signal handler, which will call set_user_mode on its way + * out. This should probably change since it's confusing. + */ } 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()); + change_sig(SIGUSR1, 1); return(0); } @@ -156,7 +210,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 +219,33 @@ void finish_fork_handler(int sig) UPT_SC(¤t->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()); + change_sig(SIGUSR1, 1); return(0); } @@ -213,8 +265,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); } @@ -227,8 +279,7 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, clone_flags &= CLONE_VM; p->thread.temp_stack = stack; - new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, - clone_flags, tramp); + new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp); if(new_pid < 0){ printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", -new_pid); @@ -246,19 +297,30 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, current->thread.request.op = OP_FORK; current->thread.request.u.fork.pid = new_pid; os_usr1_process(os_getpid()); - return(0); + + /* Enable the signal and then disable it to ensure that it is handled + * here, and nowhere else. + */ + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); + err = 0; + out: + return(err); } void reboot_tt(void) { current->thread.request.op = OP_REBOOT; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); } void halt_tt(void) { current->thread.request.op = OP_HALT; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); } void kill_off_processes_tt(void) @@ -285,6 +347,9 @@ void initial_thread_cb_tt(void (*proc)(void *), void *arg) current->thread.request.u.cb.proc = proc; current->thread.request.u.cb.arg = arg; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); } } @@ -377,8 +442,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); @@ -454,8 +519,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) @@ -479,9 +545,9 @@ int start_uml_tt(void) void *sp; int pages; - pages = (1 << CONFIG_KERNEL_STACK_ORDER) - 2; - sp = (void *) init_task.thread.kernel_stack + pages * PAGE_SIZE - - sizeof(unsigned long); + pages = (1 << CONFIG_KERNEL_STACK_ORDER); + sp = (void *) ((unsigned long) init_task.thread_info) + + pages * PAGE_SIZE - sizeof(unsigned long); return(tracer(start_kernel_proc, sp)); } diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile index 97d4f0bc1..9f9daf5c1 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 65504f8c6..458ecf9a4 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 #include #include -#include #include #include #include @@ -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 50a120d5e..c42855aed 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 #include #include +#include #include #include #include diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c index aad7e4b62..86ef67653 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 2ad8271c6..3eeea057c 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 1b71f9ce5..555ffd0ee 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 f7c845d99..1cabbd866 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 32ac316de..d8ad334cf 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 6a6322a3e..deef43bb5 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); } @@ -329,7 +330,8 @@ int tracer(int (*init_proc)(void *), void *sp) continue; } tracing = 0; - if(do_syscall(task, pid)) sig = SIGUSR2; + if(do_syscall(task, pid)) + sig = SIGUSR2; else clear_singlestep(task); break; case SIGPROF: @@ -401,7 +403,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/trap_user.c b/arch/um/kernel/tt/trap_user.c index 7a6dbf5f9..00bacacfc 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c @@ -23,6 +23,13 @@ void sig_handler_common_tt(int sig, void *sc_ptr) unprotect_kernel_mem(); + /* This is done because to allow SIGSEGV to be delivered inside a SEGV + * handler. This can happen in copy_user, and if SEGV is disabled, + * the process will die. + */ + if(sig == SIGSEGV) + change_sig(SIGSEGV, 1); + r = &TASK_REGS(get_current())->tt; save_regs = *r; is_user = user_context(SC_SP(sc)); @@ -30,7 +37,6 @@ void sig_handler_common_tt(int sig, void *sc_ptr) if(sig != SIGUSR2) r->syscall = -1; - change_sig(SIGUSR1, 1); info = &sig_info[sig]; if(!info->is_irq) unblock_signals(); @@ -39,7 +45,6 @@ void sig_handler_common_tt(int sig, void *sc_ptr) if(is_user){ interrupt_end(); block_signals(); - change_sig(SIGUSR1, 0); set_user_mode(NULL); } *r = save_regs; diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c index 9c8401120..040971893 100644 --- a/arch/um/kernel/tt/uaccess.c +++ b/arch/um/kernel/tt/uaccess.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -8,7 +8,7 @@ int copy_from_user_tt(void *to, const void *from, int n) { - if(!access_ok_tt(VERIFY_READ, from, n)) + if(!access_ok_tt(VERIFY_READ, from, n)) return(n); return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, @@ -19,7 +19,7 @@ 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, ¤t->thread.fault_addr, ¤t->thread.fault_catcher)); } @@ -28,10 +28,10 @@ int strncpy_from_user_tt(char *dst, const char *src, int count) { int n; - if(!access_ok_tt(VERIFY_READ, src, 1)) + if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); - n = __do_strncpy_from_user(dst, src, count, + n = __do_strncpy_from_user(dst, src, count, ¤t->thread.fault_addr, ¤t->thread.fault_catcher); if(n < 0) return(-EFAULT); diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index 537ee9fba..f01475512 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -8,15 +8,20 @@ #include #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; + sigjmp_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 36d3e6992..3f7aecdbe 100644 --- a/arch/um/kernel/tt/unmap.c +++ b/arch/um/kernel/tt/unmap.c @@ -3,10 +3,7 @@ * Licensed under the GPL */ -#include -#include #include -#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 61c4cc3af..0a70c5e66 100644 --- a/arch/um/kernel/tty_log.c +++ b/arch/um/kernel/tty_log.c @@ -9,10 +9,10 @@ #include #include #include -#include #include #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, ¤t_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 eb9be24ce..d035257ed 100644 --- a/arch/um/kernel/uaccess_user.c +++ b/arch/um/kernel/uaccess_user.c @@ -18,9 +18,9 @@ unsigned long __do_user_copy(void *to, const void *from, int n, { unsigned long *faddrp = (unsigned long *) fault_addr, ret; - jmp_buf jbuf; + sigjmp_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 e8f0cacc1..9146c11e5 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -27,7 +27,6 @@ #include "user_util.h" #include "kern_util.h" #include "kern.h" -#include "mprot.h" #include "mem_user.h" #include "mem.h" #include "umid.h" @@ -38,13 +37,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 +57,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 +142,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 +187,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 +218,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 +229,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,15 +299,15 @@ 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) int linux_main(int argc, char **argv) { - unsigned long avail; + unsigned long avail, diff; 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; @@ -315,6 +323,16 @@ int linux_main(int argc, char **argv) brk_start = (unsigned long) sbrk(0); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); + /* Increase physical memory size for exec-shield users + so they actually get what they asked for. This should + add zero for non-exec shield users */ + + diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + if(diff > 1024 * 1024){ + printf("Adding %ld bytes to physical memory to account for " + "exec-shield gap\n", diff); + physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + } uml_physmem = uml_start; @@ -328,12 +346,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 +365,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 +387,23 @@ 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', ¤t->thread.regs, NULL, NULL); + handle_sysrq('p', ¤t->thread.regs, NULL); #endif + uml_exitcode = 1; machine_halt(); return(0); } @@ -403,6 +428,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 1da1a0d66..78c8dc45c 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -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 %d " + "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); @@ -195,17 +199,20 @@ int not_dead_yet(char *dir) static int __init set_uml_dir(char *name, int *add) { if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ - uml_dir = malloc(strlen(name) + 1); + uml_dir = malloc(strlen(name) + 2); 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 here because do_initcalls doesn't look at + * the return value. + */ return(0); } sprintf(uml_dir, "%s/", name); } else uml_dir = name; - return 0; + return(0); } static int __init make_uml_dir(void) @@ -217,7 +224,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 +239,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 +304,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/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S new file mode 100644 index 000000000..89ed32983 --- /dev/null +++ b/arch/um/kernel/uml.lds.S @@ -0,0 +1,96 @@ +#include + +OUTPUT_FORMAT(ELF_FORMAT) +OUTPUT_ARCH(ELF_ARCH) +ENTRY(_start) +jiffies = jiffies_64; + +SECTIONS +{ + . = START + SIZEOF_HEADERS; + + __binary_start = .; +#ifdef MODE_TT + .thread_private : { + __start_thread_private = .; + errno = .; + . += 4; + arch/um/kernel/tt/unmap_fin.o (.data) + __end_thread_private = .; + } + . = ALIGN(4096); + .remap : { arch/um/kernel/tt/unmap_fin.o (.text) } +#endif + + . = ALIGN(4096); /* Init code and data */ + _stext = .; + __init_begin = .; + .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*) + } + + #include "asm/common.lds.S" + + init.data : { *(init.data) } + .data : + { + . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ + *(.data.init_task) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + . = ALIGN(0x1000); + .sbss : + { + __bss_start = .; + PROVIDE(_bss_start = .); + *(.sbss) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c index 9e4fbae93..b2c7c5d2e 100644 --- a/arch/um/kernel/user_util.c +++ b/arch/um/kernel/user_util.c @@ -5,10 +5,10 @@ #include #include -#include #include #include -#include +#include +#include #include #include #include @@ -81,19 +81,19 @@ 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); } else if(WIFEXITED(status)) - printk("process exited with status %d\n", - WEXITSTATUS(status)); + printk("process %d exited with status %d\n", + pid, WEXITSTATUS(status)); else if(WIFSIGNALED(status)) - printk("process exited with signal %d\n", - WTERMSIG(status)); + printk("process %d exited with signal %d\n", + pid, WTERMSIG(status)); else if((WSTOPSIG(status) == SIGVTALRM) || (WSTOPSIG(status) == SIGALRM) || (WSTOPSIG(status) == SIGIO) || @@ -109,8 +109,8 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) ptrace(cont_type, pid, 0, WSTOPSIG(status)); continue; } - else printk("process stopped with signal %d\n", - WSTOPSIG(status)); + else printk("process %d stopped with signal %d\n", + pid, WSTOPSIG(status)); panic("wait_for_stop failed to wait for %d to stop " "with %d\n", pid, sig); } @@ -118,29 +118,27 @@ 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) { struct termios tt; int err; - tcgetattr(fd, &tt); + CATCH_EINTR(err = tcgetattr(fd, &tt)); + if (err < 0) { + printk("tcgetattr failed, errno = %d\n", errno); + return(-errno); + } + cfmakeraw(&tt); - err = tcsetattr(fd, TCSANOW, &tt); - if((err < 0) && complain){ - printk("tcsetattr failed, errno = %d\n", errno); + + CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); + if (err < 0) { + 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); } @@ -163,6 +161,21 @@ void setup_hostinfo(void) host.release, host.version, host.machine); } +int setjmp_wrapper(void (*proc)(void *, void *), ...) +{ + va_list args; + sigjmp_buf buf; + int n; + + n = sigsetjmp(buf, 1); + if(n == 0){ + va_start(args, proc); + (*proc)(&buf, &args); + } + va_end(args); + return(n); +} + /* * 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/Makefile b/arch/um/os-Linux/Makefile index 37eea4a32..ff94c8f61 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 time.o tty.o user_syms.o drivers/ -USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file)) +USER_OBJS := $(foreach file,file.o process.o time.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 17f156104..6ae4b19d9 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 e27592985..cd4d6544d 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #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 c858f1160..4b83c6c3f 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -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 e622db007..514ab984c 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,33 +19,236 @@ #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) { - struct stat64 buf; + int flags; - if(stat64(file, &buf) == -1) + 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); +} - 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); +int os_mode_fd(int fd, int mode) +{ + int err; + + do { + err = fchmod(fd, mode); + } while((err < 0) && (errno==EINTR)) ; + + if(err < 0) + return(-errno); + + 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 +268,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 +293,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 +312,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) @@ -219,6 +496,16 @@ int os_set_fd_async(int fd, int owner) return(0); } +int os_clear_fd_async(int fd) +{ + int flags = fcntl(fd, F_GETFL); + + flags &= ~(O_ASYNC | O_NONBLOCK); + if(fcntl(fd, F_SETFL, flags) < 0) + return(-errno); + return(0); +} + int os_set_fd_block(int fd, int blocking) { int flags; @@ -270,7 +557,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 +602,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 +614,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 +628,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 a97778f31..ec4617b42 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 #include #include +#include #include #include #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 %ld", &pc) != 1){ + "%*d %*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,7 +90,7 @@ 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)); } @@ -95,7 +104,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 +113,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 +135,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/time.c b/arch/um/os-Linux/time.c new file mode 100644 index 000000000..cf30a39bc --- /dev/null +++ b/arch/um/os-Linux/time.c @@ -0,0 +1,21 @@ +#include +#include + +unsigned long long os_usecs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec); +} + +/* + * 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/os-Linux/tty.c b/arch/um/os-Linux/tty.c index 2866ddbc9..4cfdd18ea 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 index ef0fb71e4..2433c9e68 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -14,18 +14,20 @@ extern size_t strlen(const char *); extern void *memcpy(void *, const void *, size_t); +extern void *memmove(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(memmove); 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 + * 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) \ diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 7525859c5..0f65a9259 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,14 +1,21 @@ -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 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 + +# this needs to be before the foreach, because clean-files does not accept +# complete paths like $(src)/$f. +clean-files := $(SYMLINKS) + SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f) +bitops.c-dir = lib semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel @@ -24,19 +31,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 3905bab88..41b0ab2fe 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -4,20 +4,21 @@ */ #include -#include #include #include #include +#include #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,48 +137,76 @@ 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) { - unsigned long ip; + unsigned char tmp[2]; /* This is testing for a cmov (0x0f 0x4x) instruction causing a * SIGILL in init. */ if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0); - ip = UPT_IP(regs); - if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) + if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) + panic("SIGILL in init, could not read instructions!\n"); + if((tmp[0] != 0x0f) || ((tmp[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/fault.c b/arch/um/sys-i386/fault.c index 6a0ec334c..d0bbcdfdb 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/ldt.c b/arch/um/sys-i386/ldt.c index 33e302160..ba77ccaa8 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -13,6 +13,8 @@ #ifdef CONFIG_MODE_TT extern int modify_ldt(int func, void *ptr, unsigned long bytecount); +/* XXX this needs copy_to_user and copy_from_user */ + int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) { if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 70da62313..b1021e82b 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -39,10 +39,11 @@ 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, value = 0x%x, errno = %d\n", i, + regs[i], errno); } } @@ -54,7 +55,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/syscalls.c b/arch/um/sys-i386/syscalls.c index 751549bd7..6ad31749b 100644 --- a/arch/um/sys-i386/syscalls.c +++ b/arch/um/sys-i386/syscalls.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/sched.h" #include "asm/mman.h" #include "asm/uaccess.h" #include "asm/unistd.h" @@ -56,6 +57,27 @@ int old_select(struct sel_arg_struct *arg) return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); } +/* The i386 version skips reading from %esi, the fourth argument. So we must do + * this, too. + */ +int sys_clone(unsigned long clone_flags, unsigned long newsp, int *parent_tid, + int unused, int *child_tid) +{ + long ret; + + /* XXX: normal arch do here this pass, and also pass the regs to + * do_fork, instead of NULL. Currently the arch-independent code + * ignores these values, while the UML code (actually it's + * copy_thread) does the right thing. But this should change, + probably. */ + /*if (!newsp) + newsp = UPT_SP(current->thread.regs);*/ + current->thread.forking = 1; + ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); + current->thread.forking = 0; + return(ret); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile index a3eca5f22..34860f9ca 100644 --- a/arch/um/sys-i386/util/Makefile +++ b/arch/um/sys-i386/util/Makefile @@ -1,17 +1,8 @@ -host-progs := mk_sc -always := $(host-progs) 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 $@ $< - -clean : - $(RM) -f $(build-targets) - -archmrproper : clean +HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS) diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c index 224b6ad75..85cbd3039 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 4dd735320..d02f4c265 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 3767c2583..af200268f 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 defd03861..e2ab71209 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 7e7493431..cdcb1232a 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/Kconfig b/arch/v850/Kconfig index 8665652e2..4bb7e5150 100644 --- a/arch/v850/Kconfig +++ b/arch/v850/Kconfig @@ -68,7 +68,6 @@ menu "Processor type and features" bool "Anna" endchoice - #### V850E processor-specific config # All CPUs currently supported use the v850e architecture @@ -153,7 +152,6 @@ menu "Processor type and features" bool default RTE_MB_A_PCI - #### Some feature-specific configs # Everything except for the GDB simulator uses the same interrupt controller @@ -181,7 +179,6 @@ menu "Processor type and features" bool default !V850E_CACHE && !V850E2_CACHE - #### Misc config config ROM_KERNEL @@ -305,34 +302,7 @@ source "sound/Kconfig" source "drivers/usb/Kconfig" - -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - If you don't debug the kernel, you can say N. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on DEBUG_KERNEL - help - Enables console device to interprent special characters as - commands to dump state information. - -config NO_KERNEL_MSG - bool "Suppress Kernel BUG Messages" - help - Do not output any debug BUG messages within the kernel. - -endmenu +source "arch/v850/Kconfig.debug" source "security/Kconfig" diff --git a/arch/v850/Kconfig.debug b/arch/v850/Kconfig.debug new file mode 100644 index 000000000..4acfb9cca --- /dev/null +++ b/arch/v850/Kconfig.debug @@ -0,0 +1,10 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +endmenu diff --git a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile index 117bcaaa0..3930482bd 100644 --- a/arch/v850/kernel/Makefile +++ b/arch/v850/kernel/Makefile @@ -9,7 +9,7 @@ # for more details. # -extra-y := head.o init_task.o vmlinux.lds.s +extra-y := head.o init_task.o vmlinux.lds obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \ signal.o irq.o mach.o ptrace.o bug.o diff --git a/arch/v850/kernel/asm-consts.c b/arch/v850/kernel/asm-consts.c index 666930d9c..24f291369 100644 --- a/arch/v850/kernel/asm-consts.c +++ b/arch/v850/kernel/asm-consts.c @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #define DEFINE(sym, val) \ diff --git a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c index 89809fb98..336cbf21d 100644 --- a/arch/v850/kernel/irq.c +++ b/arch/v850/kernel/irq.c @@ -141,13 +141,15 @@ skip: int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ + int ret; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c index fc06058f2..c0ee8f0b7 100644 --- a/arch/v850/kernel/ptrace.c +++ b/arch/v850/kernel/ptrace.c @@ -147,14 +147,8 @@ int sys_ptrace(long request, long pid, long addr, long data) rval = ptrace_attach(child); goto out_tsk; } - rval = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->parent != current) + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; switch (request) { @@ -269,11 +263,8 @@ asmlinkage void syscall_trace(void) return; /* 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 * for normal use. strace only continues with a signal if the diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c index da39beb8e..551c41ba0 100644 --- a/arch/v850/kernel/rte_mb_a_pci.c +++ b/arch/v850/kernel/rte_mb_a_pci.c @@ -322,8 +322,6 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, /* Stubs for things we don't use. */ -struct pci_fixup pcibios_fixups[] = { { 0 } }; - /* Called after each bus is probed, but before its children are examined. */ void pcibios_fixup_bus(struct pci_bus *b) { diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c index 8e8bf5ddc..dacc9b331 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 caa9e3a04..60098e4f0 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/time.c b/arch/v850/kernel/time.c index 74067adea..d0266de06 100644 --- a/arch/v850/kernel/time.c +++ b/arch/v850/kernel/time.c @@ -40,24 +40,6 @@ unsigned long long sched_clock(void) return (unsigned long long)jiffies * (1000000000 / HZ); } -static inline void do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - extern int _stext; - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - if (pc < prof_len) - ++prof_buffer[pc]; - else - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - ++prof_buffer[prof_len-1]; - } -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -74,10 +56,7 @@ static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs) mach_tick (); do_timer (regs); - - if (! user_mode (regs)) - do_profile (regs->pc); - + profile_tick(CPU_PROFILING, regs); #if 0 /* * If we have an externally synchronized Linux clock, then update diff --git a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c index 2336da438..0ca64900d 100644 --- a/arch/v850/kernel/v850_ksyms.c +++ b/arch/v850/kernel/v850_ksyms.c @@ -14,7 +14,6 @@ #include #include #include -#include #include @@ -37,29 +36,29 @@ EXPORT_SYMBOL (ip_compute_csum); EXPORT_SYMBOL (ip_fast_csum); /* string / mem functions */ -EXPORT_SYMBOL_NOVERS (strcpy); -EXPORT_SYMBOL_NOVERS (strncpy); -EXPORT_SYMBOL_NOVERS (strcat); -EXPORT_SYMBOL_NOVERS (strncat); -EXPORT_SYMBOL_NOVERS (strcmp); -EXPORT_SYMBOL_NOVERS (strncmp); -EXPORT_SYMBOL_NOVERS (strchr); -EXPORT_SYMBOL_NOVERS (strlen); -EXPORT_SYMBOL_NOVERS (strnlen); -EXPORT_SYMBOL_NOVERS (strpbrk); -EXPORT_SYMBOL_NOVERS (strrchr); -EXPORT_SYMBOL_NOVERS (strstr); -EXPORT_SYMBOL_NOVERS (memset); -EXPORT_SYMBOL_NOVERS (memcpy); -EXPORT_SYMBOL_NOVERS (memmove); -EXPORT_SYMBOL_NOVERS (memcmp); -EXPORT_SYMBOL_NOVERS (memscan); +EXPORT_SYMBOL (strcpy); +EXPORT_SYMBOL (strncpy); +EXPORT_SYMBOL (strcat); +EXPORT_SYMBOL (strncat); +EXPORT_SYMBOL (strcmp); +EXPORT_SYMBOL (strncmp); +EXPORT_SYMBOL (strchr); +EXPORT_SYMBOL (strlen); +EXPORT_SYMBOL (strnlen); +EXPORT_SYMBOL (strpbrk); +EXPORT_SYMBOL (strrchr); +EXPORT_SYMBOL (strstr); +EXPORT_SYMBOL (memset); +EXPORT_SYMBOL (memcpy); +EXPORT_SYMBOL (memmove); +EXPORT_SYMBOL (memcmp); +EXPORT_SYMBOL (memscan); /* semaphores */ -EXPORT_SYMBOL_NOVERS (__down); -EXPORT_SYMBOL_NOVERS (__down_interruptible); -EXPORT_SYMBOL_NOVERS (__down_trylock); -EXPORT_SYMBOL_NOVERS (__up); +EXPORT_SYMBOL (__down); +EXPORT_SYMBOL (__down_interruptible); +EXPORT_SYMBOL (__down_trylock); +EXPORT_SYMBOL (__up); /* * libgcc functions - functions that are used internally by the @@ -72,8 +71,8 @@ extern void __lshrdi3 (void); extern void __muldi3 (void); extern void __negdi2 (void); -EXPORT_SYMBOL_NOVERS (__ashldi3); -EXPORT_SYMBOL_NOVERS (__ashrdi3); -EXPORT_SYMBOL_NOVERS (__lshrdi3); -EXPORT_SYMBOL_NOVERS (__muldi3); -EXPORT_SYMBOL_NOVERS (__negdi2); +EXPORT_SYMBOL (__ashldi3); +EXPORT_SYMBOL (__ashrdi3); +EXPORT_SYMBOL (__lshrdi3); +EXPORT_SYMBOL (__muldi3); +EXPORT_SYMBOL (__negdi2); diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S index 71669f7a9..bab351c37 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 2122afc52..697f467be 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -4,7 +4,7 @@ # # Note: ISA is disabled and will hopefully never be enabled. # If you managed to buy an ISA x86-64 box you'll have to fix all the -# ISA drivers you need yourself. +# ISA drivers you need yourself. # mainmenu "Linux Kernel Configuration" @@ -57,7 +57,7 @@ config EARLY_PRINTK it is not recommended because it looks ugly and doesn't cooperate with klogd/syslogd or the X server. You should normally N here, unless you want to debug such a crash. - + config HPET_TIMER bool default y @@ -78,6 +78,10 @@ config GENERIC_ISA_DMA bool default y +config GENERIC_IOMAP + bool + default y + source "init/Kconfig" @@ -90,14 +94,14 @@ choice config MK8 bool "AMD-Opteron/Athlon64" help - Optimize for AMD Opteron/Athlon64/Hammer/K8 CPUs. + Optimize for AMD Opteron/Athlon64/Hammer/K8 CPUs. config MPSC - bool "Intel x86-64" + bool "Intel x86-64" help Optimize for Intel IA32 with 64bit extension CPUs (Prescott/Nocona/Potomac) - + config GENERIC_CPU bool "Generic-x86-64" help @@ -130,8 +134,8 @@ config MICROCODE tristate "/dev/cpu/microcode - Intel CPU microcode support" ---help--- If you say Y here the 'File systems' section, you will be - able to update the microcode on Intel processors. You will - obviously need the actual microcode binary data itself which is + able to update the microcode on Intel processors. You will + obviously need the actual microcode binary data itself which is not shipped with the Linux kernel. For latest news and information on obtaining all the required @@ -165,7 +169,7 @@ config X86_HT bool depends on SMP && !MK8 default y - + config MATH_EMULATION bool @@ -231,13 +235,13 @@ config PREEMPT be preempted even if it is in kernel mode executing a system call. This allows applications to run more reliably even when the system is under load. On contrary it may also break your drivers and add - priority inheritance problems to your system. Don't select it if + priority inheritance problems to your system. Don't select it if you rely on a stable system or have slightly obscure hardware. It's also not very well tested on x86-64 currently. You have been warned. - Say Y here if you are feeling brave and building a kernel for a - desktop, embedded or real-time system. Say N if you are unsure. + Say Y here if you are feeling brave and building a kernel for a + desktop, embedded or real-time system. Say N if you are unsure. config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" @@ -297,7 +301,7 @@ config GART_IOMMU properly with 32-bit PCI devices that do not support DAC (Double Address Cycle). The IOMMU can be turned off at runtime with the iommu=off parameter. Normally the kernel will take the right choice by itself. - If unsure say Y + If unsure, say Y. # need this always enabled with GART_IOMMU for the VIA workaround config SWIOTLB @@ -310,13 +314,18 @@ config DUMMY_IOMMU depends on !GART_IOMMU && !SWIOTLB default y help - Don't use IOMMU code. This will cause problems when you have more than 4GB + Don't use IOMMU code. This will cause problems when you have more than 4GB of memory and any 32-bit devices. Don't turn on unless you know what you are doing. config X86_MCE - bool + bool "Machine check support" if EMBEDDED default y + help + Include a machine check error handler to report hardware errors. + This version will require the mcelog utility to decode some + machine check error logs. See + ftp://ftp.x86-64.org/pub/linux/tools/mcelog endmenu @@ -336,17 +345,27 @@ menu "Bus options (PCI etc.)" config PCI bool "PCI support" -# x86-64 doesn't support PCI BIOS access from long mode so always go direct. +# x86-64 doesn't support PCI BIOS access from long mode so always go direct. config PCI_DIRECT bool depends on PCI default y -config PCI_MMCONFIG - bool "Support mmconfig PCI config space access" +config PCI_MMCONFIG + bool "Support mmconfig PCI config space access" depends on PCI select ACPI_BOOT +config UNORDERED_IO + bool "Unordered IO mapping access" + depends on EXPERIMENTAL + 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" @@ -398,110 +417,10 @@ source fs/Kconfig source "arch/x86_64/oprofile/Kconfig" -menu "Kernel hacking" - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -config DEBUG_SLAB - bool "Debug memory allocations" - depends on DEBUG_KERNEL - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config DEBUG_SPINLOCK - bool "Spinlock debugging" - depends on DEBUG_KERNEL - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -# !SMP for now because the context switch early causes GPF in segment reloading -# and the GS base checking does the wrong thing then, causing a hang. -config CHECKING - bool "Additional run-time checks" - depends on DEBUG_KERNEL && !SMP - help - Enables some internal consistency checks for kernel debugging. - You should normally say N. - -config INIT_DEBUG - bool "Debug __init statements" - depends on DEBUG_KERNEL - help - Fill __init and __initdata at the end of boot. This helps debugging - illegal uses of __init and __initdata after initialization. - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - Say Y here only if you plan to use gdb to debug the kernel. - Please note that this option requires new binutils. - If you don't debug the kernel, you can say N. - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - help - Compile the kernel with frame pointers. This may help for some - debugging with external debuggers. Note the standard oops backtracer - doesn't make use of this and the x86-64 kernel doesn't ensure an consistent - frame pointer through inline assembly (semaphores etc.) - Normally you should say N. - -config IOMMU_DEBUG - depends on GART_IOMMU && DEBUG_KERNEL - bool "Enable IOMMU debugging" - help - Force the IOMMU to on even when you have less than 4GB of - memory and add debugging code. On overflow always panic. And - allow to enable IOMMU leak tracing. Can be disabled at boot - time with iommu=noforce. This will also enable scatter gather - list merging. Currently not recommended for production - code. When you use it make sure you have a big enough - IOMMU/AGP aperture. Most of the options enabled by this can - be set more finegrained using the iommu= command line - options. See Documentation/x86_64/boot-options.txt for more - details. - -config IOMMU_LEAK - bool "IOMMU leak tracing" - depends on DEBUG_KERNEL - depends on IOMMU_DEBUG - help - Add a simple leak tracer to the IOMMU code. This is useful when you - are debugging a buggy device driver that leaks IOMMU mappings. - -#config X86_REMOTE_DEBUG -# bool "kgdb debugging stub" - -endmenu +source "arch/x86_64/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" - diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug new file mode 100644 index 000000000..2ba7f5a05 --- /dev/null +++ b/arch/x86_64/Kconfig.debug @@ -0,0 +1,59 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +# !SMP for now because the context switch early causes GPF in segment reloading +# and the GS base checking does the wrong thing then, causing a hang. +config CHECKING + bool "Additional run-time checks" + depends on DEBUG_KERNEL && !SMP + help + Enables some internal consistency checks for kernel debugging. + You should normally say N. + +config INIT_DEBUG + bool "Debug __init statements" + depends on DEBUG_KERNEL + help + 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 IOMMU_DEBUG + depends on GART_IOMMU && DEBUG_KERNEL + bool "Enable IOMMU debugging" + help + Force the IOMMU to on even when you have less than 4GB of + memory and add debugging code. On overflow always panic. And + allow to enable IOMMU leak tracing. Can be disabled at boot + time with iommu=noforce. This will also enable scatter gather + list merging. Currently not recommended for production + code. When you use it make sure you have a big enough + IOMMU/AGP aperture. Most of the options enabled by this can + be set more finegrained using the iommu= command line + options. See Documentation/x86_64/boot-options.txt for more + details. + +config IOMMU_LEAK + bool "IOMMU leak tracing" + depends on DEBUG_KERNEL + depends on IOMMU_DEBUG + help + Add a simple leak tracer to the IOMMU code. This is useful when you + are debugging a buggy device driver that leaks IOMMU mappings. + +#config X86_REMOTE_DEBUG +# bool "kgdb debugging stub" + +endmenu diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 9b9a504ef..a69f7bcdf 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -37,10 +37,10 @@ LDFLAGS := -m elf_x86_64 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -e stext -CHECK := $(CHECK) -D__x86_64__=1 +CHECKFLAGS += -D__x86_64__ -m64 -cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,) -cflags-$(CONFIG_MPSC) += $(call check_gcc,-march=nocona,) +cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) +cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona) CFLAGS += $(cflags-y) CFLAGS += -mno-red-zone @@ -54,11 +54,11 @@ ifneq ($(CONFIG_DEBUG_INFO),y) CFLAGS += -fno-asynchronous-unwind-tables # -fweb shrinks the kernel a bit, but the difference is very small # it also messes up debugging, so don't use it for now. -#CFLAGS += $(call check_gcc,-fweb,) +#CFLAGS += $(call cc-option,-fweb) endif # -funit-at-a-time shrinks the kernel .text considerably # unfortunately it makes reading oopses harder. -CFLAGS += $(call check_gcc,-funit-at-a-time,) +CFLAGS += $(call cc-option,-funit-at-a-time) head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o @@ -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/boot/Makefile b/arch/x86_64/boot/Makefile index 1c2d3cbca..99b790439 100644 --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile @@ -30,7 +30,7 @@ targets := vmlinux.bin bootsect bootsect.o \ EXTRA_CFLAGS := -m32 -host-progs := tools/build +hostprogs-y := tools/build subdir- := compressed/ #Let make clean descend in compressed/ # --------------------------------------------------------------------------- diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S index 5d4cdc1ab..fd0cc734a 100644 --- a/arch/x86_64/boot/video.S +++ b/arch/x86_64/boot/video.S @@ -66,6 +66,7 @@ #define VIDEO_80x30 0x0f05 #define VIDEO_80x34 0x0f06 #define VIDEO_80x60 0x0f07 +#define VIDEO_GFX_HACK 0x0f08 #define VIDEO_LAST_SPECIAL 0x0f09 /* Video modes given by resolution */ @@ -97,7 +98,6 @@ #define PARAM_LFB_PAGES 0x32 #define PARAM_VESA_ATTRIB 0x34 - /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ #ifdef CONFIG_VIDEO_RETAIN #define DO_STORE call store_screen @@ -133,6 +133,7 @@ vid1: #ifdef CONFIG_VIDEO_RETAIN call restore_screen # Restore screen contents #endif /* CONFIG_VIDEO_RETAIN */ + call store_edid #endif /* CONFIG_VIDEO_SELECT */ call mode_params # Store mode parameters popw %ds # Restore original DS @@ -231,6 +232,41 @@ mopar_gr: xorl %eax, %eax movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) + +# switching the DAC to 8-bit is for <= 8 bpp only + movw %fs:(PARAM_LFB_DEPTH), %ax + cmpw $8, %ax + jg dac_done + +# get DAC switching capability + xorl %eax, %eax + movb 10(%di), %al + testb $1, %al + jz dac_set + +# attempt to switch DAC to 8-bit + movw $0x4f08, %ax + movw $0x0800, %bx + int $0x10 + cmpw $0x004f, %ax + jne dac_set + movb %bh, dac_size # store actual DAC size + +dac_set: +# set color size to DAC size + movb dac_size, %al + movb %al, %fs:(PARAM_LFB_COLORS+0) + movb %al, %fs:(PARAM_LFB_COLORS+2) + movb %al, %fs:(PARAM_LFB_COLORS+4) + movb %al, %fs:(PARAM_LFB_COLORS+6) + +# set color offsets to 0 + movb $0, %fs:(PARAM_LFB_COLORS+1) + movb $0, %fs:(PARAM_LFB_COLORS+3) + movb $0, %fs:(PARAM_LFB_COLORS+5) + movb $0, %fs:(PARAM_LFB_COLORS+7) + +dac_done: # get protected mode interface informations movw $0x4f0a, %ax xorw %bx, %bx @@ -440,7 +476,7 @@ setalias: # Setting of user mode (AX=mode ID) => CF=success mode_set: - movw %ax, %fs:(0x01fa) + movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S movw %ax, %bx cmpb $0xff, %ah jz setalias @@ -744,7 +780,15 @@ set_80x60: movw $0x503c, force_size jmp setvde +# Special hack for ThinkPad graphics set_gfx: +#ifdef CONFIG_VIDEO_GFX_HACK + movw $VIDEO_GFX_BIOS_AX, %ax + movw $VIDEO_GFX_BIOS_BX, %bx + int $0x10 + movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size + stc +#endif ret #ifdef CONFIG_VIDEO_RETAIN @@ -969,6 +1013,10 @@ vga_modes: .word 0x5022 # 80x34 .word VIDEO_80x60 .word 0x503c # 80x60 +#ifdef CONFIG_VIDEO_GFX_HACK + .word VIDEO_GFX_HACK + .word VIDEO_GFX_DUMMY_RESOLUTION +#endif vga_modes_end: # Detect VESA modes. @@ -1875,6 +1923,39 @@ skip10: movb %ah, %al popw %ax ret +store_edid: + pushw %es # just save all registers + pushw %ax + pushw %bx + pushw %cx + pushw %dx + pushw %di + + pushw %fs + popw %es + + movl $0x13131313, %eax # memset block with 0x13 + movw $32, %cx + movw $0x440, %di + cld + rep + stosl + + movw $0x4f15, %ax # do VBE/DDC + movw $0x01, %bx + movw $0x00, %cx + movw $0x01, %dx + movw $0x440, %di + int $0x10 + + popw %di # restore all registers + popw %dx + popw %cx + popw %bx + popw %ax + popw %es + ret + # VIDEO_SELECT-only variables mt_end: .word 0 # End of video mode table if built edit_buf: .space 6 # Line editor buffer @@ -1883,6 +1964,7 @@ scanning: .byte 0 # Performing mode scan do_restore: .byte 0 # Screen contents altered during mode change svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes graphic_mode: .byte 0 # Graphic mode with a linear frame buffer +dac_size: .byte 6 # DAC bit depth # Status messages keymsg: .ascii "Press to see video modes available, " diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index bf6969fa0..ae2f4bfea 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,5 +1,7 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc1-bk19 +# Sun Sep 12 23:13:23 2004 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -17,11 +19,11 @@ CONFIG_GENERIC_ISA_DMA=y # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -35,6 +37,7 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -42,6 +45,8 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support @@ -123,6 +128,8 @@ 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 @@ -144,6 +151,8 @@ CONFIG_UID16=y # # Generic Driver Options # +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_DEBUG_DRIVER is not set # @@ -171,7 +180,8 @@ 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_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -186,10 +196,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 @@ -273,16 +283,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_MEGARAID is not set +CONFIG_SCSI_AIC79XX=y +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=4000 +# 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 is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY 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 +308,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 @@ -324,7 +341,6 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_FUSION=y CONFIG_FUSION_MAX_SGE=40 -# CONFIG_FUSION_ISENSE is not set # CONFIG_FUSION_CTL is not set # @@ -362,11 +378,13 @@ CONFIG_IP_MULTICAST=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set @@ -392,6 +410,7 @@ CONFIG_IPV6=y # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -452,6 +471,7 @@ CONFIG_8139TOO=m # 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) @@ -575,7 +595,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -602,6 +621,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 @@ -610,6 +632,11 @@ CONFIG_HANGCHECK_TIMER=y # # CONFIG_I2C is not set +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + # # Misc devices # @@ -635,7 +662,6 @@ CONFIG_HANGCHECK_TIMER=y # Console display driver support # CONFIG_VGA_CONSOLE=y -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # @@ -686,6 +712,8 @@ CONFIG_USB=y CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers @@ -706,6 +734,7 @@ CONFIG_USB_OHCI_HCD=y CONFIG_USB_PRINTER=y CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set @@ -830,7 +859,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 # @@ -879,6 +909,7 @@ CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -906,12 +937,14 @@ CONFIG_OPROFILE=y # Kernel hacking # CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_INIT_DEBUG is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_INFO is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_INIT_DEBUG is not set +# CONFIG_SCHEDSTATS is not set # CONFIG_IOMMU_DEBUG is not set # @@ -927,5 +960,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 8e6b845f7..b802b5f08 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" @@ -365,7 +368,7 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? PAGE_COPY_EXEC : PAGE_COPY; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + mm->stack_vm = mm->total_vm = vma_pages(mpnt); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff --git a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c index 8c6964245..d259f8a6f 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 5716c8bec..5fb7d173b 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(¤t->sighand->siglock); - regs.rax = -EINTR; + regs->rax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(®s, &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(¤t->sighand->siglock); - if (ia32_restore_sigcontext(®s, &frame->sc, &eax)) + if (ia32_restore_sigcontext(regs, &frame->sc, &eax)) goto badframe; return eax; badframe: - signal_fault(®s, 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(¤t->sighand->siglock); - if (ia32_restore_sigcontext(®s, &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(®s,frame,"32bit rt sigreturn"); + signal_fault(regs,frame,"32bit rt sigreturn"); return 0; } @@ -342,6 +347,7 @@ ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __ struct pt_regs *regs, unsigned int mask) { int tmp, err = 0; + u32 eflags; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); @@ -366,7 +372,11 @@ ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __ err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user((u32)regs->rip, &sc->eip); - err |= __put_user((u32)regs->eflags, &sc->eflags); + eflags = regs->eflags; + if (current->ptrace & PT_PTRACED) { + eflags &= ~TF_MASK; + } + err |= __put_user((u32)eflags, &sc->eflags); err |= __put_user((u32)regs->rsp, &sc->esp_at_signal); tmp = save_i387_ia32(current, fpstate, regs, 0); @@ -484,7 +494,13 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka, regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -494,9 +510,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, @@ -580,7 +594,13 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -590,8 +610,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 0a2fb66b6..7acd7963b 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 @@ -589,6 +586,7 @@ ia32_sys_call_table: .quad compat_sys_mq_notify .quad compat_sys_mq_getsetattr .quad quiet_ni_syscall /* reserved for kexec */ + .quad sys32_waitid /* don't forget to change IA32_NR_syscalls */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index 01202b792..4445da812 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 ab8003492..504653451 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,47 @@ 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, ®s); + 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, ®s, 0, - parent_tid, child_tid); + newsp = regs->rsp; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); +} + +asmlinkage long sys32_waitid(int which, compat_pid_t pid, + siginfo_t32 __user *uinfo, int options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return ia32_copy_siginfo_to_user(uinfo, &info); } /* @@ -1262,7 +1288,7 @@ asmlinkage long sys32_open(const char __user * filename, int flags, int mode) if (fd >= 0) { struct file *f = filp_open(tmp, flags, mode); error = PTR_ERR(f); - if (unlikely(IS_ERR(f))) { + if (IS_ERR(f)) { put_unused_fd(fd); fd = error; } else @@ -1337,6 +1363,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/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c index 1806bff66..f82aeae6f 100644 --- a/arch/x86_64/ia32/syscall32.c +++ b/arch/x86_64/ia32/syscall32.c @@ -30,16 +30,20 @@ extern int sysctl_vsyscall32; char *syscall32_page; static int use_sysenter __initdata = -1; -/* RED-PEN: This knows too much about high level VM */ -/* Alternative would be to generate a vma with appropriate backing options - and let it be handled by generic VM */ -int map_syscall32(struct mm_struct *mm, unsigned long address) +/* + * Map the 32bit vsyscall page on demand. + * + * RED-PEN: This knows too much about high level VM. + * + * Alternative would be to generate a vma with appropriate backing options + * and let it be handled by generic VM. + */ +int __map_syscall32(struct mm_struct *mm, unsigned long address) { pte_t *pte; pmd_t *pmd; int err = 0; - down_read(&mm->mmap_sem); spin_lock(&mm->page_table_lock); pmd = pmd_alloc(mm, pgd_offset(mm, address), address); if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) { @@ -54,6 +58,14 @@ int map_syscall32(struct mm_struct *mm, unsigned long address) } else err = -ENOMEM; spin_unlock(&mm->page_table_lock); + return err; +} + +int map_syscall32(struct mm_struct *mm, unsigned long address) +{ + int err; + down_read(&mm->mmap_sem); + err = __map_syscall32(mm, address); up_read(&mm->mmap_sem); return err; } @@ -76,7 +88,8 @@ static int __init init_syscall32(void) __initcall(init_syscall32); -void __init syscall32_cpu_init(void) +/* May not be __init: called during resume */ +void syscall32_cpu_init(void) { if (use_sysenter < 0) use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL); diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index dc6f2695e..e70de986a 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o head64.o init_task.o vmlinux.lds.s +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 \ @@ -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/aperture.c b/arch/x86_64/kernel/aperture.c index 164b6d078..1d8b3912c 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/apic.c b/arch/x86_64/kernel/apic.c index 6fb84e2c7..ddd8aac2a 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -33,6 +33,8 @@ #include #include +int apic_verbosity; + int disable_apic_timer __initdata; /* Using APIC to generate smp_local_timer_interrupt? */ @@ -123,7 +125,7 @@ void __init connect_bsp_APIC(void) * PIC mode, enable APIC mode in the IMCR, i.e. * connect BSP's local APIC to INT and NMI lines. */ - printk(KERN_INFO "leaving PIC mode, enabling APIC mode.\n"); + apic_printk(APIC_VERBOSE, "leaving PIC mode, enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -138,7 +140,7 @@ void disconnect_bsp_APIC(void) * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk(KERN_INFO "disabling APIC mode, entering PIC mode.\n"); + apic_printk(APIC_QUIET, "disabling APIC mode, entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -172,10 +174,10 @@ int __init verify_local_APIC(void) * The version register is read-only in a real APIC. */ reg0 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0); apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); reg1 = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1); /* * The two version reads above should print the same @@ -199,10 +201,10 @@ int __init verify_local_APIC(void) * The ID register is read/write in a real APIC. */ reg0 = apic_read(APIC_ID); - Dprintk("Getting ID: %x\n", reg0); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); reg1 = apic_read(APIC_ID); - Dprintk("Getting ID: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); apic_write(APIC_ID, reg0); if (reg1 != (reg0 ^ APIC_ID_MASK)) return 0; @@ -213,9 +215,9 @@ int __init verify_local_APIC(void) * compatibility mode, but most boxes are anymore. */ reg0 = apic_read(APIC_LVT0); - Dprintk("Getting LVT0: %x\n", reg0); + apic_printk(APIC_DEBUG,"Getting LVT0: %x\n", reg0); reg1 = apic_read(APIC_LVT1); - Dprintk("Getting LVT1: %x\n", reg1); + apic_printk(APIC_DEBUG, "Getting LVT1: %x\n", reg1); return 1; } @@ -227,7 +229,7 @@ void __init sync_Arb_IDs(void) */ apic_wait_icr_idle(); - Dprintk("Synchronizing Arb IDs.\n"); + apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n"); apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT); } @@ -388,10 +390,10 @@ void __init setup_local_APIC (void) value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; if (!smp_processor_id() && (pic_mode || !value)) { value = APIC_DM_EXTINT; - Dprintk(KERN_INFO "enabled ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id()); } else { value = APIC_DM_EXTINT | APIC_LVT_MASKED; - Dprintk(KERN_INFO "masked ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id()); } apic_write_around(APIC_LVT0, value); @@ -407,12 +409,11 @@ void __init setup_local_APIC (void) apic_write_around(APIC_LVT1, value); if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */ + unsigned oldvalue; maxlvt = get_maxlvt(); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); - value = apic_read(APIC_ESR); - Dprintk("ESR value before enabling vector: %08x\n", value); - + oldvalue = apic_read(APIC_ESR); value = ERROR_APIC_VECTOR; // enables sending errors apic_write_around(APIC_LVTERR, value); /* @@ -421,7 +422,10 @@ void __init setup_local_APIC (void) if (maxlvt > 3) apic_write(APIC_ESR, 0); value = apic_read(APIC_ESR); - Dprintk("ESR value after enabling vector: %08x\n", value); + if (value != oldvalue) + apic_printk(APIC_VERBOSE, + "ESR value after enabling vector: %08x, after %08x\n", + oldvalue, value); } else { if (esr_disable) /* @@ -430,9 +434,9 @@ void __init setup_local_APIC (void) * ESR disabled - we can't do anything useful with the * errors anyway - mbligh */ - printk("Leaving ESR disabled.\n"); + apic_printk(APIC_DEBUG, "Leaving ESR disabled.\n"); else - printk("No ESR for 82489DX.\n"); + apic_printk(APIC_DEBUG, "No ESR for 82489DX.\n"); } nmi_watchdog_default(); @@ -564,6 +568,21 @@ static void apic_pm_activate(void) { } #endif /* CONFIG_PM */ +static int __init apic_set_verbosity(char *str) +{ + if (strcmp("debug", str) == 0) + apic_verbosity = APIC_DEBUG; + else if (strcmp("verbose", str) == 0) + apic_verbosity = APIC_VERBOSE; + else + printk(KERN_WARNING "APIC Verbosity level %s not recognised" + " use apic=verbose or apic=debug", str); + + return 0; +} + +__setup("apic=", apic_set_verbosity); + /* * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. @@ -599,7 +618,7 @@ void __init init_apic_mappings(void) apic_phys = mp_lapic_addr; set_fixmap_nocache(FIX_APIC_BASE, apic_phys); - Dprintk("mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); + apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); /* * Fetch the APIC ID of the BSP in case we have a @@ -621,7 +640,7 @@ void __init init_apic_mappings(void) ioapic_phys = __pa(ioapic_phys); } set_fixmap_nocache(idx, ioapic_phys); - Dprintk("mapped IOAPIC to %016lx (%016lx)\n", + apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n", __fix_to_virt(idx), ioapic_phys); idx++; } @@ -836,8 +855,7 @@ void smp_local_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); - x86_do_profile(regs); - + profile_tick(CPU_PROFILING, regs); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got @@ -962,7 +980,7 @@ asmlinkage void smp_error_interrupt(void) 6: Received illegal vector 7: Illegal register address */ - printk (KERN_INFO "APIC error on CPU%d: %02x(%02x)\n", + printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", smp_processor_id(), v , v1); irq_exit(); } diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c index 757f55078..37d12fa5e 100644 --- a/arch/x86_64/kernel/asm-offsets.c +++ b/arch/x86_64/kernel/asm-offsets.c @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig index 1b3aefc8d..dcb518eb2 100644 --- a/arch/x86_64/kernel/cpufreq/Kconfig +++ b/arch/x86_64/kernel/cpufreq/Kconfig @@ -41,4 +41,58 @@ config X86_POWERNOW_K8 If in doubt, say N. +config X86_POWERNOW_K8_ACPI + bool + 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 . + + 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 . + + 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 f02ed52be..d0f0b2cf3 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/early_printk.c b/arch/x86_64/kernel/early_printk.c index 98041f50e..600ec815a 100644 --- a/arch/x86_64/kernel/early_printk.c +++ b/arch/x86_64/kernel/early_printk.c @@ -8,7 +8,7 @@ /* Simple VGA output */ #ifdef __i386__ -#define VGABASE __pa(__PAGE_OFFSET + 0xb8000UL) +#define VGABASE (__ISA_IO_base + 0xb8000) #else #define VGABASE 0xffffffff800b8000UL #endif @@ -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 89f74f738..17d74eb66 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -297,7 +297,7 @@ int_very_careful: sti SAVE_REST /* Check for syscall exit trace */ - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),%edx + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx jz int_signal pushq %rdi leaq 8(%rsp),%rdi # &ptregs -> arg1 @@ -305,6 +305,7 @@ int_very_careful: popq %rdi btr $TIF_SYSCALL_TRACE,%edi btr $TIF_SYSCALL_AUDIT,%edi + btr $TIF_SINGLESTEP,%edi jmp int_restore_rest int_signal: @@ -323,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 @@ -385,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/i8259.c b/arch/x86_64/kernel/i8259.c index c52b859c9..f5d084a99 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -329,7 +329,7 @@ spurious_8259A_irq: * lets ACK and report it. [once per IRQ] */ if (!(spurious_irq_mask & irqmask)) { - printk("spurious 8259A interrupt: IRQ%d.\n", irq); + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } atomic_inc(&irq_err_count); @@ -342,7 +342,7 @@ spurious_8259A_irq: } } -void __init init_8259A(int auto_eoi) +void init_8259A(int auto_eoi) { unsigned long flags; @@ -385,6 +385,57 @@ void __init init_8259A(int auto_eoi) spin_unlock_irqrestore(&i8259A_lock, flags); } +static char irq_trigger[2]; +/** + * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ + */ +static void restore_ELCR(char *trigger) +{ + outb(trigger[0], 0x4d0); + outb(trigger[1], 0x4d1); +} + +static void save_ELCR(char *trigger) +{ + /* IRQ 0,1,2,8,13 are marked as reserved */ + trigger[0] = inb(0x4d0) & 0xF8; + trigger[1] = inb(0x4d1) & 0xDE; +} + +static int i8259A_resume(struct sys_device *dev) +{ + init_8259A(0); + restore_ELCR(irq_trigger); + return 0; +} + +static int i8259A_suspend(struct sys_device *dev, u32 state) +{ + save_ELCR(irq_trigger); + return 0; +} + +static struct sysdev_class i8259_sysdev_class = { + set_kset_name("i8259"), + .suspend = i8259A_suspend, + .resume = i8259A_resume, +}; + +static struct sys_device device_i8259A = { + .id = 0, + .cls = &i8259_sysdev_class, +}; + +static int __init i8259A_init_sysfs(void) +{ + int error = sysdev_class_register(&i8259_sysdev_class); + if (!error) + error = sysdev_register(&device_i8259A); + return error; +} + +device_initcall(i8259A_init_sysfs); + /* * IRQ2 is cascade interrupt to second interrupt controller */ diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c index 33185ca33..8bc4becb8 100644 --- a/arch/x86_64/kernel/init_task.c +++ b/arch/x86_64/kernel/init_task.c @@ -44,8 +44,7 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned; - +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp; #define ALIGN_TO_4K __attribute__((section(".data.init_task"))) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 6cb45b7eb..c309cb0f8 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -30,12 +30,15 @@ #include #include #include +#include #include #include #include #include +#define __apicdebuginit __init + int sis_apic_bug; /* not actually supported, dummy for compile */ #undef APIC_LOCKUP_DEBUG @@ -292,13 +295,13 @@ static int __init ioapic_pirq_setup(char *str) pirq_entries[i] = -1; pirqs_enabled = 1; - printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); + apic_printk(APIC_VERBOSE, "PIRQ redirection, working around broken MP-BIOS.\n"); max = MAX_PIRQS; if (ints[0] < MAX_PIRQS) max = ints[0]; for (i = 0; i < max; i++) { - printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); + apic_printk(APIC_VERBOSE, "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ @@ -357,10 +360,10 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) { int apic, i, best_guess = -1; - Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", + apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", bus, slot, pin); if (mp_bus_id_to_pci_bus[bus] == -1) { - printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); + apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; } for (i = 0; i < mp_irq_entries; i++) { @@ -402,7 +405,7 @@ static int __init EISA_ELCR(unsigned int irq) unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); + apic_printk(APIC_VERBOSE, "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -625,10 +628,10 @@ static int pin_2_irq(int idx, int apic, int pin) if ((pin >= 16) && (pin <= 23)) { if (pirq_entries[pin-16] != -1) { if (!pirq_entries[pin-16]) { - printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); + apic_printk(APIC_VERBOSE, "disabling PIRQ%d\n", pin-16); } else { irq = pirq_entries[pin-16]; - printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", + apic_printk(APIC_VERBOSE, "using PIRQ%d -> IRQ %d\n", pin-16, irq); } } @@ -719,7 +722,7 @@ void __init setup_IO_APIC_irqs(void) int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; - printk(KERN_DEBUG "init IO_APIC IRQs\n"); + apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -732,15 +735,15 @@ void __init setup_IO_APIC_irqs(void) entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); first_notcon = 0; } else - printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); + apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin); continue; } @@ -750,7 +753,7 @@ void __init setup_IO_APIC_irqs(void) if (irq_trigger(idx)) { entry.trigger = 1; entry.mask = 1; - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); } irq = pin_2_irq(idx, apic, pin); @@ -775,7 +778,7 @@ void __init setup_IO_APIC_irqs(void) } if (!first_notcon) - printk(" not connected.\n"); + apic_printk(APIC_VERBOSE," not connected.\n"); } /* @@ -800,7 +803,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) */ entry.dest_mode = INT_DELIVERY_MODE; entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.delivery_mode = dest_LowestPrio; entry.polarity = 0; entry.trigger = 0; @@ -825,13 +828,9 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) void __init UNEXPECTED_IO_APIC(void) { -#if 0 - printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n"); - printk(KERN_WARNING " to linux-smp@vger.kernel.org\n"); -#endif } -void __init print_IO_APIC(void) +void __apicdebuginit print_IO_APIC(void) { int apic, i; union IO_APIC_reg_00 reg_00; @@ -839,7 +838,10 @@ void __init print_IO_APIC(void) union IO_APIC_reg_02 reg_02; unsigned long flags; - printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); + if (apic_verbosity == APIC_QUIET) + return; + + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); @@ -955,11 +957,14 @@ void __init print_IO_APIC(void) return; } -static void print_APIC_bitfield (int base) +static __apicdebuginit void print_APIC_bitfield (int base) { unsigned int v; int i, j; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); for (i = 0; i < 8; i++) { v = apic_read(base + i*0x10); @@ -973,10 +978,13 @@ static void print_APIC_bitfield (int base) } } -void /*__init*/ print_local_APIC(void * dummy) +void __apicdebuginit print_local_APIC(void * dummy) { unsigned int v, ver, maxlvt; + if (apic_verbosity == APIC_QUIET) + return; + printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", smp_processor_id(), hard_smp_processor_id()); v = apic_read(APIC_ID); @@ -1058,12 +1066,15 @@ void print_all_local_APICs (void) on_each_cpu(print_local_APIC, NULL, 1, 1); } -void /*__init*/ print_PIC(void) +void __apicdebuginit print_PIC(void) { extern spinlock_t i8259A_lock; unsigned int v; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "\nprinting PIC contents\n"); spin_lock_irqsave(&i8259A_lock, flags); @@ -1160,9 +1171,9 @@ static void __init setup_ioapic_ids_from_mpc (void) old_id = mp_ioapics[apic].mpc_apicid; if (mp_ioapics[apic].mpc_apicid >= 0xf) { - printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", + apic_printk(APIC_QUIET,KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); - printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", + apic_printk(APIC_QUIET,KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", reg_00.bits.ID); mp_ioapics[apic].mpc_apicid = reg_00.bits.ID; } @@ -1205,7 +1216,7 @@ static void __init setup_ioapic_ids_from_mpc (void) * Read the right value from the MPC table and * write it into the ID register. */ - printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", + apic_printk(APIC_VERBOSE,KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", mp_ioapics[apic].mpc_apicid); reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; @@ -1220,9 +1231,9 @@ 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 - printk(" ok.\n"); + apic_printk(APIC_VERBOSE," ok.\n"); } } @@ -1671,7 +1682,7 @@ static inline void check_timer(void) pin1 = find_isa_irq_pin(0, mp_INT); pin2 = find_isa_irq_pin(0, mp_ExtINT); - printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2); + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2); if (pin1 != -1) { /* @@ -1689,12 +1700,12 @@ static inline void check_timer(void) return; } clear_IO_APIC_pin(0, pin1); - printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); + apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); } - printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); + apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); if (pin2 != -1) { - printk("\n..... (found pin %d) ...", pin2); + apic_printk(APIC_VERBOSE,"\n..... (found pin %d) ...", pin2); /* * legacy devices should be connected to IO APIC #0 */ @@ -1720,7 +1731,7 @@ static inline void check_timer(void) nmi_watchdog = 0; } - printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); + apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); irq_desc[0].handler = &lapic_irq_type; @@ -1728,13 +1739,13 @@ static inline void check_timer(void) enable_8259A_irq(0); if (timer_irq_works()) { - printk(" works.\n"); + apic_printk(APIC_QUIET, " works.\n"); return; } apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); - printk(" failed.\n"); + apic_printk(APIC_VERBOSE," failed.\n"); - printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); + apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ..."); init_8259A(0); make_8259A_irq(0); @@ -1743,10 +1754,10 @@ static inline void check_timer(void) unlock_ExtINT_logic(); if (timer_irq_works()) { - printk(" works.\n"); + apic_printk(APIC_VERBOSE," works.\n"); return; } - printk(" failed :(.\n"); + apic_printk(APIC_VERBOSE," failed :(.\n"); panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); } @@ -1768,7 +1779,7 @@ void __init setup_IO_APIC(void) else io_apic_irqs = ~PIC_IRQS; - printk("ENABLING IO-APIC IRQs\n"); + apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); /* * Set up the IO-APIC IRQ routing table. @@ -1783,6 +1794,98 @@ void __init setup_IO_APIC(void) print_IO_APIC(); } +struct sysfs_ioapic_data { + struct sys_device dev; + struct IO_APIC_route_entry entry[0]; +}; +static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; + +static int ioapic_suspend(struct sys_device *dev, u32 state) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + spin_lock_irqsave(&ioapic_lock, flags); + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); + *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static int ioapic_resume(struct sys_device *dev) +{ + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; + unsigned long flags; + union IO_APIC_reg_00 reg_00; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; + + spin_lock_irqsave(&ioapic_lock, flags); + reg_00.raw = io_apic_read(dev->id, 0); + if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { + reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; + io_apic_write(dev->id, 0, reg_00.raw); + } + for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { + io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); + io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +} + +static struct sysdev_class ioapic_sysdev_class = { + set_kset_name("ioapic"), + .suspend = ioapic_suspend, + .resume = ioapic_resume, +}; + +static int __init ioapic_init_sysfs(void) +{ + struct sys_device * dev; + int i, size, error = 0; + + error = sysdev_class_register(&ioapic_sysdev_class); + if (error) + return error; + + for (i = 0; i < nr_ioapics; i++ ) { + size = sizeof(struct sys_device) + nr_ioapic_registers[i] + * sizeof(struct IO_APIC_route_entry); + mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); + if (!mp_ioapic_data[i]) { + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + memset(mp_ioapic_data[i], 0, size); + dev = &mp_ioapic_data[i]->dev; + dev->id = i; + dev->cls = &ioapic_sysdev_class; + error = sysdev_register(dev); + if (error) { + kfree(mp_ioapic_data[i]); + mp_ioapic_data[i] = NULL; + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } + } + + return 0; +} + +device_initcall(ioapic_init_sysfs); + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ @@ -1815,7 +1918,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) spin_unlock_irqrestore(&ioapic_lock, flags); if (apic_id >= IO_APIC_MAX_ID) { - printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " + apic_printk(APIC_QUIET, KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " "%d\n", ioapic, apic_id, reg_00.bits.ID); apic_id = reg_00.bits.ID; } @@ -1834,7 +1937,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) if (i == IO_APIC_MAX_ID) panic("Max apic_id exceeded!\n"); - printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " + apic_printk(APIC_VERBOSE, KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " "trying %d\n", ioapic, apic_id, i); apic_id = i; @@ -1855,7 +1958,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + apic_printk(APIC_VERBOSE,KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } @@ -1893,7 +1996,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a unsigned long flags; if (!IO_APIC_IRQ(irq)) { - printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", + apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ioapic); return -EINVAL; } @@ -1908,7 +2011,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; - entry.dest.logical.logical_dest = TARGET_CPUS; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.trigger = edge_level; entry.polarity = active_high_low; entry.mask = 1; /* Disabled (masked) */ @@ -1921,20 +2024,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a entry.vector = assign_irq_vector(irq); - printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " + apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " "IRQ %d Mode:%i Active:%i)\n", ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - if (use_pci_vector() && !platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); - if (edge_level) { - irq_desc[irq].handler = &ioapic_level_type; - } else { - irq_desc[irq].handler = &ioapic_edge_type; - } - - set_intr_gate(entry.vector, interrupt[irq]); + ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); @@ -1966,3 +2061,28 @@ void send_IPI_self(int vector) apic_write_around(APIC_ICR, cfg); } #endif + + +/* + * This function currently is only a helper for the i386 smp boot process where + * we need to reprogram the ioredtbls to cater for the cpus which have come online + * so mask in all cases should simply be TARGET_CPUS + */ +void __init setup_ioapic_dest(void) +{ + int pin, ioapic, irq, irq_entry; + + if (skip_ioapic_setup == 1) + return; + + for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { + for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { + irq_entry = find_irq_entry(ioapic, pin, mp_INT); + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); + set_ioapic_affinity_irq(irq, TARGET_CPUS); + } + + } +} diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c index 0a90fd08f..cde0e868e 100644 --- a/arch/x86_64/kernel/ioport.c +++ b/arch/x86_64/kernel/ioport.c @@ -28,12 +28,12 @@ static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int ex clear_bit(i, bitmap); } - /* * this changes the io permissions bitmap in the current task. */ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) { + unsigned int i, max_long, bytes, bytes_updated; struct thread_struct * t = ¤t->thread; struct tss_struct * tss; unsigned long *bitmap; @@ -59,16 +59,34 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) /* * do it in the per-thread copy and in the TSS ... + * + * Disable preemption via get_cpu() - we must not switch away + * because the ->io_bitmap_max value must match the bitmap + * contents: */ + tss = &per_cpu(init_tss, get_cpu()); + set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); - tss = init_tss + get_cpu(); - if (tss->io_bitmap_base == IO_BITMAP_OFFSET) { /* already active? */ - set_bitmap(tss->io_bitmap, from, num, !turn_on); - } else { - memcpy(tss->io_bitmap, t->io_bitmap_ptr, IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; /* Activate it in the TSS */ - } + + /* + * Search for a (possibly new) maximum. This is simple and stupid, + * to keep it obviously correct: + */ + max_long = 0; + for (i = 0; i < IO_BITMAP_LONGS; i++) + if (t->io_bitmap_ptr[i] != ~0UL) + max_long = i; + + bytes = (max_long + 1) * sizeof(long); + bytes_updated = max(bytes, t->io_bitmap_max); + + t->io_bitmap_max = bytes; + + /* Update the TSS: */ + memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); + put_cpu(); + return 0; } @@ -83,9 +101,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 +112,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/irq.c b/arch/x86_64/kernel/irq.c index 189418294..bf6459e58 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -213,13 +213,15 @@ inline void synchronize_irq(unsigned int irq) int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status = 1; /* Force the "do bottom halves" bit */ + int ret; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + status |= action->flags; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) @@ -862,31 +864,6 @@ static int irq_affinity_write_proc (struct file *file, #endif -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, - const char __user *buffer, - unsigned long count, void *data) -{ - unsigned long full_count = count, err; - cpumask_t new_value, *mask = (cpumask_t *)data; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - #define MAX_NAMELEN 10 static void register_irq_proc (unsigned int irq) @@ -922,26 +899,15 @@ static void register_irq_proc (unsigned int irq) #endif } -unsigned long prof_cpu_mask = -1; - void init_irq_proc (void) { - struct proc_dir_entry *entry; int i; /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; + create_prof_cpu_mask(root_irq_dir); /* * Create entries for all existing IRQs. @@ -949,4 +915,3 @@ void init_irq_proc (void) for (i = 0; i < NR_IRQS; i++) register_irq_proc(i); } - diff --git a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c index c7d7dac04..d7e5d0cf4 100644 --- a/arch/x86_64/kernel/ldt.c +++ b/arch/x86_64/kernel/ldt.c @@ -135,6 +135,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) return 0; if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; + down(&mm->context.sem); size = mm->context.size*LDT_ENTRY_SIZE; if (size > bytecount) @@ -145,12 +146,17 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) err = -EFAULT; up(&mm->context.sem); if (err < 0) - return err; + goto error_return; if (size != bytecount) { /* zero-fill the rest */ - clear_user(ptr+size, bytecount-size); + if (clear_user(ptr+size, bytecount-size) != 0) { + err = -EFAULT; + goto error_return; + } } return bytecount; +error_return: + return err; } static int read_default_ldt(void __user * ptr, unsigned long bytecount) diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 3bb678f1e..cf1fe8b7f 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; @@ -48,8 +49,7 @@ static void mce_log(struct mce *mce) mce->finished = 0; smp_wmb(); for (;;) { - entry = mcelog.next; - read_barrier_depends(); + entry = rcu_dereference(mcelog.next); /* When the buffer fills up discard new entries. Assume that the earlier errors are the more interesting. */ if (entry >= MCE_LOG_LEN) { @@ -72,7 +72,8 @@ static void mce_log(struct mce *mce) static void print_mce(struct mce *m) { - printk(KERN_EMERG + printk(KERN_EMERG "\n" + KERN_EMERG "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n", m->cpu, m->mcgstatus, m->bank, m->status); if (m->rip) { @@ -101,7 +102,7 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start) if (time_before(tsc, start)) continue; print_mce(&mcelog.entry[i]); - if (mcelog.entry[i].tsc == backup->tsc) + if (backup && mcelog.entry[i].tsc == backup->tsc) backup = NULL; } if (backup) @@ -114,9 +115,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); } /* @@ -128,8 +128,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); @@ -139,17 +140,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]) @@ -157,52 +152,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 @@ -215,18 +220,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); } @@ -269,22 +271,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 */ @@ -308,7 +313,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); @@ -333,9 +340,8 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff int i, err; down(&mce_read_sem); - next = mcelog.next; - read_barrier_depends(); - + next = rcu_dereference(mcelog.next); + /* Only supports full reads right now */ if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { up(&mce_read_sem); @@ -412,15 +418,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; @@ -436,7 +443,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; } @@ -465,7 +471,7 @@ static struct sys_device device_mce = { /* Why are there no generic functions for this? */ #define ACCESSOR(name, var, start) \ static ssize_t show_ ## name(struct sys_device *s, char *buf) { \ - return sprintf(buf, "%lu\n", (unsigned long)var); \ + return sprintf(buf, "%lx\n", (unsigned long)var); \ } \ static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \ char *end; \ @@ -494,7 +500,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 654e4578d..89ad3e729 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/nmi.c b/arch/x86_64/kernel/nmi.c index 35dd5dfc0..4920c8df7 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -390,7 +390,8 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) */ alert_counter[cpu]++; if (alert_counter[cpu] == 5*nmi_hz) { - if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) { + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) { alert_counter[cpu] = 0; return; } diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c index 7eb3fc72a..cab471cf3 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 @@ -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 09fde74cb..ca608a2a0 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -31,12 +31,6 @@ #include #include -#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 00fb2645c..67d90b89a 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 #include #include #include #include +#include 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 f7d3cf3ca..6e835be5f 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -130,11 +130,20 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ while (1) { - void (*idle)(void) = pm_idle; - if (!idle) - idle = default_idle; - while (!need_resched()) + while (!need_resched()) { + void (*idle)(void); + /* + * Mark this as an RCU critical section so that + * synchronize_kernel() in the unload path waits + * for our completion. + */ + rcu_read_lock(); + idle = pm_idle; + if (!idle) + idle = default_idle; idle(); + rcu_read_unlock(); + } schedule(); } } @@ -168,9 +177,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 +186,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) @@ -255,11 +259,17 @@ void show_regs(struct pt_regs *regs) void exit_thread(void) { struct task_struct *me = current; + struct thread_struct *t = &me->thread; if (me->thread.io_bitmap_ptr) { - struct tss_struct *tss = init_tss + get_cpu(); - kfree(me->thread.io_bitmap_ptr); - me->thread.io_bitmap_ptr = NULL; - tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; + /* + * Careful, clear this in the TSS too: + */ + memset(tss->io_bitmap, 0xff, t->io_bitmap_max); + t->io_bitmap_max = 0; put_cpu(); } } @@ -367,8 +377,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, if (unlikely(me->thread.io_bitmap_ptr != NULL)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); - if (!p->thread.io_bitmap_ptr) + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; return -ENOMEM; + } memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, IO_BITMAP_BYTES); } @@ -387,8 +399,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, } err = 0; out: - if (err && p->thread.io_bitmap_ptr) + if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); + p->thread.io_bitmap_max = 0; + } return err; } @@ -409,7 +423,7 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; int cpu = smp_processor_id(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); unlazy_fpu(prev_p); @@ -495,22 +509,18 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * * Handle the IO bitmap */ if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - if (next->io_bitmap_ptr) { + if (next->io_bitmap_ptr) /* - * 2 cachelines copy ... not good, but not that - * bad either. Anyone got something better? - * This only affects processes which use ioperm(). - */ - memcpy(tss->io_bitmap, next->io_bitmap_ptr, IO_BITMAP_BYTES); - tss->io_bitmap_base = IO_BITMAP_OFFSET; - } else { + * Copy the relevant range of the IO bitmap. + * Normally this is 128 bytes or less: + */ + memcpy(tss->io_bitmap, next->io_bitmap_ptr, + max(prev->io_bitmap_max, next->io_bitmap_max)); + else { /* - * a bitmap offset pointing outside of the TSS limit - * causes a nicely controllable SIGSEGV if a process - * tries to use a port IO instruction. The first - * sys_ioperm() call sets up the bitmap properly. + * Clear any possible leftover bits: */ - tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); } } @@ -546,17 +556,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, ®s, 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, ®s, 0, - parent_tid, child_tid); + newsp = regs->rsp; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); } /* @@ -569,9 +578,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, ®s, 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 5dd7752ae..73ff5494a 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -88,6 +88,7 @@ void ptrace_disable(struct task_struct *child) { long tmp; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); } @@ -344,6 +345,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data set_tsk_thread_flag(child,TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET); @@ -395,6 +397,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -416,6 +419,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + set_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -429,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; } @@ -528,7 +534,8 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs) if (unlikely(current->audit_context)) audit_syscall_exit(current, regs->rax); - if (test_thread_flag(TIF_SYSCALL_TRACE) + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) && (current->ptrace & PT_PTRACED)) syscall_trace(regs); } diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index c0d3c8dfa..108cf17c4 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -71,7 +71,7 @@ EXPORT_SYMBOL(acpi_disabled); #ifdef CONFIG_ACPI_BOOT extern int __initdata acpi_ht; extern acpi_interrupt_flags acpi_sci_flags; -/* int __initdata acpi_force = 0; */ +int __initdata acpi_force = 0; #endif /* For PCI or other memory-mapped resources */ @@ -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 @@ -105,7 +107,8 @@ char command_line[COMMAND_LINE_SIZE]; struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY | IORESOURCE_IO }, { "pic1", 0x20, 0x21, IORESOURCE_BUSY | IORESOURCE_IO }, - { "timer", 0x40, 0x5f, IORESOURCE_BUSY | IORESOURCE_IO }, + { "timer0", 0x40, 0x43, IORESOURCE_BUSY | IORESOURCE_IO }, + { "timer1", 0x50, 0x53, IORESOURCE_BUSY | IORESOURCE_IO }, { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY | IORESOURCE_IO }, { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY | IORESOURCE_IO }, { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY | IORESOURCE_IO }, @@ -248,14 +251,14 @@ static __init void parse_cmdline_early (char ** cmdline_p) if (!memcmp(from, "acpi=force", 10)) { /* add later when we do DMI horrors: */ - /* acpi_force = 1; */ + acpi_force = 1; acpi_disabled = 0; } /* acpi=ht just means: do ACPI MADT parsing at bootup, but don't enable the full ACPI interpreter */ if (!memcmp(from, "acpi=ht", 7)) { - /* if (!acpi_force) */ + if (!acpi_force) disable_acpi(); acpi_ht = 1; } @@ -423,6 +426,20 @@ static inline void copy_edd(void) } #endif +#define EBDA_ADDR_POINTER 0x40E +static void __init reserve_ebda_region(void) +{ + unsigned int addr; + /** + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E + */ + addr = *(unsigned short *)phys_to_virt(EBDA_ADDR_POINTER); + addr <<= 4; + if (addr) + reserve_bootmem_generic(addr, PAGE_SIZE); +} + void __init setup_arch(char **cmdline_p) { unsigned long low_mem_size; @@ -487,6 +504,9 @@ void __init setup_arch(char **cmdline_p) */ reserve_bootmem_generic(0, PAGE_SIZE); + /* reserve ebda region */ + reserve_ebda_region(); + #ifdef CONFIG_SMP /* * But first pinch a few for the stack/trampoline stuff @@ -662,6 +682,26 @@ static int __init init_amd(struct cpuinfo_x86 *c) } } display_cacheinfo(c); + + if (c->cpuid_level >= 0x80000008) { + c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1; + if (c->x86_num_cores & (c->x86_num_cores - 1)) + c->x86_num_cores = 1; + +#ifdef CONFIG_NUMA + /* On a dual core setup the lower bits of apic id + distingush the cores. Fix up the CPU<->node mappings + here based on that. + Assumes number of cores is a power of two. */ + if (c->x86_num_cores > 1) { + int cpu = c->x86_apicid; + cpu_to_node[cpu] = cpu >> hweight32(c->x86_num_cores - 1); + printk(KERN_INFO "CPU %d -> Node %d\n", + cpu, cpu_to_node[cpu]); + } +#endif + } + return r; } @@ -705,7 +745,7 @@ static void __init detect_ht(struct cpuinfo_x86 *c) } if (index_lsb != index_msb ) index_msb++; - initial_apic_id = ebx >> 24 & 0xff; + initial_apic_id = hard_smp_processor_id(); phys_proc_id[cpu] = initial_apic_id >> index_msb; printk(KERN_INFO "CPU: Physical Processor ID: %d\n", @@ -748,6 +788,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 }, @@ -885,6 +926,8 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) c->x86_model_id[0] = '\0'; /* Unset */ c->x86_clflush_size = 64; c->x86_cache_alignment = c->x86_clflush_size; + c->x86_num_cores = 1; + c->x86_apicid = c == &boot_cpu_data ? 0 : c - cpu_data; memset(&c->x86_capability, 0, sizeof c->x86_capability); /* Get vendor name */ @@ -912,6 +955,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) } if (c->x86_capability[0] & (1<<19)) c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; + c->x86_apicid = misc >> 24; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; @@ -931,8 +975,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c) /* AMD-defined flags: level 0x80000001 */ xlvl = cpuid_eax(0x80000000); if ( (xlvl & 0xffff0000) == 0x80000000 ) { - if ( xlvl >= 0x80000001 ) + if ( xlvl >= 0x80000001 ) { c->x86_capability[1] = cpuid_edx(0x80000001); + c->x86_capability[5] = cpuid_ecx(0x80000001); + } if ( xlvl >= 0x80000004 ) get_model_name(c); /* Default name */ } @@ -1042,8 +1088,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, }; @@ -1132,6 +1178,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) } } + if (c->x86_num_cores > 1) + seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores); + seq_printf(m, "\n\n"); return 0; diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index 9d3137a55..b83680afe 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); @@ -193,7 +195,8 @@ void pda_init(int cpu) char boot_exception_stacks[N_EXCEPTION_STACKS * EXCEPTION_STKSZ] __attribute__((section(".bss.page_aligned"))); -void __init syscall_init(void) +/* May not be marked __init: used by software suspend */ +void syscall_init(void) { /* * LSTAR and STAR live in a bit strange symbiosis. @@ -235,10 +238,11 @@ void __init cpu_init (void) #else int cpu = smp_processor_id(); #endif - struct tss_struct * t = &init_tss[cpu]; + struct tss_struct *t = &per_cpu(init_tss, cpu); unsigned long v; char *estacks = NULL; struct task_struct *me; + int i; /* CPU 0 is initialised in head64.c */ if (cpu != 0) { @@ -302,12 +306,13 @@ void __init cpu_init (void) t->ist[v] = (unsigned long)estacks; } - t->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap); /* - * This is required because the CPU will access up to + * <= is required because the CPU will access up to * 8 bits beyond the end of the IO permission bitmap. */ - t->io_bitmap[IO_BITMAP_LONGS] = ~0UL; + for (i = 0; i <= IO_BITMAP_LONGS; i++) + t->io_bitmap[i] = ~0UL; atomic_inc(&init_mm.mm_count); me->active_mm = &init_mm; diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index f6eb0e337..99bcd7275 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(¤t->sighand->siglock); #ifdef DEBUG_SIG printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n", - saveset, newset, ®s, regs.rip); + saveset, newset, regs, regs->rip); #endif - regs.rax = -EINTR; + regs->rax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(®s, &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(¤t->sighand->siglock); - if (restore_sigcontext(®s, &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(®s,frame,"sigreturn"); + signal_fault(regs,frame,"sigreturn"); return 0; } @@ -180,6 +181,7 @@ static inline int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me) { int err = 0; + unsigned long eflags; err |= __put_user(0, &sc->gs); err |= __put_user(0, &sc->fs); @@ -203,7 +205,11 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo err |= __put_user(me->thread.trap_no, &sc->trapno); err |= __put_user(me->thread.error_code, &sc->err); err |= __put_user(regs->rip, &sc->rip); - err |= __put_user(regs->eflags, &sc->eflags); + eflags = regs->eflags; + if (current->ptrace & PT_PTRACED) { + eflags &= ~TF_MASK; + } + err |= __put_user(eflags, &sc->eflags); err |= __put_user(mask, &sc->oldmask); err |= __put_user(me->thread.cr2, &sc->cr2); @@ -287,7 +293,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; } @@ -318,7 +324,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->rsp = (unsigned long)frame; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #ifdef DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -328,9 +340,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 +348,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 = ¤t->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 +387,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(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -398,6 +403,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 +425,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!oldset) oldset = ¤t->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 +436,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/smp.c b/arch/x86_64/kernel/smp.c index 409460ebc..269ef092f 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -382,30 +382,14 @@ static struct call_data_struct * call_data; * this function sends a 'generic call function' IPI to all other CPUs * in the system. */ - -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, - int wait) -/* - * [SUMMARY] Run a function on all other CPUs. - * The function to run. This must be fast and non-blocking. - * An arbitrary pointer to pass to the function. - * currently unused. - * If true, wait (atomically) until function has completed on other CPUs. - * [RETURNS] 0 on success, else a negative status code. Does not return until - * remote CPUs are nearly ready to execute <> or are or have executed. - * - * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. - */ +static void __smp_call_function (void (*func) (void *info), void *info, + int nonatomic, int wait) { struct call_data_struct data; int cpus = num_online_cpus()-1; if (!cpus) - return 0; - - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); + return; data.func = func; data.info = info; @@ -414,7 +398,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); call_data = &data; wmb(); /* Send a message to all other CPUs and wait for them to respond */ @@ -427,8 +410,29 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, if (wait) while (atomic_read(&data.finished) != cpus) barrier(); - spin_unlock(&call_lock); +} +/* + * smp_call_function - run a function on all other CPUs. + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @nonatomic: currently unused. + * @wait: If true, wait (atomically) until function has completed on other + * CPUs. + * + * Returns 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute func or are or have executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. + * Actually there are a few legal cases, like panic. + */ +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + spin_lock(&call_lock); + __smp_call_function(func,info,nonatomic,wait); + spin_unlock(&call_lock); return 0; } @@ -452,7 +456,16 @@ static void smp_really_stop_cpu(void *dummy) void smp_send_stop(void) { - smp_call_function(smp_really_stop_cpu, NULL, 1, 0); + int nolock = 0; + /* Don't deadlock on the call lock in panic */ + if (!spin_trylock(&call_lock)) { + udelay(100); + /* ignore locking because we have paniced anyways */ + nolock = 1; + } + __smp_call_function(smp_really_stop_cpu, NULL, 1, 0); + if (!nolock) + spin_unlock(&call_lock); smp_stop_cpu(); } diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 29f2578bf..dc0f40fea 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ cpumask_t cpu_online_map; /* which logical CPU number maps to which CPU (physical APIC ID) */ volatile char x86_cpu_to_apicid[NR_CPUS]; +EXPORT_SYMBOL(x86_cpu_to_apicid); static cpumask_t cpu_callin_map; cpumask_t cpu_callout_map; @@ -390,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, ®s, 0, NULL, NULL); -} - #if APIC_DEBUG static inline void inquire_remote_apic(int apicid) { @@ -573,26 +565,17 @@ 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(); init_rsp = idle->thread.rsp; - init_tss[cpu].rsp0 = init_rsp; + per_cpu(init_tss,cpu).rsp0 = init_rsp; initial_code = start_secondary; clear_ti_thread_flag(idle->thread_info, TIF_FORK); @@ -967,6 +950,9 @@ int __devinit __cpu_up(unsigned int cpu) void __init smp_cpus_done(unsigned int max_cpus) { +#ifdef CONFIG_X86_IO_APIC + setup_ioapic_dest(); +#endif zap_low_mappings(); } diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index 751982df5..ebaa1e37d 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -129,7 +129,7 @@ void restore_processor_state(void) void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct *t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S index 99a1adf86..8a3999810 100644 --- a/arch/x86_64/kernel/suspend_asm.S +++ b/arch/x86_64/kernel/suspend_asm.S @@ -1,22 +1,18 @@ -/* originally gcc generated, but now changed. don't overwrite. */ +/* Originally gcc generated, modified by hand + * + * This may not use any stack, nor any variable that is not "NoSave": + * + * Its rewriting one kernel image with another. What is stack in "old" + * image could very well be data page in "new" image, and overwriting + * your own stack under you is bad idea. + */ .text #include #include #include -/* Input: - * rdi resume flag - */ - -ENTRY(do_magic) -.LFB5: - subq $8, %rsp -.LCFI2: - testl %edi, %edi - jne .L90 - call do_magic_suspend_1 - call save_processor_state +ENTRY(swsusp_arch_suspend) movq %rsp, saved_context_esp(%rip) movq %rax, saved_context_eax(%rip) @@ -36,36 +32,35 @@ ENTRY(do_magic) movq %r15, saved_context_r15(%rip) pushfq ; popq saved_context_eflags(%rip) - addq $8, %rsp - jmp do_magic_suspend_2 -.L90: + call swsusp_save + ret + +ENTRY(swsusp_arch_resume) /* set up cr3 */ leaq init_level4_pgt(%rip),%rax subq $__START_KERNEL_map,%rax - movq %rax,%cr3 + movq %rax,%cr3 movq mmu_cr4_features(%rip), %rax movq %rax, %rdx - andq $~(1<<7), %rdx # PGE - movq %rdx, %cr4; # turn off PGE - movq %cr3, %rcx; # flush TLB - movq %rcx, %cr3; - movq %rax, %cr4; # turn PGE back on + movq %rdx, %cr4; # turn off PGE + movq %cr3, %rcx; # flush TLB + movq %rcx, %cr3; + movq %rax, %cr4; # turn PGE back on - call do_magic_resume_1 movl nr_copy_pages(%rip), %eax xorl %ecx, %ecx - movq $0, loop(%rip) + movq $0, %r10 testl %eax, %eax - je .L108 + jz done .L105: xorl %esi, %esi - movq $0, loop2(%rip) + movq $0, %r11 jmp .L104 .p2align 4,,7 -.L111: - movq loop(%rip), %rcx +copy_one_page: + movq %r10, %rcx .L104: movq pagedir_nosave(%rip), %rdx movq %rcx, %rax @@ -75,27 +70,26 @@ ENTRY(do_magic) movzbl (%rsi,%rax), %eax movb %al, (%rsi,%rcx) - movq %cr3, %rax; # flush TLB - movq %rax, %cr3; + movq %cr3, %rax; # flush TLB + movq %rax, %cr3; - movq loop2(%rip), %rax + movq %r11, %rax incq %rax cmpq $4095, %rax movq %rax, %rsi - movq %rax, loop2(%rip) - jbe .L111 - movq loop(%rip), %rax + movq %rax, %r11 + jbe copy_one_page + movq %r10, %rax incq %rax movq %rax, %rcx - movq %rax, loop(%rip) + movq %rax, %r10 mov nr_copy_pages(%rip), %eax cmpq %rax, %rcx jb .L105 -.L108: - .align 4 +done: movl $24, %eax + movl %eax, %ds - movl %eax, %ds movq saved_context_esp(%rip), %rsp movq saved_context_ebp(%rip), %rbp movq saved_context_eax(%rip), %rax @@ -113,13 +107,5 @@ ENTRY(do_magic) movq saved_context_r14(%rip), %r14 movq saved_context_r15(%rip), %r15 pushq saved_context_eflags(%rip) ; popfq - call restore_processor_state - addq $8, %rsp - jmp do_magic_resume_2 - - .section .data.nosave -loop: - .quad 0 -loop2: - .quad 0 - .previous + call swsusp_restore + ret diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 10c511f50..ee941842d 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 @@ -33,6 +32,7 @@ #include #include #include +#include #include #ifdef CONFIG_X86_LOCAL_APIC #include @@ -42,6 +42,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 +86,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 +123,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 @@ -176,6 +180,28 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + /* Assume the lock function has either no stack frame or only a single word. + This checks if the address on the stack looks like a kernel text address. + There is a small window for false hits, but in that case the tick + is just accounted to the spinlock function. + Better would be to write these functions in assembler again + and check exactly. */ + if (in_lock_functions(pc)) { + char *v = *(char **)regs->rsp; + if ((v >= _stext && v <= _etext) || + (v >= _sinittext && v <= _einittext) || + (v >= (char *)MODULES_VADDR && v <= (char *)MODULES_END)) + return (unsigned long)v; + return ((unsigned long *)regs->rsp)[1]; + } + return pc; +} +EXPORT_SYMBOL(profile_pc); + /* * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500 * ms after the second nowtime has started, because when nowtime is written @@ -214,7 +240,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; @@ -293,19 +319,56 @@ unsigned long long monotonic_clock(void) } EXPORT_SYMBOL(monotonic_clock); +static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) +{ + static long lost_count; + static int warned; + + if (report_lost_ticks) { + printk(KERN_WARNING "time.c: Lost %d timer " + "tick(s)! ", lost); + print_symbol("rip %s)\n", regs->rip); + } + + if (lost_count == 100 && !warned) { + 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); + if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) { + printk(KERN_WARNING "Falling back to HPET\n"); + vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; + vxtime.mode = VXTIME_HPET; + do_gettimeoffset = do_gettimeoffset_hpet; + } + /* else should fall back to PIT, but code missing. */ + warned = 1; + } else + lost_count++; + +#ifdef CONFIG_CPU_FREQ + /* In some cases the CPU can change frequency without us noticing + (like going into thermal throttle) + Give cpufreq a change to catch up. */ + if ((lost_count+1) % 25 == 0) { + cpufreq_delayed_get(); + } +#endif +} 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 +417,8 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) (((long) offset << 32) / vxtime.tsc_quot) - 1; } - if (lost) { - if (report_lost_ticks) { - printk(KERN_WARNING "time.c: Lost %ld timer " - "tick(s)! ", lost); - print_symbol("rip %s)\n", regs->rip); - } + if (lost > 0) { + handle_lost_ticks(lost, regs); jiffies += lost; } @@ -376,7 +435,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ #ifndef CONFIG_X86_LOCAL_APIC - x86_do_profile(regs); + profile_tick(CPU_PROFILING, regs); #else if (!using_apic_timer) smp_local_timer_interrupt(regs); @@ -509,6 +568,38 @@ 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 + +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) +{ + static int warned; + if (cpufreq_init && !cpufreq_delayed_issched) { + cpufreq_delayed_issched = 1; + if (!warned) { + warned = 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 +609,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 +633,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 +645,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 /* @@ -705,9 +813,9 @@ void __init time_init(void) outl(0x800038a0, 0xcf8); outl(0xff000001, 0xcfc); outl(0x800038a0, 0xcf8); - hpet_address = inl(0xcfc) & 0xfffffffe; + vxtime.hpet_address = inl(0xcfc) & 0xfffffffe; printk(KERN_WARNING "time.c: WARNING: Enabled HPET " - "at %#lx.\n", hpet_address); + "at %#lx.\n", vxtime.hpet_address); } #endif if (nohpet) @@ -725,8 +833,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 +850,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) @@ -781,11 +884,12 @@ static int time_suspend(struct sys_device *dev, u32 state) static int time_resume(struct sys_device *dev) { + unsigned long flags; unsigned long sec = get_cmos_time() + clock_cmos_diff; - write_seqlock_irq(&xtime_lock); + write_seqlock_irqsave(&xtime_lock,flags); xtime.tv_sec = sec; xtime.tv_nsec = 0; - write_sequnlock_irq(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock,flags); return 0; } @@ -1038,6 +1142,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 99d0ec2ab..c0a31a4ad 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -110,9 +110,10 @@ unsigned long *in_exception_stack(int cpu, unsigned long stack) { int k; for (k = 0; k < N_EXCEPTION_STACKS; k++) { - unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; + struct tss_struct *tss = &per_cpu(init_tss, cpu); + unsigned long end = tss->ist[k] + EXCEPTION_STKSZ; - if (stack >= init_tss[cpu].ist[k] && stack <= end) + if (stack >= tss->ist[k] && stack <= end) return (unsigned long *)end; } return NULL; @@ -352,7 +353,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 */ @@ -436,7 +437,8 @@ static void do_trap(int trapnr, int signr, char *str, #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ return; \ do_trap(trapnr, signr, str, regs, error_code, NULL); \ } @@ -449,7 +451,8 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void __user *)siaddr; \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ return; \ do_trap(trapnr, signr, str, regs, error_code, &info); \ } @@ -463,14 +466,15 @@ DO_ERROR( 7, SIGSEGV, "device not available", device_not_available) DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) -DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) DO_ERROR(18, SIGSEGV, "reserved", reserved) #define DO_ERROR_STACK(trapnr, signr, str, name) \ asmlinkage void *do_##name(struct pt_regs * regs, long error_code) \ { \ struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ return regs; \ if (regs->cs & 3) { \ memcpy(pr, regs, sizeof(struct pt_regs)); \ @@ -513,7 +517,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 */ @@ -564,7 +568,8 @@ asmlinkage void default_do_nmi(struct pt_regs * regs) unsigned char reason = inb(0x61); if (!(reason & 0xc0)) { - if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) == NOTIFY_BAD) + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) + == NOTIFY_STOP) return; #ifdef CONFIG_X86_LOCAL_APIC /* @@ -579,7 +584,7 @@ asmlinkage void default_do_nmi(struct pt_regs * regs) unknown_nmi_error(reason, regs); return; } - if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_BAD) + if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) return; if (reason & 0x80) mem_parity_error(reason, regs); @@ -670,27 +675,53 @@ clear_dr7: return regs; clear_TF_reenable: - printk("clear_tf_reenable\n"); set_tsk_thread_flag(tsk, TIF_SINGLESTEP); clear_TF: /* RED-PEN could cause spurious errors */ if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP) - != NOTIFY_BAD) + != NOTIFY_STOP) regs->eflags &= ~TF_MASK; 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 +771,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 +830,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 21383547b..f656f197b 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -16,6 +16,7 @@ SECTIONS .text : { *(.text) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x9090 @@ -91,9 +92,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 1fb138482..6e3acce42 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -63,10 +62,10 @@ EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__down_failed_trylock); -EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL(__down_failed); +EXPORT_SYMBOL(__down_failed_interruptible); +EXPORT_SYMBOL(__down_failed_trylock); +EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(ip_compute_csum); @@ -76,14 +75,14 @@ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL_NOVERS(__get_user_1); -EXPORT_SYMBOL_NOVERS(__get_user_2); -EXPORT_SYMBOL_NOVERS(__get_user_4); -EXPORT_SYMBOL_NOVERS(__get_user_8); -EXPORT_SYMBOL_NOVERS(__put_user_1); -EXPORT_SYMBOL_NOVERS(__put_user_2); -EXPORT_SYMBOL_NOVERS(__put_user_4); -EXPORT_SYMBOL_NOVERS(__put_user_8); +EXPORT_SYMBOL(__get_user_1); +EXPORT_SYMBOL(__get_user_2); +EXPORT_SYMBOL(__get_user_4); +EXPORT_SYMBOL(__get_user_8); +EXPORT_SYMBOL(__put_user_1); +EXPORT_SYMBOL(__put_user_2); +EXPORT_SYMBOL(__put_user_4); +EXPORT_SYMBOL(__put_user_8); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); @@ -108,18 +107,15 @@ 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 EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL_NOVERS(__write_lock_failed); -EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(__write_lock_failed); +EXPORT_SYMBOL(__read_lock_failed); EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(smp_call_function); @@ -164,28 +160,35 @@ extern void * __memcpy(void *,const void *,__kernel_size_t); extern char * strcat(char *, const char *); extern int memcmp(const void * cs,const void * ct,size_t count); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(strcpy); -EXPORT_SYMBOL_NOVERS(strncmp); -EXPORT_SYMBOL_NOVERS(strncpy); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strcmp); -EXPORT_SYMBOL_NOVERS(strcat); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(memchr); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(memscan); -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); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(__memcpy); +EXPORT_SYMBOL(memcmp); + +#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); @@ -201,7 +204,7 @@ EXPORT_SYMBOL(smp_num_siblings); #endif extern void do_softirq_thunk(void); -EXPORT_SYMBOL_NOVERS(do_softirq_thunk); +EXPORT_SYMBOL(do_softirq_thunk); void out_of_line_bug(void); EXPORT_SYMBOL(out_of_line_bug); @@ -211,10 +214,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 32b206440..6b26a1c1e 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 000000000..6060dd908 --- /dev/null +++ b/arch/x86_64/lib/bitops.c @@ -0,0 +1,140 @@ +#include +#include + +#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 598d79de8..e7ce82a0a 100644 --- a/arch/x86_64/lib/bitstr.c +++ b/arch/x86_64/lib/bitstr.c @@ -1,3 +1,4 @@ +#include #include /* 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/csum-wrappers.c b/arch/x86_64/lib/csum-wrappers.c index c5b166224..18abae985 100644 --- a/arch/x86_64/lib/csum-wrappers.c +++ b/arch/x86_64/lib/csum-wrappers.c @@ -22,6 +22,7 @@ unsigned int csum_partial_copy_from_user(const char __user *src, char *dst, int len, unsigned int isum, int *errp) { + might_sleep(); *errp = 0; if (likely(access_ok(VERIFY_READ,src, len))) { /* Why 6, not 7? To handle odd addresses aligned we @@ -69,6 +70,7 @@ unsigned int csum_partial_copy_to_user(const char *src, char __user *dst, int len, unsigned int isum, int *errp) { + might_sleep(); if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) { *errp = -EFAULT; return 0; diff --git a/arch/x86_64/lib/memmove.c b/arch/x86_64/lib/memmove.c index 12cac5ba7..e93d5255f 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/lib/usercopy.c b/arch/x86_64/lib/usercopy.c index a17c85c5b..db8abba1a 100644 --- a/arch/x86_64/lib/usercopy.c +++ b/arch/x86_64/lib/usercopy.c @@ -14,6 +14,7 @@ #define __do_strncpy_from_user(dst,src,count,res) \ do { \ long __d0, __d1, __d2; \ + might_sleep(); \ __asm__ __volatile__( \ " testq %1,%1\n" \ " jz 2f\n" \ @@ -63,6 +64,7 @@ strncpy_from_user(char *dst, const char __user *src, long count) unsigned long __clear_user(void __user *addr, unsigned long size) { long __d0; + might_sleep(); /* no memory constraint because it doesn't change any memory gcc knows about */ asm volatile( diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 32a1d0ce9..4e12a56c9 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -58,16 +57,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 +218,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 +280,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 @@ -282,7 +315,27 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) goto bad_area_nosemaphore; again: - down_read(&mm->mmap_sem); + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the + * kernel and should generate an OOPS. Unfortunatly, in the case of an + * erroneous fault occuring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user + * space from well defined areas of code, which are listed in the + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform + * the source reference check when there is a possibilty of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. + */ + if (!down_read_trylock(&mm->mmap_sem)) { + if ((error_code & 4) == 0 && + !search_exception_tables(regs->rip)) + goto bad_area_nosemaphore; + down_read(&mm->mmap_sem); + } vma = find_vma(mm, address); if (!vma) @@ -351,18 +404,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 +429,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 +460,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 +534,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 +546,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 f393e3355..e13acb6ab 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/ioremap.c b/arch/x86_64/mm/ioremap.c index 0cc4a612f..9fc032b99 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -111,7 +111,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { void * addr; struct vm_struct * area; @@ -126,7 +126,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag * Don't remap the low PCI/ISA area, it's always mapped.. */ if (phys_addr >= 0xA0000 && last_addr < 0x100000) - return phys_to_virt(phys_addr); + return (__force void __iomem *)phys_to_virt(phys_addr); /* * Don't allow anybody to remap normal RAM that we're using.. @@ -164,7 +164,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag vunmap(addr); return NULL; } - return (void *) (offset + (char *)addr); + return (__force void __iomem *) (offset + (char *)addr); } /** @@ -189,9 +189,9 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag * Must be freed with iounmap. */ -void *ioremap_nocache (unsigned long phys_addr, unsigned long size) +void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) { - void *p = __ioremap(phys_addr, size, _PAGE_PCD); + void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD); if (!p) return p; @@ -212,7 +212,7 @@ void *ioremap_nocache (unsigned long phys_addr, unsigned long size) return p; } -void iounmap(void *addr) +void iounmap(void __iomem *addr) { struct vm_struct *p; if (addr <= high_memory) diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c index 0ec22c11c..0825e37fd 100644 --- a/arch/x86_64/mm/k8topology.c +++ b/arch/x86_64/mm/k8topology.c @@ -100,8 +100,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) limit <<= 24; limit |= (1<<24)-1; - if (limit > end_pfn_map << PAGE_SHIFT) - limit = end_pfn_map << PAGE_SHIFT; + if (limit > end_pfn << PAGE_SHIFT) + limit = end_pfn << PAGE_SHIFT; if (limit <= base) continue; diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 598a35c19..e6746a26b 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); } @@ -162,10 +162,58 @@ void __init numa_init_array(void) set_bit(0, &node_to_cpumask[cpu_to_node(0)]); } +int numa_fake __initdata = 0; + +/* Numa emulation */ +static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn) +{ + int i; + struct node nodes[MAXNODE]; + unsigned long sz = ((end_pfn - start_pfn)< 1) { + unsigned long x = 1; + while ((x << 1) < sz) + x <<= 1; + if (x < sz/2) + printk("Numa emulation unbalanced. Complain to maintainer\n"); + sz = x; + } + + memset(&nodes,0,sizeof(nodes)); + for (i = 0; i < numa_fake; i++) { + nodes[i].start = (start_pfn<> 20); + } + numnodes = numa_fake; + memnode_shift = compute_hash_shift(nodes); + if (memnode_shift < 0) { + memnode_shift = 0; + printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n"); + return -1; + } + for (i = 0; i < numa_fake; i++) + setup_node_bootmem(i, nodes[i].start, nodes[i].end); + numa_init_array(); + return 0; +} + void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) { int i; + if (numa_fake && !numa_emulation(start_pfn, end_pfn)) + return; + #ifdef CONFIG_K8_NUMA if (!numa_off && !k8_scan_nodes(start_pfn<E #define D_KEY ctx->D -static u8 pow_tab[256]; -static u8 log_tab[256]; -static u8 sbx_tab[256]; -static u8 isb_tab[256]; +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; static u32 rco_tab[10]; static u32 ft_tab[4][256]; static u32 it_tab[4][256]; @@ -113,7 +113,7 @@ static u32 it_tab[4][256]; static u32 fl_tab[4][256]; static u32 il_tab[4][256]; -static inline u8 +static inline u8 __init f_mult (u8 a, u8 b) { u8 aa = log_tab[a], cc = aa + log_tab[b]; @@ -153,14 +153,14 @@ f_mult (u8 a, u8 b) il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) -static void +static void __init gen_tabs (void) { u32 i, t; u8 p, q; /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest prmitive + 0x011b as modular polynomial - the simplest primitive root is 0x03, used here to generate the tables */ for (i = 0, p = 1; i < 256; ++i) { diff --git a/crypto/api.c b/crypto/api.c index 6f0e62571..394169a85 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -155,8 +155,12 @@ out: void crypto_free_tfm(struct crypto_tfm *tfm) { + struct crypto_alg *alg = tfm->__crt_alg; + int size = sizeof(*tfm) + alg->cra_ctxsize; + crypto_exit_ops(tfm); - crypto_alg_put(tfm->__crt_alg); + crypto_alg_put(alg); + memset(tfm, 0, size); kfree(tfm); } diff --git a/crypto/arc4.c b/crypto/arc4.c index b66eb1f0d..9efbcaae8 100644 --- a/crypto/arc4.c +++ b/crypto/arc4.c @@ -3,7 +3,7 @@ * * ARC4 Cipher Algorithm * - * Jon Oberheide + * Jon Oberheide * * 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 @@ -100,4 +100,4 @@ module_exit(arc4_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); -MODULE_AUTHOR("Jon Oberheide "); +MODULE_AUTHOR("Jon Oberheide "); diff --git a/crypto/blowfish.c b/crypto/blowfish.c index 8fd18dcdb..b6bea821c 100644 --- a/crypto/blowfish.c +++ b/crypto/blowfish.c @@ -3,9 +3,9 @@ * * Blowfish Cipher Algorithm, by Bruce Schneier. * http://www.counterpane.com/blowfish.html - * - * Adapated from Kerneli implementation. - * + * + * Adapted from Kerneli implementation. + * * Copyright (c) Herbert Valerio Riedel * Copyright (c) Kyle McMartin * Copyright (c) 2002 James Morris diff --git a/crypto/internal.h b/crypto/internal.h index b51fad1f9..e68e43886 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -17,7 +17,6 @@ #include #include #include -#include #include extern enum km_type crypto_km_types[]; diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 540dd9ac1..f6a5c9e5b 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -70,7 +70,7 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out, { /* walk->data may be pointing the first byte of the next page; however, we know we transfered at least one byte. So, - walk->data - 1 will be a virutual address in the mapped page. */ + walk->data - 1 will be a virtual address in the mapped page. */ if (out) flush_dcache_page(walk->page); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index f1e631b9c..c23d5ee69 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "tcrypt.h" /* @@ -61,7 +62,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", + "wp512", "wp384", "wp256", NULL }; static void @@ -680,6 +682,9 @@ do_test(void) test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); + test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); + test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS); + test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS); test_deflate(); test_crc32c(); #ifdef CONFIG_CRYPTO_HMAC @@ -791,6 +796,19 @@ do_test(void) test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS); break; + case 22: + test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); + break; + + case 23: + test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS); + break; + + case 24: + test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS); + break; + + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); @@ -846,7 +864,7 @@ static void __exit fini(void) { } module_init(init); module_exit(fini); -MODULE_PARM(mode, "i"); +module_param(mode, int, 0); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Quick & dirty crypto testing module"); diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index 56a825d65..18370befc 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -301,6 +301,259 @@ 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 WP512_TEST_VECTORS 8 + +struct hash_testvec wp512_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 }, + }, +}; + +#define WP384_TEST_VECTORS 8 + +struct hash_testvec wp384_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 }, + + + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, +}; + +#define WP256_TEST_VECTORS 8 + +struct hash_testvec wp256_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 }, + + + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, { + .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 }, + }, +}; + + #ifdef CONFIG_CRYPTO_HMAC /* * HMAC-MD5 test vectors from RFC2202 @@ -1186,7 +1439,7 @@ struct cipher_testvec tf_cbc_dec_tv_template[] = { /* * Serpent test vectors. These are backwards because Serpent writes - * octect sequences in right-to-left mode. + * octet sequences in right-to-left mode. */ #define SERPENT_ENC_TEST_VECTORS 4 #define SERPENT_DEC_TEST_VECTORS 4 diff --git a/crypto/tea.c b/crypto/tea.c index bf943294d..588a143c1 100644 --- a/crypto/tea.c +++ b/crypto/tea.c @@ -154,7 +154,7 @@ static void xtea_encrypt(void *ctx_arg, u8 *dst, const u8 *src) while (sum != limit) { y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; - sum += TEA_DELTA; + sum += XTEA_DELTA; z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; } diff --git a/crypto/twofish.c b/crypto/twofish.c index 5d6d02c1a..4efff8cf9 100644 --- a/crypto/twofish.c +++ b/crypto/twofish.c @@ -1,7 +1,7 @@ /* * Twofish for CryptoAPI * - * Originaly Twofish for GPG + * Originally Twofish for GPG * By Matthew Skala , July 26, 1998 * 256-bit key length added March 20, 1999 * Some modifications to reduce the text size by Werner Koch, April, 1998 @@ -514,7 +514,7 @@ static const u8 calc_sb_tbl[512] = { * preprocessed through q0 and q1 respectively; for longer keys they are the * output of previous stages. j is the index of the first key byte to use. * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2 - * twice, doing the Psuedo-Hadamard Transform, and doing the necessary + * twice, doing the Pseudo-Hadamard Transform, and doing the necessary * rotations. Its parameters are: a, the array to write the results into, * j, the index of the first output entry, k and l, the preprocessed indices * for index 2i, and m and n, the preprocessed indices for index 2i+1. diff --git a/crypto/wp512.c b/crypto/wp512.c new file mode 100644 index 000000000..fd6e20e1f --- /dev/null +++ b/crypto/wp512.c @@ -0,0 +1,1208 @@ +/* + * 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 +#include +#include +#include +#include + +#define WP512_DIGEST_SIZE 64 +#define WP384_DIGEST_SIZE 48 +#define WP256_DIGEST_SIZE 32 + +#define WP512_BLOCK_SIZE 64 +#define WP512_LENGTHBYTES 32 + +#define WHIRLPOOL_ROUNDS 10 + +struct wp512_ctx { + u8 bitLength[WP512_LENGTHBYTES]; + u8 buffer[WP512_BLOCK_SIZE]; + int bufferBits; + int bufferPos; + u64 hash[WP512_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 wp512_process_buffer(struct wp512_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 wp512_init (void *ctx) { + int i; + struct wp512_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 wp512_update(void *ctx, const u8 *source, unsigned int len) +{ + + struct wp512_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 == WP512_BLOCK_SIZE * 8) { + wp512_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 == WP512_BLOCK_SIZE * 8) { + wp512_process_buffer(wctx); + bufferBits = bufferPos = 0; + } + buffer[bufferPos] = b << (8 - bufferRem); + bufferBits += (int)bits_len; + } + + wctx->bufferBits = bufferBits; + wctx->bufferPos = bufferPos; + +} + +static void wp512_final(void *ctx, u8 *out) +{ + struct wp512_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 > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) { + if (bufferPos < WP512_BLOCK_SIZE) { + memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos); + } + wp512_process_buffer(wctx); + bufferPos = 0; + } + if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES) { + memset(&buffer[bufferPos], 0, + (WP512_BLOCK_SIZE - WP512_LENGTHBYTES) - bufferPos); + } + bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES; + memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES], + bitLength, WP512_LENGTHBYTES); + wp512_process_buffer(wctx); + for (i = 0; i < WP512_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 void wp384_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + u8 D[64]; + + wp512_final (wctx, D); + memcpy (out, D, WP384_DIGEST_SIZE); + memset (D, 0, WP512_DIGEST_SIZE); +} + +static void wp256_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + u8 D[64]; + + wp512_final (wctx, D); + memcpy (out, D, WP256_DIGEST_SIZE); + memset (D, 0, WP512_DIGEST_SIZE); +} + +static struct crypto_alg wp512 = { + .cra_name = "wp512", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp512.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP512_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp512_final } } +}; + +static struct crypto_alg wp384 = { + .cra_name = "wp384", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp384.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP384_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp384_final } } +}; + +static struct crypto_alg wp256 = { + .cra_name = "wp256", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp256.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP256_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp256_final } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&wp512); + + if (ret < 0) + goto out; + + ret = crypto_register_alg(&wp384); + if (ret < 0) + { + crypto_unregister_alg(&wp512); + goto out; + } + + ret = crypto_register_alg(&wp256); + if (ret < 0) + { + crypto_unregister_alg(&wp512); + crypto_unregister_alg(&wp384); + } +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&wp512); + crypto_unregister_alg(&wp384); + crypto_unregister_alg(&wp256); +} + +MODULE_ALIAS("wp384"); +MODULE_ALIAS("wp256"); + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm"); diff --git a/drivers/Makefile b/drivers/Makefile index 847d2c1ed..dfaafd02f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ +obj-y += video/ obj-$(CONFIG_ACPI_BOOT) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so @@ -15,6 +16,13 @@ obj-$(CONFIG_PNP) += pnp/ # char/ comes before serial/ etc so that the VT console is the boot-time # default. obj-y += char/ + +# i810fb depends on char/agp/ +obj-$(CONFIG_FB_I810) += video/i810/ + +# we also need input/serio early so serio bus is initialized by the time +# serial drivers start registering their serio ports +obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ net/ media/ @@ -26,7 +34,7 @@ obj-$(CONFIG_FC4) += fc4/ obj-$(CONFIG_SCSI) += scsi/ obj-$(CONFIG_FUSION) += message/ obj-$(CONFIG_IEEE1394) += ieee1394/ -obj-y += cdrom/ video/ +obj-y += cdrom/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_DIO) += dio/ @@ -39,7 +47,6 @@ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ -obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ @@ -50,4 +57,5 @@ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_MMC) += mmc/ obj-y += firmware/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index a742764db..96e4fafb0 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -204,6 +204,32 @@ config ACPI_TOSHIBA If you have a legacy free Toshiba laptop (such as the Libretto L1 series), say Y. +config ACPI_CUSTOM_DSDT + bool "Include Custom DSDT" + depends on X86 && ACPI_INTERPRETER && !STANDALONE + default n + help + Thist option is to load a custom ACPI DSDT + If you don't know what that is, say N. + +config ACPI_CUSTOM_DSDT_FILE + string "Custom DSDT Table file to include" + depends on ACPI_CUSTOM_DSDT + default "" + help + Enter the full path name to the file wich includes the AmlCode declaration. + +config ACPI_BLACKLIST_YEAR + int "Disable ACPI for systems before Jan 1st this year" + default 0 + help + enter a 4-digit year, eg. 2001 to disable ACPI by default + on platforms with DMI BIOS date before January 1st that year. + "acpi=force" can be used to override this mechanism. + + Enter 0 to disable this mechanism and allow ACPI to + run by default no matter what the year. (default) + config ACPI_DEBUG bool "Debug Statements" depends on ACPI_INTERPRETER diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index beb93c60d..bcc35ca79 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -47,4 +47,4 @@ obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o -obj-$(CONFIG_ACPI_BUS) += scan.o +obj-$(CONFIG_ACPI_BUS) += scan.o motherboard.o diff --git a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c index c918088a4..a267b8b3b 100644 --- a/drivers/acpi/acpi_ksyms.c +++ b/drivers/acpi/acpi_ksyms.c @@ -84,6 +84,8 @@ EXPORT_SYMBOL(acpi_resource_to_address64); EXPORT_SYMBOL(acpi_enable_event); EXPORT_SYMBOL(acpi_disable_event); EXPORT_SYMBOL(acpi_clear_event); +EXPORT_SYMBOL(acpi_set_gpe_type); +EXPORT_SYMBOL(acpi_enable_gpe); EXPORT_SYMBOL(acpi_get_timer_duration); EXPORT_SYMBOL(acpi_get_timer); EXPORT_SYMBOL(acpi_get_sleep_type_data); diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index c884d4aaa..f2ca51bef 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -42,7 +42,7 @@ #include #include -#define ASUS_ACPI_VERSION "0.28" +#define ASUS_ACPI_VERSION "0.29" #define PROC_ASUS "asus" //the directory #define PROC_MLED "mled" @@ -123,14 +123,18 @@ struct asus_hotk { L3C, //L3800C L3D, //L3400D L3H, //L3H, but also L2000E + L4R, //L4500R L5x, //L5800C L8L, //L8400L M1A, //M1300A M2E, //M2400E, L4400L + M6N, //M6800N + M6R, //M6700R P30, //Samsung P30 S1x, //S1300A, but also L1400B and M2400A (L84F) S2x, //S200 (J1 reported), Victor MP-XP7210 - xxN, //M2400N, M3700N, M6800N, S1300N, S5200N (Centrino) + xxN, //M2400N, M3700N, M5200N, S1300N, S5200N, W1OOON + //(Centrino) END_MODEL } model; //Models currently supported u16 event_count[128]; //count for each event TODO make this better @@ -246,6 +250,19 @@ static struct model_data model_conf[END_MODEL] = { .display_get = "\\INFB" }, + { + .name = "L4R", + .mt_mled = "MLED", + .mt_wled = "WLED", + .wled_status = "\\_SB.PCI0.SBRG.SG13", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\_SB.PCI0.SBSM.SEO4", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\_SB.PCI0.P0P1.VGA.GETD" + }, + { .name = "L5x", .mt_mled = "MLED", @@ -288,6 +305,31 @@ static struct model_data model_conf[END_MODEL] = { .display_get = "\\INFB" }, + { + .name = "M6N", + .mt_mled = "MLED", + .mt_wled = "WLED", + .wled_status = "\\_SB.PCI0.SBRG.SG13", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\_SB.BKLT", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\SSTE" + }, + { + .name = "M6R", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\_SB.PCI0.SBSM.SEO4", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\SSTE" + }, + + { .name = "P30", .mt_wled = "WLED", @@ -344,6 +386,9 @@ static struct proc_dir_entry *asus_proc_dir; */ static struct acpi_table_header *asus_info; +/* The actual device the driver binds to */ +static struct asus_hotk *hotk; + /* * The hotkey driver declaration */ @@ -408,7 +453,6 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, { int len = 0; int temp; - struct asus_hotk *hotk = (struct asus_hotk *) data; char buf[16]; //enough for all info /* * We use the easy way, we don't care of off and count, so we don't set eof @@ -428,7 +472,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, len += sprintf(page + len, "SFUN value : 0x%04x\n", temp); /* * Another value for userspace: the ASYM method returns 0x02 for - * battery low and 0x04 for battery critical, it's readings tend to be + * battery low and 0x04 for battery critical, its readings tend to be * more accurate than those provided by _BST. * Note: since not all the laptops provide this method, errors are * silently ignored. @@ -467,7 +511,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, /* Generic LED functions */ static int -read_led(struct asus_hotk *hotk, const char *ledname, int ledmask) +read_led(const char *ledname, int ledmask) { if (ledname) { int led_status; @@ -498,7 +542,7 @@ static int parse_arg(const char __user *buf, unsigned long count, int *val) /* FIXME: kill extraneous args so it can be called independently */ static int -write_led(const char __user *buffer, unsigned long count, struct asus_hotk *hotk, +write_led(const char __user *buffer, unsigned long count, char *ledname, int ledmask, int invert) { int value; @@ -528,8 +572,7 @@ static int proc_read_mled(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_led(hotk, hotk->methods->mled_status, MLED_ON)); + return sprintf(page, "%d\n", read_led(hotk->methods->mled_status, MLED_ON)); } @@ -537,8 +580,7 @@ static int proc_write_mled(struct file *file, const char __user *buffer, unsigned long count, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return write_led(buffer, count, hotk, hotk->methods->mt_mled, MLED_ON, 1); + return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1); } /* @@ -548,16 +590,14 @@ static int proc_read_wled(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_led(hotk, hotk->methods->wled_status, WLED_ON)); + return sprintf(page, "%d\n", read_led(hotk->methods->wled_status, WLED_ON)); } static int proc_write_wled(struct file *file, const char __user *buffer, unsigned long count, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return write_led(buffer, count, hotk, hotk->methods->mt_wled, WLED_ON, 0); + return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0); } /* @@ -567,21 +607,18 @@ static int proc_read_tled(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_led(hotk, hotk->methods->tled_status, TLED_ON)); + return sprintf(page, "%d\n", read_led(hotk->methods->tled_status, TLED_ON)); } static int proc_write_tled(struct file *file, const char __user *buffer, unsigned long count, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return write_led(buffer, count, hotk, hotk->methods->mt_tled, TLED_ON, 0); + return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0); } - -static int get_lcd_state(struct asus_hotk *hotk) +static int get_lcd_state(void) { int lcd = 0; @@ -622,13 +659,13 @@ static int get_lcd_state(struct asus_hotk *hotk) return (lcd & 1); } -static int set_lcd_state(struct asus_hotk *hotk, int value) +static int set_lcd_state(int value) { int lcd = 0; acpi_status status = 0; lcd = value ? 1 : 0; - if (lcd != get_lcd_state(hotk)) { + if (lcd != get_lcd_state()) { /* switch */ if (hotk->model != L3H) { status = @@ -651,7 +688,7 @@ static int proc_read_lcd(char *page, char **start, off_t off, int count, int *eof, void *data) { - return sprintf(page, "%d\n", get_lcd_state((struct asus_hotk *) data)); + return sprintf(page, "%d\n", get_lcd_state()); } @@ -660,16 +697,15 @@ proc_write_lcd(struct file *file, const char __user *buffer, unsigned long count, void *data) { int value; - struct asus_hotk *hotk = (struct asus_hotk *) data; count = parse_arg(buffer, count, &value); if (count > 0) - set_lcd_state(hotk, value); + set_lcd_state(value); return count; } -static int read_brightness(struct asus_hotk *hotk) +static int read_brightness(void) { int value; @@ -689,7 +725,7 @@ static int read_brightness(struct asus_hotk *hotk) /* * Change the brightness level */ -static void set_brightness(int value, struct asus_hotk *hotk) +static void set_brightness(int value) { acpi_status status = 0; @@ -702,7 +738,7 @@ static void set_brightness(int value, struct asus_hotk *hotk) } /* No SPLV method if we are here, act as appropriate */ - value -= read_brightness(hotk); + value -= read_brightness(); while (value != 0) { status = acpi_evaluate_object(NULL, (value > 0) ? hotk->methods->brightness_up : @@ -719,8 +755,7 @@ static int proc_read_brn(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct asus_hotk *hotk = (struct asus_hotk *) data; - return sprintf(page, "%d\n", read_brightness(hotk)); + return sprintf(page, "%d\n", read_brightness()); } static int @@ -728,13 +763,12 @@ proc_write_brn(struct file *file, const char __user *buffer, unsigned long count, void *data) { int value; - struct asus_hotk *hotk = (struct asus_hotk *) data; count = parse_arg(buffer, count, &value); if (count > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ - set_brightness(value, hotk); + set_brightness(value); } else if (count < 0) { printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } @@ -742,7 +776,7 @@ proc_write_brn(struct file *file, const char __user *buffer, return count; } -static void set_display(int value, struct asus_hotk *hotk) +static void set_display(int value) { /* no sanity check needed for now */ if (!write_acpi_int(hotk->handle, hotk->methods->display_set, @@ -760,10 +794,10 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof, void *data) { int value = 0; - struct asus_hotk *hotk = (struct asus_hotk *) data; if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value)) printk(KERN_WARNING "Asus ACPI: Error reading display status\n"); + value &= 0x07; /* needed for some models, shouldn't hurt others */ return sprintf(page, "%d\n", value); } @@ -778,11 +812,10 @@ proc_write_disp(struct file *file, const char __user *buffer, unsigned long count, void *data) { int value; - struct asus_hotk *hotk = (struct asus_hotk *) data; count = parse_arg(buffer, count, &value); if (count > 0) - set_display(value, hotk); + set_display(value); else if (count < 0) printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); @@ -817,7 +850,6 @@ __init asus_proc_add(char *name, proc_writefunc *writefunc, static int __init asus_hotk_add_fs(struct acpi_device *device) { struct proc_dir_entry *proc; - struct asus_hotk *hotk = acpi_driver_data(device); mode_t mode; /* @@ -869,13 +901,12 @@ static int __init asus_hotk_add_fs(struct acpi_device *device) } if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || - (hotk->methods->brightness_get && hotk->methods->brightness_get)) { + (hotk->methods->brightness_get && hotk->methods->brightness_set)) { asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode, device); } if (hotk->methods->display_set) { asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, mode, device); - } return 0; @@ -883,10 +914,7 @@ static int __init asus_hotk_add_fs(struct acpi_device *device) static int asus_hotk_remove_fs(struct acpi_device* device) { - struct asus_hotk* hotk = acpi_driver_data(device); - - - if(acpi_device_dir(device)){ + if(acpi_device_dir(device)) { remove_proc_entry(PROC_INFO,acpi_device_dir(device)); if (hotk->methods->mt_wled) remove_proc_entry(PROC_WLED,acpi_device_dir(device)); @@ -894,11 +922,12 @@ static int asus_hotk_remove_fs(struct acpi_device* device) remove_proc_entry(PROC_MLED,acpi_device_dir(device)); if (hotk->methods->mt_tled) remove_proc_entry(PROC_TLED,acpi_device_dir(device)); - if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) + if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) remove_proc_entry(PROC_LCD, acpi_device_dir(device)); - if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || (hotk->methods->brightness_get && hotk->methods->brightness_get)) + if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || + (hotk->methods->brightness_get && hotk->methods->brightness_set)) remove_proc_entry(PROC_BRN, acpi_device_dir(device)); - if (hotk->methods->display_set) + if (hotk->methods->display_set) remove_proc_entry(PROC_DISP, acpi_device_dir(device)); } return 0; @@ -907,11 +936,7 @@ static int asus_hotk_remove_fs(struct acpi_device* device) static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) { - /* TODO Find a better way to handle events count. Here, in data, we receive - * the hotk, so we can do anything! - */ - struct asus_hotk *hotk = (struct asus_hotk *) data; - + /* TODO Find a better way to handle events count.*/ if (!hotk) return; @@ -931,7 +956,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) * This function is used to initialize the hotk with right values. In this * method, we can make all the detection we want, and modify the hotk struct */ -static int __init asus_hotk_get_info(struct asus_hotk *hotk) +static int __init asus_hotk_get_info(void) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -998,11 +1023,19 @@ static int __init asus_hotk_get_info(struct asus_hotk *hotk) hotk->model = L3C; else if (strncmp(model->string.pointer, "L8L", 3) == 0) hotk->model = L8L; + else if (strncmp(model->string.pointer, "L4R", 3) == 0) + hotk->model = L4R; + else if (strncmp(model->string.pointer, "M6N", 3) == 0) + hotk->model = M6N; + else if (strncmp(model->string.pointer, "M6R", 3) == 0) + hotk->model = M6R; else if (strncmp(model->string.pointer, "M2N", 3) == 0 || strncmp(model->string.pointer, "M3N", 3) == 0 || + strncmp(model->string.pointer, "M5N", 3) == 0 || strncmp(model->string.pointer, "M6N", 3) == 0 || strncmp(model->string.pointer, "S1N", 3) == 0 || - strncmp(model->string.pointer, "S5N", 3) == 0) + strncmp(model->string.pointer, "S5N", 3) == 0 || + strncmp(model->string.pointer, "W1N", 3) == 0) hotk->model = xxN; else if (strncmp(model->string.pointer, "M1", 2) == 0) hotk->model = M1A; @@ -1025,7 +1058,6 @@ static int __init asus_hotk_get_info(struct asus_hotk *hotk) hotk->model = L5x; if (hotk->model == END_MODEL) { - /* By default use the same values, as I don't know others */ printk("unsupported, trying default values, supply the " "developers with your DSDT\n"); hotk->model = M2E; @@ -1040,16 +1072,14 @@ static int __init asus_hotk_get_info(struct asus_hotk *hotk) hotk->methods->lcd_status = NULL; /* L2B is similar enough to L3C to use its settings, with this only exception */ - else if (strncmp(model->string.pointer, "S5N", 3) == 0) + else if (strncmp(model->string.pointer, "S5N", 3) == 0 || + strncmp(model->string.pointer, "M5N", 3) == 0) hotk->methods->mt_mled = NULL; - /* S5N has no MLED */ - else if (strncmp(model->string.pointer, "M6N", 3) == 0) { - hotk->methods->display_get = NULL; //TODO - hotk->methods->lcd_status = "\\_SB.BKLT"; - hotk->methods->mt_wled = "WLED"; - hotk->methods->wled_status = "\\_SB.PCI0.SBRG.SG13"; - /* M6N differs slightly and has a usable WLED */ - } + /* S5N and M5N have no MLED */ + else if (strncmp(model->string.pointer, "M2N", 3) == 0 || + strncmp(model->string.pointer, "W1N", 3) == 0) + hotk->methods->mt_wled = "WLED"; + /* M2N and W1N have a usable WLED */ else if (asus_info) { if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) hotk->methods->mled_status = NULL; @@ -1062,20 +1092,16 @@ static int __init asus_hotk_get_info(struct asus_hotk *hotk) } - -static int __init asus_hotk_check(struct asus_hotk *hotk) +static int __init asus_hotk_check(void) { int result = 0; - if (!hotk) - return(-EINVAL); - result = acpi_bus_get_status(hotk->device); if (result) return(result); if (hotk->device->status.present) { - result = asus_hotk_get_info(hotk); + result = asus_hotk_get_info(); } else { printk(KERN_ERR " Hotkey device not present, aborting\n"); return(-EINVAL); @@ -1085,10 +1111,8 @@ static int __init asus_hotk_check(struct asus_hotk *hotk) } - static int __init asus_hotk_add(struct acpi_device *device) { - struct asus_hotk *hotk = NULL; acpi_status status = AE_OK; int result; @@ -1111,7 +1135,7 @@ static int __init asus_hotk_add(struct acpi_device *device) hotk->device = device; - result = asus_hotk_check(hotk); + result = asus_hotk_check(); if (result) goto end; @@ -1152,16 +1176,14 @@ static int __init asus_hotk_add(struct acpi_device *device) return(result); } + static int asus_hotk_remove(struct acpi_device *device, int type) { acpi_status status = 0; - struct asus_hotk *hotk = NULL; if (!device || !acpi_driver_data(device)) return(-EINVAL); - hotk = (struct asus_hotk *) acpi_driver_data(device); - status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, asus_hotk_notify); if (ACPI_FAILURE(status)) @@ -1179,20 +1201,24 @@ static int __init asus_acpi_init(void) { int result; + if (acpi_disabled) + return -ENODEV; + asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); - return(-ENODEV); + return -ENODEV; } asus_proc_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&asus_hotk_driver); - if (result < 0) { + if (result < 1) { + acpi_bus_unregister_driver(&asus_hotk_driver); remove_proc_entry(PROC_ASUS, acpi_root_dir); - return(-ENODEV); + return -ENODEV; } - return(0); + return 0; } diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 9cf61ba9d..4c010e7f1 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -2,7 +2,9 @@ * blacklist.c * * Check to see if the given machine has a known bad ACPI BIOS + * or if the BIOS is too old. * + * Copyright (C) 2004 Len Brown * Copyright (C) 2002 Andy Grover * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -30,6 +32,7 @@ #include #include #include +#include enum acpi_blacklist_predicates { @@ -56,20 +59,6 @@ struct acpi_blacklist_item */ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { - /* Portege 7020, BIOS 8.10 */ - {"TOSHIB", "7020CT ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0}, - /* Portege 4030 */ - {"TOSHIB", "4030 ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0}, - /* Portege 310/320, BIOS 7.1 */ - {"TOSHIB", "310 ", 0x19990511, ACPI_DSDT, all_versions, "Implicit Return", 0}, - /* Seattle 2, old bios rev. */ - {"INTEL ", "440BX ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* ASUS K7M */ - {"ASUS ", "K7M ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* Intel 810 Motherboard? */ - {"MNTRAL", "MO81010A", 0x00000012, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* Compaq Presario 711FR */ - {"COMAPQ", "EAGLES", 0x06040000, ACPI_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0}, /* Compaq Presario 1700 */ {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, "Multiple problems", 1}, /* Sony FX120, FX140, FX150? */ @@ -84,6 +73,45 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = }; +#if CONFIG_ACPI_BLACKLIST_YEAR + +static int __init +blacklist_by_year(void) +{ + int year; + char *s = dmi_get_system_info(DMI_BIOS_DATE); + + if (!s) + return 0; + if (!*s) + return 0; + + s = strrchr(s, '/'); + if (!s) + return 0; + + s += 1; + + year = simple_strtoul(s,NULL,0); + + if (year < 100) { /* 2-digit year */ + year += 1900; + if (year < 1996) /* no dates < spec 1.0 */ + year += 100; + } + + if (year < CONFIG_ACPI_BLACKLIST_YEAR) { + printk(KERN_ERR PREFIX "BIOS age (%d) fails cutoff (%d), " + "acpi=force is required to enable ACPI\n", + year, CONFIG_ACPI_BLACKLIST_YEAR); + return 1; + } + return 0; +} +#else +static inline int blacklist_by_year(void) { return 0; } +#endif + int __init acpi_blacklisted(void) { @@ -134,6 +162,8 @@ acpi_blacklisted(void) } } + blacklisted += blacklist_by_year(); + return blacklisted; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 51362331a..4c303e19e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -590,14 +590,20 @@ acpi_bus_init_irq (void) } -static int __init -acpi_bus_init (void) +void __init +acpi_early_init (void) { - int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {sizeof(acpi_fadt), &acpi_fadt}; - ACPI_FUNCTION_TRACE("acpi_bus_init"); + ACPI_FUNCTION_TRACE("acpi_early_init"); + + if (acpi_disabled) + return; + + /* enable workarounds, unless strict ACPI spec. compliance */ + if (!acpi_strict) + acpi_gbl_enable_interpreter_slack = TRUE; status = acpi_initialize_subsystem(); if (ACPI_FAILURE(status)) { @@ -617,7 +623,7 @@ acpi_bus_init (void) status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to get the FADT\n"); - goto error1; + goto error0; } #ifdef CONFIG_X86 @@ -640,12 +646,40 @@ acpi_bus_init (void) } #endif - status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); + status = acpi_enable_subsystem(~(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE)); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); + goto error0; + } + + return; + +error0: + disable_acpi(); + return; +} + +static int __init +acpi_bus_init (void) +{ + int result = 0; + acpi_status status = AE_OK; + extern acpi_status acpi_os_initialize1(void); + + ACPI_FUNCTION_TRACE("acpi_bus_init"); + + status = acpi_os_initialize1(); + + status = acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); goto error1; } + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to initialize ACPI OS objects\n"); + goto error1; + } #ifdef CONFIG_ACPI_EC /* * ACPI 2.0 requires the EC driver to be loaded and work before @@ -693,7 +727,6 @@ acpi_bus_init (void) /* Mimic structured exception handling */ error1: acpi_terminate(); -error0: return_VALUE(-ENODEV); } @@ -708,9 +741,6 @@ static int __init acpi_init (void) printk(KERN_INFO PREFIX "Subsystem revision %08x\n", ACPI_CA_VERSION); - /* Initial core debug level excludes drivers, so include them now */ - acpi_set_debug(ACPI_DEBUG_LOW); - if (acpi_disabled) { printk(KERN_INFO PREFIX "Interpreter disabled.\n"); return -ENODEV; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index a5b45095d..b632b93af 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -456,6 +456,15 @@ acpi_button_add ( goto end; } + if (device->wakeup.flags.valid) { + /* Button's GPE is run-wake GPE */ + acpi_set_gpe_type(device->wakeup.gpe_device, + device->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(device->wakeup.gpe_device, + device->wakeup.gpe_number, ACPI_NOT_ISR); + device->wakeup.state.enabled = 1; + } + printk(KERN_INFO PREFIX "%s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 585f59db4..9fb8caedb 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -13,6 +14,81 @@ ACPI_MODULE_NAME ("debug") #define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" #define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif + +#define MODULE_PARAM_PREFIX +module_param(acpi_dbg_layer, uint, 0400); +module_param(acpi_dbg_level, uint, 0400); + +struct acpi_dlayer { + const char *name; + unsigned long value; +}; +struct acpi_dlevel { + const char *name; + unsigned long value; +}; +#define ACPI_DEBUG_INIT(v) { .name = #v, .value = v } + +const struct acpi_dlayer acpi_debug_layers[] = +{ + ACPI_DEBUG_INIT(ACPI_UTILITIES), + ACPI_DEBUG_INIT(ACPI_HARDWARE), + ACPI_DEBUG_INIT(ACPI_EVENTS), + ACPI_DEBUG_INIT(ACPI_TABLES), + ACPI_DEBUG_INIT(ACPI_NAMESPACE), + ACPI_DEBUG_INIT(ACPI_PARSER), + ACPI_DEBUG_INIT(ACPI_DISPATCHER), + ACPI_DEBUG_INIT(ACPI_EXECUTER), + ACPI_DEBUG_INIT(ACPI_RESOURCES), + ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER), + ACPI_DEBUG_INIT(ACPI_OS_SERVICES), + ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), + ACPI_DEBUG_INIT(ACPI_COMPILER), + ACPI_DEBUG_INIT(ACPI_TOOLS), +}; + +const struct acpi_dlevel acpi_debug_levels[] = +{ + ACPI_DEBUG_INIT(ACPI_LV_ERROR), + ACPI_DEBUG_INIT(ACPI_LV_WARN), + ACPI_DEBUG_INIT(ACPI_LV_INIT), + ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), + ACPI_DEBUG_INIT(ACPI_LV_INFO), + + ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), + ACPI_DEBUG_INIT(ACPI_LV_PARSE), + ACPI_DEBUG_INIT(ACPI_LV_LOAD), + ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), + ACPI_DEBUG_INIT(ACPI_LV_EXEC), + ACPI_DEBUG_INIT(ACPI_LV_NAMES), + ACPI_DEBUG_INIT(ACPI_LV_OPREGION), + ACPI_DEBUG_INIT(ACPI_LV_BFIELD), + ACPI_DEBUG_INIT(ACPI_LV_TABLES), + ACPI_DEBUG_INIT(ACPI_LV_VALUES), + ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), + ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), + ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), + ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), + + ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), + ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), + ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), + + ACPI_DEBUG_INIT(ACPI_LV_MUTEX), + ACPI_DEBUG_INIT(ACPI_LV_THREADS), + ACPI_DEBUG_INIT(ACPI_LV_IO), + ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), + + ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), + ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), + ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), + ACPI_DEBUG_INIT(ACPI_LV_EVENTS), +}; +#define NUM_OF(v) ( sizeof(v)/sizeof(v[0]) ) + static int acpi_system_read_debug ( char *page, @@ -24,16 +100,41 @@ acpi_system_read_debug ( { char *p = page; int size = 0; + int i; if (off != 0) goto end; + p += sprintf(p, "%-25s\tHex SET\n", "Description"); + switch ((unsigned long) data) { case 0: - p += sprintf(p, "0x%08x\n", acpi_dbg_layer); + for (i = 0; i < NUM_OF(acpi_debug_layers); i++) { + p += sprintf(p, "%-25s\t0x%08lX [%c]\n", + acpi_debug_layers[i].name, + acpi_debug_layers[i].value, + (acpi_dbg_layer & acpi_debug_layers[i].value) ? + '*' : ' '); + } + p += sprintf(p, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", + ACPI_ALL_DRIVERS, + (acpi_dbg_layer & ACPI_ALL_DRIVERS) == ACPI_ALL_DRIVERS? + '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 0 ? + ' ' : '-'); + p += sprintf(p, + "--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n", + acpi_dbg_layer); break; case 1: - p += sprintf(p, "0x%08x\n", acpi_dbg_level); + for (i = 0; i < NUM_OF(acpi_debug_levels); i++) { + p += sprintf(p, "%-25s\t0x%08lX [%c]\n", + acpi_debug_levels[i].name, + acpi_debug_levels[i].value, + (acpi_dbg_level & acpi_debug_levels[i].value) ? + '*' : ' '); + } + p += sprintf(p, "--\ndebug_level = 0x%08X (* = enabled)\n", + acpi_dbg_level); break; default: p += sprintf(p, "Invalid debug option\n"); diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 360fbe5e8..4fd369018 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -58,15 +58,12 @@ * * FUNCTION: acpi_ds_parse_method * - * PARAMETERS: obj_handle - Node of the method - * Level - Current nesting level - * Context - Points to a method counter - * return_value - Not used + * PARAMETERS: obj_handle - Method node * * RETURN: Status * - * DESCRIPTION: Call the parser and parse the AML that is - * associated with the method. + * DESCRIPTION: Call the parser and parse the AML that is associated with the + * method. * * MUTEX: Assumes parser is locked * @@ -145,8 +142,9 @@ acpi_ds_parse_method ( return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, op, node, obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); @@ -190,8 +188,6 @@ acpi_ds_parse_method ( * increments the thread count, and waits at the method semaphore * for clearance to execute. * - * MUTEX: Locks/unlocks parser. - * ******************************************************************************/ acpi_status @@ -250,7 +246,8 @@ acpi_ds_begin_method_execution ( * * FUNCTION: acpi_ds_call_control_method * - * PARAMETERS: walk_state - Current state of the walk + * PARAMETERS: Thread - Info for this thread + * this_walk_state - Current walk state * Op - Current Op to be walked * * RETURN: Status @@ -267,8 +264,9 @@ acpi_ds_call_control_method ( { acpi_status status; struct acpi_namespace_node *method_node; - union acpi_operand_object *obj_desc; struct acpi_walk_state *next_walk_state; + union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; u32 i; @@ -309,7 +307,6 @@ acpi_ds_call_control_method ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* Create and init a Root Node */ op = acpi_ps_create_scope_op (); @@ -320,7 +317,7 @@ acpi_ds_call_control_method ( status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, - NULL, NULL, 1); + NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (next_walk_state); goto cleanup; @@ -348,9 +345,12 @@ acpi_ds_call_control_method ( */ this_walk_state->operands [this_walk_state->num_operands] = NULL; + info.parameters = &this_walk_state->operands[0]; + info.parameter_type = ACPI_PARAM_ARGS; + status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, - &this_walk_state->operands[0], NULL, 3); + &info, 3); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -382,7 +382,7 @@ acpi_ds_call_control_method ( /* On error, we must delete the new walk state */ cleanup: - if (next_walk_state->method_desc) { + if (next_walk_state && (next_walk_state->method_desc)) { /* Decrement the thread count on the method parse tree */ next_walk_state->method_desc->method.thread_count--; @@ -397,12 +397,13 @@ cleanup: * * FUNCTION: acpi_ds_restart_control_method * - * PARAMETERS: walk_state - State of the method when it was preempted - * Op - Pointer to new current op + * PARAMETERS: walk_state - State for preempted method (caller) + * return_desc - Return value from the called method * * RETURN: Status * - * DESCRIPTION: Restart a method that was preempted + * DESCRIPTION: Restart a method that was preempted by another (nested) method + * invocation. Handle the return value (if any) from the callee. * ******************************************************************************/ @@ -417,17 +418,35 @@ acpi_ds_restart_control_method ( ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "****Restart [%4.4s] Op %p return_value_from_callee %p\n", + (char *) &walk_state->method_node->name, walk_state->method_call_op, + return_desc)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + " return_from_this_method_used?=%X res_stack %p Walk %p\n", + walk_state->return_used, + walk_state->results, walk_state)); + + /* Did the called method return a value? */ + if (return_desc) { + /* Are we actually going to use the return value? */ + if (walk_state->return_used) { - /* - * Get the return value (if any) from the previous method. - * NULL if no return value - */ + /* Save the return value from the previous method */ + status = acpi_ds_result_push (return_desc, walk_state); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (return_desc); return_ACPI_STATUS (status); } + + /* + * Save as THIS method's return value in case it is returned + * immediately to yet another method + */ + walk_state->return_desc = return_desc; } else { /* @@ -438,11 +457,6 @@ acpi_ds_restart_control_method ( } } - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Method=%p Return=%p return_used?=%X res_stack=%p State=%p\n", - walk_state->method_call_op, return_desc, walk_state->return_used, - walk_state->results, walk_state)); - return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index e1926534b..befe750a7 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -656,11 +656,13 @@ acpi_ds_store_object_to_local ( new_obj_desc, current_obj_desc)); /* - * Store this object to the Node - * (perform the indirect store) + * Store this object to the Node (perform the indirect store) + * NOTE: No implicit conversion is performed, as per the ACPI + * specification rules on storing to Locals/Args. */ status = acpi_ex_store_object_to_node (new_obj_desc, - current_obj_desc->reference.object, walk_state); + current_obj_desc->reference.object, walk_state, + ACPI_NO_IMPLICIT_CONVERSION); /* Remove local reference if we copied the object above */ diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index e0a313f57..68084760e 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -79,7 +79,6 @@ acpi_ds_execute_arguments ( acpi_status status; union acpi_parse_object *op; struct acpi_walk_state *walk_state; - union acpi_parse_object *arg; ACPI_FUNCTION_TRACE ("ds_execute_arguments"); @@ -105,7 +104,7 @@ acpi_ds_execute_arguments ( } status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, - aml_length, NULL, NULL, 1); + aml_length, NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); @@ -126,9 +125,7 @@ acpi_ds_execute_arguments ( /* Get and init the Op created above */ - arg = op->common.value.arg; op->common.node = node; - arg->common.node = node; acpi_ps_delete_parse_tree (op); /* Evaluate the deferred arguments */ @@ -150,7 +147,7 @@ acpi_ds_execute_arguments ( /* Execute the opcode and arguments */ status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, - aml_length, NULL, NULL, 3); + aml_length, NULL, 3); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 5c6a37e05..24462789a 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -60,11 +60,10 @@ * * FUNCTION: acpi_ds_is_result_used * - * PARAMETERS: Op - * result_obj - * walk_state + * PARAMETERS: Op - Current Op + * walk_state - Current State * - * RETURN: Status + * RETURN: TRUE if result is used, FALSE otherwise * * DESCRIPTION: Check if a result object will be used by the parent * @@ -89,18 +88,39 @@ acpi_ds_is_result_used ( } /* - * If there is no parent, the result can't possibly be used! - * (An executing method typically has no parent, since each - * method is parsed separately) However, a method that is - * invoked from another method has a parent. + * If there is no parent, we are executing at the method level. + * An executing method typically has no parent, since each method + * is parsed separately. */ if (!op->common.parent) { + /* + * If this is the last statement in the method, we know it is not a + * Return() operator (would not come here.) The following code is the + * optional support for a so-called "implicit return". Some AML code + * assumes that the last value of the method is "implicitly" returned + * to the caller. Just save the last result as the return value. + * NOTE: this is optional because the ASL language does not actually + * support this behavior. + */ + if ((acpi_gbl_enable_interpreter_slack) && + (walk_state->parser_state.aml >= walk_state->parser_state.aml_end)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] will be implicitly returned\n", + acpi_ps_get_opcode_name (op->common.aml_opcode))); + + /* Use the top of the result stack as the implicit return value */ + + walk_state->return_desc = walk_state->results->results.obj_desc[0]; + return_VALUE (TRUE); + } + + /* No parent, the return value cannot possibly be used */ + return_VALUE (FALSE); } - /* - * Get info on the parent. The root Op is AML_SCOPE - */ + /* Get info on the parent. The root_op is AML_SCOPE */ + parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); if (parent_info->class == AML_CLASS_UNKNOWN) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); @@ -204,9 +224,9 @@ result_not_used: * * FUNCTION: acpi_ds_delete_result_if_not_used * - * PARAMETERS: Op - * result_obj - * walk_state + * PARAMETERS: Op - Current parse Op + * result_obj - Result of the operation + * walk_state - Current state * * RETURN: Status * @@ -338,8 +358,9 @@ acpi_ds_clear_operands ( * * FUNCTION: acpi_ds_create_operand * - * PARAMETERS: walk_state - * Arg + * PARAMETERS: walk_state - Current walk state + * Arg - Parse object for the argument + * arg_index - Which argument (zero based) * * RETURN: Status * diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index 409aa6e95..9c0d99e09 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -50,6 +50,9 @@ #include #include +#ifdef _ACPI_ASL_COMPILER +#include +#endif #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dswload") @@ -180,7 +183,17 @@ acpi_ds_load1_begin_op ( status = acpi_ns_lookup (walk_state->scope_info, path, object_type, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + acpi_dm_add_to_external_list (path); + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (path, status); + } +#else ACPI_REPORT_NSERROR (path, status); +#endif return (status); } @@ -529,7 +542,16 @@ acpi_ds_load2_begin_op ( status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (buffer_ptr, status); + } +#else ACPI_REPORT_NSERROR (buffer_ptr, status); +#endif return_ACPI_STATUS (status); } /* diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 2b3956226..81c6b46ac 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -906,8 +906,7 @@ acpi_ds_init_aml_walk ( struct acpi_namespace_node *method_node, u8 *aml_start, u32 aml_length, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc, + struct acpi_parameter_info *info, u32 pass_number) { acpi_status status; @@ -926,8 +925,17 @@ acpi_ds_init_aml_walk ( /* The next_op of the next_walk will be the beginning of the method */ walk_state->next_op = NULL; - walk_state->params = params; - walk_state->caller_return_desc = return_obj_desc; + + if (info) { + if (info->parameter_type == ACPI_PARAM_GPE) { + walk_state->gpe_event_info = ACPI_CAST_PTR (struct acpi_gpe_event_info, + info->parameters); + } + else { + walk_state->params = info->parameters; + walk_state->caller_return_desc = &info->return_object; + } + } status = acpi_ps_init_scope (&walk_state->parser_state, op); if (ACPI_FAILURE (status)) { @@ -949,7 +957,7 @@ acpi_ds_init_aml_walk ( /* Init the method arguments */ - status = acpi_ds_method_data_init_args (params, ACPI_METHOD_NUM_ARGS, walk_state); + status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 56bb801e2..d1419145e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -381,7 +381,7 @@ end: acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } -static void +static u32 acpi_ec_gpe_handler ( void *data) { @@ -389,12 +389,17 @@ acpi_ec_gpe_handler ( struct acpi_ec *ec = (struct acpi_ec *) data; if (!ec) - return; + return ACPI_INTERRUPT_NOT_HANDLED; acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); + + if (status == AE_OK) + return ACPI_INTERRUPT_HANDLED; + else + return ACPI_INTERRUPT_NOT_HANDLED; } /* -------------------------------------------------------------------------- @@ -729,6 +734,8 @@ acpi_ec_start ( if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); } + acpi_set_gpe_type (NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe (NULL, ec->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler (ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -814,6 +821,8 @@ acpi_ec_ecdt_probe (void) if (ACPI_FAILURE(status)) { goto error; } + acpi_set_gpe_type (NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe (NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index abdb3a5a2..558ec7b33 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -50,7 +50,7 @@ /******************************************************************************* * - * FUNCTION: acpi_ev_initialize + * FUNCTION: acpi_ev_initialize_events * * PARAMETERS: None * @@ -61,13 +61,13 @@ ******************************************************************************/ acpi_status -acpi_ev_initialize ( +acpi_ev_initialize_events ( void) { acpi_status status; - ACPI_FUNCTION_TRACE ("ev_initialize"); + ACPI_FUNCTION_TRACE ("ev_initialize_events"); /* Make sure we have ACPI tables */ @@ -104,7 +104,7 @@ acpi_ev_initialize ( /******************************************************************************* * - * FUNCTION: acpi_ev_handler_initialize + * FUNCTION: acpi_ev_install_xrupt_handlers * * PARAMETERS: None * @@ -115,13 +115,13 @@ acpi_ev_initialize ( ******************************************************************************/ acpi_status -acpi_ev_handler_initialize ( +acpi_ev_install_xrupt_handlers ( void) { acpi_status status; - ACPI_FUNCTION_TRACE ("ev_handler_initialize"); + ACPI_FUNCTION_TRACE ("ev_install_xrupt_handlers"); /* Install the SCI handler */ diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 221dca54d..afb36886b 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -49,6 +49,253 @@ ACPI_MODULE_NAME ("evgpe") +/******************************************************************************* + * + * FUNCTION: acpi_ev_set_gpe_type + * + * PARAMETERS: gpe_event_info - GPE to set + * Type - New type + * + * RETURN: Status + * + * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run) + * + ******************************************************************************/ + +acpi_status +acpi_ev_set_gpe_type ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_set_gpe_type"); + + + /* Validate type and update register enable masks */ + + switch (type) { + case ACPI_GPE_TYPE_WAKE: + case ACPI_GPE_TYPE_RUNTIME: + case ACPI_GPE_TYPE_WAKE_RUN: + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Disable the GPE if currently enabled */ + + status = acpi_ev_disable_gpe (gpe_event_info); + + /* Type was validated above */ + + gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK; /* Clear type bits */ + gpe_event_info->flags |= type; /* Insert type */ + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_update_gpe_enable_masks + * + * PARAMETERS: gpe_event_info - GPE to update + * Type - What to do: ACPI_GPE_DISABLE or + * ACPI_GPE_ENABLE + * + * RETURN: Status + * + * DESCRIPTION: Updates GPE register enable masks based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_update_gpe_enable_masks ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type) +{ + struct acpi_gpe_register_info *gpe_register_info; + u8 register_bit; + + + ACPI_FUNCTION_TRACE ("ev_update_gpe_enable_masks"); + + + gpe_register_info = gpe_event_info->register_info; + if (!gpe_register_info) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + register_bit = gpe_event_info->register_bit; + + /* 1) Disable case. Simply clear all enable bits */ + + if (type == ACPI_GPE_DISABLE) { + ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit); + return_ACPI_STATUS (AE_OK); + } + + /* 2) Enable case. Set/Clear the appropriate enable bits */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + case ACPI_GPE_TYPE_RUNTIME: + ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_enable_gpe + * + * PARAMETERS: gpe_event_info - GPE to enable + * write_to_hardware - Enable now, or just mark data structs + * (WAKE GPEs should be deferred) + * + * RETURN: Status + * + * DESCRIPTION: Enable a GPE based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_enable_gpe ( + struct acpi_gpe_event_info *gpe_event_info, + u8 write_to_hardware) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_enable_gpe"); + + + /* Make sure HW enable masks are updated */ + + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_ENABLE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Mark wake-enabled or HW enable, or both */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + + /*lint -fallthrough */ + + case ACPI_GPE_TYPE_RUNTIME: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); + + if (write_to_hardware) { + /* Clear the GPE (of stale events), then enable it */ + + status = acpi_hw_clear_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Enable the requested runtime GPE */ + + status = acpi_hw_write_gpe_enable_reg (gpe_event_info); + } + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_disable_gpe + * + * PARAMETERS: gpe_event_info - GPE to disable + * + * RETURN: Status + * + * DESCRIPTION: Disable a GPE based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_disable_gpe ( + struct acpi_gpe_event_info *gpe_event_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_disable_gpe"); + + + if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { + return_ACPI_STATUS (AE_OK); + } + + /* Make sure HW enable masks are updated */ + + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Mark wake-disabled or HW disable, or both */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + + /*lint -fallthrough */ + + case ACPI_GPE_TYPE_RUNTIME: + + /* Disable the requested runtime GPE */ + + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); + status = acpi_hw_write_gpe_enable_reg (gpe_event_info); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_get_gpe_event_info @@ -139,11 +386,12 @@ acpi_ev_gpe_detect ( u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; + u32 status_reg; + u32 enable_reg; acpi_status status; struct acpi_gpe_block_info *gpe_block; - u32 i; - u32 j; + acpi_native_uint i; + acpi_native_uint j; ACPI_FUNCTION_NAME ("ev_gpe_detect"); @@ -171,33 +419,32 @@ acpi_ev_gpe_detect ( /* Read the Status Register */ - status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &status_reg, &gpe_register_info->status_address); - gpe_register_info->status = (u8) in_value; if (ACPI_FAILURE (status)) { goto unlock_and_exit; } /* Read the Enable Register */ - status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &enable_reg, &gpe_register_info->enable_address); - gpe_register_info->enable = (u8) in_value; if (ACPI_FAILURE (status)) { goto unlock_and_exit; } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", - ACPI_FORMAT_UINT64 (gpe_register_info->status_address.address), - gpe_register_info->status, - ACPI_FORMAT_UINT64 (gpe_register_info->enable_address.address), - gpe_register_info->enable)); + ACPI_FORMAT_UINT64 ( + gpe_register_info->status_address.address), + status_reg, + ACPI_FORMAT_UINT64 ( + gpe_register_info->enable_address.address), + enable_reg)); /* First check if there is anything active at all in this register */ - enabled_status_byte = (u8) (gpe_register_info->status & - gpe_register_info->enable); + enabled_status_byte = (u8) (status_reg & enable_reg); if (!enabled_status_byte) { /* No active GPEs in this register, move on */ @@ -216,7 +463,7 @@ acpi_ev_gpe_detect ( */ int_status |= acpi_ev_gpe_dispatch ( &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], - j + gpe_register_info->base_gpe_number); + (u32) j + gpe_register_info->base_gpe_number); } } } @@ -255,6 +502,7 @@ acpi_ev_asynch_execute_gpe_method ( u32 gpe_number = 0; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; + struct acpi_parameter_info info; ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method"); @@ -272,6 +520,10 @@ acpi_ev_asynch_execute_gpe_method ( return_VOID; } + /* Set the GPE flags for return to enabled state */ + + (void) acpi_ev_enable_gpe (gpe_event_info, FALSE); + /* * Take a snapshot of the GPE info for this level - we copy the * info to prevent a race condition with remove_handler/remove_block. @@ -283,23 +535,33 @@ acpi_ev_asynch_execute_gpe_method ( return_VOID; } - if (local_gpe_event_info.method_node) { + /* + * Must check for control method type dispatch one more + * time to avoid race with ev_gpe_install_handler + */ + if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { /* - * Invoke the GPE Method (_Lxx, _Exx): - * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) + * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx + * control method that corresponds to this GPE */ - status = acpi_ns_evaluate_by_handle (local_gpe_event_info.method_node, NULL, NULL); + info.node = local_gpe_event_info.dispatch.method_node; + info.parameters = ACPI_CAST_PTR (union acpi_operand_object *, gpe_event_info); + info.parameter_type = ACPI_PARAM_GPE; + + status = acpi_ns_evaluate_by_handle (&info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), - acpi_ut_get_node_name (local_gpe_event_info.method_node), gpe_number)); + acpi_ut_get_node_name (local_gpe_event_info.dispatch.method_node), + gpe_number)); } } if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* - * GPE is level-triggered, we clear the GPE status bit after handling - * the event. + * GPE is level-triggered, we clear the GPE status bit after + * handling the event. */ status = acpi_hw_clear_gpe (&local_gpe_event_info); if (ACPI_FAILURE (status)) { @@ -309,7 +571,7 @@ acpi_ev_asynch_execute_gpe_method ( /* Enable this GPE */ - (void) acpi_hw_enable_gpe (&local_gpe_event_info); + (void) acpi_hw_write_gpe_enable_reg (&local_gpe_event_info); return_VOID; } @@ -354,6 +616,15 @@ acpi_ev_gpe_dispatch ( } } + /* Save current system state */ + + if (acpi_gbl_system_awake_and_running) { + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + } + else { + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + } + /* * Dispatch the GPE to either an installed handler, or the control * method associated with this GPE (_Lxx or _Exx). @@ -361,10 +632,15 @@ acpi_ev_gpe_dispatch ( * If there is neither a handler nor a method, we disable the level to * prevent further events from coming in here. */ - if (gpe_event_info->handler) { - /* Invoke the installed handler (at interrupt level) */ + switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + case ACPI_GPE_DISPATCH_HANDLER: - gpe_event_info->handler (gpe_event_info->context); + /* + * Invoke the installed handler (at interrupt level) + * Ignore return status for now. TBD: leave GPE disabled on error? + */ + (void) gpe_event_info->dispatch.handler->address ( + gpe_event_info->dispatch.handler->context); /* It is now safe to clear level-triggered events. */ @@ -377,13 +653,15 @@ acpi_ev_gpe_dispatch ( return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } - } - else if (gpe_event_info->method_node) { + break; + + case ACPI_GPE_DISPATCH_METHOD: + /* * Disable GPE, so it doesn't keep firing before the method has a * chance to run. */ - status = acpi_hw_disable_gpe (gpe_event_info); + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", @@ -402,8 +680,10 @@ acpi_ev_gpe_dispatch ( "acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%2X], event is disabled\n", gpe_number)); } - } - else { + break; + + default: + /* No handler or method to run! */ ACPI_REPORT_ERROR (( @@ -414,15 +694,68 @@ acpi_ev_gpe_dispatch ( * Disable the GPE. The GPE will remain disabled until the ACPI * Core Subsystem is restarted, or a handler is installed. */ - status = acpi_hw_disable_gpe (gpe_event_info); + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } + break; } return_VALUE (ACPI_INTERRUPT_HANDLED); } + +#ifdef ACPI_GPE_NOTIFY_CHECK + +/******************************************************************************* + * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED + * + * FUNCTION: acpi_ev_check_for_wake_only_gpe + * + * PARAMETERS: gpe_event_info - info for this GPE + * + * RETURN: Status + * + * DESCRIPTION: Determine if a a GPE is "wake-only". + * + * Called from Notify() code in interpreter when a "device_wake" + * Notify comes in. + * + ******************************************************************************/ + +acpi_status +acpi_ev_check_for_wake_only_gpe ( + struct acpi_gpe_event_info *gpe_event_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_check_for_wake_only_gpe"); + + + if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */ + ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) /* System state at GPE time */ { + /* This must be a wake-only GPE, disable it */ + + status = acpi_ev_disable_gpe (gpe_event_info); + + /* Set GPE to wake-only. Do not change wake disabled/enabled status */ + + acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE); + + ACPI_REPORT_INFO (("GPE %p was updated from wake/run to wake-only\n", + gpe_event_info)); + + /* This was a wake-only GPE */ + + return_ACPI_STATUS (AE_WAKE_ONLY_GPE); + } + + return_ACPI_STATUS (AE_OK); +} +#endif + + diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index b1fbf7dec..1913f4efe 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -53,7 +53,7 @@ * * FUNCTION: acpi_ev_valid_gpe_event * - * PARAMETERS: gpe_event_info - Info for this GPE + * PARAMETERS: gpe_event_info - Info for this GPE * * RETURN: TRUE if the gpe_event is valid * @@ -105,17 +105,18 @@ acpi_ev_valid_gpe_event ( * FUNCTION: acpi_ev_walk_gpe_list * * PARAMETERS: gpe_walk_callback - Routine called for each GPE block + * Flags - ACPI_NOT_ISR or ACPI_ISR * * RETURN: Status * * DESCRIPTION: Walk the GPE lists. - * FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ acpi_status acpi_ev_walk_gpe_list ( - ACPI_GPE_CALLBACK gpe_walk_callback) + ACPI_GPE_CALLBACK gpe_walk_callback, + u32 flags) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; @@ -125,7 +126,7 @@ acpi_ev_walk_gpe_list ( ACPI_FUNCTION_TRACE ("ev_walk_gpe_list"); - acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR); + acpi_os_acquire_lock (acpi_gbl_gpe_lock, flags); /* Walk the interrupt level descriptor list */ @@ -149,11 +150,58 @@ acpi_ev_walk_gpe_list ( } unlock_and_exit: - acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_ISR); + acpi_os_release_lock (acpi_gbl_gpe_lock, flags); return_ACPI_STATUS (status); } +/****************************************************************************** + * + * FUNCTION: acpi_ev_delete_gpe_handlers + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Delete all Handler objects found in the GPE data structs. + * Used only prior to termination. + * + ******************************************************************************/ + +acpi_status +acpi_ev_delete_gpe_handlers ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_native_uint i; + acpi_native_uint j; + + + ACPI_FUNCTION_TRACE ("ev_delete_gpe_handlers"); + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + /* Now look at the individual GPEs in this byte register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { + gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; + + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { + ACPI_MEM_FREE (gpe_event_info->dispatch.handler); + gpe_event_info->dispatch.handler = NULL; + gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; + } + } + } + + return_ACPI_STATUS (AE_OK); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_save_method_info @@ -188,6 +236,7 @@ acpi_ev_save_method_info ( u32 gpe_number; char name[ACPI_NAME_SIZE + 1]; u8 type; + acpi_status status; ACPI_FUNCTION_TRACE ("ev_save_method_info"); @@ -206,16 +255,16 @@ acpi_ev_save_method_info ( * 2) Edge/Level determination is based on the 2nd character * of the method name * - * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a - * _PRW object is found that points to this GPE. + * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE + * if a _PRW object is found that points to this GPE. */ switch (name[1]) { case 'L': - type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; + type = ACPI_GPE_LEVEL_TRIGGERED; break; case 'E': - type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; + type = ACPI_GPE_EDGE_TRIGGERED; break; default: @@ -253,27 +302,35 @@ acpi_ev_save_method_info ( /* * Now we can add this information to the gpe_event_info block - * for use during dispatch of this GPE. + * for use during dispatch of this GPE. Default type is RUNTIME, although + * this may change when the _PRW methods are executed later. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags = type; - gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; + gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD | + ACPI_GPE_TYPE_RUNTIME); + + gpe_event_info->dispatch.method_node = (struct acpi_namespace_node *) obj_handle; + + /* Update enable mask, but don't enable the HW GPE as of yet */ + + status = acpi_ev_enable_gpe (gpe_event_info, FALSE); ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: acpi_ev_get_gpe_type + * FUNCTION: acpi_ev_match_prw_and_gpe * * PARAMETERS: Callback from walk_namespace * - * RETURN: Status + * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is + * not aborted on a single _PRW failure. * * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a * Device. Run the _PRW method. If present, extract the GPE @@ -282,7 +339,7 @@ acpi_ev_save_method_info ( ******************************************************************************/ static acpi_status -acpi_ev_get_gpe_type ( +acpi_ev_match_prw_and_gpe ( acpi_handle obj_handle, u32 level, void *info, @@ -299,19 +356,18 @@ acpi_ev_get_gpe_type ( acpi_status status; - ACPI_FUNCTION_TRACE ("ev_get_gpe_type"); + ACPI_FUNCTION_TRACE ("ev_match_prw_and_gpe"); /* Check for a _PRW method under this device */ status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW, ACPI_BTYPE_PACKAGE, &pkg_desc); - if (status == AE_NOT_FOUND) { + if (ACPI_FAILURE (status)) { + /* Ignore all errors from _PRW, we don't want to abort the subsystem */ + return_ACPI_STATUS (AE_OK); } - else if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } /* The returned _PRW package must have at least two elements */ @@ -370,16 +426,21 @@ acpi_ev_get_gpe_type ( if ((gpe_device == target_gpe_device) && (gpe_number >= gpe_block->block_base_number) && (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { - /* Mark GPE for WAKE but DISABLED (even for wake) */ - gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE; + + /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ + + gpe_event_info->flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); + status = acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE); } cleanup: acpi_ut_remove_reference (pkg_desc); - - return_ACPI_STATUS (status); + return_ACPI_STATUS (AE_OK); } @@ -742,7 +803,7 @@ acpi_ev_create_gpe_info_blocks ( /* Init the event_info for each GPE within this register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - this_event->bit_mask = acpi_gbl_decode_to8bit[j]; + this_event->register_bit = acpi_gbl_decode_to8bit[j]; this_event->register_info = this_register; this_event++; } @@ -817,6 +878,7 @@ acpi_ev_create_gpe_block ( acpi_status status; struct acpi_gpe_walk_info gpe_info; + ACPI_FUNCTION_TRACE ("ev_create_gpe_block"); @@ -835,6 +897,7 @@ acpi_ev_create_gpe_block ( gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; + gpe_block->node = gpe_device; ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, sizeof (struct acpi_generic_address)); @@ -854,18 +917,6 @@ acpi_ev_create_gpe_block ( return_ACPI_STATUS (status); } - /* Dump info about this GPE block */ - - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, - "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", - gpe_block->block_base_number, - (u32) (gpe_block->block_base_number + - ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), - gpe_device->name.ascii, - gpe_block->register_count, - ACPI_FORMAT_UINT64 (gpe_block->block_address.address), - interrupt_level)); - /* Find all GPE methods (_Lxx, _Exx) for this block */ status = acpi_ns_walk_namespace (ACPI_TYPE_METHOD, gpe_device, @@ -873,27 +924,28 @@ acpi_ev_create_gpe_block ( gpe_block, NULL); /* - * Runtime option: Should Wake GPEs be enabled at runtime? The default is - * No,they should only be enabled just as the machine goes to sleep. + * Runtime option: Should Wake GPEs be enabled at runtime? The default + * is No,they should only be enabled just as the machine goes to sleep. */ if (acpi_gbl_leave_wake_gpes_disabled) { /* - * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each - * GPE that has one or more _PRWs that reference it is by definition a - * WAKE GPE and will not be enabled while the machine is running.) + * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. + * (Each GPE that has one or more _PRWs that reference it is by + * definition a WAKE GPE and will not be enabled while the machine + * is running.) */ gpe_info.gpe_block = gpe_block; gpe_info.gpe_device = gpe_device; status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_match_prw_and_gpe, &gpe_info, NULL); } /* - * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have - * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via - * the acpi_enable_gpe() external interface. + * Enable all GPEs in this block that are 1) "runtime" or "run/wake" GPEs, + * and 2) have a corresponding _Lxx or _Exx method. All other GPEs must + * be enabled via the acpi_enable_gpe() external interface. */ wake_gpe_count = 0; gpe_enabled_count = 0; @@ -903,23 +955,35 @@ acpi_ev_create_gpe_block ( /* Get the info block for this particular GPE */ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->method_node) && - ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) { - /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */ - - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + + if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) && + (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) { gpe_enabled_count++; } - if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) { + if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) { wake_gpe_count++; } } } + /* Dump info about this GPE block */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "GPE %02X to %02X [%4.4s] %u regs at %8.8X%8.8X on int 0x%X\n", + (u32) gpe_block->block_base_number, + (u32) (gpe_block->block_base_number + + ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), + gpe_device->name.ascii, + gpe_block->register_count, + ACPI_FORMAT_UINT64 (gpe_block->block_address.address), + interrupt_level)); + + + /* Enable all valid GPEs found above */ + + status = acpi_hw_enable_runtime_gpe_block (NULL, gpe_block); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Found %u Wake, Enabled %u Runtime GPEs in this block\n", wake_gpe_count, gpe_enabled_count)); @@ -1056,7 +1120,8 @@ acpi_ev_gpe_initialize ( if ((register_count0 + register_count1) == 0) { /* GPEs are not required by ACPI, this is OK */ - ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "There are no GPE blocks defined in the FADT\n")); status = AE_OK; goto cleanup; } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 1bfb10df3..35e61d522 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -88,9 +88,10 @@ acpi_ev_is_notify_object ( * * FUNCTION: acpi_ev_queue_notify_request * - * PARAMETERS: + * PARAMETERS: Node - NS node for the notified object + * notify_value - Value from the Notify() request * - * RETURN: None. + * RETURN: Status * * DESCRIPTION: Dispatch a device notification event to a previously * installed handler. @@ -139,14 +140,12 @@ acpi_ev_queue_notify_request ( acpi_notify_value_names[notify_value])); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "notify value: 0x%2.2x **Device Specific**\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", notify_value)); } - /* - * Get the notify object attached to the NS Node - */ + /* Get the notify object attached to the NS Node */ + obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* We have the notify object, Get the right handler */ @@ -194,11 +193,13 @@ acpi_ev_queue_notify_request ( } if (!handler_obj) { - /* There is no per-device notify handler for this device */ - + /* + * There is no per-device notify handler for this device. + * This may or may not be a problem. + */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "No notify handler for [%4.4s] node %p\n", - acpi_ut_get_node_name (node), node)); + "No notify handler for Notify(%4.4s, %X) node %p\n", + acpi_ut_get_node_name (node), notify_value, node)); } return (status); @@ -209,7 +210,7 @@ acpi_ev_queue_notify_request ( * * FUNCTION: acpi_ev_notify_dispatch * - * PARAMETERS: + * PARAMETERS: Context - To be passsed to the notify handler * * RETURN: None. * @@ -276,6 +277,8 @@ acpi_ev_notify_dispatch ( * * FUNCTION: acpi_ev_global_lock_thread * + * PARAMETERS: Context - From thread interface, not used + * * RETURN: None * * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the @@ -309,7 +312,9 @@ acpi_ev_global_lock_thread ( * * FUNCTION: acpi_ev_global_lock_handler * - * RETURN: Status + * PARAMETERS: Context - From thread interface, not used + * + * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED * * DESCRIPTION: Invoked directly from the SCI handler when a global lock * release interrupt occurs. Grab the global lock and queue @@ -356,6 +361,8 @@ acpi_ev_global_lock_handler ( * * FUNCTION: acpi_ev_init_global_lock_handler * + * PARAMETERS: None + * * RETURN: Status * * DESCRIPTION: Install a handler for the global lock release event @@ -395,6 +402,8 @@ acpi_ev_init_global_lock_handler (void) * * FUNCTION: acpi_ev_acquire_global_lock * + * PARAMETERS: Timeout - Max time to wait for the lock, in millisec. + * * RETURN: Status * * DESCRIPTION: Attempt to gain ownership of the Global Lock. @@ -462,6 +471,10 @@ acpi_ev_acquire_global_lock ( * * FUNCTION: acpi_ev_release_global_lock * + * PARAMETERS: None + * + * RETURN: Status + * * DESCRIPTION: Releases ownership of the Global Lock. * ******************************************************************************/ @@ -548,7 +561,7 @@ acpi_ev_terminate (void) /* Disable all GPEs in all GPE blocks */ - status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block); + status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, ACPI_NOT_ISR); /* Remove SCI handler */ @@ -558,6 +571,10 @@ acpi_ev_terminate (void) } } + /* Deallocate all handler objects installed within GPE info structs */ + + status = acpi_ev_walk_gpe_list (acpi_ev_delete_gpe_handlers, ACPI_NOT_ISR); + /* Return to original mode if necessary */ if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index ec81e587f..b7ff3b162 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -61,7 +61,7 @@ static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPA /******************************************************************************* * - * FUNCTION: acpi_ev_init_address_spaces + * FUNCTION: acpi_ev_install_region_handlers * * PARAMETERS: None * @@ -72,15 +72,20 @@ static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPA ******************************************************************************/ acpi_status -acpi_ev_init_address_spaces ( +acpi_ev_install_region_handlers ( void) { acpi_status status; acpi_native_uint i; - ACPI_FUNCTION_TRACE ("ev_init_address_spaces"); + ACPI_FUNCTION_TRACE ("ev_install_region_handlers"); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* * All address spaces (PCI Config, EC, SMBus) are scope dependent * and registration must occur for a specific device. @@ -99,9 +104,8 @@ acpi_ev_init_address_spaces ( * has already been installed (via acpi_install_address_space_handler). * Similar for AE_SAME_HANDLER. */ - for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { - status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, + status = acpi_ev_install_space_handler (acpi_gbl_root_node, acpi_gbl_default_address_spaces[i], ACPI_DEFAULT_HANDLER, NULL, NULL); switch (status) { @@ -111,15 +115,63 @@ acpi_ev_init_address_spaces ( /* These exceptions are all OK */ + status = AE_OK; break; default: - return_ACPI_STATUS (status); + goto unlock_and_exit; } } - return_ACPI_STATUS (AE_OK); +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_initialize_op_regions + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Execute _REG methods for all Operation Regions that have + * an installed default region handler. + * + ******************************************************************************/ + +acpi_status +acpi_ev_initialize_op_regions ( + void) +{ + acpi_status status; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ev_initialize_op_regions"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Run the _REG methods for op_regions in each default address space + */ + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* TBD: Make sure handler is the DEFAULT handler, otherwise + * _REG will have already been run. + */ + status = acpi_ev_execute_reg_methods (acpi_gbl_root_node, + acpi_gbl_default_address_spaces[i]); + } + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); } @@ -128,7 +180,7 @@ acpi_ev_init_address_spaces ( * FUNCTION: acpi_ev_execute_reg_method * * PARAMETERS: region_obj - Object structure - * Function - On (1) or Off (0) + * Function - Passed to _REG: On (1) or Off (0) * * RETURN: Status * @@ -138,11 +190,12 @@ acpi_ev_init_address_spaces ( acpi_status acpi_ev_execute_reg_method ( - union acpi_operand_object *region_obj, + union acpi_operand_object *region_obj, u32 function) { - union acpi_operand_object *params[3]; - union acpi_operand_object *region_obj2; + struct acpi_parameter_info info; + union acpi_operand_object *params[3]; + union acpi_operand_object *region_obj2; acpi_status status; @@ -159,10 +212,11 @@ acpi_ev_execute_reg_method ( } /* - * _REG method has two arguments - * Arg0: Integer: Operation region space ID + * The _REG method has two arguments: + * + * Arg0, Integer: Operation region space ID * Same value as region_obj->Region.space_id - * Arg1: Integer: connection status + * Arg1, Integer: connection status * 1 for connecting the handler, * 0 for disconnecting the handler * Passed as a parameter @@ -178,16 +232,21 @@ acpi_ev_execute_reg_method ( goto cleanup; } - /* Set up the parameter objects */ + /* Setup the parameter objects */ params[0]->integer.value = region_obj->region.space_id; params[1]->integer.value = function; params[2] = NULL; + info.node = region_obj2->extra.method_REG; + info.parameters = params; + info.parameter_type = ACPI_PARAM_ARGS; + /* Execute the method, no return value */ - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, region_obj2->extra.method_REG, NULL)); - status = acpi_ns_evaluate_by_handle (region_obj2->extra.method_REG, params, NULL); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname ( + ACPI_TYPE_METHOD, info.node, NULL)); + status = acpi_ns_evaluate_by_handle (&info); acpi_ut_remove_reference (params[1]); @@ -203,7 +262,6 @@ cleanup: * FUNCTION: acpi_ev_address_space_dispatch * * PARAMETERS: region_obj - Internal region object - * space_id - ID of the address space (0-255) * Function - Read or Write operation * Address - Where in the space to read or write * bit_width - Field width in bits (8, 16, 32, or 64) @@ -326,7 +384,7 @@ acpi_ev_address_space_dispatch ( ACPI_FORMAT_UINT64 (address), acpi_ut_get_region_name (region_obj->region.space_id))); - if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't @@ -347,7 +405,7 @@ acpi_ev_address_space_dispatch ( acpi_format_exception (status))); } - if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter @@ -366,8 +424,8 @@ acpi_ev_address_space_dispatch ( * * FUNCTION: acpi_ev_detach_region * - * PARAMETERS: region_obj - Region Object - * acpi_ns_is_locked - Namespace Region Already Locked? + * PARAMETERS: region_obj - Region Object + * acpi_ns_is_locked - Namespace Region Already Locked? * * RETURN: None * @@ -501,9 +559,9 @@ acpi_ev_detach_region( * * FUNCTION: acpi_ev_attach_region * - * PARAMETERS: handler_obj - Handler Object - * region_obj - Region Object - * acpi_ns_is_locked - Namespace Region Already Locked? + * PARAMETERS: handler_obj - Handler Object + * region_obj - Region Object + * acpi_ns_is_locked - Namespace Region Already Locked? * * RETURN: None * @@ -676,6 +734,273 @@ acpi_ev_install_handler ( return (status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ev_install_space_handler + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * Handler - Address of the handler + * Setup - Address of the setup function + * Context - Value passed to the handler on each access + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for all op_regions of a given space_id. + * Assumes namespace is locked + * + ******************************************************************************/ + +acpi_status +acpi_ev_install_space_handler ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, + void *context) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object *handler_obj; + acpi_status status; + acpi_object_type type; + u16 flags = 0; + + + ACPI_FUNCTION_TRACE ("ev_install_space_handler"); + + + /* + * This registration is valid for only the types below + * and the root. This is where the default handlers + * get placed. + */ + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && + (node != acpi_gbl_root_node)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + if (handler == ACPI_DEFAULT_HANDLER) { + flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; + + switch (space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + handler = acpi_ex_system_memory_space_handler; + setup = acpi_ev_system_memory_region_setup; + break; + + case ACPI_ADR_SPACE_SYSTEM_IO: + handler = acpi_ex_system_io_space_handler; + setup = acpi_ev_io_space_region_setup; + break; + + case ACPI_ADR_SPACE_PCI_CONFIG: + handler = acpi_ex_pci_config_space_handler; + setup = acpi_ev_pci_config_region_setup; + break; + + case ACPI_ADR_SPACE_CMOS: + handler = acpi_ex_cmos_space_handler; + setup = acpi_ev_cmos_region_setup; + break; + + case ACPI_ADR_SPACE_PCI_BAR_TARGET: + handler = acpi_ex_pci_bar_space_handler; + setup = acpi_ev_pci_bar_region_setup; + break; + + case ACPI_ADR_SPACE_DATA_TABLE: + handler = acpi_ex_data_table_space_handler; + setup = NULL; + break; + + default: + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + /* If the caller hasn't specified a setup routine, use the default */ + + if (!setup) { + setup = acpi_ev_default_region_setup; + } + + /* Check for an existing internal object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + /* + * The attached device object already exists. + * Make sure the handler is not already installed. + */ + handler_obj = obj_desc->device.handler; + + /* Walk the handler list for this device */ + + while (handler_obj) { + /* Same space_id indicates a handler already installed */ + + if (handler_obj->address_space.space_id == space_id) { + if (handler_obj->address_space.handler == handler) { + /* + * It is (relatively) OK to attempt to install the SAME + * handler twice. This can easily happen with PCI_Config space. + */ + status = AE_SAME_HANDLER; + goto unlock_and_exit; + } + else { + /* A handler is already installed */ + + status = AE_ALREADY_EXISTS; + } + goto unlock_and_exit; + } + + /* Walk the linked list of handlers */ + + handler_obj = handler_obj->address_space.next; + } + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Creating object on Device %p while installing handler\n", node)); + + /* obj_desc does not exist, create one */ + + if (node->type == ACPI_TYPE_ANY) { + type = ACPI_TYPE_DEVICE; + } + else { + type = node->type; + } + + obj_desc = acpi_ut_create_internal_object (type); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Init new descriptor */ + + obj_desc->common.type = (u8) type; + + /* Attach the new object to the Node */ + + status = acpi_ns_attach_object (node, obj_desc, type); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", + acpi_ut_get_region_name (space_id), space_id, + acpi_ut_get_node_name (node), node, obj_desc)); + + /* + * Install the handler + * + * At this point there is no existing handler. + * Just allocate the object for the handler and link it + * into the list. + */ + handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); + if (!handler_obj) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Init handler obj */ + + handler_obj->address_space.space_id = (u8) space_id; + handler_obj->address_space.hflags = flags; + handler_obj->address_space.region_list = NULL; + handler_obj->address_space.node = node; + handler_obj->address_space.handler = handler; + handler_obj->address_space.context = context; + handler_obj->address_space.setup = setup; + + /* Install at head of Device.address_space list */ + + handler_obj->address_space.next = obj_desc->device.handler; + + /* + * The Device object is the first reference on the handler_obj. + * Each region that uses the handler adds a reference. + */ + obj_desc->device.handler = handler_obj; + + /* + * Walk the namespace finding all of the regions this + * handler will manage. + * + * Start at the device and search the branch toward + * the leaf nodes until either the leaf is encountered or + * a device is detected that has an address handler of the + * same type. + * + * In either case, back up and search down the remainder + * of the branch + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, + handler_obj, NULL); + +unlock_and_exit: + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_execute_reg_methods + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * + * RETURN: Status + * + * DESCRIPTION: Run all _REG methods for the input Space ID; + * Note: assumes namespace is locked, or system init time. + * + ******************************************************************************/ + +acpi_status +acpi_ev_execute_reg_methods ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_execute_reg_methods"); + + + /* + * Run all _REG methods for all Operation Regions for this + * space ID. This is a separate walk in order to handle any + * interdependencies between regions and _REG methods. (i.e. handlers + * must be installed for all regions of this Space ID before we + * can run any _REG methods) + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, + &space_id, NULL); + + return_ACPI_STATUS (status); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_reg_run @@ -693,19 +1018,13 @@ acpi_ev_reg_run ( void *context, void **return_value) { - union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; + acpi_adr_space_type space_id; acpi_status status; - handler_obj = (union acpi_operand_object *) context; - - /* Parameter validation */ - - if (!handler_obj) { - return (AE_OK); - } + space_id = *ACPI_CAST_PTR (acpi_adr_space_type, context); /* Convert and validate the device handle */ @@ -732,10 +1051,9 @@ acpi_ev_reg_run ( return (AE_OK); } - /* Object is a Region */ - if (obj_desc->region.space_id != handler_obj->address_space.space_id) { + if (obj_desc->region.space_id != space_id) { /* * This region is for a different address space * -- just ignore it diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 2e480d301..e19d82297 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -54,7 +54,7 @@ * * FUNCTION: acpi_ev_system_memory_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -108,7 +108,7 @@ acpi_ev_system_memory_region_setup ( * * FUNCTION: acpi_ev_io_space_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -144,7 +144,7 @@ acpi_ev_io_space_region_setup ( * * FUNCTION: acpi_ev_pci_config_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -317,7 +317,7 @@ acpi_ev_pci_config_region_setup ( * * FUNCTION: acpi_ev_pci_bar_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -348,7 +348,7 @@ acpi_ev_pci_bar_region_setup ( * * FUNCTION: acpi_ev_cmos_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context @@ -379,7 +379,7 @@ acpi_ev_cmos_region_setup ( * * FUNCTION: acpi_ev_default_region_setup * - * PARAMETERS: region_obj - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index d33b99057..26e9b0e41 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -188,6 +188,7 @@ acpi_remove_fixed_event_handler ( * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * Context - Value passed to the handler on each GPE * @@ -243,20 +244,21 @@ acpi_install_notify_handler ( if (device == ACPI_ROOT_OBJECT) { /* Make sure the handler is not already installed */ - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - acpi_gbl_system_notify.handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && + acpi_gbl_system_notify.handler) || + ((handler_type & ACPI_DEVICE_NOTIFY) && acpi_gbl_device_notify.handler)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = node; acpi_gbl_system_notify.handler = handler; acpi_gbl_system_notify.context = context; } - else /* ACPI_DEVICE_NOTIFY */ { + + if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = node; acpi_gbl_device_notify.handler = handler; acpi_gbl_device_notify.context = context; @@ -284,9 +286,9 @@ acpi_install_notify_handler ( if (obj_desc) { /* Object exists - make sure there's no handler */ - if (((handler_type == ACPI_SYSTEM_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && obj_desc->common_notify.system_notify) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + ((handler_type & ACPI_DEVICE_NOTIFY) && obj_desc->common_notify.device_notify)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; @@ -308,7 +310,6 @@ acpi_install_notify_handler ( /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); - if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -326,12 +327,19 @@ acpi_install_notify_handler ( notify_obj->notify.handler = handler; notify_obj->notify.context = context; - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { obj_desc->common_notify.system_notify = notify_obj; } - else /* ACPI_DEVICE_NOTIFY */ { + + if (handler_type & ACPI_DEVICE_NOTIFY) { obj_desc->common_notify.device_notify = notify_obj; } + + if (handler_type == ACPI_ALL_NOTIFY) { + /* Extra ref if installed in both */ + + acpi_ut_add_reference (notify_obj); + } } @@ -349,7 +357,9 @@ unlock_and_exit: * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler + * * RETURN: Status * * DESCRIPTION: Remove a handler for notifies on an ACPI device @@ -392,15 +402,14 @@ acpi_remove_notify_handler ( goto unlock_and_exit; } - /* - * Root Object - */ + /* Root Object */ + if (device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n")); - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - !acpi_gbl_system_notify.handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && + !acpi_gbl_system_notify.handler) || + ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; @@ -415,21 +424,21 @@ acpi_remove_notify_handler ( return_ACPI_STATUS (status); } - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } - else { + + if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } - /* - * All Other Objects - */ + /* All Other Objects */ + else { /* Notifies allowed on this object? */ @@ -448,38 +457,47 @@ acpi_remove_notify_handler ( /* Object exists - make sure there's an existing handler */ - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; - } - else { - notify_obj = obj_desc->common_notify.device_notify; - } + if ((!notify_obj) || + (notify_obj->notify.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - /* Make sure all deferred tasks are completed */ + /* Remove the handler */ + obj_desc->common_notify.system_notify = NULL; + acpi_ut_remove_reference (notify_obj); + } - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - acpi_os_wait_events_complete(NULL); - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + if (handler_type & ACPI_DEVICE_NOTIFY) { + notify_obj = obj_desc->common_notify.device_notify; + if ((!notify_obj) || + (notify_obj->notify.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ - /* Remove the handler */ + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->common_notify.system_notify = NULL; - } - else { + /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; + acpi_ut_remove_reference (notify_obj); } - - acpi_ut_remove_reference (notify_obj); } @@ -497,7 +515,7 @@ unlock_and_exit: * gpe_block - GPE block (NULL == FADT GPEs) * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. - * Handler - Address of the handler + * Address - Address of the handler * Context - Value passed to the handler on each GPE * * RETURN: Status @@ -511,11 +529,12 @@ acpi_install_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, u32 type, - acpi_gpe_handler handler, + acpi_event_handler address, void *context) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_handler_info *handler; + acpi_status status; ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler"); @@ -523,7 +542,7 @@ acpi_install_gpe_handler ( /* Parameter validation */ - if (!handler) { + if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -542,27 +561,41 @@ acpi_install_gpe_handler ( /* Make sure that there isn't a handler there already */ - if (gpe_event_info->handler) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } - /* Install the handler */ + /* Allocate and init handler object */ - acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); - gpe_event_info->handler = handler; - gpe_event_info->context = context; - gpe_event_info->flags = (u8) type; - acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + handler = ACPI_MEM_CALLOCATE (sizeof (struct acpi_handler_info)); + if (!handler) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } - /* Clear the GPE (of stale events), the enable it */ + handler->address = address; + handler->context = context; + handler->method_node = gpe_event_info->dispatch.method_node; - status = acpi_hw_clear_gpe (gpe_event_info); + /* Disable the GPE before installing the handler */ + + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - status = acpi_hw_enable_gpe (gpe_event_info); + /* Install the handler */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + gpe_event_info->dispatch.handler = handler; + + /* Setup up dispatch flags to indicate handler (vs. method) */ + + gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */ + gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); + + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); unlock_and_exit: @@ -577,7 +610,7 @@ unlock_and_exit: * * PARAMETERS: gpe_number - The event to remove a handler * gpe_block - GPE block (NULL == FADT GPEs) - * Handler - Address of the handler + * Address - Address of the handler * * RETURN: Status * @@ -589,10 +622,11 @@ acpi_status acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, - acpi_gpe_handler handler) + acpi_event_handler address) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_handler_info *handler; + acpi_status status; ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler"); @@ -600,7 +634,7 @@ acpi_remove_gpe_handler ( /* Parameter validation */ - if (!handler) { + if (!address) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -617,21 +651,27 @@ acpi_remove_gpe_handler ( goto unlock_and_exit; } - /* Disable the GPE before removing the handler */ + /* Make sure that a handler is indeed installed */ - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) { + status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure that the installed handler is the same */ - if (gpe_event_info->handler != handler) { - (void) acpi_hw_enable_gpe (gpe_event_info); + if (gpe_event_info->dispatch.handler->address != address) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } + /* Disable the GPE before removing the handler */ + + status = acpi_ev_disable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); @@ -644,10 +684,21 @@ acpi_remove_gpe_handler ( /* Remove the handler */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); - gpe_event_info->handler = NULL; - gpe_event_info->context = NULL; + handler = gpe_event_info->dispatch.handler; + + /* Restore Method node (if any), set dispatch flags */ + + gpe_event_info->dispatch.method_node = handler->method_node; + gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */ + if (handler->method_node) { + gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD; + } acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + /* Now we can free the handler object */ + + ACPI_MEM_FREE (handler); + unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 640f51fb0..e941678ce 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -204,12 +204,11 @@ acpi_enable_event ( /******************************************************************************* * - * FUNCTION: acpi_enable_gpe + * FUNCTION: acpi_set_gpe_type * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? - * Called from ISR or not + * Type - New GPE type * * RETURN: Status * @@ -218,26 +217,17 @@ acpi_enable_event ( ******************************************************************************/ acpi_status -acpi_enable_gpe ( +acpi_set_gpe_type ( acpi_handle gpe_device, u32 gpe_number, - u32 flags) + u8 type) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - + ACPI_FUNCTION_TRACE ("acpi_set_gpe_type"); - /* Use semaphore lock if not executing at interrupt level */ - - if (flags & ACPI_NOT_ISR) { - status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - } /* Ensure that we have a valid GPE number */ @@ -247,91 +237,72 @@ acpi_enable_gpe ( goto unlock_and_exit; } - /* Check for Wake vs Runtime GPE */ - - if (flags & ACPI_EVENT_WAKE_ENABLE) { - /* Ensure the requested wake GPE is disabled */ - - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - - /* Defer Enable of Wake GPE until sleep time */ - - acpi_hw_enable_gpe_for_wakeup (gpe_event_info); + if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) { + return_ACPI_STATUS (AE_OK); } - else { - /* Enable the requested runtime GPE */ - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } + /* Set the new type (will disable GPE if currently enabled) */ + status = acpi_ev_set_gpe_type (gpe_event_info, type); unlock_and_exit: - if (flags & ACPI_NOT_ISR) { - (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); - } return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: acpi_disable_event + * FUNCTION: acpi_enable_gpe * - * PARAMETERS: Event - The fixed eventto be enabled - * Flags - Reserved + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Just enable, or also wake enable? + * Called from ISR or not * * RETURN: Status * - * DESCRIPTION: Disable an ACPI event (fixed) + * DESCRIPTION: Enable an ACPI event (general purpose) * ******************************************************************************/ acpi_status -acpi_disable_event ( - u32 event, +acpi_enable_gpe ( + acpi_handle gpe_device, + u32 gpe_number, u32 flags) { acpi_status status = AE_OK; - u32 value; + struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE ("acpi_disable_event"); + ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - /* Decode the Fixed Event */ + /* Use semaphore lock if not executing at interrupt level */ - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - /* - * Disable the requested fixed event (by writing a zero to the - * enable register bit) - */ - status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, - 0, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + /* Ensure that we have a valid GPE number */ - status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, - &value, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; } - if (value != 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not disable %s events\n", acpi_ut_get_event_name (event))); - return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); - } + /* Perform the enable */ + + status = acpi_ev_enable_gpe (gpe_event_info, TRUE); +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } return_ACPI_STATUS (status); } @@ -342,7 +313,7 @@ acpi_disable_event ( * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? + * Flags - Just disable, or also wake disable? * Called from ISR or not * * RETURN: Status @@ -381,21 +352,69 @@ acpi_disable_gpe ( goto unlock_and_exit; } + status = acpi_ev_disable_gpe (gpe_event_info); + +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_disable_event + * + * PARAMETERS: Event - The fixed eventto be enabled + * Flags - Reserved + * + * RETURN: Status + * + * DESCRIPTION: Disable an ACPI event (fixed) + * + ******************************************************************************/ + +acpi_status +acpi_disable_event ( + u32 event, + u32 flags) +{ + acpi_status status = AE_OK; + u32 value; + + + ACPI_FUNCTION_TRACE ("acpi_disable_event"); + + + /* Decode the Fixed Event */ + + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + /* - * Only disable the requested GPE number for wake if specified. - * Otherwise, turn it totally off + * Disable the requested fixed event (by writing a zero to the + * enable register bit) */ - if (flags & ACPI_EVENT_WAKE_DISABLE) { - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else { - status = acpi_hw_disable_gpe (gpe_event_info); + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } -unlock_and_exit: - if (flags & ACPI_NOT_ISR) { - (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + if (value != 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not disable %s events\n", acpi_ut_get_event_name (event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } + return_ACPI_STATUS (status); } diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index b31d4fdfe..8eeb938f7 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -46,7 +46,6 @@ #include #include #include -#include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evxfregn") @@ -76,12 +75,8 @@ acpi_install_address_space_handler ( acpi_adr_space_setup setup, void *context) { - union acpi_operand_object *obj_desc; - union acpi_operand_object *handler_obj; struct acpi_namespace_node *node; acpi_status status; - acpi_object_type type; - u16 flags = 0; ACPI_FUNCTION_TRACE ("acpi_install_address_space_handler"); @@ -106,202 +101,16 @@ acpi_install_address_space_handler ( goto unlock_and_exit; } - /* - * This registration is valid for only the types below - * and the root. This is where the default handlers - * get placed. - */ - if ((node->type != ACPI_TYPE_DEVICE) && - (node->type != ACPI_TYPE_PROCESSOR) && - (node->type != ACPI_TYPE_THERMAL) && - (node != acpi_gbl_root_node)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - if (handler == ACPI_DEFAULT_HANDLER) { - flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - handler = acpi_ex_system_memory_space_handler; - setup = acpi_ev_system_memory_region_setup; - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - handler = acpi_ex_system_io_space_handler; - setup = acpi_ev_io_space_region_setup; - break; - - case ACPI_ADR_SPACE_PCI_CONFIG: - handler = acpi_ex_pci_config_space_handler; - setup = acpi_ev_pci_config_region_setup; - break; - - case ACPI_ADR_SPACE_CMOS: - handler = acpi_ex_cmos_space_handler; - setup = acpi_ev_cmos_region_setup; - break; - - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - handler = acpi_ex_pci_bar_space_handler; - setup = acpi_ev_pci_bar_region_setup; - break; - - case ACPI_ADR_SPACE_DATA_TABLE: - handler = acpi_ex_data_table_space_handler; - setup = NULL; - break; - - default: - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - } - - /* If the caller hasn't specified a setup routine, use the default */ - - if (!setup) { - setup = acpi_ev_default_region_setup; - } - - /* Check for an existing internal object */ - - obj_desc = acpi_ns_get_attached_object (node); - if (obj_desc) { - /* - * The attached device object already exists. - * Make sure the handler is not already installed. - */ - handler_obj = obj_desc->device.handler; - - /* Walk the handler list for this device */ - - while (handler_obj) { - /* Same space_id indicates a handler already installed */ - - if(handler_obj->address_space.space_id == space_id) { - if (handler_obj->address_space.handler == handler) { - /* - * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen with PCI_Config space. - */ - status = AE_SAME_HANDLER; - goto unlock_and_exit; - } - else { - /* A handler is already installed */ - - status = AE_ALREADY_EXISTS; - } - goto unlock_and_exit; - } - - /* Walk the linked list of handlers */ - - handler_obj = handler_obj->address_space.next; - } - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Creating object on Device %p while installing handler\n", node)); - - /* obj_desc does not exist, create one */ - - if (node->type == ACPI_TYPE_ANY) { - type = ACPI_TYPE_DEVICE; - } - else { - type = node->type; - } - - obj_desc = acpi_ut_create_internal_object (type); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } - - /* Init new descriptor */ - - obj_desc->common.type = (u8) type; - - /* Attach the new object to the Node */ + /* Install the handler for all Regions for this Space ID */ - status = acpi_ns_attach_object (node, obj_desc, type); - - /* Remove local reference to the object */ - - acpi_ut_remove_reference (obj_desc); - - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", - acpi_ut_get_region_name (space_id), space_id, - acpi_ut_get_node_name (node), node, obj_desc)); - - /* - * Install the handler - * - * At this point there is no existing handler. - * Just allocate the object for the handler and link it - * into the list. - */ - handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); - if (!handler_obj) { - status = AE_NO_MEMORY; + status = acpi_ev_install_space_handler (node, space_id, handler, setup, context); + if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - /* Init handler obj */ - - handler_obj->address_space.space_id = (u8) space_id; - handler_obj->address_space.hflags = flags; - handler_obj->address_space.region_list = NULL; - handler_obj->address_space.node = node; - handler_obj->address_space.handler = handler; - handler_obj->address_space.context = context; - handler_obj->address_space.setup = setup; - - /* Install at head of Device.address_space list */ - - handler_obj->address_space.next = obj_desc->device.handler; - - /* - * The Device object is the first reference on the handler_obj. - * Each region that uses the handler adds a reference. - */ - obj_desc->device.handler = handler_obj; - - /* - * Walk the namespace finding all of the regions this - * handler will manage. - * - * Start at the device and search the branch toward - * the leaf nodes until either the leaf is encountered or - * a device is detected that has an address handler of the - * same type. - * - * In either case, back up and search down the remainder - * of the branch - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, - handler_obj, NULL); - - /* - * Now we can run the _REG methods for all Regions for this - * space ID. This is a separate walk in order to handle any - * interdependencies between regions and _REG methods. (i.e. handlers - * must be installed for all regions of this Space ID before we - * can run any _REG methods. - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, - handler_obj, NULL); + /* Run all _REG methods for this address space */ + + status = acpi_ev_execute_reg_methods (node, space_id); unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index dfe7e0463..1e6a89805 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -48,6 +48,7 @@ #include #include #include +#include #define _COMPONENT ACPI_EXECUTER @@ -285,7 +286,7 @@ acpi_ex_load_op ( union acpi_operand_object *ddb_handle; union acpi_operand_object *buffer_desc = NULL; struct acpi_table_header *table_ptr = NULL; - u8 *table_data_ptr; + acpi_physical_address address; struct acpi_table_header table_header; u32 i; @@ -300,18 +301,39 @@ acpi_ex_load_op ( ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Region %p %s\n", obj_desc, acpi_ut_get_object_type_name (obj_desc))); - /* Get the table header */ + /* + * If the Region Address and Length have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_region_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Get the base physical address of the region */ + + address = obj_desc->region.address; + + /* Get the table length from the table header */ table_header.length = 0; - for (i = 0; i < sizeof (struct acpi_table_header); i++) { + for (i = 0; i < 8; i++) { status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, - (acpi_physical_address) i, 8, + (acpi_physical_address) (i + address), 8, ((u8 *) &table_header) + i); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } + /* Sanity check the table length */ + + if (table_header.length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } + /* Allocate a buffer for the entire table */ table_ptr = ACPI_MEM_ALLOCATE (table_header.length); @@ -319,17 +341,12 @@ acpi_ex_load_op ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* Copy the header to the buffer */ - - ACPI_MEMCPY (table_ptr, &table_header, sizeof (struct acpi_table_header)); - table_data_ptr = ACPI_PTR_ADD (u8, table_ptr, sizeof (struct acpi_table_header)); - - /* Get the table from the op region */ + /* Get the entire table from the op region */ for (i = 0; i < table_header.length; i++) { status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, - (acpi_physical_address) i, 8, - ((u8 *) table_data_ptr + i)); + (acpi_physical_address) (i + address), 8, + ((u8 *) table_ptr + i)); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -355,6 +372,12 @@ acpi_ex_load_op ( } table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer); + + /* Sanity check the table length */ + + if (table_ptr->length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } break; diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 4ce49b9bf..03ccfb9e1 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -130,6 +130,21 @@ acpi_ex_setup_region ( if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { + if (acpi_gbl_enable_interpreter_slack) { + /* + * Slack mode only: We will go ahead and allow access to this + * field if it is within the region length rounded up to the next + * access width boundary. + */ + if (ACPI_ROUND_UP (rgn_desc->region.length, + obj_desc->common_field.access_byte_width) >= + (obj_desc->common_field.base_byte_offset + + obj_desc->common_field.access_byte_width + + field_datum_byte_offset)) { + return_ACPI_STATUS (AE_OK); + } + } + if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider @@ -154,40 +169,7 @@ acpi_ex_setup_region ( field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); - if (!acpi_strict) { - /* - * Allow access to the field if it is within the region size - * rounded up to a multiple of the access byte width. This - * overcomes "off-by-one" programming errors in the AML often - * found in Toshiba laptops. These errors were allowed by - * the Microsoft ASL compiler. - */ - u32 rounded_length = ACPI_ROUND_UP(rgn_desc->region.length, - obj_desc->common_field.access_byte_width); - - if (rounded_length < (obj_desc->common_field.base_byte_offset - + field_datum_byte_offset - + obj_desc->common_field.access_byte_width)) { - return_ACPI_STATUS (AE_AML_REGION_LIMIT); - } else { - static int warn_once = 1; - if (warn_once) { - // Could also associate a flag with each field, and - // warn once for each field. - ACPI_REPORT_WARNING(( - "The ACPI AML in your computer contains errors, " - "please nag the manufacturer to correct it.\n")); - ACPI_REPORT_WARNING(( - "Allowing relaxed access to fields; " - "turn on CONFIG_ACPI_DEBUG for details.\n")); - warn_once = 0; - } - return_ACPI_STATUS (AE_OK); - } - } - else { - return_ACPI_STATUS (AE_AML_REGION_LIMIT); - } + return_ACPI_STATUS (AE_AML_REGION_LIMIT); } return_ACPI_STATUS (AE_OK); @@ -277,7 +259,7 @@ acpi_ex_access_region ( rgn_desc->region.space_id)); } else if (status == AE_NOT_EXIST) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + ACPI_REPORT_ERROR (( "Region %s(%X) has no handler\n", acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id)); @@ -764,16 +746,85 @@ acpi_ex_set_buffer_datum ( } +/******************************************************************************* + * + * FUNCTION: acpi_ex_common_buffer_setup + * + * PARAMETERS: obj_desc - Field object + * buffer_length - Length of caller's buffer + * datum_count - Where the datum_count is returned + * + * RETURN: Status, datum_count + * + * DESCRIPTION: Common code to validate the incoming buffer size and compute + * the number of field "datums" that must be read or written. + * A "datum" is the smallest unit that can be read or written + * to the field, it is either 1,2,4, or 8 bytes. + * + ******************************************************************************/ + +acpi_status +acpi_ex_common_buffer_setup ( + union acpi_operand_object *obj_desc, + u32 buffer_length, + u32 *datum_count) +{ + u32 byte_field_length; + u32 actual_byte_field_length; + + + ACPI_FUNCTION_TRACE ("ex_common_buffer_setup"); + + + /* + * Incoming buffer must be at least as long as the field, we do not + * allow "partial" field reads/writes. We do not care if the buffer is + * larger than the field, this typically happens when an integer is + * read/written to a field that is actually smaller than an integer. + */ + byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length); + if (byte_field_length > buffer_length) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field size %X (bytes) is too large for buffer (%X)\n", + byte_field_length, buffer_length)); + + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } + + /* + * Create "actual" field byte count (minimum number of bytes that + * must be read), then convert to datum count (minimum number + * of datum-sized units that must be read) + */ + actual_byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.start_field_bit_offset + + obj_desc->common_field.bit_length); + + + *datum_count = ACPI_ROUND_UP_TO (actual_byte_field_length, + obj_desc->common_field.access_byte_width); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "buffer_bytes %X, actual_bytes %X, Datums %X, byte_gran %X\n", + byte_field_length, actual_byte_field_length, + *datum_count, obj_desc->common_field.access_byte_width)); + + return_ACPI_STATUS (AE_OK); +} + + /******************************************************************************* * * FUNCTION: acpi_ex_extract_from_field * - * PARAMETERS: *obj_desc - Field to be read - * *Value - Where to store value + * PARAMETERS: obj_desc - Field to be read + * Buffer - Where to store the field data + * buffer_length - Length of Buffer * * RETURN: Status * - * DESCRIPTION: Retrieve the value of the given field + * DESCRIPTION: Retrieve the current value of the given field * ******************************************************************************/ @@ -789,7 +840,6 @@ acpi_ex_extract_from_field ( acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; - u32 byte_field_length; u32 datum_count; u32 i; @@ -797,39 +847,13 @@ acpi_ex_extract_from_field ( ACPI_FUNCTION_TRACE ("ex_extract_from_field"); - /* - * The field must fit within the caller's buffer - */ - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); - if (byte_field_length > buffer_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Field size %X (bytes) too large for buffer (%X)\n", - byte_field_length, buffer_length)); - - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); - } - - /* Convert field byte count to datum count, round up if necessary */ - - datum_count = ACPI_ROUND_UP_TO (byte_field_length, - obj_desc->common_field.access_byte_width); + /* Validate buffer, compute number of datums */ - /* - * If the field is not aligned on a datum boundary and does not - * fit within a single datum, we must read an extra datum. - * - * We could just split the aligned and non-aligned cases since the - * aligned case is so very simple, but this would require more code. - */ - if ((obj_desc->common_field.end_field_valid_bits != 0) && - (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { - datum_count++; + status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "byte_len %X, datum_len %X, byte_gran %X\n", - byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); - /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where the buffer @@ -942,12 +966,13 @@ acpi_ex_extract_from_field ( * * FUNCTION: acpi_ex_insert_into_field * - * PARAMETERS: *obj_desc - Field to be set - * Buffer - Value to store + * PARAMETERS: obj_desc - Field to be written + * Buffer - Data to be written + * buffer_length - Length of Buffer * * RETURN: Status * - * DESCRIPTION: Store the value into the given field + * DESCRIPTION: Store the Buffer contents into the given field * ******************************************************************************/ @@ -964,42 +989,19 @@ acpi_ex_insert_into_field ( acpi_integer merged_datum; acpi_integer previous_raw_datum; acpi_integer this_raw_datum; - u32 byte_field_length; u32 datum_count; ACPI_FUNCTION_TRACE ("ex_insert_into_field"); - /* - * Incoming buffer must be at least as long as the field, we do not - * allow "partial" field writes. We do not care if the buffer is - * larger than the field, this typically happens when an integer is - * written to a field that is actually smaller than an integer. - */ - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( - obj_desc->common_field.bit_length); - if (buffer_length < byte_field_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Buffer length %X too small for field %X\n", - buffer_length, byte_field_length)); + /* Validate buffer, compute number of datums */ - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( - obj_desc->common_field.start_field_bit_offset + - obj_desc->common_field.bit_length); - - /* Convert byte count to datum count, round up if necessary */ - - datum_count = ACPI_ROUND_UP_TO (byte_field_length, - obj_desc->common_field.access_byte_width); - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Bytes %X, Datums %X, byte_gran %X\n", - byte_field_length, datum_count, obj_desc->common_field.access_byte_width)); - /* * Break the request into up to three parts (similar to an I/O request): * 1) non-aligned part at start diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index 74fd68491..961a949e9 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -389,6 +389,8 @@ acpi_ex_do_math_op ( acpi_integer operand1) { + ACPI_FUNCTION_ENTRY (); + switch (opcode) { case AML_ADD_OP: /* Add (Operand0, Operand1, Result) */ @@ -452,15 +454,17 @@ acpi_ex_do_math_op ( * FUNCTION: acpi_ex_do_logical_op * * PARAMETERS: Opcode - AML opcode - * Operand0 - Integer operand #0 - * Operand1 - Integer operand #1 + * obj_desc0 - operand #0 + * obj_desc1 - operand #1 * * RETURN: TRUE/FALSE result of the operation * * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the * functions here is to prevent a lot of pointer dereferencing * to obtain the operands and to simplify the generation of the - * logical value. + * logical value. Both operands must already be validated as + * 1) Both the same type, and + * 2) Either Integer, Buffer, or String type. * * Note: cleanest machine code seems to be produced by the code * below, rather than using statements of the form: @@ -471,54 +475,137 @@ acpi_ex_do_math_op ( u8 acpi_ex_do_logical_op ( u16 opcode, - acpi_integer operand0, - acpi_integer operand1) + union acpi_operand_object *obj_desc0, + union acpi_operand_object *obj_desc1) { + acpi_integer operand0; + acpi_integer operand1; + u8 *ptr0; + u8 *ptr1; + u32 length0; + u32 length1; + u32 i; - switch (opcode) { + ACPI_FUNCTION_ENTRY (); - case AML_LAND_OP: /* LAnd (Operand0, Operand1) */ - if (operand0 && operand1) { - return (TRUE); - } - break; + if (ACPI_GET_OBJECT_TYPE (obj_desc0) == ACPI_TYPE_INTEGER) { + /* Both operands are of type integer */ + operand0 = obj_desc0->integer.value; + operand1 = obj_desc1->integer.value; - case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + switch (opcode) { + case AML_LAND_OP: /* LAnd (Operand0, Operand1) */ - if (operand0 == operand1) { - return (TRUE); - } - break; + if (operand0 && operand1) { + return (TRUE); + } + break; + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ - case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + if (operand0 == operand1) { + return (TRUE); + } + break; - if (operand0 > operand1) { - return (TRUE); - } - break; + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + if (operand0 > operand1) { + return (TRUE); + } + break; + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + if (operand0 < operand1) { + return (TRUE); + } + break; - case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + case AML_LOR_OP: /* LOr (Operand0, Operand1) */ - if (operand0 < operand1) { - return (TRUE); + if (operand0 || operand1) { + return (TRUE); + } + break; + + default: + break; } - break; + } + else { + /* + * Case for Buffer/String objects. + * NOTE: takes advantage of common Buffer/String object fields + */ + length0 = obj_desc0->buffer.length; + ptr0 = obj_desc0->buffer.pointer; + + length1 = obj_desc1->buffer.length; + ptr1 = obj_desc1->buffer.pointer; + + switch (opcode) { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + /* Length and all bytes must be equal */ - case AML_LOR_OP: /* LOr (Operand0, Operand1) */ + if (length0 != length1) { + return (FALSE); + } - if (operand0 || operand1) { + for (i = 0; i < length0; i++) { + if (ptr0[i] != ptr1[i]) { + return (FALSE); + } + } return (TRUE); - } - break; - default: - break; + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + /* Lexicographic compare: Scan the 1-to-1 data */ + + for (i = 0; (i < length0) && (i < length1); i++) { + if (ptr0[i] > ptr1[i]) { + return (TRUE); + } + } + + /* Bytes match, now check lengths */ + + if (length0 > length1) { + return (TRUE); + } + + /* Length0 <= Length1 */ + + return (FALSE); + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + /* Lexicographic compare: Scan the 1-to-1 data */ + + for (i = 0; (i < length0) && (i < length1); i++) { + if (ptr0[i] < ptr1[i]) { + return (TRUE); + } + } + + /* Bytes match, now check lengths */ + + if (length0 < length1) { + return (TRUE); + } + + /* Length0 >= Length1 */ + + return (FALSE); + + default: + break; + } } return (FALSE); diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index cee2c126e..c709ed2f5 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -54,7 +54,7 @@ * * FUNCTION: acpi_ex_unlink_mutex * - * PARAMETERS: *obj_desc - The mutex to be unlinked + * PARAMETERS: obj_desc - The mutex to be unlinked * * RETURN: Status * @@ -73,6 +73,8 @@ acpi_ex_unlink_mutex ( return; } + /* Doubly linked list */ + if (obj_desc->mutex.next) { (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; } @@ -90,8 +92,8 @@ acpi_ex_unlink_mutex ( * * FUNCTION: acpi_ex_link_mutex * - * PARAMETERS: *obj_desc - The mutex to be linked - * *list_head - head of the "acquired_mutex" list + * PARAMETERS: obj_desc - The mutex to be linked + * list_head - head of the "acquired_mutex" list * * RETURN: Status * @@ -130,8 +132,8 @@ acpi_ex_link_mutex ( * * FUNCTION: acpi_ex_acquire_mutex * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -173,9 +175,8 @@ acpi_ex_acquire_mutex ( return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* - * Support for multiple acquires by the owning thread - */ + /* Support for multiple acquires by the owning thread */ + if (obj_desc->mutex.owner_thread) { /* Special case for Global Lock, allow all threads */ @@ -199,10 +200,11 @@ acpi_ex_acquire_mutex ( return_ACPI_STATUS (status); } - /* Have the mutex, update mutex and walk info */ + /* Have the mutex: update mutex and walk info and save the sync_level */ - obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.owner_thread = walk_state->thread; obj_desc->mutex.acquisition_depth = 1; + obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; @@ -218,7 +220,7 @@ acpi_ex_acquire_mutex ( * * FUNCTION: acpi_ex_release_mutex * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * @@ -281,9 +283,8 @@ acpi_ex_release_mutex ( return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* - * Match multiple Acquires with multiple Releases - */ + /* Match multiple Acquires with multiple Releases */ + obj_desc->mutex.acquisition_depth--; if (obj_desc->mutex.acquisition_depth != 0) { /* Just decrement the depth and return */ @@ -299,10 +300,10 @@ acpi_ex_release_mutex ( status = acpi_ex_system_release_mutex (obj_desc); - /* Update the mutex and walk state */ + /* Update the mutex and walk state, restore sync_level before acquire */ obj_desc->mutex.owner_thread = NULL; - walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; + walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; return_ACPI_STATUS (status); } @@ -312,7 +313,7 @@ acpi_ex_release_mutex ( * * FUNCTION: acpi_ex_release_all_mutexes * - * PARAMETERS: *mutex_list - Head of the mutex list + * PARAMETERS: mutex_list - Head of the mutex list * * RETURN: Status * @@ -332,9 +333,8 @@ acpi_ex_release_all_mutexes ( ACPI_FUNCTION_ENTRY (); - /* - * Traverse the list of owned mutexes, releasing each one. - */ + /* Traverse the list of owned mutexes, releasing each one */ + while (next) { this = next; next = this->mutex.next; @@ -352,7 +352,11 @@ acpi_ex_release_all_mutexes ( /* Mark mutex unowned */ - this->mutex.owner_thread = NULL; + this->mutex.owner_thread = NULL; + + /* Update Thread sync_level (Last mutex is the important one) */ + + thread->current_sync_level = this->mutex.original_sync_level; } } diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 70602ad44..0b6f86a91 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -97,6 +97,7 @@ acpi_ex_opcode_2A_0T_0R ( { union acpi_operand_object **operand = &walk_state->operands[0]; struct acpi_namespace_node *node; + u32 value; acpi_status status = AE_OK; @@ -113,16 +114,46 @@ acpi_ex_opcode_2A_0T_0R ( node = (struct acpi_namespace_node *) operand[0]; + /* Second value is the notify value */ + + value = (u32) operand[1]->integer.value; + /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unexpected notify object type [%s]\n", acpi_ut_get_type_name (node->type))); status = AE_AML_OPERAND_TYPE; break; } +#ifdef ACPI_GPE_NOTIFY_CHECK + /* + * GPE method wake/notify check. Here, we want to ensure that we + * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx + * GPE method during system runtime. If we do, the GPE is marked + * as "wake-only" and disabled. + * + * 1) Is the Notify() value == device_wake? + * 2) Is this a GPE deferred method? (An _Lxx or _Exx method) + * 3) Did the original GPE happen at system runtime? + * (versus during wake) + * + * If all three cases are true, this is a wake-only GPE that should + * be disabled at runtime. + */ + if (value == 2) /* device_wake */ { + status = acpi_ev_check_for_wake_only_gpe (walk_state->gpe_event_info); + if (ACPI_FAILURE (status)) { + /* AE_WAKE_ONLY_GPE only error, means ignore this notify */ + + return_ACPI_STATUS (AE_OK) + } + } +#endif + /* * Dispatch the notify to the appropriate handler * NOTE: the request is queued for execution after this method @@ -130,8 +161,7 @@ acpi_ex_opcode_2A_0T_0R ( * from this thread -- because handlers may in turn run other * control methods. */ - status = acpi_ev_queue_notify_request (node, - (u32) operand[1]->integer.value); + status = acpi_ev_queue_notify_request (node, value); break; @@ -543,9 +573,17 @@ acpi_ex_opcode_2A_0T_1R ( * Execute the Opcode */ if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ { + /* Both operands must be of the same type */ + + if (ACPI_GET_OBJECT_TYPE (operand[0]) != + ACPI_GET_OBJECT_TYPE (operand[1])) { + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + logical_result = acpi_ex_do_logical_op (walk_state->opcode, - operand[0]->integer.value, - operand[1]->integer.value); + operand[0], + operand[1]); goto store_logical_result; } diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index e998da7cd..504d53f4a 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -187,15 +187,15 @@ acpi_ex_resolve_object_to_value ( return_ACPI_STATUS (status); } + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] value_obj is %p\n", + stack_desc->reference.offset, obj_desc)); + /* * Now we can delete the original Reference Object and - * replace it with the resolve value + * replace it with the resolved value */ acpi_ut_remove_reference (stack_desc); *stack_ptr = obj_desc; - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %d] value_obj is %p\n", - stack_desc->reference.offset, obj_desc)); break; diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index 8c884652c..25464f751 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -102,7 +102,8 @@ acpi_ex_store ( * Storing an object into a Named node. */ status = acpi_ex_store_object_to_node (source_desc, - (struct acpi_namespace_node *) dest_desc, walk_state); + (struct acpi_namespace_node *) dest_desc, walk_state, + ACPI_IMPLICIT_CONVERSION); return_ACPI_STATUS (status); } @@ -153,7 +154,7 @@ acpi_ex_store ( /* Storing an object into a Name "container" */ status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object, - walk_state); + walk_state, ACPI_IMPLICIT_CONVERSION); break; @@ -399,6 +400,7 @@ acpi_ex_store_object_to_index ( * PARAMETERS: source_desc - Value to be stored * Node - Named object to receive the value * walk_state - Current walk state + * implicit_conversion - Perform implicit conversion (yes/no) * * RETURN: Status * @@ -421,7 +423,8 @@ acpi_status acpi_ex_store_object_to_node ( union acpi_operand_object *source_desc, struct acpi_namespace_node *node, - struct acpi_walk_state *walk_state) + struct acpi_walk_state *walk_state, + u8 implicit_conversion) { acpi_status status = AE_OK; union acpi_operand_object *target_desc; @@ -451,6 +454,14 @@ acpi_ex_store_object_to_node ( return_ACPI_STATUS (status); } + /* If no implicit conversion, drop into the default case below */ + + if (!implicit_conversion) { + /* Force execution of default (no implicit conversion) */ + + target_type = ACPI_TYPE_ANY; + } + /* * Do the actual store operation */ diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index f3fddc274..3910b5ec9 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -51,104 +51,24 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_enable_gpe + * FUNCTION: acpi_hw_write_gpe_enable_reg * * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled * * RETURN: Status * - * DESCRIPTION: Enable a single GPE. + * DESCRIPTION: Write a GPE enable register. Note: The bit for this GPE must + * already be cleared or set in the parent register + * enable_for_run mask. * ******************************************************************************/ acpi_status -acpi_hw_enable_gpe ( - struct acpi_gpe_event_info *gpe_event_info) -{ - u32 in_byte; - acpi_status status; - - - ACPI_FUNCTION_ENTRY (); - - - /* - * Read the current value of the register, set the appropriate bit - * to enable the GPE, and write out the new register. - */ - status = acpi_hw_low_level_read (8, &in_byte, - &gpe_event_info->register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Write with the new GPE bit enabled */ - - status = acpi_hw_low_level_write (8, (in_byte | gpe_event_info->bit_mask), - &gpe_event_info->register_info->enable_address); - - return (status); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_enable_gpe_for_wakeup - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled - * - * RETURN: None - * - * DESCRIPTION: Keep track of which GPEs the OS has requested not be - * disabled when going to sleep. - * - ******************************************************************************/ - -void -acpi_hw_enable_gpe_for_wakeup ( +acpi_hw_write_gpe_enable_reg ( struct acpi_gpe_event_info *gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; - - - ACPI_FUNCTION_ENTRY (); - - - /* Get the info block for the entire GPE register */ - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - return; - } - - /* - * Set the bit so we will not enable this GPE when sleeping (and disable - * it upon wake) - */ - gpe_register_info->wake_enable |= gpe_event_info->bit_mask; - gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_disable_gpe - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled - * - * RETURN: Status - * - * DESCRIPTION: Disable a single GPE. - * - ******************************************************************************/ - -acpi_status -acpi_hw_disable_gpe ( - struct acpi_gpe_event_info *gpe_event_info) -{ - u32 in_byte; acpi_status status; - struct acpi_gpe_register_info *gpe_register_info; ACPI_FUNCTION_ENTRY (); @@ -158,67 +78,15 @@ acpi_hw_disable_gpe ( gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { - return (AE_BAD_PARAMETER); - } - - /* - * Read the current value of the register, clear the appropriate bit, - * and write out the new register value to disable the GPE. - */ - status = acpi_hw_low_level_read (8, &in_byte, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); + return (AE_NOT_EXIST); } - /* Write the byte with this GPE bit cleared */ + /* Write the entire GPE (runtime) enable register */ - status = acpi_hw_low_level_write (8, (in_byte & ~(gpe_event_info->bit_mask)), + status = acpi_hw_low_level_write (8, gpe_register_info->enable_for_run, &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Make sure this GPE is disabled for wake, also */ - - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); - return (AE_OK); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_disable_gpe_for_wakeup - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled - * - * RETURN: None - * - * DESCRIPTION: Keep track of which GPEs the OS has requested not be - * disabled when going to sleep. - * - ******************************************************************************/ -void -acpi_hw_disable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info) -{ - struct acpi_gpe_register_info *gpe_register_info; - - - ACPI_FUNCTION_ENTRY (); - - - /* Get the info block for the entire GPE register */ - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - return; - } - - /* Clear the bit so we will disable this when sleeping */ - - gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask); + return (status); } @@ -228,7 +96,7 @@ acpi_hw_disable_gpe_for_wakeup ( * * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared * - * RETURN: status_status + * RETURN: Status * * DESCRIPTION: Clear the status bit for a single GPE. * @@ -248,7 +116,7 @@ acpi_hw_clear_gpe ( * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_hw_low_level_write (8, gpe_event_info->bit_mask, + status = acpi_hw_low_level_write (8, gpe_event_info->register_bit, &gpe_event_info->register_info->status_address); return (status); @@ -274,7 +142,7 @@ acpi_hw_get_gpe_status ( acpi_event_status *event_status) { u32 in_byte; - u8 bit_mask; + u8 register_bit; struct acpi_gpe_register_info *gpe_register_info; acpi_status status; acpi_event_status local_event_status = 0; @@ -293,33 +161,28 @@ acpi_hw_get_gpe_status ( /* Get the register bitmask for this GPE */ - bit_mask = gpe_event_info->bit_mask; - - /* GPE Enabled? */ + register_bit = gpe_event_info->register_bit; - status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } + /* GPE currently enabled? (enabled for runtime?) */ - if (bit_mask & in_byte) { + if (register_bit & gpe_register_info->enable_for_run) { local_event_status |= ACPI_EVENT_FLAG_ENABLED; } - /* GPE Enabled for wake? */ + /* GPE enabled for wake? */ - if (bit_mask & gpe_register_info->wake_enable) { + if (register_bit & gpe_register_info->enable_for_wake) { local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED; } - /* GPE active (set)? */ + /* GPE currently active (status bit == 1)? */ status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - if (bit_mask & in_byte) { + if (register_bit & in_byte) { local_event_status |= ACPI_EVENT_FLAG_SET; } @@ -411,64 +274,43 @@ acpi_hw_clear_gpe_block ( /****************************************************************************** * - * FUNCTION: acpi_hw_prepare_gpe_block_for_sleep + * FUNCTION: acpi_hw_enable_runtime_gpe_block * * PARAMETERS: gpe_xrupt_info - GPE Interrupt info * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within - * a single GPE block + * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes + * combination wake/run GPEs.) * ******************************************************************************/ -static acpi_status -acpi_hw_prepare_gpe_block_for_sleep ( +acpi_status +acpi_hw_enable_runtime_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) { u32 i; - struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; acpi_status status; - /* Get the register info for the entire GPE block */ - - gpe_register_info = gpe_block->register_info; + /* NOTE: assumes that all GPEs are currently disabled */ /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { - /* - * Read the enabled/disabled status of all GPEs. We - * will be using it to restore all the GPEs later. - * - * NOTE: Wake GPEs are are ALL disabled at this time, so when we wake - * and restore this register, they will be automatically disabled. - */ - status = acpi_hw_low_level_read (8, &in_value, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); + if (!gpe_block->register_info[i].enable_for_run) { + continue; } - gpe_register_info->enable = (u8) in_value; + /* Enable all "runtime" GPEs in this register */ - /* - * 1) Disable all runtime GPEs - * 2) Enable all wakeup GPEs - */ - status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, - &gpe_register_info->enable_address); + status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_run, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE (status)) { return (status); } - - /* Point to next GPE register */ - - gpe_register_info++; } return (AE_OK); @@ -477,122 +319,125 @@ acpi_hw_prepare_gpe_block_for_sleep ( /****************************************************************************** * - * FUNCTION: acpi_hw_prepare_gpes_for_sleep + * FUNCTION: acpi_hw_enable_wakeup_gpe_block * - * PARAMETERS: None + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs. - * Called with interrupts disabled. The interrupt handler also - * modifies gpe_register_info->Enable, so it should not be - * given the chance to run until after the runtime GPEs are - * re-enabled. + * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes + * combination wake/run GPEs.) * ******************************************************************************/ acpi_status -acpi_hw_prepare_gpes_for_sleep ( - void) +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) { + u32 i; acpi_status status; - ACPI_FUNCTION_ENTRY (); + /* Examine each GPE Register within the block */ + for (i = 0; i < gpe_block->register_count; i++) { + if (!gpe_block->register_info[i].enable_for_wake) { + continue; + } - status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep); - return (status); + /* Enable all "wake" GPEs in this register */ + + status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake, + &gpe_block->register_info[i].enable_address); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + return (AE_OK); } /****************************************************************************** * - * FUNCTION: acpi_hw_restore_gpe_block_on_wake + * FUNCTION: acpi_hw_disable_all_gpes * - * PARAMETERS: gpe_xrupt_info - GPE Interrupt info - * gpe_block - Gpe Block info + * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR * * RETURN: Status * - * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one - * GPE block + * DESCRIPTION: Disable and clear all GPEs * ******************************************************************************/ -static acpi_status -acpi_hw_restore_gpe_block_on_wake ( - struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) +acpi_status +acpi_hw_disable_all_gpes ( + u32 flags) { - u32 i; - struct acpi_gpe_register_info *gpe_register_info; acpi_status status; - /* This callback processes one entire GPE block */ + ACPI_FUNCTION_TRACE ("hw_disable_all_gpes"); - /* Get the register info for the entire GPE block */ - gpe_register_info = gpe_block->register_info; + status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, flags); + status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, flags); + return_ACPI_STATUS (status); +} - /* Examine each GPE register within the block */ - for (i = 0; i < gpe_block->register_count; i++) { - /* Clear the entire status register */ +/****************************************************************************** + * + * FUNCTION: acpi_hw_enable_all_runtime_gpes + * + * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR + * + * RETURN: Status + * + * DESCRIPTION: Enable all GPEs of the given type + * + ******************************************************************************/ - status = acpi_hw_low_level_write (8, 0xFF, - &gpe_block->register_info[i].status_address); - if (ACPI_FAILURE (status)) { - return (status); - } +acpi_status +acpi_hw_enable_all_runtime_gpes ( + u32 flags) +{ + acpi_status status; - /* - * Restore the GPE Enable register, which will do the following: - * - * 1) Disable all wakeup GPEs - * 2) Enable all runtime GPEs - * - * (On sleep, we saved the enabled status of all GPEs) - */ - status = acpi_hw_low_level_write (8, gpe_register_info->enable, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - /* Point to next GPE register */ + ACPI_FUNCTION_TRACE ("hw_enable_all_runtime_gpes"); - gpe_register_info++; - } - return (AE_OK); + status = acpi_ev_walk_gpe_list (acpi_hw_enable_runtime_gpe_block, flags); + return_ACPI_STATUS (status); } /****************************************************************************** * - * FUNCTION: acpi_hw_restore_gpes_on_wake + * FUNCTION: acpi_hw_enable_all_wakeup_gpes * - * PARAMETERS: None + * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR * * RETURN: Status * - * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all - * GPE blocks + * DESCRIPTION: Enable all GPEs of the given type * ******************************************************************************/ acpi_status -acpi_hw_restore_gpes_on_wake ( - void) +acpi_hw_enable_all_wakeup_gpes ( + u32 flags) { acpi_status status; - ACPI_FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE ("hw_enable_all_wakeup_gpes"); - status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake); - return (status); + status = acpi_ev_walk_gpe_list (acpi_hw_enable_wakeup_gpe_block, flags); + return_ACPI_STATUS (status); } + diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index a7c651316..cb998fe9e 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -61,6 +61,7 @@ * RETURN: none * * DESCRIPTION: Clears all fixed and general purpose status bits + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ @@ -103,7 +104,7 @@ acpi_hw_clear_acpi_status ( /* Clear the GPE Bits in all GPE registers in all GPE blocks */ - status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block); + status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, ACPI_ISR); unlock_and_exit: if (flags & ACPI_MTX_LOCK) { @@ -135,7 +136,7 @@ acpi_get_sleep_type_data ( u8 *sleep_type_b) { acpi_status status = AE_OK; - union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data"); @@ -152,8 +153,9 @@ acpi_get_sleep_type_data ( /* * Evaluate the namespace object containing the values for this state */ + info.parameters = NULL; status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], - NULL, &obj_desc); + &info); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); @@ -163,48 +165,50 @@ acpi_get_sleep_type_data ( /* Must have a return object */ - if (!obj_desc) { + if (!info.return_object) { ACPI_REPORT_ERROR (("Missing Sleep State object\n")); status = AE_NOT_EXIST; } /* It must be of type Package */ - else if (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_PACKAGE) { + else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) { ACPI_REPORT_ERROR (("Sleep State object not a Package\n")); status = AE_AML_OPERAND_TYPE; } /* The package must have at least two elements */ - else if (obj_desc->package.count < 2) { + else if (info.return_object->package.count < 2) { ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); status = AE_AML_NO_OPERAND; } /* The first two elements must both be of type Integer */ - else if ((ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) { + else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n", - acpi_ut_get_object_type_name (obj_desc->package.elements[0]), - acpi_ut_get_object_type_name (obj_desc->package.elements[1]))); + acpi_ut_get_object_type_name (info.return_object->package.elements[0]), + acpi_ut_get_object_type_name (info.return_object->package.elements[1]))); status = AE_AML_OPERAND_TYPE; } else { /* * Valid _Sx_ package size, type, and value */ - *sleep_type_a = (u8) (obj_desc->package.elements[0])->integer.value; - *sleep_type_b = (u8) (obj_desc->package.elements[1])->integer.value; + *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value; } if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_sleep_state_names[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", + acpi_gbl_sleep_state_names[sleep_state], info.return_object, + acpi_ut_get_object_type_name (info.return_object))); } - acpi_ut_remove_reference (obj_desc); + acpi_ut_remove_reference (info.return_object); return_ACPI_STATUS (status); } @@ -245,8 +249,8 @@ acpi_hw_get_bit_register_info ( * return_value - Value that was read from the register * Flags - Lock the hardware or not * - * RETURN: Value is read from specified Register. Value returned is - * normalized to bit0 (is shifted all the way right) + * RETURN: Status and the value read from specified Register. Value + * returned is normalized to bit0 (is shifted all the way right) * * DESCRIPTION: ACPI bit_register read function. * @@ -280,6 +284,8 @@ acpi_get_register ( } } + /* Read from the register */ + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, bit_reg_info->parent_register, ®ister_value); @@ -309,10 +315,10 @@ acpi_get_register ( * * PARAMETERS: register_id - ID of ACPI bit_register to access * Value - (only used on write) value to write to the - * Register, NOT pre-normalized to the bit pos. + * Register, NOT pre-normalized to the bit pos * Flags - Lock the hardware or not * - * RETURN: None + * RETURN: Status * * DESCRIPTION: ACPI Bit Register write function. * @@ -457,10 +463,11 @@ unlock_and_exit: * * FUNCTION: acpi_hw_register_read * - * PARAMETERS: use_lock - Mutex hw access. - * register_id - register_iD + Offset. + * PARAMETERS: use_lock - Mutex hw access + * register_id - register_iD + Offset + * return_value - Value that was read from the register * - * RETURN: Value read or written. + * RETURN: Status and the value read. * * DESCRIPTION: Acpi register read function. Registers are read at the * given offset. @@ -568,10 +575,11 @@ unlock_and_exit: * * FUNCTION: acpi_hw_register_write * - * PARAMETERS: use_lock - Mutex hw access. - * register_id - register_iD + Offset. + * PARAMETERS: use_lock - Mutex hw access + * register_id - register_iD + Offset + * Value - The value to write * - * RETURN: Value read or written. + * RETURN: Status * * DESCRIPTION: Acpi register Write function. Registers are written at the * given offset. @@ -687,11 +695,11 @@ unlock_and_exit: * * PARAMETERS: Width - 8, 16, or 32 * Value - Where the value is returned - * Register - GAS register structure + * Reg - GAS register structure * * RETURN: Status * - * DESCRIPTION: Read from either memory, IO, or PCI config space. + * DESCRIPTION: Read from either memory or IO space. * ******************************************************************************/ @@ -701,8 +709,6 @@ acpi_hw_low_level_read ( u32 *value, struct acpi_generic_address *reg) { - struct acpi_pci_id pci_id; - u16 pci_register; acpi_status status; @@ -721,8 +727,8 @@ acpi_hw_low_level_read ( *value = 0; /* - * Three address spaces supported: - * Memory, IO, or PCI_Config. + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient */ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: @@ -740,19 +746,6 @@ acpi_hw_low_level_read ( break; - case ACPI_ADR_SPACE_PCI_CONFIG: - - pci_id.segment = 0; - pci_id.bus = 0; - pci_id.device = ACPI_PCI_DEVICE (reg->address); - pci_id.function = ACPI_PCI_FUNCTION (reg->address); - pci_register = (u16) ACPI_PCI_REGISTER (reg->address); - - status = acpi_os_read_pci_configuration (&pci_id, pci_register, - value, width); - break; - - default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); @@ -774,11 +767,11 @@ acpi_hw_low_level_read ( * * PARAMETERS: Width - 8, 16, or 32 * Value - To be written - * Register - GAS register structure + * Reg - GAS register structure * * RETURN: Status * - * DESCRIPTION: Write to either memory, IO, or PCI config space. + * DESCRIPTION: Write to either memory or IO space. * ******************************************************************************/ @@ -788,8 +781,6 @@ acpi_hw_low_level_write ( u32 value, struct acpi_generic_address *reg) { - struct acpi_pci_id pci_id; - u16 pci_register; acpi_status status; @@ -807,8 +798,8 @@ acpi_hw_low_level_write ( } /* - * Three address spaces supported: - * Memory, IO, or PCI_Config. + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient */ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: @@ -826,19 +817,6 @@ acpi_hw_low_level_write ( break; - case ACPI_ADR_SPACE_PCI_CONFIG: - - pci_id.segment = 0; - pci_id.bus = 0; - pci_id.device = ACPI_PCI_DEVICE (reg->address); - pci_id.function = ACPI_PCI_FUNCTION (reg->address); - pci_register = (u16) ACPI_PCI_REGISTER (reg->address); - - status = acpi_os_write_pci_configuration (&pci_id, pci_register, - (acpi_integer) value, width); - break; - - default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index f0c04149f..6ffa80ba2 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -265,19 +265,21 @@ acpi_enter_sleep_state ( sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); - if (sleep_state != ACPI_STATE_S5) { - /* Clear wake status */ + /* Clear wake status */ - status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + /* Clear all fixed and general purpose status bits */ + status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (sleep_state != ACPI_STATE_S5) { /* Disable BM arbitration */ status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); @@ -287,10 +289,16 @@ acpi_enter_sleep_state ( } /* - * 1) Disable all runtime GPEs + * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_prepare_gpes_for_sleep (); + status = acpi_hw_disable_all_gpes (ACPI_ISR); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = FALSE; + + status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -420,10 +428,16 @@ acpi_enter_sleep_state_s4bios ( } /* - * 1) Disable all runtime GPEs + * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_prepare_gpes_for_sleep (); + status = acpi_hw_disable_all_gpes (ACPI_ISR); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = FALSE; + + status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -453,6 +467,7 @@ acpi_enter_sleep_state_s4bios ( * RETURN: Status * * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. * ******************************************************************************/ @@ -540,19 +555,25 @@ acpi_leave_sleep_state ( /* * Restore the GPEs: - * 1) Disable all wakeup GPEs + * 1) Disable/Clear all GPEs * 2) Enable all runtime GPEs */ - status = acpi_hw_restore_gpes_on_wake (); + status = acpi_hw_disable_all_gpes (ACPI_NOT_ISR); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = TRUE; + + status = acpi_hw_enable_all_runtime_gpes (ACPI_NOT_ISR); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Enable power button */ - acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, ACPI_MTX_DO_NOT_LOCK); - acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); /* Enable BM arbitration */ diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index 8878aff9d..1f94d6ffa 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -52,11 +52,11 @@ * * FUNCTION: acpi_get_timer_resolution * - * PARAMETERS: none + * PARAMETERS: Resolution - Where the resolution is returned * - * RETURN: Number of bits of resolution in the PM Timer (24 or 32). + * RETURN: Status and timer resolution * - * DESCRIPTION: Obtains resolution of the ACPI PM Timer. + * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits). * ******************************************************************************/ @@ -86,11 +86,11 @@ acpi_get_timer_resolution ( * * FUNCTION: acpi_get_timer * - * PARAMETERS: none + * PARAMETERS: Ticks - Where the timer value is returned * - * RETURN: Current value of the ACPI PM Timer (in ticks). + * RETURN: Status and current ticks * - * DESCRIPTION: Obtains current value of ACPI PM Timer. + * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). * ******************************************************************************/ @@ -118,11 +118,11 @@ acpi_get_timer ( * * FUNCTION: acpi_get_timer_duration * - * PARAMETERS: start_ticks - * end_ticks - * time_elapsed + * PARAMETERS: start_ticks - Starting timestamp + * end_ticks - End timestamp + * time_elapsed - Where the elapsed time is returned * - * RETURN: time_elapsed + * RETURN: Status and time_elapsed * * DESCRIPTION: Computes the time elapsed (in microseconds) between two * PM Timer time stamps, taking into account the possibility of @@ -136,7 +136,7 @@ acpi_get_timer ( * Note that this function accommodates only a single timer * rollover. Thus for 24-bit timers, this function should only * be used for calculating durations less than ~4.6 seconds - * (~20 minutes for 32-bit timers) -- calculations below + * (~20 minutes for 32-bit timers) -- calculations below: * * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes @@ -164,7 +164,6 @@ acpi_get_timer_duration ( /* * Compute Tick Delta: - * ------------------- * Handle (max one) timer rollovers on 24- versus 32-bit timers. */ if (start_ticks < end_ticks) { @@ -188,10 +187,7 @@ acpi_get_timer_duration ( } /* - * Compute Duration: - * ----------------- - * - * Requires a 64-bit divide: + * Compute Duration (Requires a 64-bit divide): * * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY; */ diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c new file mode 100644 index 000000000..ee9c5d13e --- /dev/null +++ b/drivers/acpi/motherboard.c @@ -0,0 +1,177 @@ +/* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +/* Purpose: Prevent PCMCIA cards from using motherboard resources. */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("acpi_motherboard") + +/* Dell use PNP0C01 instead of PNP0C02 */ +#define ACPI_MB_HID1 "PNP0C01" +#define ACPI_MB_HID2 "PNP0C02" + +/** + * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved + * Doesn't care about the failure of 'request_region', since other may reserve + * the io ports as well + */ +#define IS_RESERVED_ADDR(base, len) \ + (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \ + && ((base) + (len) > PCIBIOS_MIN_IO)) + +/* + * Clearing the flag (IORESOURCE_BUSY) allows drivers to use + * the io ports if they really know they can use it, while + * still preventing hotplug PCI devices from using it. + */ + +static acpi_status +acpi_reserve_io_ranges (struct acpi_resource *res, void *data) +{ + struct resource *requested_res = NULL; + + ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges"); + + if (res->id == ACPI_RSTYPE_IO) { + struct acpi_resource_io *io_res = &res->data.io; + + if (io_res->min_base_address != io_res->max_base_address) + return AE_OK; + if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + io_res->min_base_address, + io_res->min_base_address + io_res->range_length)); + requested_res = request_region(io_res->min_base_address, + io_res->range_length, "motherboard"); + } + } else if (res->id == ACPI_RSTYPE_FIXED_IO) { + struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io; + + if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + fixed_io_res->base_address, + fixed_io_res->base_address + fixed_io_res->range_length)); + requested_res = request_region(fixed_io_res->base_address, + fixed_io_res->range_length, "motherboard"); + } + } else { + /* Memory mapped IO? */ + } + + if (requested_res) + requested_res->flags &= ~IORESOURCE_BUSY; + return AE_OK; +} + +static int acpi_motherboard_add (struct acpi_device *device) +{ + if (!device) + return -EINVAL; + acpi_walk_resources(device->handle, METHOD_NAME__CRS, + acpi_reserve_io_ranges, NULL); + + return 0; +} + +static struct acpi_driver acpi_motherboard_driver1 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID1, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static struct acpi_driver acpi_motherboard_driver2 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID2, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static void __init +acpi_reserve_resources (void) +{ + if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1a_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1b_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK"); + + if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK"); + + if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4) + request_region(acpi_gbl_FADT->xpm_tmr_blk.address, + 4, "PM_TMR"); + + if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len) + request_region(acpi_gbl_FADT->xpm2_cnt_blk.address, + acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK"); + + /* Length of GPE blocks must be a non-negative multiple of 2 */ + + if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len && + !(acpi_gbl_FADT->gpe0_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe0_blk.address, + acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK"); + + if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len && + !(acpi_gbl_FADT->gpe1_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe1_blk.address, + acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK"); +} + +static int __init acpi_motherboard_init(void) +{ + acpi_bus_register_driver(&acpi_motherboard_driver1); + acpi_bus_register_driver(&acpi_motherboard_driver2); + /* + * Guarantee motherboard IO reservation first + * This module must run after scan.c + */ + if (!acpi_disabled) + acpi_reserve_resources (); + return 0; +} + +/** + * Reserve motherboard resources after PCI claim BARs, + * but before PCI assign resources for uninitialized PCI devices + */ +fs_initcall(acpi_motherboard_init); diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 23baf93bf..765217be4 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -193,7 +193,7 @@ acpi_ns_root_initialize (void) case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; - obj_desc->mutex.sync_level = (u16) ACPI_STRTOUL + obj_desc->mutex.sync_level = (u8) ACPI_STRTOUL (val, NULL, 10); if (ACPI_STRCMP (init_val->name, "_GL_") == 0) { diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index c9dd49ff7..89b997717 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -267,7 +267,7 @@ acpi_ns_install_node ( else { #ifdef ACPI_ALPHABETIC_NAMESPACE /* - * Walk the list whilst searching for the the correct + * Walk the list whilst searching for the correct * alphabetic placement. */ previous_child_node = NULL; diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index b054b365c..418f03ee2 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -77,13 +77,10 @@ acpi_status acpi_ns_evaluate_relative ( - struct acpi_namespace_node *handle, char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { acpi_status status; - struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *node = NULL; union acpi_generic_state *scope_info; char *internal_path = NULL; @@ -95,7 +92,7 @@ acpi_ns_evaluate_relative ( /* * Must have a valid object handle */ - if (!handle) { + if (!info || !info->node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -118,8 +115,8 @@ acpi_ns_evaluate_relative ( goto cleanup; } - prefix_node = acpi_ns_map_handle_to_node (handle); - if (!prefix_node) { + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; @@ -127,7 +124,7 @@ acpi_ns_evaluate_relative ( /* Lookup the name in the namespace */ - scope_info->scope.node = prefix_node; + scope_info->scope.node = info->node; status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); @@ -147,7 +144,8 @@ acpi_ns_evaluate_relative ( ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", pathname, node, acpi_ns_get_attached_object (node))); - status = acpi_ns_evaluate_by_handle (node, params, return_object); + info->node = node; + status = acpi_ns_evaluate_by_handle (info); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -166,6 +164,7 @@ cleanup1: * FUNCTION: acpi_ns_evaluate_by_name * * PARAMETERS: Pathname - Fully qualified pathname to the object + * Info - Contains: * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * Params - List of parameters to pass to the method, @@ -184,11 +183,9 @@ cleanup1: acpi_status acpi_ns_evaluate_by_name ( char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { acpi_status status; - struct acpi_namespace_node *node = NULL; char *internal_path = NULL; @@ -211,7 +208,7 @@ acpi_ns_evaluate_by_name ( status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, - &node); + &info->node); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -226,9 +223,9 @@ acpi_ns_evaluate_by_name ( * to evaluate it. */ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", - pathname, node, acpi_ns_get_attached_object (node))); + pathname, info->node, acpi_ns_get_attached_object (info->node))); - status = acpi_ns_evaluate_by_handle (node, params, return_object); + status = acpi_ns_evaluate_by_handle (info); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -254,6 +251,7 @@ cleanup: * Params - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. + * param_type - Type of Parameter list * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * @@ -267,13 +265,9 @@ cleanup: acpi_status acpi_ns_evaluate_by_handle ( - struct acpi_namespace_node *handle, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { - struct acpi_namespace_node *node; acpi_status status; - union acpi_operand_object *local_return_object; ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle"); @@ -287,15 +281,13 @@ acpi_ns_evaluate_by_handle ( /* Parameter Validation */ - if (!handle) { + if (!info) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - if (return_object) { - /* Initialize the return value to an invalid object */ + /* Initialize the return value to an invalid object */ - *return_object = NULL; - } + info->return_object = NULL; /* Get the prefix handle and Node */ @@ -304,8 +296,8 @@ acpi_ns_evaluate_by_handle ( return_ACPI_STATUS (status); } - node = acpi_ns_map_handle_to_node (handle); - if (!node) { + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -315,8 +307,8 @@ acpi_ns_evaluate_by_handle ( * so that proper scoping context will be established * before execution. */ - if (acpi_ns_get_type (node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { - node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object); + if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object); } /* @@ -328,19 +320,18 @@ acpi_ns_evaluate_by_handle ( * In both cases, the namespace is unlocked by the * acpi_ns* procedure */ - if (acpi_ns_get_type (node) == ACPI_TYPE_METHOD) { + if (acpi_ns_get_type (info->node) == ACPI_TYPE_METHOD) { /* * Case 1) We have an actual control method to execute */ - status = acpi_ns_execute_control_method (node, params, - &local_return_object); + status = acpi_ns_execute_control_method (info); } else { /* * Case 2) Object is NOT a method, just return its * current value */ - status = acpi_ns_get_object_value (node, &local_return_object); + status = acpi_ns_get_object_value (info); } /* @@ -348,20 +339,6 @@ acpi_ns_evaluate_by_handle ( * be dealt with */ if (status == AE_CTRL_RETURN_VALUE) { - /* - * If the Method returned a value and the caller - * provided a place to store a returned value, Copy - * the returned value to the object descriptor provided - * by the caller. - */ - if (return_object) { - /* - * Valid return object, copy the pointer to - * the returned object - */ - *return_object = local_return_object; - } - /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ status = AE_OK; @@ -396,9 +373,7 @@ acpi_ns_evaluate_by_handle ( acpi_status acpi_ns_execute_control_method ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status; union acpi_operand_object *obj_desc; @@ -409,7 +384,7 @@ acpi_ns_execute_control_method ( /* Verify that there is a method associated with this object */ - obj_desc = acpi_ns_get_attached_object (method_node); + obj_desc = acpi_ns_get_attached_object (info->node); if (!obj_desc) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n")); @@ -417,7 +392,7 @@ acpi_ns_execute_control_method ( return_ACPI_STATUS (AE_NULL_OBJECT); } - ACPI_DUMP_PATHNAME (method_node, "Execute Method:", + ACPI_DUMP_PATHNAME (info->node, "Execute Method:", ACPI_LV_INFO, _COMPONENT); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n", @@ -444,7 +419,7 @@ acpi_ns_execute_control_method ( return_ACPI_STATUS (status); } - status = acpi_psx_execute (method_node, params, return_obj_desc); + status = acpi_psx_execute (info); acpi_ex_exit_interpreter (); return_ACPI_STATUS (status); @@ -468,11 +443,10 @@ acpi_ns_execute_control_method ( acpi_status acpi_ns_get_object_value ( - struct acpi_namespace_node *node, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status = AE_OK; - struct acpi_namespace_node *resolved_node = node; + struct acpi_namespace_node *resolved_node = info->node; ACPI_FUNCTION_TRACE ("ns_get_object_value"); @@ -518,9 +492,9 @@ acpi_ns_get_object_value ( if (ACPI_SUCCESS (status)) { status = AE_CTRL_RETURN_VALUE; - *return_obj_desc = ACPI_CAST_PTR (union acpi_operand_object, resolved_node); + info->return_object = ACPI_CAST_PTR (union acpi_operand_object, resolved_node); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n", - *return_obj_desc, acpi_ut_get_object_type_name (*return_obj_desc))); + info->return_object, acpi_ut_get_object_type_name (info->return_object))); } } diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index c8e9317ab..861787520 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -149,7 +149,7 @@ acpi_ns_initialize_devices ( return_ACPI_STATUS (status); } - /* Walk namespace for all objects of type Device or Processor */ + /* Walk namespace for all objects */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL); @@ -337,25 +337,29 @@ acpi_ns_init_one_device ( void *context, void **return_value) { - acpi_status status; - struct acpi_namespace_node *node; - u32 flags; struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context; + struct acpi_parameter_info pinfo; + u32 flags; + acpi_status status; ACPI_FUNCTION_TRACE ("ns_init_one_device"); - node = acpi_ns_map_handle_to_node (obj_handle); - if (!node) { + pinfo.parameters = NULL; + pinfo.parameter_type = ACPI_PARAM_ARGS; + + pinfo.node = acpi_ns_map_handle_to_node (obj_handle); + if (!pinfo.node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* - * We will run _STA/_INI on Devices and Processors only + * We will run _STA/_INI on Devices, Processors and thermal_zones only */ - if ((node->type != ACPI_TYPE_DEVICE) && - (node->type != ACPI_TYPE_PROCESSOR)) { + if ((pinfo.node->type != ACPI_TYPE_DEVICE) && + (pinfo.node->type != ACPI_TYPE_PROCESSOR) && + (pinfo.node->type != ACPI_TYPE_THERMAL)) { return_ACPI_STATUS (AE_OK); } @@ -368,17 +372,17 @@ acpi_ns_init_one_device ( /* * Run _STA to determine if we can run _INI on the device. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, node, "_STA")); - status = acpi_ut_execute_STA (node, &flags); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); + status = acpi_ut_execute_STA (pinfo.node, &flags); if (ACPI_FAILURE (status)) { - if (node->type == ACPI_TYPE_DEVICE) { + if (pinfo.node->type == ACPI_TYPE_DEVICE) { /* Ignore error and move on to next device */ return_ACPI_STATUS (AE_OK); } - /* _STA is not required for Processor objects */ + /* _STA is not required for Processor or thermal_zone objects */ } else { info->num_STA++; @@ -393,22 +397,22 @@ acpi_ns_init_one_device ( /* * The device is present. Run _INI. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, obj_handle, "_INI")); - status = acpi_ns_evaluate_relative (obj_handle, "_INI", NULL, NULL); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); + status = acpi_ns_evaluate_relative ("_INI", &pinfo); if (ACPI_FAILURE (status)) { /* No _INI (AE_NOT_FOUND) means device requires no initialization */ if (status != AE_NOT_FOUND) { /* Ignore error and move on to next device */ - #ifdef ACPI_DEBUG_OUTPUT - char *scope_name = acpi_ns_get_external_pathname (obj_handle); +#ifdef ACPI_DEBUG_OUTPUT + char *scope_name = acpi_ns_get_external_pathname (pinfo.node); ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", scope_name, acpi_format_exception (status))); ACPI_MEM_FREE (scope_name); - #endif +#endif } status = AE_OK; @@ -422,7 +426,7 @@ acpi_ns_init_one_device ( if (acpi_gbl_init_handler) { /* External initialization handler is present, call it */ - status = acpi_gbl_init_handler (obj_handle, ACPI_INIT_DEVICE_INI); + status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI); } diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c index f550ce5c1..530982a38 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/namespace/nsparse.c @@ -94,8 +94,9 @@ acpi_ns_one_complete_parse ( return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, table_desc->aml_start, - table_desc->aml_length, NULL, NULL, pass_number); + status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, + table_desc->aml_start, table_desc->aml_length, + NULL, pass_number); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 312835443..8e916b5e2 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -174,8 +174,7 @@ acpi_evaluate_object ( { acpi_status status; acpi_status status2; - union acpi_operand_object **internal_params = NULL; - union acpi_operand_object *internal_return_obj = NULL; + struct acpi_parameter_info info; acpi_size buffer_space_needed; u32 i; @@ -183,6 +182,11 @@ acpi_evaluate_object ( ACPI_FUNCTION_TRACE ("acpi_evaluate_object"); + info.node = handle; + info.parameters = NULL; + info.return_object = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + /* * If there are parameters to be passed to the object * (which must be a control method), the external objects @@ -193,9 +197,10 @@ acpi_evaluate_object ( * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ - internal_params = ACPI_MEM_CALLOCATE (((acpi_size) external_params->count + 1) * - sizeof (void *)); - if (!internal_params) { + info.parameters = ACPI_MEM_CALLOCATE ( + ((acpi_size) external_params->count + 1) * + sizeof (void *)); + if (!info.parameters) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -205,15 +210,16 @@ acpi_evaluate_object ( */ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], - &internal_params[i]); + &info.parameters[i]); if (ACPI_FAILURE (status)) { - acpi_ut_delete_internal_object_list (internal_params); + acpi_ut_delete_internal_object_list (info.parameters); return_ACPI_STATUS (status); } } - internal_params[external_params->count] = NULL; + info.parameters[external_params->count] = NULL; } + /* * Three major cases: * 1) Fully qualified pathname @@ -225,8 +231,7 @@ acpi_evaluate_object ( /* * The path is fully qualified, just evaluate by name */ - status = acpi_ns_evaluate_by_name (pathname, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_by_name (pathname, &info); } else if (!handle) { /* @@ -256,15 +261,13 @@ acpi_evaluate_object ( * The null pathname case means the handle is for * the actual object to be evaluated */ - status = acpi_ns_evaluate_by_handle (handle, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_by_handle (&info); } else { /* * Both a Handle and a relative Pathname */ - status = acpi_ns_evaluate_relative (handle, pathname, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_relative (pathname, &info); } } @@ -274,11 +277,11 @@ acpi_evaluate_object ( * copy the return value to an external object. */ if (return_buffer) { - if (!internal_return_obj) { + if (!info.return_object) { return_buffer->length = 0; } else { - if (ACPI_GET_DESCRIPTOR_TYPE (internal_return_obj) == ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_DESCRIPTOR_TYPE (info.return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to @@ -288,7 +291,7 @@ acpi_evaluate_object ( * support for various types at a later date if necessary. */ status = AE_TYPE; - internal_return_obj = NULL; /* No need to delete a NS Node */ + info.return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } @@ -297,7 +300,7 @@ acpi_evaluate_object ( * Find out how large a buffer is needed * to contain the returned object */ - status = acpi_ut_get_object_size (internal_return_obj, + status = acpi_ut_get_object_size (info.return_object, &buffer_space_needed); if (ACPI_SUCCESS (status)) { /* Validate/Allocate/Clear caller buffer */ @@ -309,13 +312,14 @@ acpi_evaluate_object ( */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Needed buffer size %X, %s\n", - (u32) buffer_space_needed, acpi_format_exception (status))); + (u32) buffer_space_needed, + acpi_format_exception (status))); } else { /* * We have enough space for the object, build it */ - status = acpi_ut_copy_iobject_to_eobject (internal_return_obj, + status = acpi_ut_copy_iobject_to_eobject (info.return_object, return_buffer); } } @@ -323,7 +327,7 @@ acpi_evaluate_object ( } } - if (internal_return_obj) { + if (info.return_object) { /* * Delete the internal return object. NOTE: Interpreter * must be locked to avoid race condition. @@ -334,7 +338,7 @@ acpi_evaluate_object ( * Delete the internal return object. (Or at least * decrement the reference count by one) */ - acpi_ut_remove_reference (internal_return_obj); + acpi_ut_remove_reference (info.return_object); acpi_ex_exit_interpreter (); } } @@ -342,10 +346,10 @@ acpi_evaluate_object ( /* * Free the input parameter list (if we created one), */ - if (internal_params) { + if (info.parameters) { /* Free the allocated parameter block */ - acpi_ut_delete_internal_object_list (internal_params); + acpi_ut_delete_internal_object_list (info.parameters); } return_ACPI_STATUS (status); diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index a1acb9f12..0508b4d79 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -281,7 +281,7 @@ acpi_get_object_info ( if (info.type == ACPI_TYPE_DEVICE) { /* * Get extra info for ACPI Devices objects only: - * Run the Device _HID, _UID, _CID, _STA, and _ADR methods. + * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info.Valid bitfield is used @@ -330,7 +330,7 @@ acpi_get_object_info ( status = acpi_ut_execute_sxds (node, info.highest_dstates); if (ACPI_SUCCESS (status)) { - info.valid |= ACPI_VALID_STA; + info.valid |= ACPI_VALID_SXDS; } status = AE_OK; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 0646b2955..1f63b4d71 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -51,6 +51,7 @@ acpi_table_print_srat_entry ( switch (header->type) { case ACPI_SRAT_PROCESSOR_AFFINITY: +#ifdef ACPI_DEBUG_OUTPUT { struct acpi_table_processor_affinity *p = (struct acpi_table_processor_affinity*) header; @@ -58,9 +59,11 @@ acpi_table_print_srat_entry ( p->apic_id, p->lsapic_eid, p->proximity_domain, p->flags.enabled?"enabled":"disabled")); } +#endif /* ACPI_DEBUG_OUTPUT */ break; case ACPI_SRAT_MEMORY_AFFINITY: +#ifdef ACPI_DEBUG_OUTPUT { struct acpi_table_memory_affinity *p = (struct acpi_table_memory_affinity*) header; @@ -70,6 +73,7 @@ acpi_table_print_srat_entry ( p->flags.enabled ? "enabled" : "disabled", p->flags.hot_pluggable ? " hot-pluggable" : "")); } +#endif /* ACPI_DEBUG_OUTPUT */ break; default: @@ -94,8 +98,6 @@ acpi_parse_slit (unsigned long phys_addr, unsigned long size) /* downcast just for %llu vs %lu for i386/ia64 */ localities = (u32) slit->localities; - printk(KERN_INFO PREFIX "SLIT localities %ux%u\n", localities, localities); - acpi_numa_slit_init(slit); return 0; @@ -103,7 +105,9 @@ acpi_parse_slit (unsigned long phys_addr, unsigned long size) static int __init -acpi_parse_processor_affinity (acpi_table_entry_header *header) +acpi_parse_processor_affinity ( + acpi_table_entry_header *header, + const unsigned long end) { struct acpi_table_processor_affinity *processor_affinity; @@ -121,7 +125,9 @@ acpi_parse_processor_affinity (acpi_table_entry_header *header) static int __init -acpi_parse_memory_affinity (acpi_table_entry_header *header) +acpi_parse_memory_affinity ( + acpi_table_entry_header *header, + const unsigned long end) { struct acpi_table_memory_affinity *memory_affinity; @@ -148,8 +154,6 @@ acpi_parse_srat (unsigned long phys_addr, unsigned long size) srat = (struct acpi_table_srat *) __va(phys_addr); - printk(KERN_INFO PREFIX "SRAT revision %d\n", srat->table_revision); - return 0; } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 433fdd701..a7c4fdfcb 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -51,10 +51,13 @@ ACPI_MODULE_NAME ("osl") struct acpi_os_dpc { - OSD_EXECUTION_CALLBACK function; + acpi_osd_exec_callback function; void *context; }; +#ifdef CONFIG_ACPI_CUSTOM_DSDT +#include CONFIG_ACPI_CUSTOM_DSDT_FILE +#endif #ifdef ENABLE_DEBUGGER #include @@ -64,12 +67,18 @@ extern char line_buf[80]; #endif /*ENABLE_DEBUGGER*/ static unsigned int acpi_irq_irq; -static OSD_HANDLER acpi_irq_handler; +static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; acpi_status acpi_os_initialize(void) +{ + return AE_OK; +} + +acpi_status +acpi_os_initialize1(void) { /* * Initialize PCI configuration space access, as we'll need to access @@ -165,11 +174,11 @@ acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr) } acpi_status -acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void **virt) +acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void __iomem **virt) { if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys)) { - *virt = phys_to_virt(phys); + *virt = (void __iomem *) phys_to_virt(phys); } else { *virt = ioremap(phys, size); } @@ -191,7 +200,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void **virt) } void -acpi_os_unmap_memory(void *virt, acpi_size size) +acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { iounmap(virt); } @@ -235,7 +244,14 @@ acpi_os_table_override (struct acpi_table_header *existing_table, if (!existing_table || !new_table) return AE_BAD_PARAMETER; +#ifdef CONFIG_ACPI_CUSTOM_DSDT + if (strncmp(existing_table->signature, "DSDT", 4) == 0) + *new_table = (struct acpi_table_header*)AmlCode; + else + *new_table = NULL; +#else *new_table = NULL; +#endif return AE_OK; } @@ -246,7 +262,7 @@ acpi_irq(int irq, void *dev_id, struct pt_regs *regs) } acpi_status -acpi_os_install_interrupt_handler(u32 gsi, OSD_HANDLER handler, void *context) +acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *context) { unsigned int irq; @@ -274,7 +290,7 @@ acpi_os_install_interrupt_handler(u32 gsi, OSD_HANDLER handler, void *context) } acpi_status -acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) +acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) { if (irq) { free_irq(irq, acpi_irq); @@ -370,30 +386,31 @@ acpi_os_read_memory( u32 width) { u32 dummy; - void *virt_addr; + void __iomem *virt_addr; int iomem = 0; if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { - virt_addr = phys_to_virt(phys_addr); + /* HACK ALERT! We can use readb/w/l on real memory too.. */ + virt_addr = (void __iomem *) phys_to_virt(phys_addr); } else { iomem = 1; virt_addr = ioremap(phys_addr, width); } } else - virt_addr = phys_to_virt(phys_addr); + virt_addr = (void __iomem *) phys_to_virt(phys_addr); if (!value) value = &dummy; switch (width) { case 8: - *(u8*) value = *(u8*) virt_addr; + *(u8*) value = readb(virt_addr); break; case 16: - *(u16*) value = *(u16*) virt_addr; + *(u16*) value = readw(virt_addr); break; case 32: - *(u32*) value = *(u32*) virt_addr; + *(u32*) value = readl(virt_addr); break; default: BUG(); @@ -413,28 +430,29 @@ acpi_os_write_memory( u32 value, u32 width) { - void *virt_addr; + void __iomem *virt_addr; int iomem = 0; if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { - virt_addr = phys_to_virt(phys_addr); + /* HACK ALERT! We can use writeb/w/l on real memory too */ + virt_addr = (void __iomem *) phys_to_virt(phys_addr); } else { iomem = 1; virt_addr = ioremap(phys_addr, width); } } else - virt_addr = phys_to_virt(phys_addr); + virt_addr = (void __iomem *) phys_to_virt(phys_addr); switch (width) { case 8: - *(u8*) virt_addr = value; + writeb(value, virt_addr); break; case 16: - *(u16*) virt_addr = value; + writew(value, virt_addr); break; case 32: - *(u32*) virt_addr = value; + writel(value, virt_addr); break; default: BUG(); @@ -470,6 +488,8 @@ acpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value return AE_ERROR; } + BUG_ON(!raw_pci_ops); + result = raw_pci_ops->read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); @@ -496,6 +516,8 @@ acpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integ return AE_ERROR; } + BUG_ON(!raw_pci_ops); + result = raw_pci_ops->write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); @@ -624,7 +646,7 @@ acpi_os_execute_deferred ( acpi_status acpi_os_queue_for_execution( u32 priority, - OSD_EXECUTION_CALLBACK function, + acpi_osd_exec_callback function, void *context) { acpi_status status = AE_OK; @@ -952,7 +974,7 @@ acpi_os_readable(void *ptr, acpi_size len) { #if defined(__i386__) || defined(__x86_64__) char tmp; - return !__get_user(tmp, (char *)ptr) && !__get_user(tmp, (char *)ptr + len - 1); + return !__get_user(tmp, (char __user *)ptr) && !__get_user(tmp, (char __user *)ptr + len - 1); #endif return 1; } @@ -1066,15 +1088,15 @@ __setup("acpi_serialize", acpi_serialize_setup); * Run-time events on the same GPE this flag is available * to tell Linux to keep the wake-time GPEs enabled at run-time. */ -static int __init -acpi_leave_gpes_disabled_setup(char *str) +int __init +acpi_wake_gpes_always_on_setup(char *str) { - printk(KERN_INFO PREFIX "leave wake GPEs disabled\n"); + printk(KERN_INFO PREFIX "wake GPEs not disabled\n"); - acpi_gbl_leave_wake_gpes_disabled = TRUE; + acpi_gbl_leave_wake_gpes_disabled = FALSE; return 1; } -__setup("acpi_leave_gpes_disabled", acpi_leave_gpes_disabled_setup); +__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 198e2206b..30620375b 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -251,7 +251,7 @@ #define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) #define ARGI_DEBUG_OP ARG_NONE #define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) #define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) @@ -270,10 +270,10 @@ #define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) #define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) #define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index b7917cfdc..9281f6aec 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -57,7 +57,7 @@ * * FUNCTION: acpi_psx_execute * - * PARAMETERS: method_node - A method object containing both the AML + * PARAMETERS: Info->Node - A method object containing both the AML * address and length. * **Params - List of parameters to pass to method, * terminated by NULL. Params itself may be @@ -73,9 +73,7 @@ acpi_status acpi_psx_execute ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status; union acpi_operand_object *obj_desc; @@ -89,29 +87,30 @@ acpi_psx_execute ( /* Validate the Node and get the attached object */ - if (!method_node) { + if (!info || !info->node) { return_ACPI_STATUS (AE_NULL_ENTRY); } - obj_desc = acpi_ns_get_attached_object (method_node); + obj_desc = acpi_ns_get_attached_object (info->node); if (!obj_desc) { return_ACPI_STATUS (AE_NULL_OBJECT); } /* Init for new method, wait on concurrency semaphore */ - status = acpi_ds_begin_method_execution (method_node, obj_desc, NULL); + status = acpi_ds_begin_method_execution (info->node, obj_desc, NULL); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - if (params) { + if ((info->parameter_type == ACPI_PARAM_ARGS) && + (info->parameters)) { /* * The caller "owns" the parameters, so give each one an extra * reference */ - for (i = 0; params[i]; i++) { - acpi_ut_add_reference (params[i]); + for (i = 0; info->parameters[i]; i++) { + acpi_ut_add_reference (info->parameters[i]); } } @@ -121,7 +120,7 @@ acpi_psx_execute ( */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Parse **** Entry=%p obj=%p\n", - method_node, obj_desc)); + info->node, obj_desc)); /* Create and init a Root Node */ @@ -147,8 +146,9 @@ acpi_psx_execute ( goto cleanup2; } - status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, info->node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE (status)) { goto cleanup3; } @@ -159,7 +159,6 @@ acpi_psx_execute ( acpi_ps_delete_parse_tree (op); if (ACPI_FAILURE (status)) { goto cleanup1; /* Walk state is already deleted */ - } /* @@ -167,7 +166,7 @@ acpi_psx_execute ( */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Execution **** Entry=%p obj=%p\n", - method_node, obj_desc)); + info->node, obj_desc)); /* Create and init a Root Node */ @@ -179,8 +178,8 @@ acpi_psx_execute ( /* Init new op with the method name and pointer back to the NS node */ - acpi_ps_set_name (op, method_node->name.integer); - op->common.node = method_node; + acpi_ps_set_name (op, info->node->name.integer); + op->common.node = info->node; /* Create and initialize a new walk state */ @@ -190,8 +189,9 @@ acpi_psx_execute ( goto cleanup2; } - status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, params, return_obj_desc, 3); + status = acpi_ds_init_aml_walk (walk_state, op, info->node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, info, 3); if (ACPI_FAILURE (status)) { goto cleanup3; } @@ -210,13 +210,14 @@ cleanup2: acpi_ps_delete_parse_tree (op); cleanup1: - if (params) { + if ((info->parameter_type == ACPI_PARAM_ARGS) && + (info->parameters)) { /* Take away the extra reference that we gave the parameters above */ - for (i = 0; params[i]; i++) { + for (i = 0; info->parameters[i]; i++) { /* Ignore errors, just do them all */ - (void) acpi_ut_update_object_reference (params[i], REF_DECREMENT); + (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT); } } @@ -228,10 +229,10 @@ cleanup1: * If the method has returned an object, signal this to the caller with * a control exception code */ - if (*return_obj_desc) { + if (info->return_object) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned obj_desc=%p\n", - *return_obj_desc)); - ACPI_DUMP_STACK_ENTRY (*return_obj_desc); + info->return_object)); + ACPI_DUMP_STACK_ENTRY (info->return_object); status = AE_CTRL_RETURN_VALUE; } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 13e922551..86e8a0ca0 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -29,6 +29,7 @@ * for IRQ management (e.g. start()->_SRS). */ +#include #include #include #include @@ -71,7 +72,7 @@ struct acpi_pci_link_irq { u8 active; /* Current IRQ */ u8 edge_level; /* All IRQs */ u8 active_high_low; /* All IRQs */ - u8 setonboot; + u8 initialized; u8 resource_type; u8 possible_count; u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; @@ -447,7 +448,7 @@ acpi_pci_link_set ( #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) -static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = { +static int acpi_irq_penalty[ACPI_MAX_IRQS] = { PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ @@ -467,7 +468,7 @@ static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = { /* >IRQ15 */ }; -int +int __init acpi_irq_penalty_init(void) { struct list_head *node = NULL; @@ -517,7 +518,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) { ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); - if (link->irq.setonboot) + if (link->irq.initialized) return_VALUE(0); /* @@ -571,7 +572,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) { acpi_device_bid(link->device), link->irq.active); } - link->irq.setonboot = 1; + link->irq.initialized = 1; return_VALUE(0); } @@ -694,6 +695,42 @@ end: } +static int +acpi_pci_link_resume ( + struct acpi_pci_link *link) +{ + ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); + + if (link->irq.active && link->irq.initialized) + return_VALUE(acpi_pci_link_set(link, link->irq.active)); + else + return_VALUE(0); +} + + +static int +irqrouter_resume( + struct sys_device *dev) +{ + struct list_head *node = NULL; + struct acpi_pci_link *link = NULL; + + ACPI_FUNCTION_TRACE("irqrouter_resume"); + + list_for_each(node, &acpi_link.entries) { + + link = list_entry(node, struct acpi_pci_link, node); + if (!link) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); + continue; + } + + acpi_pci_link_resume(link); + } + return_VALUE(0); +} + + static int acpi_pci_link_remove ( struct acpi_device *device, @@ -786,11 +823,42 @@ int __init acpi_irq_balance_set(char *str) __setup("acpi_irq_balance", acpi_irq_balance_set); +static struct sysdev_class irqrouter_sysdev_class = { + set_kset_name("irqrouter"), + .resume = irqrouter_resume, +}; + + +static struct sys_device device_irqrouter = { + .id = 0, + .cls = &irqrouter_sysdev_class, +}; + + +static int __init irqrouter_init_sysfs(void) +{ + int error; + + ACPI_FUNCTION_TRACE("irqrouter_init_sysfs"); + + if (acpi_disabled || acpi_noirq) + return_VALUE(0); + + error = sysdev_class_register(&irqrouter_sysdev_class); + if (!error) + error = sysdev_register(&device_irqrouter); + + return_VALUE(error); +} + +device_initcall(irqrouter_init_sysfs); + + static int __init acpi_pci_link_init (void) { ACPI_FUNCTION_TRACE("acpi_pci_link_init"); - if (acpi_pci_disabled) + if (acpi_noirq) return_VALUE(0); acpi_link.count = 0; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 657ddef48..4c3d2a7d2 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -288,6 +288,86 @@ acpi_power_off_device ( return_VALUE(0); } +/* + * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): + * 1. Power on the power resources required for the wakeup device + * 2. Enable _PSW (power state wake) for the device if present + */ +int acpi_enable_wakeup_device_power (struct acpi_device *dev) +{ + union acpi_object arg = {ACPI_TYPE_INTEGER}; + struct acpi_object_list arg_list = {1, &arg}; + acpi_status status = AE_OK; + int i; + int ret = 0; + + ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_power"); + if (!dev || !dev->wakeup.flags.valid) + return -1; + + arg.integer.value = 1; + /* Open power resource */ + for (i = 0; i < dev->wakeup.resources.count; i++) { + ret = acpi_power_on(dev->wakeup.resources.handles[i]); + if (ret) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error transition power state\n")); + dev->wakeup.flags.valid = 0; + return -1; + } + } + + /* Execute PSW */ + status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); + if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n")); + dev->wakeup.flags.valid = 0; + ret = -1; + } + + return ret; +} + +/* + * Shutdown a wakeup device, counterpart of above method + * 1. Disable _PSW (power state wake) + * 2. Shutdown down the power resources + */ +int acpi_disable_wakeup_device_power (struct acpi_device *dev) +{ + union acpi_object arg = {ACPI_TYPE_INTEGER}; + struct acpi_object_list arg_list = {1, &arg}; + acpi_status status = AE_OK; + int i; + int ret = 0; + + ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device_power"); + + if (!dev || !dev->wakeup.flags.valid) + return -1; + + arg.integer.value = 0; + /* Execute PSW */ + status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); + if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n")); + dev->wakeup.flags.valid = 0; + return -1; + } + + /* Close power resource */ + for (i = 0; i < dev->wakeup.resources.count; i++) { + ret = acpi_power_off_device(dev->wakeup.resources.handles[i]); + if (ret) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error transition power state\n")); + dev->wakeup.flags.valid = 0; + return -1; + } + } + + return ret; +} /* -------------------------------------------------------------------------- Device Power Management diff --git a/drivers/acpi/processor.c b/drivers/acpi/processor.c index 8d7b78df6..83fb743aa 100644 --- a/drivers/acpi/processor.c +++ b/drivers/acpi/processor.c @@ -44,6 +44,9 @@ #include #include #include +#include +#include +#include #include #include @@ -859,7 +862,6 @@ static void acpi_processor_ppc_exit(void) { * _PCT and _PSS structures are read out and written into struct * acpi_processor_performance. */ - static int acpi_processor_set_pdc (struct acpi_processor *pr) { acpi_status status = AE_OK; @@ -1047,6 +1049,8 @@ acpi_processor_get_performance_info ( if (!pr || !pr->performance || !pr->handle) return_VALUE(-EINVAL); + acpi_processor_set_pdc(pr); + status = acpi_get_handle(pr->handle, "_PCT", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -1054,8 +1058,6 @@ acpi_processor_get_performance_info ( return_VALUE(-ENODEV); } - acpi_processor_set_pdc(pr); - result = acpi_processor_get_performance_control(pr); if (result) return_VALUE(result); @@ -1121,7 +1123,7 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static int +static ssize_t acpi_processor_write_performance ( struct file *file, const char __user *buffer, @@ -2146,6 +2148,37 @@ acpi_processor_remove_fs ( return_VALUE(0); } +/* Use the acpiid in MADT to map cpus in case of SMP */ +#ifndef CONFIG_SMP +#define convert_acpiid_to_cpu(acpi_id) (0xff) +#else + +#ifdef CONFIG_IA64 +#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid +#define arch_cpu_to_apicid ia64_cpu_to_sapicid +#define ARCH_BAD_APICID (0xffff) +#else +#define arch_acpiid_to_apicid x86_acpiid_to_apicid +#define arch_cpu_to_apicid x86_cpu_to_apicid +#define ARCH_BAD_APICID (0xff) +#endif + +static u8 convert_acpiid_to_cpu(u8 acpi_id) +{ + u16 apic_id; + int i; + + apic_id = arch_acpiid_to_apicid[acpi_id]; + if (apic_id == ARCH_BAD_APICID) + return -1; + + for (i = 0; i < NR_CPUS; i++) { + if (arch_cpu_to_apicid[i] == apic_id) + return i; + } + return -1; +} +#endif /* -------------------------------------------------------------------------- Driver Interface @@ -2158,7 +2191,8 @@ acpi_processor_get_info ( acpi_status status = 0; union acpi_object object = {0}; struct acpi_buffer buffer = {sizeof(union acpi_object), &object}; - static int cpu_index = 0; + u8 cpu_index; + static int cpu0_initialized; ACPI_FUNCTION_TRACE("acpi_processor_get_info"); @@ -2168,13 +2202,6 @@ acpi_processor_get_info ( if (num_online_cpus() > 1) errata.smp = TRUE; - /* - * Extra Processor objects may be enumerated on MP systems with - * less than the max # of CPUs. They should be ignored. - */ - if ((cpu_index + 1) > num_online_cpus()) - return_VALUE(-ENODEV); - acpi_processor_errata(pr); /* @@ -2206,9 +2233,27 @@ acpi_processor_get_info ( * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c */ - pr->id = cpu_index++; pr->acpi_id = object.processor.proc_id; + cpu_index = convert_acpiid_to_cpu(pr->acpi_id); + + if ( !cpu0_initialized && (cpu_index == 0xff)) { + /* Handle UP system running SMP kernel, with no LAPIC in MADT */ + cpu_index = 0; + } else if (cpu_index > num_online_cpus()) { + /* + * Extra Processor objects may be enumerated on MP systems with + * less than the max # of CPUs. They should be ignored. + */ + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error getting cpuindex for acpiid 0x%x\n", + pr->acpi_id)); + return_VALUE(-ENODEV); + } + cpu0_initialized = 1; + + pr->id = cpu_index; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, pr->acpi_id)); @@ -2234,7 +2279,6 @@ acpi_processor_get_info ( * (In particular, allocating the IO range for Cardbus) */ request_region(pr->throttling.address, 6, "ACPI CPU throttle"); - request_region(acpi_fadt.xpm_tmr_blk.address, 4, "ACPI timer"); } acpi_processor_get_power_info(pr); @@ -2373,8 +2417,15 @@ acpi_processor_remove ( pr = (struct acpi_processor *) acpi_driver_data(device); /* Unregister the idle handler when processor #0 is removed. */ - if (pr->id == 0) + if (pr->id == 0) { pm_idle = pm_idle_save; + /* + * We are about to unload the current idle thread pm callback + * (pm_idle), Wait for all processors to update cached/local + * copies of pm_idle before proceeding. + */ + synchronize_kernel(); + } status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify); diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index eaf77c635..01dea9b94 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -289,6 +289,7 @@ acpi_rs_set_srs_method_data ( acpi_handle handle, struct acpi_buffer *in_buffer) { + struct acpi_parameter_info info; union acpi_operand_object *params[2]; acpi_status status; struct acpi_buffer buffer; @@ -329,10 +330,14 @@ acpi_rs_set_srs_method_data ( params[0]->common.flags = AOPOBJ_DATA_VALID; params[1] = NULL; + info.node = handle; + info.parameters = params; + info.parameter_type = ACPI_PARAM_ARGS; + /* * Execute the method, no return value */ - status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL); + status = acpi_ns_evaluate_relative ("_SRS", &info); /* * Clean up and return the status from acpi_ns_evaluate_relative diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 362f6252b..d02aa1df3 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -259,7 +259,8 @@ acpi_walk_resources ( /* Setup pointers */ resource = (struct acpi_resource *) buffer.pointer; - buffer_end = (struct acpi_resource *) ((u8 *) buffer.pointer + buffer.length); + buffer_end = ACPI_CAST_PTR (struct acpi_resource, + ((u8 *) buffer.pointer + buffer.length)); /* Walk the resource list */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index be148f489..4e46eeddf 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -23,7 +23,8 @@ extern struct acpi_device *acpi_root; #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); -static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED; +spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED; +LIST_HEAD(acpi_wakeup_device_list); static void acpi_device_release(struct kobject * kobj) { @@ -115,9 +116,6 @@ acpi_bus_get_power_flags ( status = acpi_get_handle(device->handle, "_IRC", &handle); if (ACPI_SUCCESS(status)) device->power.flags.inrush_current = 1; - status = acpi_get_handle(device->handle, "_PRW", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.wake_capable = 1; /* * Enumerate supported power management states @@ -163,6 +161,127 @@ acpi_bus_get_power_flags ( return 0; } +static int +acpi_match_ids ( + struct acpi_device *device, + char *ids) +{ + int error = 0; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + + if (device->flags.hardware_id) + if (strstr(ids, device->pnp.hardware_id)) + goto Done; + + if (device->flags.compatible_ids) { + struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; + int i; + + /* compare multiple _CID entries against driver ids */ + for (i = 0; i < cid_list->count; i++) + { + if (strstr(ids, cid_list->id[i].value)) + goto Done; + } + } + error = -ENOENT; + + Done: + if (buffer.pointer) + acpi_os_free(buffer.pointer); + return error; +} + +static acpi_status +acpi_bus_extract_wakeup_device_power_package ( + struct acpi_device *device, + union acpi_object *package) +{ + int i = 0; + union acpi_object *element = NULL; + + if (!device || !package || (package->package.count < 2)) + return AE_BAD_PARAMETER; + + element = &(package->package.elements[0]); + if (!element) + return AE_BAD_PARAMETER; + if (element->type == ACPI_TYPE_PACKAGE) { + if ((element->package.count < 2) || + (element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) || + (element->package.elements[1].type != ACPI_TYPE_INTEGER)) + return AE_BAD_DATA; + device->wakeup.gpe_device = element->package.elements[0].reference.handle; + device->wakeup.gpe_number = (u32)element->package.elements[1].integer.value; + }else if (element->type == ACPI_TYPE_INTEGER) { + device->wakeup.gpe_number = element->integer.value; + }else + return AE_BAD_DATA; + + element = &(package->package.elements[1]); + if (element->type != ACPI_TYPE_INTEGER) { + return AE_BAD_DATA; + } + device->wakeup.sleep_state = element->integer.value; + + if ((package->package.count - 2) > ACPI_MAX_HANDLES) { + return AE_NO_MEMORY; + } + device->wakeup.resources.count = package->package.count - 2; + for (i=0; i < device->wakeup.resources.count; i++) { + element = &(package->package.elements[i + 2]); + if (element->type != ACPI_TYPE_ANY ) { + return AE_BAD_DATA; + } + + device->wakeup.resources.handles[i] = element->reference.handle; + } + + return AE_OK; +} + +static int +acpi_bus_get_wakeup_device_flags ( + struct acpi_device *device) +{ + acpi_status status = 0; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *package = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_get_wakeup_flags"); + + /* _PRW */ + status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n")); + goto end; + } + + package = (union acpi_object *) buffer.pointer; + status = acpi_bus_extract_wakeup_device_power_package(device, package); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _PRW package\n")); + goto end; + } + + acpi_os_free(buffer.pointer); + + device->wakeup.flags.valid = 1; + /* Power button, Lid switch always enable wakeup*/ + if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) + device->wakeup.flags.run_wake = 1; + + /* TBD: lock */ + INIT_LIST_HEAD(&device->wakeup_list); + spin_lock(&acpi_device_lock); + list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); + spin_unlock(&acpi_device_lock); + +end: + if (ACPI_FAILURE(status)) + device->flags.wake_capable = 0; + return 0; +} /* -------------------------------------------------------------------------- Performance Management @@ -195,30 +314,7 @@ acpi_bus_match ( struct acpi_device *device, struct acpi_driver *driver) { - int error = 0; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - - if (device->flags.hardware_id) - if (strstr(driver->ids, device->pnp.hardware_id)) - goto Done; - - if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; - int i; - - /* compare multiple _CID entries against driver ids */ - for (i = 0; i < cid_list->count; i++) - { - if (strstr(driver->ids, cid_list->id[i].value)) - goto Done; - } - } - error = -ENOENT; - - Done: - if (buffer.pointer) - acpi_os_free(buffer.pointer); - return error; + return acpi_match_ids(device, driver->ids); } @@ -276,6 +372,7 @@ acpi_bus_driver_init ( static int acpi_driver_attach(struct acpi_driver * drv) { struct list_head * node, * next; + int count = 0; ACPI_FUNCTION_TRACE("acpi_driver_attach"); @@ -290,6 +387,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) { atomic_inc(&drv->references); + count++; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", drv->name, dev->pnp.bus_id)); } @@ -297,7 +395,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); - return_VALUE(0); + return_VALUE(count); } static int acpi_driver_detach(struct acpi_driver * drv) @@ -328,28 +426,30 @@ static int acpi_driver_detach(struct acpi_driver * drv) * acpi_bus_register_driver * ------------------------ * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. + * devices that match the driver's criteria and binds. Returns the + * number of devices that were claimed by the driver, or a negative + * error status for failure. */ int acpi_bus_register_driver ( struct acpi_driver *driver) { - int error = 0; + int count; ACPI_FUNCTION_TRACE("acpi_bus_register_driver"); if (acpi_disabled) return_VALUE(-ENODEV); - if (driver) { - spin_lock(&acpi_device_lock); - list_add_tail(&driver->node, &acpi_bus_drivers); - spin_unlock(&acpi_device_lock); - acpi_driver_attach(driver); - } else - error = -EINVAL; + if (!driver) + return_VALUE(-EINVAL); - return_VALUE(error); + spin_lock(&acpi_device_lock); + list_add_tail(&driver->node, &acpi_bus_drivers); + spin_unlock(&acpi_device_lock); + count = acpi_driver_attach(driver); + + return_VALUE(count); } @@ -469,6 +569,11 @@ acpi_bus_get_flags ( if (ACPI_SUCCESS(status)) device->flags.power_manageable = 1; + /* Presence of _PRW indicates wake capable */ + status = acpi_get_handle(device->handle, "_PRW", &temp); + if (ACPI_SUCCESS(status)) + device->flags.wake_capable = 1; + /* TBD: Peformance management */ return_VALUE(0); @@ -740,6 +845,16 @@ acpi_bus_add ( goto end; } + /* + * Wakeup device management + *----------------------- + */ + if (device->flags.wake_capable) { + result = acpi_bus_get_wakeup_device_flags(device); + if (result) + goto end; + } + /* * Performance Management * ---------------------- diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile index 975d03d59..bb52f85d0 100644 --- a/drivers/acpi/sleep/Makefile +++ b/drivers/acpi/sleep/Makefile @@ -1,5 +1,5 @@ obj-y := poweroff.o -obj-$(CONFIG_ACPI_SLEEP) += main.o +obj-$(CONFIG_ACPI_SLEEP) += main.o wakeup.o obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc.o EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index c7b17e7fa..847a90ed5 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -35,16 +35,16 @@ static int init_8259A_after_S1; /** * acpi_pm_prepare - Do preliminary suspend work. - * @state: suspend state we're entering. + * @pm_state: suspend state we're entering. * * Make sure we support the state. If we do, and we need it, set the * firmware waking vector and do arch-specific nastiness to get the * wakeup code to the waking vector. */ -static int acpi_pm_prepare(u32 state) +static int acpi_pm_prepare(u32 pm_state) { - u32 acpi_state = acpi_suspend_states[state]; + u32 acpi_state = acpi_suspend_states[pm_state]; if (!sleep_states[acpi_state]) return -EPERM; @@ -52,13 +52,14 @@ static int acpi_pm_prepare(u32 state) /* do we have a wakeup address for S2 and S3? */ /* Here, we support only S4BIOS, those we set the wakeup address */ /* S4OS is only supported for now via swsusp.. */ - if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_DISK) { + if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) { if (!acpi_wakeup_address) return -EFAULT; acpi_set_firmware_waking_vector( (acpi_physical_address) acpi_wakeup_address); } ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -66,23 +67,23 @@ static int acpi_pm_prepare(u32 state) /** * acpi_pm_enter - Actually enter a sleep state. - * @state: State we're entering. + * @pm_state: State we're entering. * * Flush caches and go to sleep. For STR or STD, we have to call * arch-specific assembly, which in turn call acpi_enter_sleep_state(). * It's unfortunate, but it works. Please fix if you're feeling frisky. */ -static int acpi_pm_enter(u32 state) +static int acpi_pm_enter(u32 pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; - u32 acpi_state = acpi_suspend_states[state]; + u32 acpi_state = acpi_suspend_states[pm_state]; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ - if (state > PM_SUSPEND_STANDBY) { + if (pm_state > PM_SUSPEND_STANDBY) { int error = acpi_save_state_mem(); if (error) return error; @@ -90,7 +91,8 @@ static int acpi_pm_enter(u32 state) local_irq_save(flags); - switch (state) + acpi_enable_wakeup_device(acpi_state); + switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); @@ -118,7 +120,7 @@ static int acpi_pm_enter(u32 state) * And, in the case of the latter, the memory image should have already * been loaded from disk. */ - if (state > PM_SUSPEND_STANDBY) + if (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); @@ -128,15 +130,18 @@ static int acpi_pm_enter(u32 state) /** * acpi_pm_finish - Finish up suspend sequence. - * @state: State we're coming out of. + * @pm_state: State we're coming out of. * * This is called after we wake back up (or if entering the sleep state * failed). */ -static int acpi_pm_finish(u32 state) +static int acpi_pm_finish(u32 pm_state) { - acpi_leave_sleep_state(state); + u32 acpi_state = acpi_suspend_states[pm_state]; + + acpi_leave_sleep_state(acpi_state); + acpi_disable_wakeup_device(acpi_state); /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); @@ -199,7 +204,7 @@ static int __init acpi_sleep_init(void) return 0; printk(KERN_INFO PREFIX "(supports"); - for (i=0; iwakeup.flags.valid) + continue; + spin_unlock(&acpi_device_lock); + if (dev->wakeup.flags.run_wake) + seq_printf(seq, "%4s %4d %8s\n", + dev->pnp.bus_id, (u32) dev->wakeup.sleep_state, + dev->wakeup.state.enabled ? "*enabled" : "*disabled"); + else + seq_printf(seq, "%4s %4d %8s\n", + dev->pnp.bus_id, (u32) dev->wakeup.sleep_state, + dev->wakeup.state.enabled ? "enabled" : "disabled"); + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); + return 0; +} + +static ssize_t +acpi_system_write_wakeup_device ( + struct file *file, + const char __user *buffer, + size_t count, + loff_t *ppos) +{ + struct list_head * node, * next; + char strbuf[5]; + char str[5] = ""; + int len = count; + + if (len > 4) len = 4; + + if (copy_from_user(strbuf, buffer, len)) + return -EFAULT; + strbuf[len] = '\0'; + sscanf(strbuf, "%s", str); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list); + if (!dev->wakeup.flags.valid) + continue; + + if (!strncmp(dev->pnp.bus_id, str, 4)) { + dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0:1; + break; + } + } + spin_unlock(&acpi_device_lock); + return count; +} + +static int +acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data); +} + +static struct file_operations acpi_system_wakeup_device_fops = { + .open = acpi_system_wakeup_device_open_fs, + .read = seq_read, + .write = acpi_system_write_wakeup_device, + .llseek = seq_lseek, + .release = single_release, +}; static struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, @@ -388,6 +467,13 @@ static int acpi_sleep_proc_init(void) S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_alarm_fops; + + /* 'wakeup device' [R/W]*/ + entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); + if (entry) + entry->proc_fops = &acpi_system_wakeup_device_fops; + return 0; } diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index ad38f4153..cfaf8f5b0 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h @@ -2,3 +2,6 @@ extern u8 sleep_states[]; extern int acpi_suspend (u32 state); +extern void acpi_enable_wakeup_device_prep(u8 sleep_state); +extern void acpi_enable_wakeup_device(u8 sleep_state); +extern void acpi_disable_wakeup_device(u8 sleep_state); diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c new file mode 100644 index 000000000..9c004b948 --- /dev/null +++ b/drivers/acpi/sleep/wakeup.c @@ -0,0 +1,181 @@ +/* + * wakeup.c - support wakeup devices + */ + +#include +#include +#include +#include +#include +#include +#include "sleep.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("wakeup_devices") + +/** + * acpi_enable_wakeup_device_prep - prepare wakeup devices + * @sleep_state: ACPI state + * Enable all wakup devices power if the devices' wakeup level + * is higher than requested sleep level + */ +extern struct list_head acpi_wakeup_device_list; +extern spinlock_t acpi_device_lock; + +void +acpi_enable_wakeup_device_prep( + u8 sleep_state) +{ + struct list_head * node, * next; + + ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + if (!dev->wakeup.flags.valid || + !dev->wakeup.state.enabled || + (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + spin_unlock(&acpi_device_lock); + acpi_enable_wakeup_device_power(dev); + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); +} + +/** + * acpi_enable_wakeup_device - enable wakeup devices + * @sleep_state: ACPI state + * Enable all wakup devices's GPE + */ +void +acpi_enable_wakeup_device( + u8 sleep_state) +{ + struct list_head * node, * next; + + /* + * Caution: this routine must be invoked when interrupt is disabled + * Refer ACPI2.0: P212 + */ + ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + /* If users want to disable run-wake GPE, + * we only disable it for wake and leave it for runtime + */ + if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_ISR); + spin_lock(&acpi_device_lock); + continue; + } + + if (!dev->wakeup.flags.valid || + !dev->wakeup.state.enabled || + (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + spin_unlock(&acpi_device_lock); + /* run-wake GPE has been enabled */ + if (!dev->wakeup.flags.run_wake) + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_ISR); + dev->wakeup.state.active = 1; + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); +} + +/** + * acpi_disable_wakeup_device - disable devices' wakeup capability + * @sleep_state: ACPI state + * Disable all wakup devices's GPE and wakeup capability + */ +void +acpi_disable_wakeup_device ( + u8 sleep_state) +{ + struct list_head * node, * next; + + ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + spin_lock(&acpi_device_lock); + continue; + } + + if (!dev->wakeup.flags.valid || + !dev->wakeup.state.active || + (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + spin_unlock(&acpi_device_lock); + acpi_disable_wakeup_device_power(dev); + /* Never disable run-wake GPE */ + if (!dev->wakeup.flags.run_wake) { + acpi_disable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + acpi_clear_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + } + dev->wakeup.state.active = 0; + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); +} + +static int __init acpi_wakeup_device_init(void) +{ + struct list_head * node, * next; + + if (acpi_disabled) + return 0; + printk("ACPI wakeup devices: \n"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device * dev = container_of(node, + struct acpi_device, wakeup_list); + + /* In case user doesn't load button driver */ + if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + dev->wakeup.state.enabled = 1; + spin_lock(&acpi_device_lock); + } + printk("%4s ", dev->pnp.bus_id); + } + spin_unlock(&acpi_device_lock); + printk("\n"); + + return 0; +} + +late_initcall(acpi_wakeup_device_init); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index e7480822b..fb64bd5d2 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -101,7 +101,7 @@ acpi_table_print ( else name = header->signature; - printk(KERN_INFO PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name, header->revision, header->oem_id, header->oem_table_id, header->oem_revision, header->asl_compiler_id, header->asl_compiler_revision, @@ -587,7 +587,7 @@ acpi_table_init (void) return -ENODEV; } - printk(KERN_INFO PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", rsdp->revision, rsdp->oem_id, (void *) rsdp_phys); if (rsdp->revision < 2) diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index b7328345d..4a9669590 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -115,17 +115,14 @@ acpi_tb_find_table ( * Instance - the non zero instance of the table, allows * support for multiple tables of the same type * Flags - Physical/Virtual support - * ret_buffer - pointer to a structure containing a buffer to - * receive the table + * table_pointer - Where a buffer containing the table is + * returned * * RETURN: Status * - * DESCRIPTION: This function is called to get an ACPI table. The caller - * supplies an out_buffer large enough to contain the entire ACPI - * table. Upon completion - * the out_buffer->Length field will indicate the number of bytes - * copied into the out_buffer->buf_ptr buffer. This table will be - * a complete table including the header. + * DESCRIPTION: This function is called to get an ACPI table. A buffer is + * allocated for the table and returned in table_pointer. + * This table will be a complete table including the header. * ******************************************************************************/ @@ -136,12 +133,11 @@ acpi_get_firmware_table ( u32 flags, struct acpi_table_header **table_pointer) { - struct acpi_pointer rsdp_address; - struct acpi_pointer address; acpi_status status; - struct acpi_table_header header; - struct acpi_table_desc table_info; - struct acpi_table_desc rsdt_info; + struct acpi_pointer address; + struct acpi_table_header *header = NULL; + struct acpi_table_desc *table_info = NULL; + struct acpi_table_desc *rsdt_info; u32 table_count; u32 i; u32 j; @@ -152,45 +148,41 @@ acpi_get_firmware_table ( /* * Ensure that at least the table manager is initialized. We don't - * require that the entire ACPI subsystem is up for this interface - */ - - /* - * If we have a buffer, we must have a length too + * require that the entire ACPI subsystem is up for this interface. + * If we have a buffer, we must have a length too */ - if ((instance == 0) || - (!signature) || + if ((instance == 0) || + (!signature) || (!table_pointer)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - rsdt_info.pointer = NULL; + /* Ensure that we have a RSDP */ if (!acpi_gbl_RSDP) { /* Get the RSDP */ - status = acpi_os_get_root_pointer (flags, &rsdp_address); + status = acpi_os_get_root_pointer (flags, &address); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } /* Map and validate the RSDP */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory (rsdp_address.pointer.physical, sizeof (struct rsdp_descriptor), + status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor), (void *) &acpi_gbl_RSDP); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } else { - acpi_gbl_RSDP = rsdp_address.pointer.logical; + acpi_gbl_RSDP = address.pointer.logical; } - /* - * The signature and checksum must both be correct - */ + /* The signature and checksum must both be correct */ + if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ @@ -204,10 +196,9 @@ acpi_get_firmware_table ( } } - /* Get the RSDT and validate it */ + /* Get the RSDT address via the RSDP */ acpi_tb_get_rsdt_address (&address); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, @@ -217,20 +208,40 @@ acpi_get_firmware_table ( address.pointer_type |= flags; - status = acpi_tb_get_table (&address, &rsdt_info); + /* Get and validate the RSDT */ + + rsdt_info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc)); + if (!rsdt_info) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_tb_get_table (&address, rsdt_info); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } - status = acpi_tb_validate_rsdt (rsdt_info.pointer); + status = acpi_tb_validate_rsdt (rsdt_info->pointer); if (ACPI_FAILURE (status)) { goto cleanup; } - /* Get the number of table pointers within the RSDT */ + /* Allocate a scratch table header and table descriptor */ + + header = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_header)); + if (!header) { + status = AE_NO_MEMORY; + goto cleanup; + } + + table_info = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_desc)); + if (!table_info) { + status = AE_NO_MEMORY; + goto cleanup; + } - table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info.pointer); + /* Get the number of table pointers within the RSDT */ + table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info->pointer); address.pointer_type = acpi_gbl_table_flags | flags; /* @@ -241,35 +252,36 @@ acpi_get_firmware_table ( /* Get the next table pointer, handle RSDT vs. XSDT */ if (acpi_gbl_RSDP->revision < 2) { - address.pointer.value = (ACPI_CAST_PTR (RSDT_DESCRIPTOR, rsdt_info.pointer))->table_offset_entry[i]; + address.pointer.value = (ACPI_CAST_PTR ( + RSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; } else { - address.pointer.value = - (ACPI_CAST_PTR (XSDT_DESCRIPTOR, rsdt_info.pointer))->table_offset_entry[i]; + address.pointer.value = (ACPI_CAST_PTR ( + XSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; } /* Get the table header */ - status = acpi_tb_get_table_header (&address, &header); + status = acpi_tb_get_table_header (&address, header); if (ACPI_FAILURE (status)) { goto cleanup; } /* Compare table signatures and table instance */ - if (!ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) { + if (!ACPI_STRNCMP (header->signature, signature, ACPI_NAME_SIZE)) { /* An instance of the table was found */ j++; if (j >= instance) { /* Found the correct instance, get the entire table */ - status = acpi_tb_get_table_body (&address, &header, &table_info); + status = acpi_tb_get_table_body (&address, header, table_info); if (ACPI_FAILURE (status)) { goto cleanup; } - *table_pointer = table_info.pointer; + *table_pointer = table_info->pointer; goto cleanup; } } @@ -281,7 +293,15 @@ acpi_get_firmware_table ( cleanup: - acpi_os_unmap_memory (rsdt_info.pointer, (acpi_size) rsdt_info.pointer->length); + acpi_os_unmap_memory (rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); + ACPI_MEM_FREE (rsdt_info); + + if (header) { + ACPI_MEM_FREE (header); + } + if (table_info) { + ACPI_MEM_FREE (table_info); + } return_ACPI_STATUS (status); } @@ -389,14 +409,17 @@ acpi_tb_scan_memory_for_rsdp ( * Flags - Current memory mode (logical vs. * physical addressing) * - * RETURN: Status + * RETURN: Status, RSDP physical address * * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor * pointer structure. If it is found, set *RSDP to point to it. * - * NOTE: The RSDp must be either in the first 1_k of the Extended - * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section - * 5.2.2; assertion #421). + * NOTE1: The RSDp must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) + * Only a 32-bit physical address is necessary. + * + * NOTE2: This function is always available, regardless of the + * initialization state of the rest of ACPI. * ******************************************************************************/ @@ -407,8 +430,8 @@ acpi_tb_find_rsdp ( { u8 *table_ptr; u8 *mem_rover; - u64 phys_addr; - acpi_status status = AE_OK; + u32 physical_address; + acpi_status status; ACPI_FUNCTION_TRACE ("tb_find_rsdp"); @@ -419,36 +442,57 @@ acpi_tb_find_rsdp ( */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { /* - * 1) Search EBDA (low memory) paragraphs + * 1a) Get the location of the EBDA */ - status = acpi_os_map_memory ((u64) ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH, (void *) &table_ptr); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", - ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", + ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); return_ACPI_STATUS (status); } - mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE); - acpi_os_unmap_memory (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE); + ACPI_MOVE_16_TO_32 (&physical_address, table_ptr); + physical_address <<= 4; /* Convert segment to physical address */ + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH); - if (mem_rover) { - /* Found it, return the physical address */ + /* EBDA present? */ - phys_addr = ACPI_LO_RSDP_WINDOW_BASE; - phys_addr += ACPI_PTR_DIFF (mem_rover,table_ptr); + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + status = acpi_os_map_memory ((acpi_physical_address) physical_address, + ACPI_EBDA_WINDOW_SIZE, + (void *) &table_ptr); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", + physical_address, ACPI_EBDA_WINDOW_SIZE)); + return_ACPI_STATUS (status); + } - table_info->physical_address = phys_addr; - return_ACPI_STATUS (AE_OK); + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE); + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE); + + if (mem_rover) { + /* Found it, return the physical address */ + + physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr); + + table_info->physical_address = (acpi_physical_address) physical_address; + return_ACPI_STATUS (AE_OK); + } } /* - * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - status = acpi_os_map_memory ((u64) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } @@ -459,10 +503,9 @@ acpi_tb_find_rsdp ( if (mem_rover) { /* Found it, return the physical address */ - phys_addr = ACPI_HI_RSDP_WINDOW_BASE; - phys_addr += ACPI_PTR_DIFF (mem_rover, table_ptr); + physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = phys_addr; + table_info->physical_address = (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -472,19 +515,29 @@ acpi_tb_find_rsdp ( */ else { /* - * 1) Search EBDA (low memory) paragraphs + * 1a) Get the location of the EBDA */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_LO_RSDP_WINDOW_BASE), - ACPI_LO_RSDP_WINDOW_SIZE); - if (mem_rover) { - /* Found it, return the physical address */ - - table_info->physical_address = ACPI_TO_INTEGER (mem_rover); - return_ACPI_STATUS (AE_OK); + ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION); + physical_address <<= 4; /* Convert segment to physical address */ + + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address), + ACPI_EBDA_WINDOW_SIZE); + if (mem_rover) { + /* Found it, return the physical address */ + + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); + return_ACPI_STATUS (AE_OK); + } } /* - * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 7b94ac081..05388672d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -60,6 +60,7 @@ #define ACPI_THERMAL_NOTIFY_HOT 0xF1 #define ACPI_THERMAL_MODE_ACTIVE 0x00 #define ACPI_THERMAL_MODE_PASSIVE 0x01 +#define ACPI_THERMAL_MODE_CRT 0xff #define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" #define ACPI_THERMAL_MAX_ACTIVE 10 @@ -160,6 +161,7 @@ struct acpi_thermal { unsigned long last_temperature; unsigned long polling_frequency; u8 cooling_mode; + volatile u8 zombie; struct acpi_thermal_flags flags; struct acpi_thermal_state state; struct acpi_thermal_trips trips; @@ -289,13 +291,6 @@ acpi_thermal_set_cooling_mode ( status = acpi_get_handle(tz->handle, "_SCP", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); - status = acpi_get_handle(tz->handle, "_PSV", &handle); - if(!ACPI_FAILURE(status)) { - tz->cooling_mode = 1; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", - mode?"passive":"active")); - return_VALUE(0); - } return_VALUE(-ENODEV); } @@ -653,7 +648,10 @@ static void acpi_thermal_run ( unsigned long data) { - acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_thermal_check, (void *) data); + struct acpi_thermal *tz = (struct acpi_thermal *)data; + if (!tz->zombie) + acpi_os_queue_for_execution(OSD_PRIORITY_GPE, + acpi_thermal_check, (void *) data); } @@ -665,7 +663,7 @@ acpi_thermal_check ( struct acpi_thermal *tz = (struct acpi_thermal *) data; unsigned long sleep_time = 0; int i = 0; - struct acpi_thermal_state state = tz->state; + struct acpi_thermal_state state; ACPI_FUNCTION_TRACE("acpi_thermal_check"); @@ -674,6 +672,8 @@ acpi_thermal_check ( return_VOID; } + state = tz->state; + result = acpi_thermal_get_temperature(tz); if (result) return_VOID; @@ -899,8 +899,10 @@ acpi_thermal_write_trip_points ( struct seq_file *m = (struct seq_file *)file->private_data; struct acpi_thermal *tz = (struct acpi_thermal *)m->private; - char limit_string[25] = {'\0'}; - int critical, hot, passive, active0, active1; + char limit_string[65] = {'\0'}; + int num, critical, hot, passive; + int active[ACPI_THERMAL_MAX_ACTIVE]; + int i = 0; ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points"); @@ -916,7 +918,11 @@ acpi_thermal_write_trip_points ( limit_string[count] = '\0'; - if (sscanf(limit_string, "%d:%d:%d:%d:%d", &critical, &hot, &passive, &active0, &active1) != 5) { + num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &critical, &hot, &passive, + &active[0], &active[1], &active[2], &active[3], &active[4], + &active[5], &active[6], &active[7], &active[8], &active[9]); + if(!(num >=5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n")); return_VALUE(-EINVAL); } @@ -924,8 +930,11 @@ acpi_thermal_write_trip_points ( tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical); tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot); tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive); - tz->trips.active[0].temperature = CELSIUS_TO_KELVIN(active0); - tz->trips.active[1].temperature = CELSIUS_TO_KELVIN(active1); + for (i = 0; i < num - 3; i++) { + if (!(tz->trips.active[i].flags.valid)) + break; + tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]); + } return_VALUE(count); } @@ -941,12 +950,14 @@ static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset) goto end; if (!tz->flags.cooling_mode) { - seq_puts(seq, "\n"); - goto end; + seq_puts(seq, "\n"); } - seq_printf(seq, "cooling mode: %s\n", - tz->cooling_mode?"passive":"active"); + if ( tz->cooling_mode == ACPI_THERMAL_MODE_CRT ) + seq_printf(seq, "cooling mode: critical\n"); + else + seq_printf(seq, "cooling mode: %s\n", + tz->cooling_mode?"passive":"active"); end: return 0; @@ -988,6 +999,8 @@ acpi_thermal_write_cooling_mode ( if (result) return_VALUE(result); + acpi_thermal_check(tz); + return_VALUE(count); } @@ -1225,16 +1238,34 @@ acpi_thermal_get_info ( if (result) return_VALUE(result); - /* Set the cooling mode [_SCP] to active cooling (default) */ - result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); - if (!result) - tz->flags.cooling_mode = 1; - /* Get trip points [_CRT, _PSV, etc.] (required) */ result = acpi_thermal_get_trip_points(tz); if (result) return_VALUE(result); + /* Set the cooling mode [_SCP] to active cooling (default) */ + result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); + if (!result) + tz->flags.cooling_mode = 1; + else { + /* Oh,we have not _SCP method. + Generally show cooling_mode by _ACx, _PSV,spec 12.2*/ + tz->flags.cooling_mode = 0; + if ( tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) { + if ( tz->trips.passive.temperature > tz->trips.active[0].temperature ) + tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE; + else + tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE; + } else if ( !tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) { + tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE; + } else if ( tz->trips.active[0].flags.valid && !tz->trips.passive.flags.valid ) { + tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE; + } else { + /* _ACx and _PSV are optional, but _CRT is required */ + tz->cooling_mode = ACPI_THERMAL_MODE_CRT; + } + } + /* Get default polling frequency [_TZP] (optional) */ if (tzp) tz->polling_frequency = tzp; @@ -1324,8 +1355,14 @@ acpi_thermal_remove ( tz = (struct acpi_thermal *) acpi_driver_data(device); - if (timer_pending(&(tz->timer))) - del_timer(&(tz->timer)); + /* avoid timer adding new defer task */ + tz->zombie = 1; + /* wait for running timer (on other CPUs) finish */ + del_timer_sync(&(tz->timer)); + /* synchronize deferred task */ + acpi_os_wait_events_complete(NULL); + /* deferred task may reinsert timer */ + del_timer_sync(&(tz->timer)); status = acpi_remove_notify_handler(tz->handle, ACPI_DEVICE_NOTIFY, acpi_thermal_notify); @@ -1347,6 +1384,7 @@ acpi_thermal_remove ( acpi_thermal_remove_fs(device); + kfree(tz); return_VALUE(0); } diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 2050d238d..58ec6733e 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -259,8 +259,8 @@ acpi_ut_validate_buffer ( * * FUNCTION: acpi_ut_initialize_buffer * - * PARAMETERS: required_length - Length needed - * Buffer - Buffer to be validated + * PARAMETERS: Buffer - Buffer to be validated + * required_length - Length needed * * RETURN: Status * @@ -603,7 +603,8 @@ acpi_ut_free_and_track ( * * FUNCTION: acpi_ut_find_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * * RETURN: A list element if found; NULL otherwise. * @@ -646,7 +647,8 @@ acpi_ut_find_allocation ( * * FUNCTION: acpi_ut_track_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * Size - Size of the allocation * alloc_type - MEM_MALLOC or MEM_CALLOC * Component - Component type of caller @@ -733,7 +735,8 @@ unlock_and_exit: * * FUNCTION: acpi_ut_remove_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * Component - Component type of caller * Module - Source file name of caller * Line - Line number of caller diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index c3f5900b6..0aa1fde7e 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -133,7 +133,7 @@ acpi_ut_evaluate_object ( u32 expected_return_btypes, union acpi_operand_object **return_desc) { - union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; acpi_status status; u32 return_btype; @@ -141,9 +141,13 @@ acpi_ut_evaluate_object ( ACPI_FUNCTION_TRACE ("ut_evaluate_object"); + info.node = prefix_node; + info.parameters = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + /* Evaluate the object/method */ - status = acpi_ns_evaluate_relative (prefix_node, path, NULL, &obj_desc); + status = acpi_ns_evaluate_relative (path, &info); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", @@ -159,7 +163,7 @@ acpi_ut_evaluate_object ( /* Did we get a return object? */ - if (!obj_desc) { + if (!info.return_object) { if (expected_return_btypes) { ACPI_REPORT_METHOD_ERROR ("No object was returned from", prefix_node, path, AE_NOT_EXIST); @@ -172,7 +176,7 @@ acpi_ut_evaluate_object ( /* Map the return object type to the bitmapped type */ - switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + switch (ACPI_GET_OBJECT_TYPE (info.return_object)) { case ACPI_TYPE_INTEGER: return_btype = ACPI_BTYPE_INTEGER; break; @@ -202,17 +206,17 @@ acpi_ut_evaluate_object ( ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Type returned from %s was incorrect: %X\n", - path, ACPI_GET_OBJECT_TYPE (obj_desc))); + path, ACPI_GET_OBJECT_TYPE (info.return_object))); /* On error exit, we must delete the return object */ - acpi_ut_remove_reference (obj_desc); + acpi_ut_remove_reference (info.return_object); return_ACPI_STATUS (AE_TYPE); } /* Object type is OK, return it */ - *return_desc = obj_desc; + *return_desc = info.return_object; return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index e1d19936e..f42848ab7 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -142,16 +142,11 @@ unknown: */ /* Debug switch - level and trace mask */ - -#ifdef ACPI_DEBUG_OUTPUT -u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; -#else -u32 acpi_dbg_level = ACPI_NORMAL_DEFAULT; -#endif +u32 acpi_dbg_level = 0; /* Debug switch - layer (component) mask */ -u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT; +u32 acpi_dbg_layer = 0; u32 acpi_gbl_nesting_level = 0; @@ -171,27 +166,40 @@ u8 acpi_gbl_shutdown = TRUE; const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; -const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { - "\\_S0_", - "\\_S1_", - "\\_S2_", - "\\_S3_", - "\\_S4_", - "\\_S5_"}; - -const char *acpi_gbl_highest_dstate_names[4] = { - "_S1D", - "_S2D", - "_S3D", - "_S4D"}; +const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = +{ + "\\_S0_", + "\\_S1_", + "\\_S2_", + "\\_S3_", + "\\_S4_", + "\\_S5_" +}; -/* Strings supported by the _OSI predefined (internal) method */ +const char *acpi_gbl_highest_dstate_names[4] = +{ + "_S1D", + "_S2D", + "_S3D", + "_S4D" +}; -const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { - "Linux", - "Windows 2000", - "Windows 2001", - "Windows 2001.1"}; +/* + * Strings supported by the _OSI predefined (internal) method. + * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS. + */ +const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = +{ + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001.1", + "Windows 2001 SP0", + "Windows 2001 SP1", + "Windows 2001 SP2", + "Windows 2001 SP3", + "Windows 2001 SP4" +}; /****************************************************************************** @@ -213,7 +221,7 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_SB_", ACPI_TYPE_DEVICE, NULL}, {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, - {"_TZ_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_TZ_", ACPI_TYPE_THERMAL, NULL}, {"_REV", ACPI_TYPE_INTEGER, "2"}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, @@ -561,26 +569,37 @@ acpi_ut_get_node_name ( struct acpi_namespace_node *node = (struct acpi_namespace_node *) object; + /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ + if (!object) { - return ("NULL NODE"); + return ("NULL"); } - if (object == ACPI_ROOT_OBJECT) + /* Check for Root node */ + + if ((object == ACPI_ROOT_OBJECT) || + (object == acpi_gbl_root_node)) { - node = acpi_gbl_root_node; + return ("\"\\\" "); } + /* Descriptor must be a namespace node */ + if (node->descriptor != ACPI_DESC_TYPE_NAMED) { - return ("****"); + return ("####"); } + /* Name must be a valid ACPI name */ + if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii)) { - return ("----"); + return ("????"); } + /* Return the name */ + return (node->name.ascii); } @@ -783,10 +802,6 @@ acpi_ut_init_globals ( ACPI_FUNCTION_TRACE ("ut_init_globals"); - /* Runtime configuration */ - - acpi_gbl_create_osi_method = TRUE; - acpi_gbl_all_methods_serialized = FALSE; /* Memory allocation and cache lists */ @@ -880,6 +895,7 @@ acpi_ut_init_globals ( /* Hardware oriented */ acpi_gbl_events_initialized = FALSE; + acpi_gbl_system_awake_and_running = TRUE; /* Namespace */ diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 5cbd93eef..45c14f9ef 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -157,9 +157,8 @@ acpi_enable_subsystem ( } } - /* - * Enable ACPI mode - */ + /* Enable ACPI mode */ + if (!(flags & ACPI_NO_ACPI_ENABLE)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n")); @@ -173,7 +172,21 @@ acpi_enable_subsystem ( } /* - * Initialize ACPI Event handling + * Install the default op_region handlers. These are installed unless + * other handlers have already been installed via the + * install_address_space_handler interface. + */ + if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + + status = acpi_ev_install_region_handlers (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Initialize ACPI Event handling (Fixed and General Purpose) * * NOTE: We must have the hardware AND events initialized before we can execute * ANY control methods SAFELY. Any control method can require ACPI hardware @@ -182,18 +195,18 @@ acpi_enable_subsystem ( if (!(flags & ACPI_NO_EVENT_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n")); - status = acpi_ev_initialize (); + status = acpi_ev_initialize_events (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } - /* Install the SCI handler, Global Lock handler, and GPE handlers */ + /* Install the SCI handler and Global Lock handler */ if (!(flags & ACPI_NO_HANDLER_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL/GPE handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n")); - status = acpi_ev_handler_initialize (); + status = acpi_ev_install_xrupt_handlers (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -226,18 +239,16 @@ acpi_initialize_objects ( /* - * Install the default op_region handlers. These are installed unless - * other handlers have already been installed via the - * install_address_space_handler interface. + * Run all _REG methods * - * NOTE: This will cause _REG methods to be run. Any objects accessed + * NOTE: Any objects accessed * by the _REG methods will be automatically initialized, even if they * contain executable AML (see call to acpi_ns_initialize_objects below). */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n")); - status = acpi_ev_init_address_spaces (); + status = acpi_ev_initialize_op_regions (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -249,7 +260,7 @@ acpi_initialize_objects ( * objects: operation_regions, buffer_fields, Buffers, and Packages. */ if (!(flags & ACPI_NO_OBJECT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Objects\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n")); status = acpi_ns_initialize_objects (); if (ACPI_FAILURE (status)) { diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index bcd60fb8d..907c5933a 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -3,7 +3,7 @@ # fore_200e-objs := fore200e.o -host-progs := fore200e_mkfirm +hostprogs-y := fore200e_mkfirm # Files generated that shall be removed upon make clean clean-files := atmsar11.bin atmsar11.bin1 atmsar11.bin2 pca200e.bin \ diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index fe809480e..9be4013f5 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -2291,11 +2291,10 @@ static int __init do_pci_device(struct pci_dev *pci_dev) // read resources from PCI configuration space u8 irq = pci_dev->irq; - u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0)); - u32 iobase = pci_resource_start (pci_dev, 1); PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at" - " IO %x, IRQ %u, MEM %p", iobase, irq, membase); + " IO %x, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1), + irq, bus_to_virt(pci_resource_start(pci_dev, 0))); // check IO region err = pci_request_region(pci_dev, 1, DEV_LABEL); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 8b137034d..81127d178 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -173,7 +173,7 @@ static void dump_mem(struct eni_dev *eni_dev) int i; for (i = 0; i < eni_dev->free_len; i++) - printk(KERN_DEBUG " %d: 0x%lx %d\n",i, + printk(KERN_DEBUG " %d: %p %d\n",i, eni_dev->free_list[i].start, 1 << eni_dev->free_list[i].order); } @@ -191,19 +191,19 @@ static void dump(struct atm_dev *dev) printk(KERN_NOTICE "TX buffers\n"); for (i = 0; i < NR_CHAN; i++) if (eni_dev->tx[i].send) - printk(KERN_NOTICE " TX %d @ 0x%lx: %ld\n",i, + printk(KERN_NOTICE " TX %d @ %p: %ld\n",i, eni_dev->tx[i].send,eni_dev->tx[i].words*4); printk(KERN_NOTICE "RX buffers\n"); for (i = 0; i < 1024; i++) if (eni_dev->rx_map[i] && ENI_VCC(eni_dev->rx_map[i])->rx) - printk(KERN_NOTICE " RX %d @ 0x%lx: %ld\n",i, + printk(KERN_NOTICE " RX %d @ %p: %ld\n",i, ENI_VCC(eni_dev->rx_map[i])->recv, ENI_VCC(eni_dev->rx_map[i])->words*4); printk(KERN_NOTICE "----\n"); } -static void eni_put_free(struct eni_dev *eni_dev,unsigned long start, +static void eni_put_free(struct eni_dev *eni_dev, void __iomem *start, unsigned long size) { struct eni_free *list; @@ -215,17 +215,17 @@ static void eni_put_free(struct eni_dev *eni_dev,unsigned long start, len = eni_dev->free_len; while (size) { if (len >= eni_dev->free_list_size) { - printk(KERN_CRIT "eni_put_free overflow (0x%lx,%ld)\n", + printk(KERN_CRIT "eni_put_free overflow (%p,%ld)\n", start,size); break; } - for (order = 0; !((start | size) & (1 << order)); order++); + for (order = 0; !(((unsigned long)start | size) & (1 << order)); order++); if (MID_MIN_BUF_SIZE > (1 << order)) { printk(KERN_CRIT "eni_put_free: order %d too small\n", order); break; } - list[len].start = start; + list[len].start = (void __iomem *) start; list[len].order = order; len++; start += 1 << order; @@ -236,10 +236,10 @@ static void eni_put_free(struct eni_dev *eni_dev,unsigned long start, } -static unsigned long eni_alloc_mem(struct eni_dev *eni_dev,unsigned long *size) +static void __iomem *eni_alloc_mem(struct eni_dev *eni_dev, unsigned long *size) { struct eni_free *list; - unsigned long start; + void __iomem *start; int len,i,order,best_order,index; list = eni_dev->free_list; @@ -273,7 +273,7 @@ static unsigned long eni_alloc_mem(struct eni_dev *eni_dev,unsigned long *size) } -static void eni_free_mem(struct eni_dev *eni_dev,unsigned long start, +static void eni_free_mem(struct eni_dev *eni_dev, void __iomem *start, unsigned long size) { struct eni_free *list; @@ -283,20 +283,20 @@ static void eni_free_mem(struct eni_dev *eni_dev,unsigned long start, list = eni_dev->free_list; len = eni_dev->free_len; for (order = -1; size; order++) size >>= 1; - DPRINTK("eni_free_mem: 0x%lx+0x%lx (order %d)\n",start,size,order); + DPRINTK("eni_free_mem: %p+0x%lx (order %d)\n",start,size,order); for (i = 0; i < len; i++) - if (list[i].start == (start^(1 << order)) && + if (((unsigned long) list[i].start) == ((unsigned long)start^(1 << order)) && list[i].order == order) { DPRINTK("match[%d]: 0x%lx/0x%lx(0x%x), %d/%d\n",i, list[i].start,start,1 << order,list[i].order,order); list[i] = list[--len]; - start &= ~(unsigned long) (1 << order); + start = (void __iomem *) ((unsigned long) start & ~(unsigned long) (1 << order)); order++; i = -1; continue; } if (len >= eni_dev->free_list_size) { - printk(KERN_ALERT "eni_free_mem overflow (0x%lx,%d)\n",start, + printk(KERN_ALERT "eni_free_mem overflow (%p,%d)\n",start, order); return; } @@ -333,7 +333,7 @@ static void rx_ident_err(struct atm_vcc *vcc) printk(KERN_ALERT " host descr 0x%lx, rx pos 0x%lx, descr value " "0x%x\n",eni_vcc->descr,eni_vcc->rx_pos, (unsigned) readl(eni_vcc->recv+eni_vcc->descr*4)); - printk(KERN_ALERT " last 0x%p, servicing %d\n",eni_vcc->last, + printk(KERN_ALERT " last %p, servicing %d\n",eni_vcc->last, eni_vcc->servicing); EVENT("---dump ends here---\n",0,0); printk(KERN_NOTICE "---recent events---\n"); @@ -617,7 +617,8 @@ static int rx_aal5(struct atm_vcc *vcc) static inline int rx_vcc(struct atm_vcc *vcc) { - unsigned long vci_dsc,tmp; + void __iomem *vci_dsc; + unsigned long tmp; struct eni_vcc *eni_vcc; eni_vcc = ENI_VCC(vcc); @@ -728,7 +729,7 @@ static void dequeue_rx(struct atm_dev *dev) struct eni_vcc *eni_vcc; struct atm_vcc *vcc; struct sk_buff *skb; - unsigned long vci_dsc; + void __iomem *vci_dsc; int first; eni_dev = ENI_DEV(dev); @@ -808,7 +809,7 @@ static int open_rx_first(struct atm_vcc *vcc) static int open_rx_second(struct atm_vcc *vcc) { - unsigned long here; + void __iomem *here; struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; unsigned long size; @@ -840,7 +841,7 @@ static int open_rx_second(struct atm_vcc *vcc) static void close_rx(struct atm_vcc *vcc) { DECLARE_WAITQUEUE(wait,current); - unsigned long here; + void __iomem *here; struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; @@ -1289,7 +1290,8 @@ static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp, struct eni_dev *eni_dev = ENI_DEV(vcc->dev); struct eni_vcc *eni_vcc = ENI_VCC(vcc); struct eni_tx *tx; - unsigned long size,mem; + unsigned long size; + void __iomem *mem; int rate,ubr,unlimited,new_tx; int pre,res,order; int error; @@ -1687,9 +1689,9 @@ static int __devinit get_esi_asic(struct atm_dev *dev) #undef GET_SEPROM -static int __devinit get_esi_fpga(struct atm_dev *dev,unsigned long base) +static int __devinit get_esi_fpga(struct atm_dev *dev, void __iomem *base) { - unsigned long mac_base; + void __iomem *mac_base; int i; mac_base = base+EPROM_SIZE-sizeof(struct midway_eprom); @@ -1703,7 +1705,8 @@ static int __devinit eni_do_init(struct atm_dev *dev) struct midway_eprom *eprom; struct eni_dev *eni_dev; struct pci_dev *pci_dev; - unsigned long real_base,base; + unsigned long real_base; + void __iomem *base; unsigned char revision; int error,i,last; @@ -1730,13 +1733,13 @@ static int __devinit eni_do_init(struct atm_dev *dev) } printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); - if (!(base = (unsigned long) ioremap_nocache(real_base,MAP_MAX_SIZE))) { + if (!(base = ioremap_nocache(real_base,MAP_MAX_SIZE))) { printk("\n"); printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page " "mapping\n",dev->number); return error; } - eni_dev->base_diff = real_base-base; + eni_dev->base_diff = real_base - (unsigned long) base; /* id may not be present in ASIC Tonga boards - check this @@@ */ if (!eni_dev->asic) { eprom = (struct midway_eprom *) (base+EPROM_SIZE-sizeof(struct @@ -1790,7 +1793,9 @@ static int __devinit eni_do_init(struct atm_dev *dev) static int __devinit eni_start(struct atm_dev *dev) { struct eni_dev *eni_dev; - unsigned long buf,buffer_mem; + + void __iomem *buf; + unsigned long buffer_mem; int error; DPRINTK(">eni_start\n"); @@ -1828,7 +1833,7 @@ static int __devinit eni_start(struct atm_dev *dev) tasklet_init(&eni_dev->task,eni_tasklet,(unsigned long) dev); eni_dev->events = 0; /* initialize memory management */ - buffer_mem = eni_dev->mem-(buf-eni_dev->ram); + buffer_mem = eni_dev->mem - (buf - eni_dev->ram); eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2; eni_dev->free_list = (struct eni_free *) kmalloc( sizeof(struct eni_free)*(eni_dev->free_list_size+1),GFP_KERNEL); @@ -1955,7 +1960,7 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) */ tasklet_disable(&eni_dev->task); skb_queue_walk(&eni_dev->tx_queue, skb) { - unsigned long dsc; + void __iomem *dsc; if (ATM_SKB(skb)->vcc != vcc) continue; dsc = tx->send+ENI_PRV_POS(skb)*4; @@ -2136,9 +2141,9 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) if (!tx->send) continue; if (!--left) { - return sprintf(page,"tx[%d]: 0x%06lx-0x%06lx " + return sprintf(page,"tx[%d]: 0x%ld-0x%ld " "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, - tx->send-eni_dev->ram, + (unsigned long) (tx->send - eni_dev->ram), tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, tx->reserved,tx->shaping, tx == eni_dev->ubr ? " (UBR)" : ""); @@ -2162,9 +2167,9 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) if (--left) continue; length = sprintf(page,"vcc %4d: ",vcc->vci); if (eni_vcc->rx) { - length += sprintf(page+length,"0x%06lx-0x%06lx " + length += sprintf(page+length,"0x%ld-0x%ld " "(%6ld bytes)", - eni_vcc->recv-eni_dev->ram, + (unsigned long) (eni_vcc->recv - eni_dev->ram), eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1, eni_vcc->words*4); if (eni_vcc->tx) length += sprintf(page+length,", "); @@ -2183,8 +2188,8 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) unsigned long offset; if (--left) continue; - offset = eni_dev->ram+eni_dev->base_diff; - return sprintf(page,"free 0x%06lx-0x%06lx (%6d bytes)\n", + offset = (unsigned long) eni_dev->ram+eni_dev->base_diff; + return sprintf(page,"free %p-%p (%6d bytes)\n", fe->start-offset,fe->start-offset+(1 << fe->order)-1, 1 << fe->order); } diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h index e7af66bd8..385090c2a 100644 --- a/drivers/atm/eni.h +++ b/drivers/atm/eni.h @@ -33,12 +33,12 @@ struct eni_free { - unsigned long start; /* counting in bytes */ + void __iomem *start; /* counting in bytes */ int order; }; struct eni_tx { - unsigned long send; /* base, 0 if unused */ + void __iomem *send; /* base, 0 if unused */ int prescaler; /* shaping prescaler */ int resolution; /* shaping divider */ unsigned long tx_pos; /* current TX write position */ @@ -51,7 +51,7 @@ struct eni_tx { struct eni_vcc { int (*rx)(struct atm_vcc *vcc); /* RX function, NULL if none */ - unsigned long recv; /* receive buffer */ + void __iomem *recv; /* receive buffer */ unsigned long words; /* its size in words */ unsigned long descr; /* next descriptor (RX) */ unsigned long rx_pos; /* current RX descriptor pos */ @@ -72,13 +72,13 @@ struct eni_dev { u32 events; /* pending events */ /*-------------------------------- base pointers into Midway address space */ - unsigned long phy; /* PHY interface chip registers */ - unsigned long reg; /* register base */ - unsigned long ram; /* RAM base */ - unsigned long vci; /* VCI table */ - unsigned long rx_dma; /* RX DMA queue */ - unsigned long tx_dma; /* TX DMA queue */ - unsigned long service; /* service list */ + void __iomem *phy; /* PHY interface chip registers */ + void __iomem *reg; /* register base */ + void __iomem *ram; /* RAM base */ + void __iomem *vci; /* VCI table */ + void __iomem *rx_dma; /* RX DMA queue */ + void __iomem *tx_dma; /* TX DMA queue */ + void __iomem *service; /* service list */ /*-------------------------------- TX part */ struct eni_tx tx[NR_CHAN]; /* TX channels */ struct eni_tx *ubr; /* UBR channel */ diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 91b85a95d..68919a710 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1667,7 +1667,7 @@ static int __devinit fs_init (struct fs_dev *dev) dev->hw_base = pci_resource_start(pci_dev, 0); - dev->base = (ulong) ioremap(dev->hw_base, 0x1000); + dev->base = ioremap(dev->hw_base, 0x1000); reset_chip (dev); @@ -1704,8 +1704,7 @@ static int __devinit fs_init (struct fs_dev *dev) } /* Try again after 10ms. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout ((HZ+99)/100); + msleep(10); } if (!to) { diff --git a/drivers/atm/firestream.h b/drivers/atm/firestream.h index 8ef266cc8..49e783e35 100644 --- a/drivers/atm/firestream.h +++ b/drivers/atm/firestream.h @@ -477,7 +477,7 @@ struct fs_dev { struct timer_list timer; unsigned long hw_base; /* mem base address */ - unsigned long base; /* Mapping of base address */ + void __iomem *base; /* Mapping of base address */ int channo; unsigned long channel_mask; diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index aca550b66..420216561 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -565,7 +565,7 @@ typedef struct host_cmdq_entry { typedef struct chunk { void* alloc_addr; /* base address of allocated chunk */ void* align_addr; /* base address of aligned chunk */ - u32 dma_addr; /* DMA address of aligned chunk */ + dma_addr_t dma_addr; /* DMA address of aligned chunk */ int direction; /* direction of DMA mapping */ u32 alloc_size; /* length of allocated chunk */ u32 align_size; /* length of aligned chunk */ diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 71e5b5146..74b490bc4 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1007,6 +1007,7 @@ he_start(struct atm_dev *dev) { struct he_dev *he_dev; struct pci_dev *pci_dev; + unsigned long membase; u16 command; u32 gen_cntl_0, host_cntl, lb_swap; @@ -1019,8 +1020,8 @@ he_start(struct atm_dev *dev) he_dev = HE_DEV(dev); pci_dev = he_dev->pci_dev; - he_dev->membase = pci_dev->resource[0].start; - HPRINTK("membase = 0x%lx irq = %d.\n", he_dev->membase, pci_dev->irq); + membase = pci_resource_start(pci_dev, 0); + HPRINTK("membase = 0x%lx irq = %d.\n", membase, pci_dev->irq); /* * pci bus controller initialization @@ -1080,7 +1081,7 @@ he_start(struct atm_dev *dev) hprintk("can't set latency timer to %d\n", timer); } - if (!(he_dev->membase = (unsigned long) ioremap(he_dev->membase, HE_REGMAP_SIZE))) { + if (!(he_dev->membase = ioremap(membase, HE_REGMAP_SIZE))) { hprintk("can't set up page mapping\n"); return -EINVAL; } @@ -1962,7 +1963,7 @@ he_service_tbrq(struct he_dev *he_dev, int group) struct he_tpd *tpd; int slot, updated = 0; #ifdef USE_TPD_POOL - struct list_head *p; + struct he_tpd *__tpd; #endif /* 2.1.6 transmit buffer return queue */ @@ -1977,8 +1978,7 @@ he_service_tbrq(struct he_dev *he_dev, int group) TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); #ifdef USE_TPD_POOL tpd = NULL; - list_for_each(p, &he_dev->outstanding_tpds) { - struct he_tpd *__tpd = list_entry(p, struct he_tpd, entry); + list_for_each_entry(__tpd, &he_dev->outstanding_tpds, entry) { if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { tpd = __tpd; list_del(&__tpd->entry); @@ -2595,9 +2595,8 @@ he_close(struct atm_vcc *vcc) while (((tx_inuse = atomic_read(&vcc->sk->sk_wmem_alloc)) > 0) && (retry < MAX_RETRY)) { - set_current_state(TASK_UNINTERRUPTIBLE); - (void) schedule_timeout(sleep); - if (sleep < HZ) + msleep(sleep); + if (sleep < 250) sleep = sleep * 2; ++retry; diff --git a/drivers/atm/he.h b/drivers/atm/he.h index 0a4adaf4b..7075ef4aa 100644 --- a/drivers/atm/he.h +++ b/drivers/atm/he.h @@ -265,7 +265,7 @@ struct he_cs_stper struct he_dev { unsigned int number; unsigned int irq; - unsigned long membase; + void __iomem *membase; char prod_id[30]; char mac_addr[6]; diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index b2bede540..3959cf83e 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -2516,7 +2516,7 @@ idt77252_close(struct atm_vcc *vcc) struct vc_map *vc = vcc->dev_data; unsigned long flags; unsigned long addr; - int timeout; + unsigned long timeout; down(&card->mutex); @@ -2566,9 +2566,9 @@ done: } spin_unlock_irqrestore(&vc->lock, flags); - timeout = 5 * HZ; + timeout = 5 * 1000; while (atomic_read(&vc->scq->used) > 0) { - timeout = schedule_timeout(timeout); + timeout = msleep_interruptible(timeout); if (!timeout) break; } @@ -3164,7 +3164,7 @@ deinit_card(struct idt77252_dev *card) for (i = 0; i < 4; i++) { if (card->fbq[i]) - iounmap((void *) card->fbq[i]); + iounmap(card->fbq[i]); } if (card->membase) @@ -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)); @@ -3715,26 +3722,24 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) card->tst_timer.function = tst_timer; /* Do the I/O remapping... */ - card->membase = (unsigned long) ioremap(membase, 1024); + card->membase = 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,22 +3748,19 @@ 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 */ card->sramsize = probe_sram(card); for (i = 0; i < 4; i++) { - card->fbq[i] = (unsigned long) - ioremap(srambase | 0x200000 | (i << 18), 4); + card->fbq[i] = 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 +3771,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 +3784,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 +3793,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 +3862,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/atm/idt77252.h b/drivers/atm/idt77252.h index 5a087c4e9..cfdd15e7d 100644 --- a/drivers/atm/idt77252.h +++ b/drivers/atm/idt77252.h @@ -355,9 +355,9 @@ struct idt77252_dev struct pci_dev *pcidev; /* PCI handle (desriptor) */ struct atm_dev *atmdev; /* ATM device desriptor */ - unsigned long membase; /* SAR's memory base address */ + void __iomem *membase; /* SAR's memory base address */ unsigned long srambase; /* SAR's sram base address */ - unsigned long fbq[4]; /* FBQ fill addresses */ + void __iomem *fbq[4]; /* FBQ fill addresses */ struct semaphore mutex; spinlock_t cmd_lock; /* for r/w utility/sram */ diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 53f6d29c5..e23d3f714 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -191,7 +191,7 @@ #define LANAI_EEPROM_SIZE (128) typedef int vci_t; -typedef unsigned long bus_addr_t; +typedef void __iomem *bus_addr_t; /* DMA buffer in host memory for TX, RX, or service list. */ struct lanai_buffer { @@ -471,7 +471,7 @@ enum lanai_register { static inline bus_addr_t reg_addr(const struct lanai_dev *lanai, enum lanai_register reg) { - return lanai->base + (bus_addr_t) reg; + return lanai->base + reg; } static inline u32 reg_read(const struct lanai_dev *lanai, @@ -651,7 +651,7 @@ static inline u32 cardvcc_read(const struct lanai_vcc *lvcc, { u32 val; APRINTK(lvcc->vbase != 0, "cardvcc_read: unbound vcc!\n"); - val= readl(lvcc->vbase + (bus_addr_t) offset); + val= readl(lvcc->vbase + offset); RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n", lvcc->vci, (int) offset, val); return val; @@ -666,7 +666,7 @@ static inline void cardvcc_write(const struct lanai_vcc *lvcc, (unsigned int) val, lvcc->vci, (unsigned int) offset); RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n", lvcc->vci, (unsigned int) offset, (unsigned int) val); - writel(val, lvcc->vbase + (bus_addr_t) offset); + writel(val, lvcc->vbase + offset); } /* -------------------- COMPUTE SIZE OF AN AAL5 PDU: */ @@ -813,7 +813,7 @@ static void lanai_shutdown_tx_vci(struct lanai_dev *lanai, DPRINTK("read, write = %d, %d\n", read, write); break; } - schedule_timeout(HZ / 25); + msleep(40); } /* 15.2.2 - clear out all tx registers */ cardvcc_write(lvcc, 0, vcc_txreadptr); @@ -2177,7 +2177,7 @@ static int __init lanai_dev_open(struct atm_dev *atmdev) /* 3.2: PCI initialization */ if ((result = lanai_pci_start(lanai)) != 0) goto error; - raw_base = (bus_addr_t) lanai->pci->resource[0].start; + raw_base = lanai->pci->resource[0].start; lanai->base = (bus_addr_t) ioremap(raw_base, LANAI_MAPPING_SIZE); if (lanai->base == 0) { printk(KERN_ERR DEV_LABEL ": couldn't remap I/O space\n"); diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index b63669c1f..3f18782bd 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -467,6 +467,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) u32 u32d[4]; u32 ns_cfg_rctsize; int bcount; + unsigned long membase; error = 0; @@ -494,8 +495,8 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) card->index = i; card->atmdev = NULL; card->pcidev = pcidev; - card->membase = pci_resource_start(pcidev, 1); - card->membase = (unsigned long) ioremap(card->membase, NS_IOREMAP_SIZE); + membase = pci_resource_start(pcidev, 1); + card->membase = ioremap(membase, NS_IOREMAP_SIZE); if (card->membase == 0) { printk("nicstar%d: can't ioremap() membase.\n",i); diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h index f762abcf2..a7eaee736 100644 --- a/drivers/atm/nicstar.h +++ b/drivers/atm/nicstar.h @@ -763,7 +763,7 @@ typedef struct ns_dev { int index; /* Card ID to the device driver */ int sram_size; /* In k x 32bit words. 32 or 128 */ - unsigned long membase; /* Card's memory base address */ + void __iomem *membase; /* Card's memory base address */ unsigned long max_pcr; int rct_size; /* Number of entries */ int vpibits; diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c index ef6b0c9f8..7a842ef71 100644 --- a/drivers/atm/nicstarmac.c +++ b/drivers/atm/nicstarmac.c @@ -162,7 +162,7 @@ nicstar_read_eprom_status( virt_addr_t base ) */ static u_int8_t -read_eprom_byte(u_int32_t base, u_int8_t offset) +read_eprom_byte(virt_addr_t base, u_int8_t offset) { u_int32_t val = 0; int i,j=0; diff --git a/drivers/atm/nicstarmac.h b/drivers/atm/nicstarmac.h index 0592daee4..80beec52f 100644 --- a/drivers/atm/nicstarmac.h +++ b/drivers/atm/nicstarmac.h @@ -7,7 +7,7 @@ ******************************************************************************/ -typedef unsigned int virt_addr_t; +typedef void __iomem *virt_addr_t; u_int32_t nicstar_read_eprom_status( virt_addr_t base ); void nicstar_init_eprom( virt_addr_t base ); diff --git a/drivers/base/class.c b/drivers/base/class.c index 2693bb545..70be97450 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/firmware_class.c b/drivers/base/firmware_class.c index a57ba84eb..6e17867db 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -235,6 +235,8 @@ firmware_data_write(struct kobject *kobj, struct firmware *fw; ssize_t retval; + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; down(&fw_lock); fw = fw_priv->fw; if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { diff --git a/drivers/base/node.c b/drivers/base/node.c index c1187363f..df74785ef 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/DAC960.c b/drivers/block/DAC960.c index 56b9ce97c..48c3e6399 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -288,12 +288,17 @@ static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) Controller->PCIDevice, DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T), sizeof(DAC960_V2_ScatterGatherSegment_T), 0); + if (ScatterGatherPool == NULL) + return DAC960_Failure(Controller, + "AUXILIARY STRUCTURE CREATION (SG)"); RequestSensePool = pci_pool_create("DAC960_V2_RequestSense", Controller->PCIDevice, sizeof(DAC960_SCSI_RequestSense_T), sizeof(int), 0); - if (ScatterGatherPool == NULL || RequestSensePool == NULL) + if (RequestSensePool == NULL) { + pci_pool_destroy(ScatterGatherPool); return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION (SG)"); + } Controller->ScatterGatherPool = ScatterGatherPool; Controller->V2.RequestSensePool = RequestSensePool; } @@ -535,7 +540,7 @@ static void DAC960_WaitForCommand(DAC960_Controller_T *Controller) static void DAC960_BA_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_CommandMailbox_T *NextCommandMailbox = Controller->V2.NextCommandMailbox; @@ -560,7 +565,7 @@ static void DAC960_BA_QueueCommand(DAC960_Command_T *Command) static void DAC960_LP_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_CommandMailbox_T *NextCommandMailbox = Controller->V2.NextCommandMailbox; @@ -586,7 +591,7 @@ static void DAC960_LP_QueueCommand(DAC960_Command_T *Command) static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -612,7 +617,7 @@ static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command) static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -638,7 +643,7 @@ static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command) static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -664,7 +669,7 @@ static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command) static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox = Controller->V1.NextCommandMailbox; @@ -689,7 +694,7 @@ static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command) static void DAC960_PD_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; while (DAC960_PD_MailboxFullP(ControllerBaseAddress)) @@ -706,7 +711,7 @@ static void DAC960_PD_QueueCommand(DAC960_Command_T *Command) static void DAC960_P_QueueCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; switch (CommandMailbox->Common.CommandOpcode) @@ -1127,7 +1132,7 @@ static boolean DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller, static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_HardwareType_T hw_type = Controller->HardwareType; struct pci_dev *PCI_Device = Controller->PCIDevice; struct dma_loaf *DmaPages = &Controller->DmaPages; @@ -1333,7 +1338,7 @@ skip_mailboxes: static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; struct pci_dev *PCI_Device = Controller->PCIDevice; struct dma_loaf *DmaPages = &Controller->DmaPages; size_t DmaPagesSize; @@ -2674,7 +2679,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device, unsigned char DeviceFunction = PCI_Device->devfn; unsigned char ErrorStatus, Parameter0, Parameter1; unsigned int IRQ_Channel = PCI_Device->irq; - void *BaseAddress; + void __iomem *BaseAddress; int i; Controller = (DAC960_Controller_T *) @@ -5196,7 +5201,7 @@ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5239,7 +5244,7 @@ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5282,7 +5287,7 @@ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5321,7 +5326,7 @@ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5360,7 +5365,7 @@ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; unsigned long flags; spin_lock_irqsave(&Controller->queue_lock, flags); @@ -5399,7 +5404,7 @@ static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel, struct pt_regs *InterruptRegisters) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; - void *ControllerBaseAddress = Controller->BaseAddress; + void __iomem *ControllerBaseAddress = Controller->BaseAddress; unsigned long flags; spin_lock_irqsave(&Controller->queue_lock, flags); diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index be8f8992a..d5e8e7190 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2282,8 +2282,8 @@ DAC960_Command_T; typedef struct DAC960_Controller { - void *BaseAddress; - void *MemoryMappedAddress; + void __iomem *BaseAddress; + void __iomem *MemoryMappedAddress; DAC960_FirmwareType_T FirmwareType; DAC960_HardwareType_T HardwareType; DAC960_IO_Address_T IO_Address; @@ -2527,7 +2527,7 @@ DAC960_Controller_T; * dma_addr_t. */ static inline -void dma_addr_writeql(dma_addr_t addr, void *write_address) +void dma_addr_writeql(dma_addr_t addr, void __iomem *write_address) { union { u64 wq; @@ -2643,7 +2643,7 @@ DAC960_BA_ErrorStatusRegister_T; */ static inline -void DAC960_BA_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_BA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2653,7 +2653,7 @@ void DAC960_BA_HardwareMailboxNewCommand(void *ControllerBaseAddress) } static inline -void DAC960_BA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2663,7 +2663,7 @@ void DAC960_BA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) } static inline -void DAC960_BA_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_BA_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2673,7 +2673,7 @@ void DAC960_BA_GenerateInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_BA_ControllerReset(void *ControllerBaseAddress) +void DAC960_BA_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2683,7 +2683,7 @@ void DAC960_BA_ControllerReset(void *ControllerBaseAddress) } static inline -void DAC960_BA_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_BA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2693,7 +2693,7 @@ void DAC960_BA_MemoryMailboxNewCommand(void *ControllerBaseAddress) } static inline -boolean DAC960_BA_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -2702,7 +2702,7 @@ boolean DAC960_BA_HardwareMailboxFullP(void *ControllerBaseAddress) } static inline -boolean DAC960_BA_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -2711,7 +2711,7 @@ boolean DAC960_BA_InitializationInProgressP(void *ControllerBaseAddress) } static inline -void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -2721,7 +2721,7 @@ void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -2731,7 +2731,7 @@ void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_BA_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_BA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -2742,7 +2742,7 @@ void DAC960_BA_AcknowledgeInterrupt(void *ControllerBaseAddress) } static inline -boolean DAC960_BA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -2751,7 +2751,7 @@ boolean DAC960_BA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -boolean DAC960_BA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -2760,7 +2760,7 @@ boolean DAC960_BA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -void DAC960_BA_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_BA_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -2771,7 +2771,7 @@ void DAC960_BA_EnableInterrupts(void *ControllerBaseAddress) } static inline -void DAC960_BA_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_BA_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -2782,7 +2782,7 @@ void DAC960_BA_DisableInterrupts(void *ControllerBaseAddress) } static inline -boolean DAC960_BA_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -2805,7 +2805,7 @@ void DAC960_BA_WriteCommandMailbox(DAC960_V2_CommandMailbox_T static inline -void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_BA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, dma_addr_t CommandMailboxDMA) { dma_addr_writeql(CommandMailboxDMA, @@ -2814,19 +2814,19 @@ void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress, } static inline DAC960_V2_CommandIdentifier_T -DAC960_BA_ReadCommandIdentifier(void *ControllerBaseAddress) +DAC960_BA_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset); } static inline DAC960_V2_CommandStatus_T -DAC960_BA_ReadCommandStatus(void *ControllerBaseAddress) +DAC960_BA_ReadCommandStatus(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2); } static inline boolean -DAC960_BA_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_BA_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -2948,7 +2948,7 @@ DAC960_LP_ErrorStatusRegister_T; */ static inline -void DAC960_LP_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LP_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2958,7 +2958,7 @@ void DAC960_LP_HardwareMailboxNewCommand(void *ControllerBaseAddress) } static inline -void DAC960_LP_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2968,7 +2968,7 @@ void DAC960_LP_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) } static inline -void DAC960_LP_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_LP_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2978,7 +2978,7 @@ void DAC960_LP_GenerateInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_LP_ControllerReset(void *ControllerBaseAddress) +void DAC960_LP_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2988,7 +2988,7 @@ void DAC960_LP_ControllerReset(void *ControllerBaseAddress) } static inline -void DAC960_LP_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LP_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -2998,7 +2998,7 @@ void DAC960_LP_MemoryMailboxNewCommand(void *ControllerBaseAddress) } static inline -boolean DAC960_LP_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3007,7 +3007,7 @@ boolean DAC960_LP_HardwareMailboxFullP(void *ControllerBaseAddress) } static inline -boolean DAC960_LP_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3016,7 +3016,7 @@ boolean DAC960_LP_InitializationInProgressP(void *ControllerBaseAddress) } static inline -void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3026,7 +3026,7 @@ void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3036,7 +3036,7 @@ void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_LP_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_LP_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3047,7 +3047,7 @@ void DAC960_LP_AcknowledgeInterrupt(void *ControllerBaseAddress) } static inline -boolean DAC960_LP_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3056,7 +3056,7 @@ boolean DAC960_LP_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -boolean DAC960_LP_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3065,7 +3065,7 @@ boolean DAC960_LP_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -void DAC960_LP_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_LP_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3075,7 +3075,7 @@ void DAC960_LP_EnableInterrupts(void *ControllerBaseAddress) } static inline -void DAC960_LP_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_LP_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3085,7 +3085,7 @@ void DAC960_LP_DisableInterrupts(void *ControllerBaseAddress) } static inline -boolean DAC960_LP_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3107,7 +3107,7 @@ void DAC960_LP_WriteCommandMailbox(DAC960_V2_CommandMailbox_T } static inline -void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_LP_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, dma_addr_t CommandMailboxDMA) { dma_addr_writeql(CommandMailboxDMA, @@ -3116,19 +3116,19 @@ void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress, } static inline DAC960_V2_CommandIdentifier_T -DAC960_LP_ReadCommandIdentifier(void *ControllerBaseAddress) +DAC960_LP_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset); } static inline DAC960_V2_CommandStatus_T -DAC960_LP_ReadCommandStatus(void *ControllerBaseAddress) +DAC960_LP_ReadCommandStatus(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2); } static inline boolean -DAC960_LP_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_LP_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -3262,7 +3262,7 @@ DAC960_LA_ErrorStatusRegister_T; */ static inline -void DAC960_LA_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3272,7 +3272,7 @@ void DAC960_LA_HardwareMailboxNewCommand(void *ControllerBaseAddress) } static inline -void DAC960_LA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3282,7 +3282,7 @@ void DAC960_LA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) } static inline -void DAC960_LA_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_LA_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3292,7 +3292,7 @@ void DAC960_LA_GenerateInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_LA_ControllerReset(void *ControllerBaseAddress) +void DAC960_LA_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3302,7 +3302,7 @@ void DAC960_LA_ControllerReset(void *ControllerBaseAddress) } static inline -void DAC960_LA_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_LA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3312,7 +3312,7 @@ void DAC960_LA_MemoryMailboxNewCommand(void *ControllerBaseAddress) } static inline -boolean DAC960_LA_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3321,7 +3321,7 @@ boolean DAC960_LA_HardwareMailboxFullP(void *ControllerBaseAddress) } static inline -boolean DAC960_LA_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3330,7 +3330,7 @@ boolean DAC960_LA_InitializationInProgressP(void *ControllerBaseAddress) } static inline -void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3340,7 +3340,7 @@ void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3350,7 +3350,7 @@ void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_LA_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_LA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3361,7 +3361,7 @@ void DAC960_LA_AcknowledgeInterrupt(void *ControllerBaseAddress) } static inline -boolean DAC960_LA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3370,7 +3370,7 @@ boolean DAC960_LA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -boolean DAC960_LA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3379,7 +3379,7 @@ boolean DAC960_LA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -void DAC960_LA_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_LA_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3389,7 +3389,7 @@ void DAC960_LA_EnableInterrupts(void *ControllerBaseAddress) } static inline -void DAC960_LA_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_LA_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0xFF; @@ -3399,7 +3399,7 @@ void DAC960_LA_DisableInterrupts(void *ControllerBaseAddress) } static inline -boolean DAC960_LA_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3422,7 +3422,7 @@ void DAC960_LA_WriteCommandMailbox(DAC960_V1_CommandMailbox_T } static inline -void DAC960_LA_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_LA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, DAC960_V1_CommandMailbox_T *CommandMailbox) { writel(CommandMailbox->Words[0], @@ -3436,20 +3436,20 @@ void DAC960_LA_WriteHardwareMailbox(void *ControllerBaseAddress, } static inline DAC960_V1_CommandIdentifier_T -DAC960_LA_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +DAC960_LA_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) { return readb(ControllerBaseAddress + DAC960_LA_StatusCommandIdentifierRegOffset); } static inline DAC960_V1_CommandStatus_T -DAC960_LA_ReadStatusRegister(void *ControllerBaseAddress) +DAC960_LA_ReadStatusRegister(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset); } static inline boolean -DAC960_LA_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_LA_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -3583,7 +3583,7 @@ DAC960_PG_ErrorStatusRegister_T; */ static inline -void DAC960_PG_HardwareMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_PG_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3593,7 +3593,7 @@ void DAC960_PG_HardwareMailboxNewCommand(void *ControllerBaseAddress) } static inline -void DAC960_PG_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3603,7 +3603,7 @@ void DAC960_PG_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) } static inline -void DAC960_PG_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_PG_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3613,7 +3613,7 @@ void DAC960_PG_GenerateInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_PG_ControllerReset(void *ControllerBaseAddress) +void DAC960_PG_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3623,7 +3623,7 @@ void DAC960_PG_ControllerReset(void *ControllerBaseAddress) } static inline -void DAC960_PG_MemoryMailboxNewCommand(void *ControllerBaseAddress) +void DAC960_PG_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3633,7 +3633,7 @@ void DAC960_PG_MemoryMailboxNewCommand(void *ControllerBaseAddress) } static inline -boolean DAC960_PG_HardwareMailboxFullP(void *ControllerBaseAddress) +boolean DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3642,7 +3642,7 @@ boolean DAC960_PG_HardwareMailboxFullP(void *ControllerBaseAddress) } static inline -boolean DAC960_PG_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3651,7 +3651,7 @@ boolean DAC960_PG_InitializationInProgressP(void *ControllerBaseAddress) } static inline -void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3661,7 +3661,7 @@ void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3671,7 +3671,7 @@ void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_PG_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_PG_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3682,7 +3682,7 @@ void DAC960_PG_AcknowledgeInterrupt(void *ControllerBaseAddress) } static inline -boolean DAC960_PG_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3691,7 +3691,7 @@ boolean DAC960_PG_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -boolean DAC960_PG_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3700,7 +3700,7 @@ boolean DAC960_PG_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) } static inline -void DAC960_PG_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_PG_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0; @@ -3712,7 +3712,7 @@ void DAC960_PG_EnableInterrupts(void *ControllerBaseAddress) } static inline -void DAC960_PG_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_PG_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = 0; @@ -3724,7 +3724,7 @@ void DAC960_PG_DisableInterrupts(void *ControllerBaseAddress) } static inline -boolean DAC960_PG_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3747,7 +3747,7 @@ void DAC960_PG_WriteCommandMailbox(DAC960_V1_CommandMailbox_T } static inline -void DAC960_PG_WriteHardwareMailbox(void *ControllerBaseAddress, +void DAC960_PG_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, DAC960_V1_CommandMailbox_T *CommandMailbox) { writel(CommandMailbox->Words[0], @@ -3761,20 +3761,20 @@ void DAC960_PG_WriteHardwareMailbox(void *ControllerBaseAddress, } static inline DAC960_V1_CommandIdentifier_T -DAC960_PG_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +DAC960_PG_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) { return readb(ControllerBaseAddress + DAC960_PG_StatusCommandIdentifierRegOffset); } static inline DAC960_V1_CommandStatus_T -DAC960_PG_ReadStatusRegister(void *ControllerBaseAddress) +DAC960_PG_ReadStatusRegister(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset); } static inline boolean -DAC960_PG_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_PG_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) @@ -3903,7 +3903,7 @@ DAC960_PD_ErrorStatusRegister_T; */ static inline -void DAC960_PD_NewCommand(void *ControllerBaseAddress) +void DAC960_PD_NewCommand(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3913,7 +3913,7 @@ void DAC960_PD_NewCommand(void *ControllerBaseAddress) } static inline -void DAC960_PD_AcknowledgeStatus(void *ControllerBaseAddress) +void DAC960_PD_AcknowledgeStatus(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3923,7 +3923,7 @@ void DAC960_PD_AcknowledgeStatus(void *ControllerBaseAddress) } static inline -void DAC960_PD_GenerateInterrupt(void *ControllerBaseAddress) +void DAC960_PD_GenerateInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3933,7 +3933,7 @@ void DAC960_PD_GenerateInterrupt(void *ControllerBaseAddress) } static inline -void DAC960_PD_ControllerReset(void *ControllerBaseAddress) +void DAC960_PD_ControllerReset(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = 0; @@ -3943,7 +3943,7 @@ void DAC960_PD_ControllerReset(void *ControllerBaseAddress) } static inline -boolean DAC960_PD_MailboxFullP(void *ControllerBaseAddress) +boolean DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3952,7 +3952,7 @@ boolean DAC960_PD_MailboxFullP(void *ControllerBaseAddress) } static inline -boolean DAC960_PD_InitializationInProgressP(void *ControllerBaseAddress) +boolean DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3961,7 +3961,7 @@ boolean DAC960_PD_InitializationInProgressP(void *ControllerBaseAddress) } static inline -void DAC960_PD_AcknowledgeInterrupt(void *ControllerBaseAddress) +void DAC960_PD_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) { DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = 0; @@ -3971,7 +3971,7 @@ void DAC960_PD_AcknowledgeInterrupt(void *ControllerBaseAddress) } static inline -boolean DAC960_PD_StatusAvailableP(void *ControllerBaseAddress) +boolean DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3980,7 +3980,7 @@ boolean DAC960_PD_StatusAvailableP(void *ControllerBaseAddress) } static inline -void DAC960_PD_EnableInterrupts(void *ControllerBaseAddress) +void DAC960_PD_EnableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = 0; @@ -3990,7 +3990,7 @@ void DAC960_PD_EnableInterrupts(void *ControllerBaseAddress) } static inline -void DAC960_PD_DisableInterrupts(void *ControllerBaseAddress) +void DAC960_PD_DisableInterrupts(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = 0; @@ -4000,7 +4000,7 @@ void DAC960_PD_DisableInterrupts(void *ControllerBaseAddress) } static inline -boolean DAC960_PD_InterruptsEnabledP(void *ControllerBaseAddress) +boolean DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = @@ -4009,7 +4009,7 @@ boolean DAC960_PD_InterruptsEnabledP(void *ControllerBaseAddress) } static inline -void DAC960_PD_WriteCommandMailbox(void *ControllerBaseAddress, +void DAC960_PD_WriteCommandMailbox(void __iomem *ControllerBaseAddress, DAC960_V1_CommandMailbox_T *CommandMailbox) { writel(CommandMailbox->Words[0], @@ -4023,20 +4023,20 @@ void DAC960_PD_WriteCommandMailbox(void *ControllerBaseAddress, } static inline DAC960_V1_CommandIdentifier_T -DAC960_PD_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +DAC960_PD_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) { return readb(ControllerBaseAddress + DAC960_PD_StatusCommandIdentifierRegOffset); } static inline DAC960_V1_CommandStatus_T -DAC960_PD_ReadStatusRegister(void *ControllerBaseAddress) +DAC960_PD_ReadStatusRegister(void __iomem *ControllerBaseAddress) { return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset); } static inline boolean -DAC960_PD_ReadErrorStatus(void *ControllerBaseAddress, +DAC960_PD_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, unsigned char *Parameter1) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index c44f27f24..a1d50242b 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -166,7 +166,7 @@ config BLK_CPQ_CISS_DA config CISS_SCSI_TAPE bool "SCSI tape drive support for Smart Array 5xxx" - depends on BLK_CPQ_CISS_DA && SCSI + depends on BLK_CPQ_CISS_DA && SCSI && PROC_FS help When enabled (Y), this option allows SCSI tape drives and SCSI medium changers (tape robots) to be accessed via a Compaq 5xxx array @@ -301,6 +301,15 @@ config BLK_DEV_SX8 Use devices /dev/sx8/$N and /dev/sx8/$Np$M. +config BLK_DEV_UB + tristate "Low Performance USB Block driver" + depends on USB + help + This driver supports certain USB attached storage devices + such as flash keys. + + If unsure, say N. + config BLK_DEV_RAM tristate "RAM disk support" ---help--- diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 2654b5b76..c8fbbf14c 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -42,4 +42,5 @@ obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o +obj-$(CONFIG_BLK_DEV_UB) += ub.o diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 42c1e5663..62e3a7ed3 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -386,16 +386,6 @@ static void fd_motor_off(unsigned long drive) fd_select(drive); udelay (1); fd_deselect(drive); - -#ifdef MODULE -/* - this is the last interrupt for any drive access, happens after - release (from floppy_off). So we have to wait until now to decrease - the use count. -*/ - if (decusecount) - MOD_DEC_USE_COUNT; -#endif } static void floppy_off (unsigned int nr) @@ -1590,10 +1580,6 @@ static int floppy_open(struct inode *inode, struct file *filp) local_irq_save(flags); fd_ref[drive]++; fd_device[drive] = system; -#ifdef MODULE - if (unit[drive].motor == 0) - MOD_INC_USE_COUNT; -#endif local_irq_restore(flags); unit[drive].dtype=&data_types[system]; @@ -1839,6 +1825,7 @@ int init_module(void) return amiga_floppy_init(); } +#if 0 /* not safe to unload */ void cleanup_module(void) { int i; @@ -1860,3 +1847,4 @@ void cleanup_module(void) unregister_blkdev(FLOPPY_MAJOR, "fd"); } #endif +#endif diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5509e5620..ccdcfa13b 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -46,14 +46,14 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.6.2)" +#define DRIVER_NAME "HP CISS Driver (v 2.6.2)" #define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i"); + " SA6i V100"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -82,7 +82,7 @@ const struct pci_device_id cciss_pci_device_id[] = { 0x0E11, 0x4091, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS, 0x103C, 0x3211, 0, 0, 0}, {0,} }; @@ -115,7 +115,7 @@ static struct board_type products[] = { /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 -#define READ_AHEAD 256 +#define READ_AHEAD 1024 #define NR_CMDS 384 /* #commands that can be outstanding */ #define MAX_CTLR 8 @@ -192,10 +192,10 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, /* * Report information about this controller. */ -#define ENG_GIG 1048576000 +#define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) #define RAID_UNKNOWN 6 -static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG", +static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG", "UNKNOWN"}; static struct proc_dir_entry *proc_cciss; @@ -209,7 +209,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, ctlr_info_t *h = (ctlr_info_t*)data; drive_info_struct *drv; unsigned long flags; - unsigned int vol_sz, vol_sz_frac; + sector_t vol_sz, vol_sz_frac; ctlr = h->ctlr; @@ -246,32 +246,21 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, pos += size; len += size; cciss_proc_tape_report(ctlr, buffer, &pos, &len); for(i=0; i<=h->highest_lun; i++) { - sector_t tmp; drv = &h->drv[i]; if (drv->block_size == 0) continue; - vol_sz = drv->nr_blocks; - sector_div(vol_sz, ENG_GIG_FACTOR); - - /* - * Awkwardly do this: - * vol_sz_frac = - * (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR; - */ - tmp = drv->nr_blocks; - vol_sz_frac = sector_div(tmp, ENG_GIG_FACTOR); - - /* Now, vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR) */ + vol_sz = drv->nr_blocks; + vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); vol_sz_frac *= 100; sector_div(vol_sz_frac, ENG_GIG_FACTOR); if (drv->raid_level > 5) drv->raid_level = RAID_UNKNOWN; size = sprintf(buffer+len, "cciss/c%dd%d:" - "\t%4d.%02dGB\tRAID %s\n", - ctlr, i, vol_sz,vol_sz_frac, + "\t%4u.%02uGB\tRAID %s\n", + ctlr, i, (int)vol_sz, (int)vol_sz_frac, raid_label[drv->raid_level]); pos += size; len += size; } @@ -578,7 +567,7 @@ int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p); if (err) return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -610,7 +599,7 @@ int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p); if (err) return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -866,6 +855,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, kfree(buff); return -EFAULT; } + } else { + memset(buff, 0, iocommand.buf_size); } if ((c = cmd_alloc(host , 0)) == NULL) { @@ -1012,6 +1003,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, copy_from_user(buff[sg_used], data_ptr, sz)) { status = -ENOMEM; goto cleanup1; + } else { + memset(buff[sg_used], 0, sz); } left -= sz; data_ptr += sz; @@ -1477,12 +1470,19 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, drv->sectors = 32; // Sectors per track drv->cylinders = total_size / 255 / 32; } else { + unsigned int t; + drv->block_size = block_size; drv->nr_blocks = total_size; drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8; drv->cylinders += inq_buff->data_byte[5]; + drv->raid_level = inq_buff->data_byte[8]; + t = drv->heads * drv->sectors; + if (t > 1) { + drv->cylinders = total_size/t; + } } } else { /* Get geometry failed */ printk(KERN_WARNING "cciss: reading geometry failed, " @@ -1509,8 +1509,8 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { - *total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1; - *block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0])); + *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1; + *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0])); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; @@ -1844,13 +1844,13 @@ cleanup1: /* * Map (physical) PCI mem into (virtual) kernel space */ -static ulong remap_pci_mem(ulong base, ulong size) +static void __iomem *remap_pci_mem(ulong base, ulong size) { ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; - ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + void __iomem *page_remapped = ioremap(page_base, page_offs+size); - return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); + return page_remapped ? (page_remapped + page_offs) : NULL; } /* @@ -2300,7 +2300,6 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; - unchar irq = pdev->irq; __u32 board_id, scratchpad = 0; __u64 cfg_offset; __u32 cfg_base_addr; @@ -2359,11 +2358,11 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) #ifdef CCISS_DEBUG printk("command = %x\n", command); - printk("irq = %x\n", irq); + printk("irq = %x\n", pdev->irq); printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = irq; + c->intr = pdev->irq; /* * Memory base addr is first addr , the second points to the config @@ -2411,9 +2410,9 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) #ifdef CCISS_DEBUG printk("cfg offset = %x\n", cfg_offset); #endif /* CCISS_DEBUG */ - c->cfgtable = (CfgTable_struct *) - remap_pci_mem(pci_resource_start(pdev, cfg_base_addr_index) - + cfg_offset, sizeof(CfgTable_struct)); + c->cfgtable = remap_pci_mem(pci_resource_start(pdev, + cfg_base_addr_index) + cfg_offset, + sizeof(CfgTable_struct)); c->board_id = board_id; #ifdef CCISS_DEBUG @@ -2825,7 +2824,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) } free_irq(hba[i]->intr, hba[i]); pci_set_drvdata(pdev, NULL); - iounmap((void*)hba[i]->vaddr); + iounmap(hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 825855cd4..8ab689c21 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -43,12 +43,12 @@ struct ctlr_info char firm_ver[4]; // Firmware version struct pci_dev *pdev; __u32 board_id; - unsigned long vaddr; + void __iomem *vaddr; unsigned long paddr; unsigned long io_mem_addr; unsigned long io_mem_length; - CfgTable_struct *cfgtable; - int intr; + CfgTable_struct __iomem *cfgtable; + unsigned int intr; int interrupts_enabled; int max_commands; int commands_outstanding; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index b42a8d33f..204b31829 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -138,7 +138,7 @@ static struct gendisk *ida_gendisk[MAX_CTLR][NWD]; int cpqarray_init_step2(void); static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev); -static void *remap_pci_mem(ulong base, ulong size); +static void __iomem *remap_pci_mem(ulong base, ulong size); static int cpqarray_eisa_detect(void); static int pollcomplete(int ctlr); static void getgeometry(int ctlr); @@ -551,10 +551,10 @@ static int __init cpqarray_init_one( struct pci_dev *pdev, } static struct pci_driver cpqarray_pci_driver = { - name: "cpqarray", - probe: cpqarray_init_one, - remove: __devexit_p(cpqarray_remove_one_pci), - id_table: cpqarray_pci_device_id, + .name = "cpqarray", + .probe = cpqarray_init_one, + .remove = __devexit_p(cpqarray_remove_one_pci), + .id_table = cpqarray_pci_device_id, }; /* @@ -722,11 +722,11 @@ DBGINFO( /* * Map (physical) PCI mem into (virtual) kernel space */ -static void *remap_pci_mem(ulong base, ulong size) +static void __iomem *remap_pci_mem(ulong base, ulong size) { ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; - void *page_remapped = ioremap(page_base, page_offs+size); + void __iomem *page_remapped = ioremap(page_base, page_offs+size); return (page_remapped ? (page_remapped + page_offs) : NULL); } diff --git a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h index 112e39422..6a9ded054 100644 --- a/drivers/block/cpqarray.h +++ b/drivers/block/cpqarray.h @@ -90,7 +90,7 @@ struct ctlr_info { __u32 board_id; char *product_name; - void *vaddr; + void __iomem *vaddr; unsigned long paddr; unsigned long io_mem_addr; unsigned long io_mem_length; diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index e82caa224..c68215b35 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -365,7 +365,9 @@ static ssize_t disk_size_read(struct gendisk * disk, char *page) static ssize_t disk_stats_read(struct gendisk * disk, char *page) { + preempt_disable(); disk_round_stats(disk); + preempt_enable(); return sprintf(page, "%8u %8u %8llu %8u " "%8u %8u %8llu %8u " @@ -494,7 +496,9 @@ static int diskstats_show(struct seq_file *s, void *v) "\n\n"); */ + preempt_disable(); disk_round_stats(gp); + preempt_enable(); seq_printf(s, "%4d %4d %s %u %u %llu %u %u %u %llu %u %u %u %u\n", gp->major, n + gp->first_minor, disk_name(gp, n, buf), disk_stat_read(gp, reads), disk_stat_read(gp, read_merges), diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index 283a9f2fa..43ff0c6ed 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c @@ -194,7 +194,8 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, return -EACCES; if (disk->fops->ioctl) { ret = disk->fops->ioctl(inode, file, cmd, arg); - if (ret != -EINVAL) + /* -EINVAL to handle old uncorrected drivers */ + if (ret != -EINVAL && ret != -ENOTTY) return ret; } fsync_bdev(bdev); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 17c403ebd..26fdf6be6 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -154,6 +154,8 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev) return ret; } +EXPORT_SYMBOL(blk_get_backing_dev_info); + void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) { q->activity_fn = fn; @@ -262,6 +264,45 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) EXPORT_SYMBOL(blk_queue_make_request); +/** + * blk_queue_ordered - does this queue support ordered writes + * @q: the request queue + * @flag: see below + * + * Description: + * For journalled file systems, doing ordered writes on a commit + * block instead of explicitly doing wait_on_buffer (which is bad + * for performance) can be a big win. Block drivers supporting this + * feature should call this function and indicate so. + * + **/ +void blk_queue_ordered(request_queue_t *q, int flag) +{ + if (flag) + set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); + else + clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); +} + +EXPORT_SYMBOL(blk_queue_ordered); + +/** + * blk_queue_issue_flush_fn - set function for issuing a flush + * @q: the request queue + * @iff: the function to be called issuing the flush + * + * Description: + * If a driver supports issuing a flush command, the support is notified + * to the block layer by defining it through this call. + * + **/ +void blk_queue_issue_flush_fn(request_queue_t *q, issue_flush_fn *iff) +{ + q->issue_flush_fn = iff; +} + +EXPORT_SYMBOL(blk_queue_issue_flush_fn); + /** * blk_queue_bounce_limit - set bounce buffer limit for queue * @q: the request queue for the device @@ -311,7 +352,7 @@ void blk_queue_max_sectors(request_queue_t *q, unsigned short max_sectors) printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors); } - q->max_sectors = max_sectors; + q->max_sectors = q->max_hw_sectors = max_sectors; } EXPORT_SYMBOL(blk_queue_max_sectors); @@ -413,7 +454,8 @@ EXPORT_SYMBOL(blk_queue_hardsect_size); void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b) { /* zero is "infinity" */ - t->max_sectors = min_not_zero(t->max_sectors,b->max_sectors); + t->max_sectors = t->max_hw_sectors = + min_not_zero(t->max_sectors,b->max_sectors); t->max_phys_segments = min(t->max_phys_segments,b->max_phys_segments); t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments); @@ -482,15 +524,14 @@ struct request *blk_queue_find_tag(request_queue_t *q, int tag) EXPORT_SYMBOL(blk_queue_find_tag); /** - * blk_queue_free_tags - release tag maintenance info + * __blk_queue_free_tags - release tag maintenance info * @q: the request queue for the device * * Notes: * blk_cleanup_queue() will take care of calling this function, if tagging - * has been used. So there's usually no need to call this directly, unless - * tagging is just being disabled but the queue remains in function. + * has been used. So there's no need to call this directly. **/ -void blk_queue_free_tags(request_queue_t *q) +static void __blk_queue_free_tags(request_queue_t *q) { struct blk_queue_tag *bqt = q->queue_tags; @@ -514,12 +555,27 @@ void blk_queue_free_tags(request_queue_t *q) q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED); } +/** + * blk_queue_free_tags - release tag maintenance info + * @q: the request queue for the device + * + * Notes: + * This is used to disabled tagged queuing to a device, yet leave + * queue in function. + **/ +void blk_queue_free_tags(request_queue_t *q) +{ + clear_bit(QUEUE_FLAG_QUEUED, &q->queue_flags); +} + EXPORT_SYMBOL(blk_queue_free_tags); static int init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) { int bits, i; + struct request **tag_index; + unsigned long *tag_map; if (depth > q->nr_requests * 2) { depth = q->nr_requests * 2; @@ -527,32 +583,31 @@ init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) __FUNCTION__, depth); } - tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); - if (!tags->tag_index) + tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); + if (!tag_index) goto fail; bits = (depth / BLK_TAGS_PER_LONG) + 1; - tags->tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC); - if (!tags->tag_map) + tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC); + if (!tag_map) goto fail; - memset(tags->tag_index, 0, depth * sizeof(struct request *)); - memset(tags->tag_map, 0, bits * sizeof(unsigned long)); + memset(tag_index, 0, depth * sizeof(struct request *)); + memset(tag_map, 0, bits * sizeof(unsigned long)); tags->max_depth = depth; tags->real_max_depth = bits * BITS_PER_LONG; + tags->tag_index = tag_index; + tags->tag_map = tag_map; /* * set the upper bits if the depth isn't a multiple of the word size */ for (i = depth; i < bits * BLK_TAGS_PER_LONG; i++) - __set_bit(i, tags->tag_map); + __set_bit(i, tag_map); - INIT_LIST_HEAD(&tags->busy_list); - tags->busy = 0; - atomic_set(&tags->refcnt, 1); return 0; fail: - kfree(tags->tag_index); + kfree(tag_index); return -ENOMEM; } @@ -564,13 +619,26 @@ fail: int blk_queue_init_tags(request_queue_t *q, int depth, struct blk_queue_tag *tags) { - if (!tags) { + int rc; + + BUG_ON(tags && q->queue_tags && tags != q->queue_tags); + + if (!tags && !q->queue_tags) { tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC); if (!tags) goto fail; if (init_tag_map(q, tags, depth)) goto fail; + + INIT_LIST_HEAD(&tags->busy_list); + tags->busy = 0; + atomic_set(&tags->refcnt, 1); + } else if (q->queue_tags) { + if ((rc = blk_queue_resize_tags(q, depth))) + return rc; + set_bit(QUEUE_FLAG_QUEUED, &q->queue_flags); + return 0; } else atomic_inc(&tags->refcnt); @@ -1335,8 +1403,8 @@ void blk_cleanup_queue(request_queue_t * q) if (rl->rq_pool) mempool_destroy(rl->rq_pool); - if (blk_queue_tagged(q)) - blk_queue_free_tags(q); + if (q->queue_tags) + __blk_queue_free_tags(q); kmem_cache_free(requestq_cachep, q); } @@ -1925,10 +1993,11 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, } rq->flags |= REQ_NOMERGE; - rq->waiting = &wait; + if (!rq->waiting) + rq->waiting = &wait; elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); generic_unplug_device(q); - wait_for_completion(&wait); + wait_for_completion(rq->waiting); rq->waiting = NULL; if (rq->errors) @@ -1939,6 +2008,72 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, EXPORT_SYMBOL(blk_execute_rq); +/** + * blkdev_issue_flush - queue a flush + * @bdev: blockdev to issue flush for + * @error_sector: error sector + * + * Description: + * Issue a flush for the block device in question. Caller can supply + * room for storing the error offset in case of a flush error, if they + * wish to. Caller must run wait_for_completion() on its own. + */ +int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) +{ + request_queue_t *q; + + if (bdev->bd_disk == NULL) + return -ENXIO; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + if (!q->issue_flush_fn) + return -EOPNOTSUPP; + + return q->issue_flush_fn(q, bdev->bd_disk, error_sector); +} + +EXPORT_SYMBOL(blkdev_issue_flush); + +/** + * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices + * @q: device queue + * @disk: gendisk + * @error_sector: error offset + * + * Description: + * Devices understanding the SCSI command set, can use this function as + * a helper for issuing a cache flush. Note: driver is required to store + * the error offset (in case of error flushing) in ->sector of struct + * request. + */ +int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT); + int ret; + + rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; + rq->sector = 0; + memset(rq->cmd, 0, sizeof(rq->cmd)); + rq->cmd[0] = 0x35; + rq->cmd_len = 12; + rq->data = NULL; + rq->data_len = 0; + rq->timeout = 60 * HZ; + + ret = blk_execute_rq(q, disk, rq); + + if (ret && error_sector) + *error_sector = rq->sector; + + blk_put_request(rq); + return ret; +} + +EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn); + void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); @@ -2192,7 +2327,7 @@ EXPORT_SYMBOL(__blk_attempt_remerge); static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err; sector_t sector; sector = bio->bi_sector; @@ -2210,9 +2345,11 @@ static int __make_request(request_queue_t *q, struct bio *bio) spin_lock_prefetch(q->queue_lock); - barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); - - ra = bio->bi_rw & (1 << BIO_RW_AHEAD); + barrier = bio_barrier(bio); + if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) { + err = -EOPNOTSUPP; + goto end_io; + } again: spin_lock_irq(q->queue_lock); @@ -2292,7 +2429,8 @@ get_rq: /* * READA bit set */ - if (ra) + err = -EWOULDBLOCK; + if (bio_rw_ahead(bio)) goto end_io; freereq = get_request_wait(q, rw); @@ -2303,10 +2441,9 @@ get_rq: req->flags |= REQ_CMD; /* - * inherit FAILFAST from bio and don't stack up - * retries for read ahead + * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) */ - if (ra || test_bit(BIO_RW_FAILFAST, &bio->bi_rw)) + if (bio_rw_ahead(bio) || bio_failfast(bio)) req->flags |= REQ_FAILFAST; /* @@ -2340,7 +2477,7 @@ out: return 0; end_io: - bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK); + bio_endio(bio, nr_sectors << 9, err); return 0; } @@ -2399,6 +2536,7 @@ void generic_make_request(struct bio *bio) sector_t maxsector; int ret, nr_sectors = bio_sectors(bio); + might_sleep(); /* Test device or partition size, when known. */ maxsector = bio->bi_bdev->bd_inode->i_size >> 9; if (maxsector) { @@ -2446,11 +2584,11 @@ end_io: break; } - if (unlikely(bio_sectors(bio) > q->max_sectors)) { + if (unlikely(bio_sectors(bio) > q->max_hw_sectors)) { printk("bio too big device %s (%u > %u)\n", bdevname(bio->bi_bdev, b), bio_sectors(bio), - q->max_sectors); + q->max_hw_sectors); goto end_io; } @@ -2647,9 +2785,16 @@ void blk_recalc_rq_sectors(struct request *rq, int nsect) static int __end_that_request_first(struct request *req, int uptodate, int nr_bytes) { - int total_bytes, bio_nbytes, error = 0, next_idx = 0; + int total_bytes, bio_nbytes, error, next_idx = 0; struct bio *bio; + /* + * extend uptodate bool to allow < 0 value to be direct io error + */ + error = 0; + if (end_io_error(uptodate)) + error = !uptodate ? -EIO : uptodate; + /* * for a REQ_BLOCK_PC request, we want to carry any eventual * sense key with us all the way through @@ -2658,7 +2803,6 @@ static int __end_that_request_first(struct request *req, int uptodate, req->errors = 0; if (!uptodate) { - error = -EIO; if (blk_fs_request(req) && !(req->flags & REQ_QUIET)) printk("end_request: I/O error, dev %s, sector %llu\n", req->rq_disk ? req->rq_disk->disk_name : "?", @@ -2741,7 +2885,7 @@ static int __end_that_request_first(struct request *req, int uptodate, /** * end_that_request_first - end I/O on a request * @req: the request being processed - * @uptodate: 0 for I/O error + * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error * @nr_sectors: number of sectors to end I/O on * * Description: @@ -2762,7 +2906,7 @@ EXPORT_SYMBOL(end_that_request_first); /** * end_that_request_chunk - end I/O on a request * @req: the request being processed - * @uptodate: 0 for I/O error + * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error * @nr_bytes: number of bytes to complete * * Description: @@ -3063,13 +3207,61 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count) unsigned long ra_kb; ssize_t ret = queue_var_store(&ra_kb, page, count); + spin_lock_irq(q->queue_lock); if (ra_kb > (q->max_sectors >> 1)) ra_kb = (q->max_sectors >> 1); q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10); + spin_unlock_irq(q->queue_lock); + return ret; } +static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) +{ + int max_sectors_kb = q->max_sectors >> 1; + + return queue_var_show(max_sectors_kb, (page)); +} + +static ssize_t +queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) +{ + unsigned long max_sectors_kb, + max_hw_sectors_kb = q->max_hw_sectors >> 1, + page_kb = 1 << (PAGE_CACHE_SHIFT - 10); + ssize_t ret = queue_var_store(&max_sectors_kb, page, count); + int ra_kb; + + if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) + return -EINVAL; + /* + * Take the queue lock to update the readahead and max_sectors + * values synchronously: + */ + spin_lock_irq(q->queue_lock); + /* + * Trim readahead window as well, if necessary: + */ + ra_kb = q->backing_dev_info.ra_pages << (PAGE_CACHE_SHIFT - 10); + if (ra_kb > max_sectors_kb) + q->backing_dev_info.ra_pages = + max_sectors_kb >> (PAGE_CACHE_SHIFT - 10); + + q->max_sectors = max_sectors_kb << 1; + spin_unlock_irq(q->queue_lock); + + return ret; +} + +static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page) +{ + int max_hw_sectors_kb = q->max_hw_sectors >> 1; + + return queue_var_show(max_hw_sectors_kb, (page)); +} + + static struct queue_sysfs_entry queue_requests_entry = { .attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR }, .show = queue_requests_show, @@ -3082,9 +3274,22 @@ static struct queue_sysfs_entry queue_ra_entry = { .store = queue_ra_store, }; +static struct queue_sysfs_entry queue_max_sectors_entry = { + .attr = {.name = "max_sectors_kb", .mode = S_IRUGO | S_IWUSR }, + .show = queue_max_sectors_show, + .store = queue_max_sectors_store, +}; + +static struct queue_sysfs_entry queue_max_hw_sectors_entry = { + .attr = {.name = "max_hw_sectors_kb", .mode = S_IRUGO }, + .show = queue_max_hw_sectors_show, +}; + static struct attribute *default_attrs[] = { &queue_requests_entry.attr, &queue_ra_entry.attr, + &queue_max_hw_sectors_entry.attr, + &queue_max_sectors_entry.attr, NULL, }; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index b98b70b8f..75ad39dc6 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -128,23 +128,11 @@ static void nbd_end_request(struct request *req) { int uptodate = (req->errors == 0) ? 1 : 0; request_queue_t *q = req->q; - struct nbd_device *lo = req->rq_disk->private_data; unsigned long flags; dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, req, uptodate? "done": "failed"); - spin_lock(&lo->queue_lock); - while (req->ref_count > 1) { /* still in send */ - spin_unlock(&lo->queue_lock); - printk(KERN_DEBUG "%s: request %p still in use (%d), waiting\n", - lo->disk->disk_name, req, req->ref_count); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); /* wait a second */ - spin_lock(&lo->queue_lock); - } - spin_unlock(&lo->queue_lock); - spin_lock_irqsave(q->queue_lock, flags); if (!end_that_request_first(req, uptodate, req->nr_sectors)) { end_that_request_last(req); @@ -228,7 +216,7 @@ static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, return result; } -void nbd_send_req(struct nbd_device *lo, struct request *req) +static int nbd_send_req(struct nbd_device *lo, struct request *req) { int result, i, flags; struct nbd_request request; @@ -288,11 +276,11 @@ void nbd_send_req(struct nbd_device *lo, struct request *req) } } up(&lo->tx_lock); - return; + return 0; error_out: up(&lo->tx_lock); - req->errors++; + return 1; } static struct request *nbd_find_request(struct nbd_device *lo, char *handle) @@ -477,26 +465,19 @@ static void do_nbd_request(request_queue_t * q) } list_add(&req->queuelist, &lo->queue_head); - req->ref_count++; /* make sure req does not get freed */ spin_unlock(&lo->queue_lock); - nbd_send_req(lo, req); - - if (req->errors) { + if (nbd_send_req(lo, req) != 0) { printk(KERN_ERR "%s: Request send failed\n", lo->disk->disk_name); - spin_lock(&lo->queue_lock); - list_del_init(&req->queuelist); - req->ref_count--; - spin_unlock(&lo->queue_lock); - nbd_end_request(req); - spin_lock_irq(q->queue_lock); - continue; + if (nbd_find_request(lo, (char *)&req) != NULL) { + /* we still own req */ + req->errors++; + nbd_end_request(req); + } else /* we're racing with nbd_clear_que */ + printk(KERN_DEBUG "nbd: can't find req\n"); } - spin_lock(&lo->queue_lock); - req->ref_count--; - spin_unlock(&lo->queue_lock); spin_lock_irq(q->queue_lock); continue; diff --git a/drivers/block/rd.c b/drivers/block/rd.c index fe8332e34..b3c7f07c1 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 41d023931..f8fb5322f 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -127,12 +127,16 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_read(MODE_SENSE), safe_for_read(MODE_SENSE_10), safe_for_read(START_STOP), + safe_for_read(GPCMD_VERIFY_10), + safe_for_read(VERIFY_16), + safe_for_read(READ_BUFFER), /* Audio CD commands */ safe_for_read(GPCMD_PLAY_CD), safe_for_read(GPCMD_PLAY_AUDIO_10), safe_for_read(GPCMD_PLAY_AUDIO_MSF), safe_for_read(GPCMD_PLAY_AUDIO_TI), + safe_for_read(GPCMD_PAUSE_RESUME), /* CD/DVD data reading */ safe_for_read(GPCMD_READ_CD), @@ -146,6 +150,12 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_read(GPCMD_READ_TOC_PMA_ATIP), safe_for_read(GPCMD_REPORT_KEY), safe_for_read(GPCMD_SCAN), + safe_for_read(GPCMD_GET_CONFIGURATION), + safe_for_read(GPCMD_READ_FORMAT_CAPACITIES), + safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION), + safe_for_read(GPCMD_GET_PERFORMANCE), + safe_for_read(GPCMD_SEEK), + safe_for_read(GPCMD_STOP_PLAY_SCAN), /* Basic writing commands */ safe_for_write(WRITE_6), @@ -154,8 +164,25 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_write(WRITE_12), safe_for_write(WRITE_VERIFY_12), safe_for_write(WRITE_16), - safe_for_write(WRITE_BUFFER), safe_for_write(WRITE_LONG), + safe_for_write(ERASE), + safe_for_write(GPCMD_MODE_SELECT_10), + safe_for_write(MODE_SELECT), + safe_for_write(GPCMD_BLANK), + safe_for_write(GPCMD_CLOSE_TRACK), + safe_for_write(GPCMD_FLUSH_CACHE), + safe_for_write(GPCMD_FORMAT_UNIT), + safe_for_write(GPCMD_REPAIR_RZONE_TRACK), + safe_for_write(GPCMD_RESERVE_RZONE_TRACK), + safe_for_write(GPCMD_SEND_DVD_STRUCTURE), + 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), + safe_for_write(GPCMD_SET_STREAMING), }; unsigned char type = cmd_type[cmd[0]]; @@ -511,6 +538,7 @@ int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, * old junk scsi send command ioctl */ case SCSI_IOCTL_SEND_COMMAND: + printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); err = -EINVAL; if (!arg) break; diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 0a0234129..02a541ae7 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -242,7 +242,7 @@ struct carm_request { struct carm_host { unsigned long flags; - void *mmio; + void __iomem *mmio; void *shm; dma_addr_t shm_dma; @@ -283,13 +283,13 @@ struct carm_host { }; struct carm_response { - u32 ret_handle; - u32 status; + __le32 ret_handle; + __le32 status; } __attribute__((packed)); struct carm_msg_sg { - u32 start; - u32 len; + __le32 start; + __le32 len; } __attribute__((packed)); struct carm_msg_rw { @@ -297,10 +297,10 @@ struct carm_msg_rw { u8 id; u8 sg_count; u8 sg_type; - u32 handle; - u32 lba; - u16 lba_count; - u16 lba_high; + __le32 handle; + __le32 lba; + __le16 lba_count; + __le16 lba_high; struct carm_msg_sg sg[32]; } __attribute__((packed)); @@ -309,15 +309,15 @@ struct carm_msg_allocbuf { u8 subtype; u8 n_sg; u8 sg_type; - u32 handle; - u32 addr; - u32 len; - u32 evt_pool; - u32 n_evt; - u32 rbuf_pool; - u32 n_rbuf; - u32 msg_pool; - u32 n_msg; + __le32 handle; + __le32 addr; + __le32 len; + __le32 evt_pool; + __le32 n_evt; + __le32 rbuf_pool; + __le32 n_rbuf; + __le32 msg_pool; + __le32 n_msg; struct carm_msg_sg sg[8]; } __attribute__((packed)); @@ -326,8 +326,8 @@ struct carm_msg_ioctl { u8 subtype; u8 array_id; u8 reserved1; - u32 handle; - u32 data_addr; + __le32 handle; + __le32 data_addr; u32 reserved2; } __attribute__((packed)); @@ -335,48 +335,48 @@ struct carm_msg_sync_time { u8 type; u8 subtype; u16 reserved1; - u32 handle; + __le32 handle; u32 reserved2; - u32 timestamp; + __le32 timestamp; } __attribute__((packed)); struct carm_msg_get_fw_ver { u8 type; u8 subtype; u16 reserved1; - u32 handle; - u32 data_addr; + __le32 handle; + __le32 data_addr; u32 reserved2; } __attribute__((packed)); struct carm_fw_ver { - u32 version; + __le32 version; u8 features; u8 reserved1; u16 reserved2; } __attribute__((packed)); struct carm_array_info { - u32 size; + __le32 size; - u16 size_hi; - u16 stripe_size; + __le16 size_hi; + __le16 stripe_size; - u32 mode; + __le32 mode; - u16 stripe_blk_sz; - u16 reserved1; + __le16 stripe_blk_sz; + __le16 reserved1; - u16 cyl; - u16 head; + __le16 cyl; + __le16 head; - u16 sect; + __le16 sect; u8 array_id; u8 reserved2; char name[40]; - u32 array_status; + __le32 array_status; /* device list continues beyond this point? */ } __attribute__((packed)); @@ -451,7 +451,7 @@ static inline int carm_lookup_bucket(u32 msg_size) return -ENOENT; } -static void carm_init_buckets(void *mmio) +static void carm_init_buckets(void __iomem *mmio) { unsigned int i; @@ -474,7 +474,7 @@ static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host, static int carm_send_msg(struct carm_host *host, struct carm_request *crq) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; u32 msg = (u32) carm_ref_msg_dma(host, crq->tag); u32 cm_bucket = crq->msg_bucket; u32 tmp; @@ -965,7 +965,7 @@ static void carm_handle_array_info(struct carm_host *host, port = &host->port[cur_port]; lo = (u64) le32_to_cpu(desc->size); - hi = (u64) le32_to_cpu(desc->size_hi); + hi = (u64) le16_to_cpu(desc->size_hi); port->capacity = lo | (hi << 32); port->dev_geom_head = le16_to_cpu(desc->head); @@ -1060,7 +1060,7 @@ static inline void carm_handle_rw(struct carm_host *host, } static inline void carm_handle_resp(struct carm_host *host, - u32 ret_handle_le, u32 status) + __le32 ret_handle_le, u32 status) { u32 handle = le32_to_cpu(ret_handle_le); unsigned int msg_idx; @@ -1158,7 +1158,7 @@ err_out: static inline void carm_handle_responses(struct carm_host *host) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; struct carm_response *resp = (struct carm_response *) host->shm; unsigned int work = 0; unsigned int idx = host->resp_idx % RMSG_Q_LEN; @@ -1176,7 +1176,7 @@ static inline void carm_handle_responses(struct carm_host *host) else if ((status & (1 << 31)) == 0) { VPRINTK("handling msg response on index %u\n", idx); carm_handle_resp(host, resp[idx].ret_handle, status); - resp[idx].status = 0xffffffff; + resp[idx].status = cpu_to_le32(0xffffffff); } /* asynchronous events the hardware throws our way */ @@ -1185,7 +1185,7 @@ static inline void carm_handle_responses(struct carm_host *host) u8 evt_type = *evt_type_ptr; printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n", pci_name(host->pdev), (int) evt_type); - resp[idx].status = 0xffffffff; + resp[idx].status = cpu_to_le32(0xffffffff); } idx = NEXT_RESP(idx); @@ -1199,7 +1199,7 @@ static inline void carm_handle_responses(struct carm_host *host) static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) { struct carm_host *host = __host; - void *mmio; + void __iomem *mmio; u32 mask; int handled = 0; unsigned long flags; @@ -1364,7 +1364,7 @@ static void carm_fsm_task (void *_data) schedule_work(&host->fsm_task); } -static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) +static int carm_init_wait(void __iomem *mmio, u32 bits, unsigned int test_bit) { unsigned int i; @@ -1390,19 +1390,19 @@ static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) static void carm_init_responses(struct carm_host *host) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; unsigned int i; struct carm_response *resp = (struct carm_response *) host->shm; for (i = 0; i < RMSG_Q_LEN; i++) - resp[i].status = 0xffffffff; + resp[i].status = cpu_to_le32(0xffffffff); writel(0, mmio + CARM_RESP_IDX); } static int carm_init_host(struct carm_host *host) { - void *mmio = host->mmio; + void __iomem *mmio = host->mmio; u32 tmp; u8 tmp8; int rc; @@ -1414,7 +1414,7 @@ static int carm_init_host(struct carm_host *host) tmp8 = readb(mmio + CARM_INITC); if (tmp8 & 0x01) { tmp8 &= ~0x01; - writeb(tmp8, CARM_INITC); + writeb(tmp8, mmio + CARM_INITC); readb(mmio + CARM_INITC); /* flush */ DPRINTK("snooze...\n"); diff --git a/drivers/block/ub.c b/drivers/block/ub.c new file mode 100644 index 000000000..f605535d3 --- /dev/null +++ b/drivers/block/ub.c @@ -0,0 +1,2097 @@ +/* + * The low performance USB storage driver (ub). + * + * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com) + * + * This work is a part of Linux kernel, is derived from it, + * and is not licensed separately. See file COPYING for details. + * + * TODO (sorted by decreasing priority) + * -- ZIP does "ub: resid 18 len 0 act 0" and whole transport quits (toggles?) + * -- set readonly flag for CDs, set removable flag for CF readers + * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) + * -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...) + * -- special case some senses, e.g. 3a/0 -> no media present, reduce retries + * -- do something about spin-down devices, they are extremely dangerous + * (ZIP is one. Needs spin-up command as well.) + * -- verify the 13 conditions and do bulk resets + * -- normal pool of commands instead of cmdv[]? + * -- kill last_pipe and simply do two-state clearing on both pipes + * -- verify protocol (bulk) from USB descriptors (maybe...) + * -- highmem and sg + * -- move top_sense and work_bcs into separate allocations (if they survive) + * for cache purists and esoteric architectures. + * -- prune comments, they are too volumnous + * -- Exterminate P3 printks + * -- Resove XXX's + */ +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "ub" +#define DEVFS_NAME DRV_NAME + +#define UB_MAJOR 125 /* Stolen from Experimental range for a week - XXX */ + +/* + * Definitions which have to be scattered once we understand the layout better. + */ + +/* Transport (despite PR in the name) */ +#define US_PR_BULK 0x50 /* bulk only */ + +/* Protocol */ +#define US_SC_SCSI 0x06 /* Transparent */ + +/* + */ +#define UB_MINORS_PER_MAJOR 8 + +#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ + +#define UB_SENSE_SIZE 18 + +/* + */ + +/* command block wrapper */ +struct bulk_cb_wrap { + u32 Signature; /* contains 'USBC' */ + u32 Tag; /* unique per command id */ + u32 DataTransferLength; /* size of data */ + u8 Flags; /* direction in bit 0 */ + u8 Lun; /* LUN normally 0 */ + u8 Length; /* of of the CDB */ + u8 CDB[UB_MAX_CDB_SIZE]; /* max command */ +}; + +#define US_BULK_CB_WRAP_LEN 31 +#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */ +#define US_BULK_FLAG_IN 1 +#define US_BULK_FLAG_OUT 0 + +/* command status wrapper */ +struct bulk_cs_wrap { + u32 Signature; /* should = 'USBS' */ + u32 Tag; /* same as original command */ + u32 Residue; /* amount not transferred */ + u8 Status; /* see below */ +}; + +#define US_BULK_CS_WRAP_LEN 13 +#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */ +/* This is for Olympus Camedia digital cameras */ +#define US_BULK_CS_OLYMPUS_SIGN 0x55425355 /* spells out 'USBU' */ +#define US_BULK_STAT_OK 0 +#define US_BULK_STAT_FAIL 1 +#define US_BULK_STAT_PHASE 2 + +/* bulk-only class specific requests */ +#define US_BULK_RESET_REQUEST 0xff +#define US_BULK_GET_MAX_LUN 0xfe + +/* + */ +struct ub_dev; + +#define UB_MAX_REQ_SG 1 +#define UB_MAX_SECTORS 64 + +/* + * A second ought to be enough for a 32K transfer (UB_MAX_SECTORS) + * even if a webcam hogs the bus (famous last words). + * Some CDs need a second to spin up though. + * ZIP drive rejects commands when it's not spinning, + * so it does not need long timeouts either. + */ +#define UB_URB_TIMEOUT (HZ*2) +#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ + +/* + * An instance of a SCSI command in transit. + */ +#define UB_DIR_NONE 0 +#define UB_DIR_READ 1 +#define UB_DIR_ILLEGAL2 2 +#define UB_DIR_WRITE 3 + +#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ + (((c)==UB_DIR_READ)? 'r': 'n')) + +enum ub_scsi_cmd_state { + UB_CMDST_INIT, /* Initial state */ + UB_CMDST_CMD, /* Command submitted */ + UB_CMDST_DATA, /* Data phase */ + UB_CMDST_CLR2STS, /* Clearing before requesting status */ + UB_CMDST_STAT, /* Status phase */ + UB_CMDST_CLEAR, /* Clearing a stall (halt, actually) */ + UB_CMDST_SENSE, /* Sending Request Sense */ + UB_CMDST_DONE /* Final state */ +}; + +static char *ub_scsi_cmd_stname[] = { + ". ", + "Cmd", + "dat", + "c2s", + "sts", + "clr", + "Sen", + "fin" +}; + +struct ub_scsi_cmd { + unsigned char cdb[UB_MAX_CDB_SIZE]; + unsigned char cdb_len; + + unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ + unsigned char trace_index; + enum ub_scsi_cmd_state state; + unsigned int tag; + struct ub_scsi_cmd *next; + + int error; /* Return code - valid upon done */ + int act_len; /* Return size */ + + int stat_count; /* Retries getting status. */ + + /* + * We do not support transfers from highmem pages + * because the underlying USB framework does not do what we need. + */ + char *data; /* Requested buffer */ + unsigned int len; /* Requested length */ + // struct scatterlist sgv[UB_MAX_REQ_SG]; + + void (*done)(struct ub_dev *, struct ub_scsi_cmd *); + void *back; +}; + +/* + */ +struct ub_capacity { + unsigned long nsec; /* Linux size - 512 byte sectors */ + unsigned int bsize; /* Linux hardsect_size */ + unsigned int bshift; /* Shift between 512 and hard sects */ +}; + +/* + * The SCSI command tracing structure. + */ + +#define SCMD_ST_HIST_SZ 8 +#define SCMD_TRACE_SZ 15 /* No more than 256 (trace_index) */ + +struct ub_scsi_cmd_trace { + int hcur; + unsigned int tag; + unsigned int req_size, act_size; + unsigned char op; + unsigned char dir; + unsigned char key, asc, ascq; + char st_hst[SCMD_ST_HIST_SZ]; +}; + +struct ub_scsi_trace { + int cur; + struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ]; +}; + +/* + * This is a direct take-off from linux/include/completion.h + * The difference is that I do not wait on this thing, just poll. + * When I want to wait (ub_probe), I just use the stock completion. + * + * Note that INIT_COMPLETION takes no lock. It is correct. But why + * in the bloody hell that thing takes struct instead of pointer to struct + * is quite beyond me. I just copied it from the stock completion. + */ +struct ub_completion { + unsigned int done; + spinlock_t lock; +}; + +static inline void ub_init_completion(struct ub_completion *x) +{ + x->done = 0; + spin_lock_init(&x->lock); +} + +#define UB_INIT_COMPLETION(x) ((x).done = 0) + +static void ub_complete(struct ub_completion *x) +{ + unsigned long flags; + + spin_lock_irqsave(&x->lock, flags); + x->done++; + spin_unlock_irqrestore(&x->lock, flags); +} + +static int ub_is_completed(struct ub_completion *x) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&x->lock, flags); + ret = x->done; + spin_unlock_irqrestore(&x->lock, flags); + return ret; +} + +/* + */ +struct ub_scsi_cmd_queue { + int qlen, qmax; + struct ub_scsi_cmd *head, *tail; +}; + +/* + * The UB device instance. + */ +struct ub_dev { + spinlock_t lock; + int id; /* Number among ub's */ + atomic_t poison; /* The USB device is disconnected */ + int openc; /* protected by ub_lock! */ + /* kref is too implicit for our taste */ + unsigned int tagcnt; + int changed; /* Media was changed */ + int removable; + int readonly; + char name[8]; + struct usb_device *dev; + struct usb_interface *intf; + + struct ub_capacity capacity; + struct gendisk *disk; + + unsigned int send_bulk_pipe; /* cached pipe values */ + unsigned int recv_bulk_pipe; + unsigned int send_ctrl_pipe; + unsigned int recv_ctrl_pipe; + + struct tasklet_struct tasklet; + + /* XXX Use Ingo's mempool (once we have more than one) */ + int cmda[1]; + struct ub_scsi_cmd cmdv[1]; + + struct ub_scsi_cmd_queue cmd_queue; + struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */ + unsigned char top_sense[UB_SENSE_SIZE]; + + struct ub_completion work_done; + struct urb work_urb; + struct timer_list work_timer; + int last_pipe; /* What might need clearing */ + struct bulk_cb_wrap work_bcb; + struct bulk_cs_wrap work_bcs; + struct usb_ctrlrequest work_cr; + + struct ub_scsi_trace tr; +}; + +/* + */ +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_end_rq(struct request *rq, int uptodate); +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_urb_complete(struct urb *urb, struct pt_regs *pt); +static void ub_scsi_action(unsigned long _dev); +static void ub_scsi_dispatch(struct ub_dev *sc); +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + int stalled_pipe); +static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); +static int ub_sync_tur(struct ub_dev *sc); +static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret); + +/* + */ +static struct usb_device_id ub_usb_ids[] = { + // { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) }, /* SDDR-31 */ + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, ub_usb_ids); + +/* + * Find me a way to identify "next free minor" for add_disk(), + * and the array disappears the next day. However, the number of + * hosts has something to do with the naming and /proc/partitions. + * This has to be thought out in detail before changing. + * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. + */ +#define UB_MAX_HOSTS 26 +static char ub_hostv[UB_MAX_HOSTS]; +static spinlock_t ub_lock = SPIN_LOCK_UNLOCKED; /* Locks globals and ->openc */ + +/* + * The SCSI command tracing procedures. + */ + +static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int n; + struct ub_scsi_cmd_trace *t; + + if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0; + t = &sc->tr.vec[n]; + + memset(t, 0, sizeof(struct ub_scsi_cmd_trace)); + t->tag = cmd->tag; + t->op = cmd->cdb[0]; + t->dir = cmd->dir; + t->req_size = cmd->len; + t->st_hst[0] = cmd->state; + + sc->tr.cur = n; + cmd->trace_index = n; +} + +static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int n; + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) { + if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0; + t->st_hst[n] = cmd->state; + t->hcur = n; + } +} + +static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) + t->act_size = cmd->act_len; +} + +static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + unsigned char *sense) +{ + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) { + t->key = sense[2] & 0x0F; + t->asc = sense[12]; + t->ascq = sense[13]; + } +} + +static ssize_t ub_diag_show(struct device *dev, char *page) +{ + struct usb_interface *intf; + struct ub_dev *sc; + int cnt; + unsigned long flags; + int nc, nh; + int i, j; + struct ub_scsi_cmd_trace *t; + + intf = to_usb_interface(dev); + sc = usb_get_intfdata(intf); + if (sc == NULL) + return 0; + + cnt = 0; + spin_lock_irqsave(&sc->lock, flags); + + cnt += sprintf(page + cnt, + "qlen %d qmax %d changed %d removable %d readonly %d\n", + sc->cmd_queue.qlen, sc->cmd_queue.qmax, + sc->changed, sc->removable, sc->readonly); + + if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0; + for (j = 0; j < SCMD_TRACE_SZ; j++) { + t = &sc->tr.vec[nc]; + + cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op); + if (t->op == REQUEST_SENSE) { + cnt += sprintf(page + cnt, " [sense %x %02x %02x]", + t->key, t->asc, t->ascq); + } else { + cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir)); + cnt += sprintf(page + cnt, " [%5d %5d]", + t->req_size, t->act_size); + } + if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0; + for (i = 0; i < SCMD_ST_HIST_SZ; i++) { + cnt += sprintf(page + cnt, " %s", + ub_scsi_cmd_stname[(int)t->st_hst[nh]]); + if (++nh == SCMD_ST_HIST_SZ) nh = 0; + } + cnt += sprintf(page + cnt, "\n"); + + if (++nc == SCMD_TRACE_SZ) nc = 0; + } + + spin_unlock_irqrestore(&sc->lock, flags); + return cnt; +} + +static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */ + +/* + * The id allocator. + * + * This also stores the host for indexing by minor, which is somewhat dirty. + */ +static int ub_id_get(void) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&ub_lock, flags); + for (i = 0; i < UB_MAX_HOSTS; i++) { + if (ub_hostv[i] == 0) { + ub_hostv[i] = 1; + spin_unlock_irqrestore(&ub_lock, flags); + return i; + } + } + spin_unlock_irqrestore(&ub_lock, flags); + return -1; +} + +static void ub_id_put(int id) +{ + + if (id < 0 || id >= UB_MAX_HOSTS) { + printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id); + return; + } + if (ub_hostv[id] == 0) { + printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id); + return; + } + ub_hostv[id] = 0; +} + +/* + * Final cleanup and deallocation. + * This must be called with ub_lock taken. + */ +static void ub_cleanup(struct ub_dev *sc) +{ + ub_id_put(sc->id); + kfree(sc); +} + +/* + * The "command allocator". + */ +static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc) +{ + struct ub_scsi_cmd *ret; + + if (sc->cmda[0]) + return NULL; + ret = &sc->cmdv[0]; + sc->cmda[0] = 1; + return ret; +} + +static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + if (cmd != &sc->cmdv[0]) { + printk(KERN_WARNING "%s: releasing a foreign cmd %p\n", + sc->name, cmd); + return; + } + if (!sc->cmda[0]) { + printk(KERN_WARNING "%s: releasing a free cmd\n", sc->name); + return; + } + sc->cmda[0] = 0; +} + +/* + * The command queue. + */ +static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + + if (t->qlen++ == 0) { + t->head = cmd; + t->tail = cmd; + } else { + t->tail->next = cmd; + t->tail = cmd; + } + + if (t->qlen > t->qmax) + t->qmax = t->qlen; +} + +static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + + if (t->qlen++ == 0) { + t->head = cmd; + t->tail = cmd; + } else { + cmd->next = t->head; + t->head = cmd; + } + + if (t->qlen > t->qmax) + t->qmax = t->qlen; +} + +static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + struct ub_scsi_cmd *cmd; + + if (t->qlen == 0) + return NULL; + if (--t->qlen == 0) + t->tail = NULL; + cmd = t->head; + t->head = cmd->next; + cmd->next = NULL; + return cmd; +} + +#define ub_cmdq_peek(sc) ((sc)->cmd_queue.head) + +/* + * The request function is our main entry point + */ + +static inline int ub_bd_rq_fn_1(request_queue_t *q) +{ +#if 0 + int writing = 0, pci_dir, i, n_elem; + u32 tmp; + unsigned int msg_size; +#endif + struct ub_dev *sc = q->queuedata; + struct request *rq; +#if 0 /* We use rq->buffer for now */ + struct scatterlist *sg; + int n_elem; +#endif + struct ub_scsi_cmd *cmd; + int ub_dir; + unsigned int block, nblks; + int rc; + + if ((rq = elv_next_request(q)) == NULL) + return 1; + + if (atomic_read(&sc->poison) || sc->changed) { + blkdev_dequeue_request(rq); + ub_end_rq(rq, 0); + return 0; + } + + if ((cmd = ub_get_cmd(sc)) == NULL) { + blk_stop_queue(q); + return 1; + } + + blkdev_dequeue_request(rq); + + if (rq_data_dir(rq) == WRITE) + ub_dir = UB_DIR_WRITE; + else + ub_dir = UB_DIR_READ; + + /* + * get scatterlist from block layer + */ +#if 0 /* We use rq->buffer for now */ + sg = &cmd->sgv[0]; + n_elem = blk_rq_map_sg(q, rq, sg); + if (n_elem <= 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; /* request with no s/g entries? */ + } + + if (n_elem != 1) { /* Paranoia */ + printk(KERN_WARNING "%s: request with %d segments\n", + sc->name, n_elem); + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } +#endif + /* + * XXX Unfortunately, this check does not work. It is quite possible + * to get bogus non-null rq->buffer if you allow sg by mistake. + */ + if (rq->buffer == NULL) { + /* + * This must not happen if we set the queue right. + * The block level must create bounce buffers for us. + */ + static int do_print = 1; + if (do_print) { + printk(KERN_WARNING "%s: unmapped request\n", sc->name); + do_print = 0; + } + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } + + /* + * build the command + */ + block = rq->sector; + nblks = rq->nr_sectors; + + memset(cmd, 0, sizeof(struct ub_scsi_cmd)); + cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; + /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ + cmd->cdb[2] = block >> 24; + cmd->cdb[3] = block >> 16; + cmd->cdb[4] = block >> 8; + cmd->cdb[5] = block; + cmd->cdb[7] = nblks >> 8; + cmd->cdb[8] = nblks; + cmd->cdb_len = 10; + cmd->dir = ub_dir; + cmd->state = UB_CMDST_INIT; + cmd->data = rq->buffer; + cmd->len = nblks * 512; + cmd->done = ub_rw_cmd_done; + cmd->back = rq; + + cmd->tag = sc->tagcnt++; + if ((rc = ub_submit_scsi(sc, cmd)) != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } + + return 0; +} + +static void ub_bd_rq_fn(request_queue_t *q) +{ + do { } while (ub_bd_rq_fn_1(q) == 0); +} + +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct request *rq = cmd->back; + struct gendisk *disk = sc->disk; + request_queue_t *q = disk->queue; + int uptodate; + + if (cmd->error == 0) + uptodate = 1; + else + uptodate = 0; + + ub_put_cmd(sc, cmd); + ub_end_rq(rq, uptodate); + blk_start_queue(q); +} + +static void ub_end_rq(struct request *rq, int uptodate) +{ + int rc; + + rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors); + // assert(rc == 0); + end_that_request_last(rq); +} + +/* + * Submit a regular SCSI operation (not an auto-sense). + * + * The Iron Law of Good Submit Routine is: + * Zero return - callback is done, Nonzero return - callback is not done. + * No exceptions. + * + * Host is assumed locked. + * + * XXX We only support Bulk for the moment. + */ +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + + if (cmd->state != UB_CMDST_INIT || + (cmd->dir != UB_DIR_NONE && cmd->len == 0)) { + return -EINVAL; + } + + ub_cmdq_add(sc, cmd); + /* + * We can call ub_scsi_dispatch(sc) right away here, but it's a little + * safer to jump to a tasklet, in case upper layers do something silly. + */ + tasklet_schedule(&sc->tasklet); + return 0; +} + +/* + * Submit the first URB for the queued command. + * This function does not deal with queueing in any way. + */ +static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct bulk_cb_wrap *bcb; + int rc; + + bcb = &sc->work_bcb; + + /* set up the command wrapper */ + bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); + bcb->Tag = cmd->tag; /* Endianness is not important */ + bcb->DataTransferLength = cpu_to_le32(cmd->len); + bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0; + bcb->Lun = 0; /* No multi-LUN yet */ + bcb->Length = cmd->cdb_len; + + /* copy the command payload */ + memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE); + + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->send_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, + bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + + /* Fill what we shouldn't be filling, because usb-storage did so. */ + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + return rc; + } + + cmd->state = UB_CMDST_CMD; + ub_cmdtr_state(sc, cmd); + return 0; +} + +/* + * Timeout handler. + */ +static void ub_urb_timeout(unsigned long arg) +{ + struct ub_dev *sc = (struct ub_dev *) arg; + unsigned long flags; + + spin_lock_irqsave(&sc->lock, flags); + usb_unlink_urb(&sc->work_urb); + spin_unlock_irqrestore(&sc->lock, flags); +} + +/* + * Completion routine for the work URB. + * + * This can be called directly from usb_submit_urb (while we have + * the sc->lock taken) and from an interrupt (while we do NOT have + * the sc->lock taken). Therefore, bounce this off to a tasklet. + */ +static void ub_urb_complete(struct urb *urb, struct pt_regs *pt) +{ + struct ub_dev *sc = urb->context; + + ub_complete(&sc->work_done); + tasklet_schedule(&sc->tasklet); +} + +static void ub_scsi_action(unsigned long _dev) +{ + struct ub_dev *sc = (struct ub_dev *) _dev; + unsigned long flags; + + spin_lock_irqsave(&sc->lock, flags); + ub_scsi_dispatch(sc); + spin_unlock_irqrestore(&sc->lock, flags); +} + +static void ub_scsi_dispatch(struct ub_dev *sc) +{ + struct ub_scsi_cmd *cmd; + int rc; + + while ((cmd = ub_cmdq_peek(sc)) != NULL) { + if (cmd->state == UB_CMDST_DONE) { + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + } else if (cmd->state == UB_CMDST_INIT) { + ub_cmdtr_new(sc, cmd); + if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) + break; + cmd->error = rc; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + } else { + if (!ub_is_completed(&sc->work_done)) + break; + ub_scsi_urb_compl(sc, cmd); + } + } +} + +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct urb *urb = &sc->work_urb; + struct bulk_cs_wrap *bcs; + int pipe; + int rc; + +/* P3 */ /** printk("ub: urb status %d pipe 0x%08x len %d act %d\n", + urb->status, urb->pipe, urb->transfer_buffer_length, urb->actual_length); **/ + + if (atomic_read(&sc->poison)) { + /* A little too simplistic, I feel... */ + goto Bad_End; + } + + if (cmd->state == UB_CMDST_CLEAR) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * A STALL is illegal on a control pipe! + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: " + "stall on control pipe for device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_sense(sc, cmd); + + } else if (cmd->state == UB_CMDST_CLR2STS) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * A STALL is illegal on a control pipe! + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: " + "stall on control pipe for device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_stat(sc, cmd); + + } else if (cmd->state == UB_CMDST_CMD) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLEAR; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status != 0) + goto Bad_End; + if (urb->actual_length != US_BULK_CB_WRAP_LEN) { + /* XXX Must do reset here to unconfuse the device */ + goto Bad_End; + } + + if (cmd->dir == UB_DIR_NONE) { + ub_state_stat(sc, cmd); + return; + } + + UB_INIT_COMPLETION(sc->work_done); + + if (cmd->dir == UB_DIR_READ) + pipe = sc->recv_bulk_pipe; + else + pipe = sc->send_bulk_pipe; + sc->last_pipe = pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, + cmd->data, cmd->len, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + + cmd->state = UB_CMDST_DATA; + ub_cmdtr_state(sc, cmd); + + } else if (cmd->state == UB_CMDST_DATA) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLR2STS; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status == -EOVERFLOW) { + /* + * A babble? Failure, but we must transfer CSW now. + */ + cmd->error = -EOVERFLOW; /* A cheap trick... */ + } else { + if (urb->status != 0) + goto Bad_End; + } + + cmd->act_len = urb->actual_length; + ub_cmdtr_act_len(sc, cmd); + + ub_state_stat(sc, cmd); + + } else if (cmd->state == UB_CMDST_STAT) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLEAR; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status != 0) + goto Bad_End; + + if (urb->actual_length == 0) { + /* + * Some broken devices add unnecessary zero-length + * packets to the end of their data transfers. + * Such packets show up as 0-length CSWs. If we + * encounter such a thing, try to read the CSW again. + */ + if (++cmd->stat_count >= 4) { + printk(KERN_NOTICE "%s: " + "unable to get CSW on device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * ub_state_stat only not dropping the count... + */ + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->recv_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, + sc->recv_bulk_pipe, &sc->work_bcs, + US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); + if (rc != 0) { + /* XXX Clear stalls */ + printk("%s: CSW #%d submit failed (%d)\n", + sc->name, cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + return; + } + + /* + * Check the returned Bulk protocol status. + */ + + bcs = &sc->work_bcs; + rc = le32_to_cpu(bcs->Residue); + if (rc != cmd->len - cmd->act_len) { + /* + * It is all right to transfer less, the caller has + * to check. But it's not all right if the device + * counts disagree with our counts. + */ + /* P3 */ printk("%s: resid %d len %d act %d\n", + sc->name, rc, cmd->len, cmd->act_len); + goto Bad_End; + } + + if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && + bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) { + /* XXX Rate-limit, even for P3 tagged */ + /* P3 */ printk("ub: signature 0x%x\n", bcs->Signature); + /* Windows ignores signatures, so do we. */ + } + + if (bcs->Tag != cmd->tag) { + /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n", + sc->name, cmd->tag, bcs->Tag); + goto Bad_End; + } + + switch (bcs->Status) { + case US_BULK_STAT_OK: + break; + case US_BULK_STAT_FAIL: + ub_state_sense(sc, cmd); + return; + case US_BULK_STAT_PHASE: + /* XXX We must reset the transport here */ + /* P3 */ printk("%s: status PHASE\n", sc->name); + goto Bad_End; + default: + printk(KERN_INFO "%s: unknown CSW status 0x%x\n", + sc->name, bcs->Status); + goto Bad_End; + } + + /* Not zeroing error to preserve a babble indicator */ + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + + } else if (cmd->state == UB_CMDST_SENSE) { + /* + * We do not look at sense, because even if there was no sense, + * we get into UB_CMDST_SENSE from a STALL or CSW FAIL only. + * We request sense because we want to clear CHECK CONDITION + * on devices with delusions of SCSI, and not because we + * are curious in any way about the sense itself. + */ + /* if ((cmd->top_sense[2] & 0x0F) == NO_SENSE) { foo } */ + + ub_state_done(sc, cmd, -EIO); + } else { + printk(KERN_WARNING "%s: " + "wrong command state %d on device %u\n", + sc->name, cmd->state, sc->dev->devnum); + goto Bad_End; + } + return; + +Bad_End: /* Little Excel is dead */ + ub_state_done(sc, cmd, -EIO); +} + +/* + * Factorization helper for the command state machine: + * Finish the command. + */ +static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) +{ + + cmd->error = rc; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); +} + +/* + * Factorization helper for the command state machine: + * Submit a CSW read and go to STAT state. + */ +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int rc; + + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->recv_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, + &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + + cmd->stat_count = 0; + cmd->state = UB_CMDST_STAT; + ub_cmdtr_state(sc, cmd); +} + +/* + * Factorization helper for the command state machine: + * Submit a REQUEST SENSE and go to SENSE state. + */ +static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd *scmd; + int rc; + + if (cmd->cdb[0] == REQUEST_SENSE) { + rc = -EPIPE; + goto error; + } + + memset(&sc->top_sense, 0, UB_SENSE_SIZE); + scmd = &sc->top_rqs_cmd; + scmd->cdb[0] = REQUEST_SENSE; + scmd->cdb_len = 6; + scmd->dir = UB_DIR_READ; + scmd->state = UB_CMDST_INIT; + scmd->data = sc->top_sense; + scmd->len = UB_SENSE_SIZE; + scmd->done = ub_top_sense_done; + scmd->back = cmd; + + scmd->tag = sc->tagcnt++; + + cmd->state = UB_CMDST_SENSE; + ub_cmdtr_state(sc, cmd); + + ub_cmdq_insert(sc, scmd); + return; + +error: + ub_state_done(sc, cmd, rc); +} + +/* + * A helper for the command's state machine: + * Submit a stall clear. + */ +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + int stalled_pipe) +{ + int endp; + struct usb_ctrlrequest *cr; + int rc; + + endp = usb_pipeendpoint(stalled_pipe); + if (usb_pipein (stalled_pipe)) + endp |= USB_DIR_IN; + + cr = &sc->work_cr; + cr->bRequestType = USB_RECIP_ENDPOINT; + cr->bRequest = USB_REQ_CLEAR_FEATURE; + cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); + cr->wIndex = cpu_to_le16(endp); + cr->wLength = cpu_to_le16(0); + + UB_INIT_COMPLETION(sc->work_done); + + usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, + (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); + sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT; + add_timer(&sc->work_timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + del_timer(&sc->work_timer); + ub_complete(&sc->work_done); + return rc; + } + return 0; +} + +/* + */ +static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) +{ + unsigned char *sense = scmd->data; + struct ub_scsi_cmd *cmd; + + ub_cmdtr_sense(sc, scmd, sense); + + if ((cmd = ub_cmdq_peek(sc)) == NULL) { + printk(KERN_WARNING "%s: sense done while idle\n", sc->name); + return; + } + if (cmd != scmd->back) { + printk(KERN_WARNING "%s: " + "sense done for wrong command 0x%x on device %u\n", + sc->name, cmd->tag, sc->dev->devnum); + return; + } + if (cmd->state != UB_CMDST_SENSE) { + printk(KERN_WARNING "%s: " + "sense done with bad cmd state %d on device %u\n", + sc->name, cmd->state, sc->dev->devnum); + return; + } + + ub_scsi_urb_compl(sc, cmd); +} + +#if 0 +/* Determine what the maximum LUN supported is */ +int usb_stor_Bulk_max_lun(struct us_data *us) +{ + int result; + + /* issue the command */ + result = usb_stor_control_msg(us, us->recv_ctrl_pipe, + US_BULK_GET_MAX_LUN, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + 0, us->ifnum, us->iobuf, 1, HZ); + + /* + * Some devices (i.e. Iomega Zip100) need this -- apparently + * the bulk pipes get STALLed when the GetMaxLUN request is + * processed. This is, in theory, harmless to all other devices + * (regardless of if they stall or not). + */ + if (result < 0) { + usb_stor_clear_halt(us, us->recv_bulk_pipe); + usb_stor_clear_halt(us, us->send_bulk_pipe); + } + + US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", + result, us->iobuf[0]); + + /* if we have a successful request, return the result */ + if (result == 1) + return us->iobuf[0]; + + /* return the default -- no LUNs */ + return 0; +} +#endif + +/* + * This is called from a process context. + */ +static void ub_revalidate(struct ub_dev *sc) +{ + + sc->readonly = 0; /* XXX Query this from the device */ + + /* + * XXX sd.c sets capacity to zero in such case. However, it doesn't + * work for us. In case of zero capacity, block layer refuses to + * have the /dev/uba opened (why?) Set capacity to some random value. + */ + sc->capacity.nsec = 50; + sc->capacity.bsize = 512; + sc->capacity.bshift = 0; + + if (ub_sync_tur(sc) != 0) + return; /* Not ready */ + sc->changed = 0; + + if (ub_sync_read_cap(sc, &sc->capacity) != 0) { + /* + * The retry here means something is wrong, either with the + * device, with the transport, or with our code. + * We keep this because sd.c has retries for capacity. + */ + if (ub_sync_read_cap(sc, &sc->capacity) != 0) { + sc->capacity.nsec = 100; + sc->capacity.bsize = 512; + sc->capacity.bshift = 0; + } + } +} + +/* + * The open funcion. + * This is mostly needed to keep refcounting, but also to support + * media checks on removable media drives. + */ +static int ub_bd_open(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ub_dev *sc; + unsigned long flags; + int rc; + + if ((sc = disk->private_data) == NULL) + return -ENXIO; + spin_lock_irqsave(&ub_lock, flags); + if (atomic_read(&sc->poison)) { + spin_unlock_irqrestore(&ub_lock, flags); + return -ENXIO; + } + sc->openc++; + spin_unlock_irqrestore(&ub_lock, flags); + + if (sc->removable || sc->readonly) + check_disk_change(inode->i_bdev); + + /* XXX sd.c and floppy.c bail on open if media is not present. */ + + if (sc->readonly && (filp->f_mode & FMODE_WRITE)) { + rc = -EROFS; + goto err_open; + } + + return 0; + +err_open: + spin_lock_irqsave(&ub_lock, flags); + --sc->openc; + if (sc->openc == 0 && atomic_read(&sc->poison)) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); + return rc; +} + +/* + */ +static int ub_bd_release(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ub_dev *sc = disk->private_data; + unsigned long flags; + + spin_lock_irqsave(&ub_lock, flags); + --sc->openc; + if (sc->openc == 0 && atomic_read(&sc->poison)) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); + return 0; +} + +/* + * The ioctl interface. + */ +static int ub_bd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ +// void __user *usermem = (void *) arg; +// struct carm_port *port = ino->i_bdev->bd_disk->private_data; +// struct hd_geometry geom; + +#if 0 + switch (cmd) { + case HDIO_GETGEO: + if (usermem == NULL) // XXX Bizzare. Why? + return -EINVAL; + + geom.heads = (u8) port->dev_geom_head; + geom.sectors = (u8) port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + geom.start = get_start_sect(ino->i_bdev); + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + + default: ; + } +#endif + + return -ENOTTY; +} + +/* + * This is called once a new disk was seen by the block layer or by ub_probe(). + * The main onjective here is to discover the features of the media such as + * the capacity, read-only status, etc. USB storage generally does not + * need to be spun up, but if we needed it, this would be the place. + * + * This call can sleep. + * + * The return code is not used. + */ +static int ub_bd_revalidate(struct gendisk *disk) +{ + struct ub_dev *sc = disk->private_data; + + ub_revalidate(sc); + /* This is pretty much a long term P3 */ + printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", + sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + + set_capacity(disk, sc->capacity.nsec); + // set_disk_ro(sdkp->disk, sc->readonly); + return 0; +} + +/* + * The check is called by the block layer to verify if the media + * is still available. It is supposed to be harmless, lightweight and + * non-intrusive in case the media was not changed. + * + * This call can sleep. + * + * The return code is bool! + */ +static int ub_bd_media_changed(struct gendisk *disk) +{ + struct ub_dev *sc = disk->private_data; + + if (!sc->removable) + return 0; + + /* + * We clean checks always after every command, so this is not + * as dangerous as it looks. If the TEST_UNIT_READY fails here, + * the device is actually not ready with operator or software + * intervention required. One dangerous item might be a drive which + * spins itself down, and come the time to write dirty pages, this + * will fail, then block layer discards the data. Since we never + * spin drives up, such devices simply cannot be used with ub anyway. + */ + if (ub_sync_tur(sc) != 0) { + sc->changed = 1; + /* P3 */ printk("%s: made changed\n", sc->name); + return 1; + } + + /* The sd.c clears this before returning (one-shot flag). Why? */ + /* P3 */ printk("%s: %s changed\n", sc->name, + sc->changed? "is": "was not"); + return sc->changed; +} + +static struct block_device_operations ub_bd_fops = { + .owner = THIS_MODULE, + .open = ub_bd_open, + .release = ub_bd_release, + .ioctl = ub_bd_ioctl, + .media_changed = ub_bd_media_changed, + .revalidate_disk = ub_bd_revalidate, +}; + +/* + * Common ->done routine for commands executed synchronously. + */ +static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct completion *cop = cmd->back; + complete(cop); +} + +/* + * Test if the device has a check condition on it, synchronously. + */ +static int ub_sync_tur(struct ub_dev *sc) +{ + struct ub_scsi_cmd *cmd; + enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) }; + unsigned long flags; + struct completion compl; + int rc; + + init_completion(&compl); + + rc = -ENOMEM; + if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) + goto err_alloc; + memset(cmd, 0, ALLOC_SIZE); + + cmd->cdb[0] = TEST_UNIT_READY; + cmd->cdb_len = 6; + cmd->dir = UB_DIR_NONE; + cmd->state = UB_CMDST_INIT; + cmd->done = ub_probe_done; + cmd->back = &compl; + + spin_lock_irqsave(&sc->lock, flags); + cmd->tag = sc->tagcnt++; + + rc = ub_submit_scsi(sc, cmd); + spin_unlock_irqrestore(&sc->lock, flags); + + if (rc != 0) { + printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */ + goto err_submit; + } + + wait_for_completion(&compl); + + rc = cmd->error; + +err_submit: + kfree(cmd); +err_alloc: + return rc; +} + +/* + * Read the SCSI capacity synchronously (for probing). + */ +static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret) +{ + struct ub_scsi_cmd *cmd; + char *p; + enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 }; + unsigned long flags; + unsigned int bsize, shift; + unsigned long nsec; + struct completion compl; + int rc; + + init_completion(&compl); + + rc = -ENOMEM; + if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) + goto err_alloc; + memset(cmd, 0, ALLOC_SIZE); + p = (char *)cmd + sizeof(struct ub_scsi_cmd); + + cmd->cdb[0] = 0x25; + cmd->cdb_len = 10; + cmd->dir = UB_DIR_READ; + cmd->state = UB_CMDST_INIT; + cmd->data = p; + cmd->len = 8; + cmd->done = ub_probe_done; + cmd->back = &compl; + + spin_lock_irqsave(&sc->lock, flags); + cmd->tag = sc->tagcnt++; + + rc = ub_submit_scsi(sc, cmd); + spin_unlock_irqrestore(&sc->lock, flags); + + if (rc != 0) { + printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */ + goto err_submit; + } + + wait_for_completion(&compl); + + if (cmd->error != 0) { + printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */ + rc = -EIO; + goto err_read; + } + if (cmd->act_len != 8) { + printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */ + rc = -EIO; + goto err_read; + } + + /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */ + nsec = be32_to_cpu(*(u32 *)p) + 1; + bsize = be32_to_cpu(*(u32 *)(p + 4)); + switch (bsize) { + case 512: shift = 0; break; + case 1024: shift = 1; break; + case 2048: shift = 2; break; + case 4096: shift = 3; break; + default: + printk("ub: Bad sector size %u\n", bsize); /* P3 */ + rc = -EDOM; + goto err_inv_bsize; + } + + ret->bsize = bsize; + ret->bshift = shift; + ret->nsec = nsec << shift; + rc = 0; + +err_inv_bsize: +err_read: +err_submit: + kfree(cmd); +err_alloc: + return rc; +} + +/* + */ +static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt) +{ + struct completion *cop = urb->context; + complete(cop); +} + +static void ub_probe_timeout(unsigned long arg) +{ + struct completion *cop = (struct completion *) arg; + complete(cop); +} + +/* + * Clear initial stalls. + */ +static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) +{ + int endp; + struct usb_ctrlrequest *cr; + struct completion compl; + struct timer_list timer; + int rc; + + init_completion(&compl); + + endp = usb_pipeendpoint(stalled_pipe); + if (usb_pipein (stalled_pipe)) + endp |= USB_DIR_IN; + + cr = &sc->work_cr; + cr->bRequestType = USB_RECIP_ENDPOINT; + cr->bRequest = USB_REQ_CLEAR_FEATURE; + cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); + cr->wIndex = cpu_to_le16(endp); + cr->wLength = cpu_to_le16(0); + + usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, + (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); + sc->work_urb.transfer_flags = 0; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + init_timer(&timer); + timer.function = ub_probe_timeout; + timer.data = (unsigned long) &compl; + timer.expires = jiffies + UB_CTRL_TIMEOUT; + add_timer(&timer); + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { + printk(KERN_WARNING + "%s: Unable to submit a probe clear (%d)\n", sc->name, rc); + del_timer_sync(&timer); + return rc; + } + + wait_for_completion(&compl); + + del_timer_sync(&timer); + /* + * Most of the time, URB was done and dev set to NULL, and so + * the unlink bounces out with ENODEV. We do not call usb_kill_urb + * because we still think about a backport to 2.4. + */ + usb_unlink_urb(&sc->work_urb); + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); + + return 0; +} + +/* + * Get the pipe settings. + */ +static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, + struct usb_interface *intf) +{ + struct usb_host_interface *altsetting = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; + struct usb_endpoint_descriptor *ep; + int i; + + /* + * Find the endpoints we need. + * We are expecting a minimum of 2 endpoints - in and out (bulk). + * We will ignore any others. + */ + for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { + ep = &altsetting->endpoint[i].desc; + + /* Is it a BULK endpoint? */ + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) { + /* BULK in or out? */ + if (ep->bEndpointAddress & USB_DIR_IN) + ep_in = ep; + else + ep_out = ep; + } + } + + if (ep_in == NULL || ep_out == NULL) { + printk(KERN_NOTICE "%s: device %u failed endpoint check\n", + sc->name, sc->dev->devnum); + return -EIO; + } + + /* Calculate and store the pipe values */ + sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0); + sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0); + sc->send_bulk_pipe = usb_sndbulkpipe(dev, + ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, + ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + return 0; +} + +/* + * Probing is done in the process context, which allows us to cheat + * and not to build a state machine for the discovery. + */ +static int ub_probe(struct usb_interface *intf, + const struct usb_device_id *dev_id) +{ + struct ub_dev *sc; + request_queue_t *q; + struct gendisk *disk; + int rc; + + rc = -ENOMEM; + if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL) + goto err_core; + memset(sc, 0, sizeof(struct ub_dev)); + spin_lock_init(&sc->lock); + usb_init_urb(&sc->work_urb); + tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); + atomic_set(&sc->poison, 0); + + init_timer(&sc->work_timer); + sc->work_timer.data = (unsigned long) sc; + sc->work_timer.function = ub_urb_timeout; + + ub_init_completion(&sc->work_done); + sc->work_done.done = 1; /* A little yuk, but oh well... */ + + rc = -ENOSR; + if ((sc->id = ub_id_get()) == -1) + goto err_id; + snprintf(sc->name, 8, DRV_NAME "%c", sc->id + 'a'); + + sc->dev = interface_to_usbdev(intf); + sc->intf = intf; + // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + + usb_set_intfdata(intf, sc); + usb_get_dev(sc->dev); + // usb_get_intf(sc->intf); /* Do we need this? */ + + /* XXX Verify that we can handle the device (from descriptors) */ + + ub_get_pipes(sc, sc->dev, intf); + + if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0) + goto err_diag; + + /* + * At this point, all USB initialization is done, do upper layer. + * We really hate halfway initialized structures, so from the + * invariants perspective, this ub_dev is fully constructed at + * this point. + */ + + /* + * This is needed to clear toggles. It is a problem only if we do + * `rmmod ub && modprobe ub` without disconnects, but we like that. + */ + ub_probe_clear_stall(sc, sc->recv_bulk_pipe); + ub_probe_clear_stall(sc, sc->send_bulk_pipe); + + /* + * The way this is used by the startup code is a little specific. + * A SCSI check causes a USB stall. Our common case code sees it + * and clears the check, after which the device is ready for use. + * But if a check was not present, any command other than + * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE). + * + * If we neglect to clear the SCSI check, the first real command fails + * (which is the capacity readout). We clear that and retry, but why + * causing spurious retries for no reason. + * + * Revalidation may start with its own TEST_UNIT_READY, but that one + * has to succeed, so we clear checks with an additional one here. + * In any case it's not our business how revaliadation is implemented. + */ + ub_sync_tur(sc); + + sc->removable = 1; /* XXX Query this from the device */ + + ub_revalidate(sc); + /* This is pretty much a long term P3 */ + printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", + sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + + /* + * Just one disk per sc currently, but maybe more. + */ + rc = -ENOMEM; + if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL) + goto err_diskalloc; + + sc->disk = disk; + sprintf(disk->disk_name, DRV_NAME "%c", sc->id + 'a'); + sprintf(disk->devfs_name, DEVFS_NAME "/%c", sc->id + 'a'); + disk->major = UB_MAJOR; + disk->first_minor = sc->id * UB_MINORS_PER_MAJOR; + disk->fops = &ub_bd_fops; + disk->private_data = sc; + disk->driverfs_dev = &intf->dev; + + rc = -ENOMEM; + if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL) + goto err_blkqinit; + + disk->queue = q; + + // blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + blk_queue_max_hw_segments(q, UB_MAX_REQ_SG); + blk_queue_max_phys_segments(q, UB_MAX_REQ_SG); + // blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); + blk_queue_max_sectors(q, UB_MAX_SECTORS); + // blk_queue_hardsect_size(q, xxxxx); + + /* + * This is a serious infraction, caused by a deficiency in the + * USB sg interface (usb_sg_wait()). We plan to remove this once + * we get mileage on the driver and can justify a change to USB API. + * See blk_queue_bounce_limit() to understand this part. + * + * XXX And I still need to be aware of the DMA mask in the HC. + */ + q->bounce_pfn = blk_max_low_pfn; + q->bounce_gfp = GFP_NOIO; + + q->queuedata = sc; + + set_capacity(disk, sc->capacity.nsec); + if (sc->removable) + disk->flags |= GENHD_FL_REMOVABLE; + + add_disk(disk); + + return 0; + +err_blkqinit: + put_disk(disk); +err_diskalloc: + device_remove_file(&sc->intf->dev, &dev_attr_diag); +err_diag: + usb_set_intfdata(intf, NULL); + // usb_put_intf(sc->intf); + usb_put_dev(sc->dev); + spin_lock_irq(&ub_lock); + ub_id_put(sc->id); + spin_unlock_irq(&ub_lock); +err_id: + kfree(sc); +err_core: + return rc; +} + +static void ub_disconnect(struct usb_interface *intf) +{ + struct ub_dev *sc = usb_get_intfdata(intf); + struct gendisk *disk = sc->disk; + request_queue_t *q = disk->queue; + unsigned long flags; + + /* + * Fence stall clearnings, operations triggered by unlinkings and so on. + * We do not attempt to unlink any URBs, because we do not trust the + * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. + */ + atomic_set(&sc->poison, 1); + + /* + * Blow away queued commands. + * + * Actually, this never works, because before we get here + * the HCD terminates outstanding URB(s). It causes our + * SCSI command queue to advance, commands fail to submit, + * and the whole queue drains. So, we just use this code to + * print warnings. + */ + spin_lock_irqsave(&sc->lock, flags); + { + struct ub_scsi_cmd *cmd; + int cnt = 0; + while ((cmd = ub_cmdq_pop(sc)) != NULL) { + cmd->error = -ENOTCONN; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + cnt++; + } + if (cnt != 0) { + printk(KERN_WARNING "%s: " + "%d was queued after shutdown\n", sc->name, cnt); + } + } + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * Unregister the upper layer, this waits for all commands to end. + */ + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (q) + blk_cleanup_queue(q); + + /* + * If we zero disk->private_data BEFORE put_disk, we have to check + * for NULL all over the place in open, release, check_media and + * revalidate, because the block level semaphore is well inside the + * put_disk. But we cannot zero after the call, because *disk is gone. + * The sd.c is blatantly racy in this area. + */ + /* disk->private_data = NULL; */ + put_disk(disk); + sc->disk = NULL; + + /* + * We really expect blk_cleanup_queue() to wait, so no amount + * of paranoya is too much. + * + * Taking a lock on a structure which is about to be freed + * is very nonsensual. Here it is largely a way to do a debug freeze, + * and a bracket which shows where the nonsensual code segment ends. + * + * Testing for -EINPROGRESS is always a bug, so we are bending + * the rules a little. + */ + spin_lock_irqsave(&sc->lock, flags); + if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */ + printk(KERN_WARNING "%s: " + "URB is active after disconnect\n", sc->name); + } + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * At this point there must be no commands coming from anyone + * and no URBs left in transit. + */ + + device_remove_file(&sc->intf->dev, &dev_attr_diag); + usb_set_intfdata(intf, NULL); + // usb_put_intf(sc->intf); + sc->intf = NULL; + usb_put_dev(sc->dev); + sc->dev = NULL; + + spin_lock_irqsave(&ub_lock, flags); + if (sc->openc == 0) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); +} + +struct usb_driver ub_driver = { + .owner = THIS_MODULE, + .name = "ub", + .probe = ub_probe, + .disconnect = ub_disconnect, + .id_table = ub_usb_ids, +}; + +static int __init ub_init(void) +{ + int rc; + + /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu\n", + sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev)); + + if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) + goto err_regblkdev; + devfs_mk_dir(DEVFS_NAME); + + if ((rc = usb_register(&ub_driver)) != 0) + goto err_register; + + return 0; + +err_register: + devfs_remove(DEVFS_NAME); + unregister_blkdev(UB_MAJOR, DRV_NAME); +err_regblkdev: + return rc; +} + +static void __exit ub_exit(void) +{ + usb_deregister(&ub_driver); + + devfs_remove(DEVFS_NAME); + unregister_blkdev(UB_MAJOR, DRV_NAME); +} + +module_init(ub_init); +module_exit(ub_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 2b126d8d2..db7083a0c 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -108,11 +108,11 @@ struct cardinfo { int irq; unsigned long csr_base; - unsigned char *csr_remap; + unsigned char __iomem *csr_remap; unsigned long csr_len; #ifdef CONFIG_MM_MAP_MEMORY unsigned long mem_base; - unsigned char *mem_remap; + unsigned char __iomem *mem_remap; unsigned long mem_len; #endif @@ -926,7 +926,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i goto failed_req_mem; } - if (!(card->mem_remap = (unsigned char *)ioremap(card->mem_base, cards->mem_len))) { + if (!(card->mem_remap = ioremap(card->mem_base, cards->mem_len))) { printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); ret = -ENOMEM; @@ -1107,12 +1107,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->mm_pages[1].page_dma); failed_magic: #ifdef CONFIG_MM_MAP_MEMORY - iounmap((void *) card->mem_remap); + iounmap(card->mem_remap); failed_remap_mem: release_mem_region(card->mem_base, card->mem_len); failed_req_mem: #endif - iounmap((void *) card->csr_remap); + iounmap(card->csr_remap); failed_remap_csr: release_mem_region(card->csr_base, card->csr_len); failed_req_csr: diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 5ba134216..fb990ec38 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -188,9 +188,7 @@ static int hci_uart_flush(struct hci_dev *hdev) } /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + tty_ldisc_flush(tty); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); @@ -280,7 +278,9 @@ static int hci_uart_tty_open(struct tty_struct *tty) spin_lock_init(&hu->rx_lock); - /* Flush any pending characters in the driver and line discipline */ + /* Flush any pending characters in the driver and line discipline. */ + /* FIXME: why is this needed. Note don't use ldisc_ref here as the + open path is before the ldisc is referencable */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 9babb21df..bca968310 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -96,7 +96,7 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, /* ISSC Bluetooth Adapter v3.1 */ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 2e1ee63d1..e57d19031 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -354,6 +354,19 @@ static void cdrom_sysctl_register(void); #endif /* CONFIG_SYSCTL */ static struct cdrom_device_info *topCdromPtr; +static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + if (cgc->sense) { + cgc->sense->sense_key = 0x05; + cgc->sense->asc = 0x20; + cgc->sense->ascq = 0x00; + } + + cgc->stat = -EIO; + return -EIO; +} + /* This macro makes sure we don't have to check on cdrom_device_ops * existence in the run-time routines below. Change_capability is a * hack to have the capability flags defined const, while we can still @@ -411,6 +424,9 @@ int register_cdrom(struct cdrom_device_info *cdi) else cdi->cdda_method = CDDA_OLD; + if (!cdo->generic_packet) + cdo->generic_packet = cdrom_dummy_generic_packet; + cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); spin_lock(&cdrom_lock); cdi->next = topCdromPtr; @@ -472,6 +488,9 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi, if (be16_to_cpu(eh->data_len) < sizeof(*med)) return 1; + if (eh->nea || eh->notification_class != 0x4) + return 1; + memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); return 0; } @@ -605,13 +624,16 @@ static int cdrom_flush_cache(struct cdrom_device_info *cdi) static int cdrom_mrw_exit(struct cdrom_device_info *cdi) { disc_information di; - int ret = 0; + int ret; - if (cdrom_get_disc_info(cdi, &di)) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type)) return 1; + ret = 0; if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { - printk(KERN_INFO "cdrom: issuing MRW back ground format suspend\n"); + printk(KERN_INFO "cdrom: issuing MRW back ground " + "format suspend\n"); ret = cdrom_mrw_bgformat_susp(cdi, 0); } @@ -715,8 +737,10 @@ int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) static int cdrom_media_erasable(struct cdrom_device_info *cdi) { disc_information di; + int ret; - if (cdrom_get_disc_info(cdi, &di)) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di), n_first_track)) return -1; return di.erasable; @@ -752,7 +776,8 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) return 1; } - if (cdrom_get_disc_info(cdi, &di)) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di),disc_type)) return 1; if (!di.erasable) @@ -766,10 +791,12 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) * 3 - MRW formatting complete */ ret = 0; - printk(KERN_INFO "cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]); + printk(KERN_INFO "cdrom open: mrw_status '%s'\n", + mrw_format_status[di.mrw_status]); if (!di.mrw_status) ret = 1; - else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart) + else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && + mrw_format_restart) ret = cdrom_mrw_bgformat(cdi, 1); return ret; @@ -1922,7 +1949,8 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, int lba, int nframes) { struct packet_command cgc; - int nr, ret; + int ret = 0; + int nr; cdi->last_sense = 0; @@ -1944,8 +1972,8 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, return -ENOMEM; if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { - kfree(cgc.buffer); - return -EFAULT; + ret = -EFAULT; + goto out; } cgc.data_direction = CGC_DATA_READ; @@ -1956,13 +1984,17 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); if (ret) break; - __copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr); + if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { + ret = -EFAULT; + break; + } ubuf += CD_FRAMESIZE_RAW * nr; nframes -= nr; lba += nr; } +out: kfree(cgc.buffer); - return 0; + return ret; } static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, @@ -2504,7 +2536,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; struct request_sense sense; - char buffer[32]; + unsigned char buffer[32]; int ret = 0; memset(&cgc, 0, sizeof(cgc)); @@ -2631,8 +2663,9 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, case CDROMVOLCTRL: case CDROMVOLREAD: { struct cdrom_volctrl volctrl; - char mask[32]; + char mask[sizeof(buffer)]; unsigned short offset; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); IOCTL_IN(arg, struct cdrom_volctrl, volctrl); @@ -2642,17 +2675,27 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0))) return ret; - /* some drives have longer pages, adjust and reread. */ - if (buffer[1] > cgc.buflen) { - cgc.buflen = buffer[1] + 2; - if ((ret = cdrom_mode_sense(cdi, &cgc, - GPMODE_AUDIO_CTL_PAGE, 0))) - return ret; + /* originally the code depended on buffer[1] to determine + how much data is available for transfer. buffer[1] is + unfortunately ambigious and the only reliable way seem + to be to simply skip over the block descriptor... */ + offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6)); + + if (offset + 16 > sizeof(buffer)) + return -E2BIG; + + if (offset + 16 > cgc.buflen) { + cgc.buflen = offset+16; + ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 0); + if (ret) + return ret; } - - /* get the offset from the length of the page. length - is measure from byte 2 an on, thus the 14. */ - offset = buffer[1] - 14; + + /* sanity check */ + if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || + buffer[offset+1] < 14) + return -EINVAL; /* now we have the current volume settings. if it was only a CDROMVOLREAD, return these values */ @@ -2677,7 +2720,8 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, buffer[offset+15] = volctrl.channel3 & mask[offset+15]; /* set volume */ - cgc.buffer = buffer; + cgc.buffer = buffer + offset - 8; + memset(cgc.buffer, 0, 8); return cdrom_mode_select(cdi, &cgc); } @@ -2760,7 +2804,7 @@ static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 { struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - int ret; + int ret, buflen; init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; @@ -2773,14 +2817,18 @@ static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; - cgc.buflen = be16_to_cpu(ti->track_information_length) + + buflen = be16_to_cpu(ti->track_information_length) + sizeof(ti->track_information_length); - if (cgc.buflen > sizeof(track_information)) - cgc.buflen = sizeof(track_information); + if (buflen > sizeof(track_information)) + buflen = sizeof(track_information); - cgc.cmd[8] = cgc.buflen; - return cdo->generic_packet(cdi, &cgc); + cgc.cmd[8] = cgc.buflen = buflen; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* return actual fill size */ + return buflen; } /* requires CD R/RW */ @@ -2788,7 +2836,7 @@ static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information * { struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - int ret; + int ret, buflen; /* set up command and get the disc info */ init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); @@ -2802,14 +2850,18 @@ static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information * /* not all drives have the same disc_info length, so requeue * packet with the length the drive tells us it can supply */ - cgc.buflen = be16_to_cpu(di->disc_information_length) + + buflen = be16_to_cpu(di->disc_information_length) + sizeof(di->disc_information_length); - if (cgc.buflen > sizeof(disc_information)) - cgc.buflen = sizeof(disc_information); + if (buflen > sizeof(disc_information)) + buflen = sizeof(disc_information); - cgc.cmd[8] = cgc.buflen; - return cdo->generic_packet(cdi, &cgc); + cgc.cmd[8] = cgc.buflen = buflen; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* return actual fill size */ + return buflen; } /* return the last written block on the CD-R media. this is for the udf @@ -2820,27 +2872,37 @@ int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) disc_information di; track_information ti; __u32 last_track; - int ret = -1; + int ret = -1, ti_size; if (!CDROM_CAN(CDC_GENERIC_PACKET)) goto use_toc; - if ((ret = cdrom_get_disc_info(cdi, &di))) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < (int)(offsetof(typeof(di), last_track_lsb) + + sizeof(di.last_track_lsb))) goto use_toc; + /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ last_track = (di.last_track_msb << 8) | di.last_track_lsb; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < (int)offsetof(typeof(ti), track_start)) goto use_toc; /* if this track is blank, try the previous. */ if (ti.blank) { - last_track--; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + if (last_track==1) goto use_toc; + last_track--; + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); } + if (ti_size < (int)(offsetof(typeof(ti), track_size) + + sizeof(ti.track_size))) + goto use_toc; + /* if last recorded field is valid, return it. */ - if (ti.lra_v) { + if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) + + sizeof(ti.last_rec_address))) { *last_written = be32_to_cpu(ti.last_rec_address); } else { /* make it up instead */ @@ -2853,11 +2915,12 @@ int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) /* this is where we end up if the drive either can't do a GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if - it fails. then we return the toc contents. */ + it doesn't give enough information or fails. then we return + the toc contents. */ use_toc: toc.cdte_format = CDROM_MSF; toc.cdte_track = CDROM_LEADOUT; - if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)) + if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) return ret; sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); *last_written = toc.cdte_addr.lba; @@ -2870,32 +2933,38 @@ static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_wri disc_information di; track_information ti; __u16 last_track; - int ret = -1; + int ret, ti_size; if (!CDROM_CAN(CDC_GENERIC_PACKET)) goto use_last_written; - if ((ret = cdrom_get_disc_info(cdi, &di))) + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) + + sizeof(di.last_track_lsb)) goto use_last_written; + /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ last_track = (di.last_track_msb << 8) | di.last_track_lsb; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) goto use_last_written; /* if this track is blank, try the previous. */ if (ti.blank) { + if (last_track == 1) + goto use_last_written; last_track--; - if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti))) + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < 0) goto use_last_written; } /* if next recordable address field is valid, use it. */ - if (ti.nwa_v) + if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) + + sizeof(ti.next_writable)) { *next_writable = be32_to_cpu(ti.next_writable); - else - goto use_last_written; - - return 0; + return 0; + } use_last_written: if ((ret = cdrom_get_last_written(cdi, next_writable))) { diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index cbe336429..09873fa1b 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -729,8 +729,7 @@ static void restart_on_error(void) res_reg[1]); } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2 * HZ); + msleep(2000); sony_get_toc(); } @@ -960,8 +959,7 @@ retry_cd_operation: if (((result_buffer[0] & 0xf0) == 0x20) && (num_retries < MAX_CDU31A_RETRIES)) { num_retries++; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 10); /* Wait .1 seconds on retries */ + msleep(100); goto retry_cd_operation; } diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c index 4cb0fb491..b4f5e0295 100644 --- a/drivers/cdrom/mcd.c +++ b/drivers/cdrom/mcd.c @@ -1021,10 +1021,9 @@ static int mcd_open(struct cdrom_device_info *cdi, int purpose) st = statusCmd(); /* check drive status */ if (st == -1) goto err_out; /* drive doesn't respond */ - if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ); - } + if ((st & MST_READY) == 0) /* no disk? wait a sec... */ + msleep(1000); + } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if (updateToc() < 0) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 3a2acc0fb..0509ae21e 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -121,7 +121,10 @@ struct capability_entry { }; static struct capability_entry capability_table[] __initdata = { - { "6330", CDC_LOCK | CDC_DVD_RAM }, + { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, { "6321", CDC_LOCK }, { "632B", 0 }, { NULL , CDC_LOCK }, @@ -332,10 +335,19 @@ static int send_request(struct request *req) struct disk_info *diskinfo = req->rq_disk->private_data; u64 len; dma_addr_t dmaaddr; + int direction; + u16 cmd; struct scatterlist sg; BUG_ON(req->nr_phys_segments > 1); - BUG_ON(rq_data_dir(req) != READ); + + if (rq_data_dir(req) == READ) { + direction = DMA_FROM_DEVICE; + cmd = viomajorsubtype_cdio | viocdread; + } else { + direction = DMA_TO_DEVICE; + cmd = viomajorsubtype_cdio | viocdwrite; + } if (blk_rq_map_sg(req->q, req, &sg) == 0) { printk(VIOCD_KERN_WARNING @@ -343,7 +355,7 @@ static int send_request(struct request *req) return -1; } - if (dma_map_sg(diskinfo->dev, &sg, 1, DMA_FROM_DEVICE) == 0) { + if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) { printk(VIOCD_KERN_WARNING "error allocating sg tce\n"); return -1; } @@ -351,8 +363,7 @@ static int send_request(struct request *req) len = sg_dma_len(&sg); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_cdio | viocdread, + HvLpEvent_Type_VirtualIo, cmd, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), @@ -457,6 +468,41 @@ static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) return 0; } +static int viocd_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + unsigned int buflen = cgc->buflen; + int ret = -EIO; + + switch (cgc->cmd[0]) { + case GPCMD_READ_DISC_INFO: + { + disc_information *di = (disc_information *)cgc->buffer; + + if (buflen >= 2) { + di->disc_information_length = cpu_to_be16(1); + ret = 0; + } + if (buflen >= 3) + di->erasable = + (cdi->ops->capability & ~cdi->mask + & (CDC_DVD_RAM | CDC_RAM)) != 0; + } + break; + default: + if (cgc->sense) { + /* indicate Unknown code */ + cgc->sense->sense_key = 0x05; + cgc->sense->asc = 0x20; + cgc->sense->ascq = 0x00; + } + break; + } + + cgc->stat = ret; + return ret; +} + /* This routine handles incoming CD LP events */ static void vio_handle_cd_event(struct HvLpEvent *event) { @@ -510,6 +556,7 @@ return_complete: case viocdclose: break; + case viocdwrite: case viocdread: /* * Since this is running in interrupt mode, we need to @@ -518,7 +565,8 @@ return_complete: di = &viocd_diskinfo[bevent->disk]; spin_lock_irqsave(&viocd_reqlock, flags); dma_unmap_single(di->dev, bevent->token, bevent->len, - DMA_FROM_DEVICE); + ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); req = (struct request *)bevent->event.xCorrelationToken; rwreq--; @@ -555,7 +603,8 @@ static struct cdrom_device_ops viocd_dops = { .release = viocd_release, .media_changed = viocd_media_changed, .lock_door = viocd_lock_door, - .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM + .generic_packet = viocd_packet, + .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM }; static int __init find_capability(const char *type) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 37e067351..f7bfe2059 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -59,7 +59,7 @@ config VT_CONSOLE config HW_CONSOLE bool - depends on VT && !S390 && !UM + depends on VT && !S390 && !USERMODE default y config SERIAL_NONSTANDARD @@ -424,6 +424,14 @@ config A2232 will also be built as a module. This has to be loaded before "ser_a2232". If you want to do this, answer M here. +config SGI_SNSC + bool "SGI Altix system controller communication support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) + help + If you have an SGI Altix and you want to enable system + controller communication from user space (you want this!), + say Y. Otherwise, say N. + source "drivers/serial/Kconfig" config UNIX98_PTYS @@ -587,39 +595,6 @@ config HVCS which will also be compiled when this driver is built as a module. -config QIC02_TAPE - tristate "QIC-02 tape support" - help - If you have a non-SCSI tape drive like that, say Y. - - To compile this driver as a module, choose M here: the - module will be called tpqic02. - -config QIC02_DYNCONF - bool "Do you want runtime configuration for QIC-02" - depends on QIC02_TAPE - help - You can either configure this driver once and for all by editing a - header file (), in which case you - should say N, or you can fetch a program via anonymous FTP which is - able to configure this driver during runtime. The program to do - this is called 'qic02conf' and it is part of the - tpqic02-support-X.Y.tar.gz support package. - - If you want to use the qic02conf program, say Y. - -comment "Edit configuration parameters in ./include/linux/tpqic02.h!" - depends on QIC02_TAPE && !QIC02_DYNCONF - -comment "Setting runtime QIC-02 configuration is done with qic02conf" - depends on QIC02_TAPE && QIC02_DYNCONF - -comment "from the tpqic02-support package. It is available at" - depends on QIC02_TAPE && QIC02_DYNCONF - -comment "metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/" - depends on QIC02_TAPE && QIC02_DYNCONF - source "drivers/char/ipmi/Kconfig" source "drivers/char/watchdog/Kconfig" @@ -778,7 +753,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 + depends on RTC!=y && !IA64 && !ARM ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -1006,5 +981,13 @@ config HANGCHECK_TIMER out to lunch past a certain margin. It can reboot the system or merely print a warning. +config MMTIMER + tristate "MMTIMER Memory mapped RTC for SGI Altix" + depends on IA64_GENERIC || IA64_SGI_SN2 + default y + help + The mmtimer device allows direct userspace access to the + Altix system timer. + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index b927c16bb..c95223457 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 @@ -39,8 +42,10 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o -obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o +obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o obj-$(CONFIG_RAW_DRIVER) += raw.o +obj-$(CONFIG_SGI_SNSC) += snsc.o +obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_HVCS) += hvcs.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 773279d48..d9b4a6e7f 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -1,5 +1,5 @@ config AGP - tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU && !M68K + tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU && !M68K && !ARM default y if GART_IOMMU ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -130,7 +130,7 @@ config AGP_VIA depends on AGP && X86 && !X86_64 help This option gives you AGP support for the GLX component of - XFree86 4.x on VIA MPV3/Apollo Pro chipsets. + XFree86 4.x on VIA MVP3/Apollo Pro chipsets. You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI. If unsure, say N. diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 2128374e7..f83e3e342 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -123,7 +123,7 @@ struct agp_bridge_data { void *current_size; void *dev_private_data; struct pci_dev *dev; - u32 *gatt_table; + u32 __iomem *gatt_table; u32 *gatt_table_real; unsigned long scratch_page; unsigned long scratch_page_real; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index f1db2f86a..a45d36c3b 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -24,11 +24,11 @@ static struct pci_device_id agp_amdk7_pci_table[]; struct amd_page_map { unsigned long *real; - unsigned long *remapped; + unsigned long __iomem *remapped; }; static struct _amd_irongate_private { - volatile u8 *registers; + volatile u8 __iomem *registers; struct amd_page_map **gatt_pages; int num_tables; } amd_irongate_private; @@ -54,7 +54,7 @@ static int amd_create_page_map(struct amd_page_map *page_map) global_cache_flush(); for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) - page_map->remapped[i] = agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, page_map->remapped+i); return 0; } @@ -151,7 +151,7 @@ static int amd_create_gatt_table(void) } agp_bridge->gatt_table_real = (u32 *)page_dir.real; - agp_bridge->gatt_table = (u32 *)page_dir.remapped; + agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); /* Get the address for the gart region. @@ -165,9 +165,8 @@ static int amd_create_gatt_table(void) /* Calculate the agp offset */ for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = - virt_to_phys(amd_irongate_private.gatt_pages[i]->real); - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1, + page_dir.remapped+GET_PAGE_DIR_OFF(addr)); } return 0; @@ -178,7 +177,7 @@ static int amd_free_gatt_table(void) struct amd_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; - page_dir.remapped = (unsigned long *)agp_bridge->gatt_table; + page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; amd_free_gatt_pages(); amd_free_page_map(&page_dir); @@ -218,7 +217,7 @@ static int amd_irongate_configure(void) /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp); temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096); + amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); /* Write out the address of the gatt table */ OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, @@ -263,7 +262,7 @@ static void amd_irongate_cleanup(void) pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp); temp = ((temp & ~(0x0000000f)) | previous_size->size_value); pci_write_config_dword(agp_bridge->dev, AMD_APSIZE, temp); - iounmap((void *) amd_irongate_private.registers); + iounmap((void __iomem *) amd_irongate_private.registers); } /* @@ -282,7 +281,7 @@ static void amd_irongate_tlbflush(struct agp_memory *temp) static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; @@ -297,7 +296,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) + if (!PGE_EMPTY(agp_bridge, readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; j++; } @@ -310,8 +309,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - agp_generic_mask_memory(mem->memory[i], mem->type); + writel(agp_generic_mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } amd_irongate_tlbflush(mem); return 0; @@ -320,7 +318,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { int i; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) @@ -329,8 +327,7 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } amd_irongate_tlbflush(mem); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 924ffc3db..2e8b2aee9 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -73,7 +73,7 @@ static void amd64_tlbflush(struct agp_memory *temp) static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; - long tmp; + long long tmp; u32 pte; num_entries = agp_num_entries(); @@ -90,7 +90,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) /* gatt table should be empty. */ while (j < (pg_start + mem->page_count)) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; j++; } @@ -108,7 +108,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) pte |=(tmp & 0x00000000fffff000ULL); pte |= GPTE_VALID | GPTE_COHERENT; - agp_bridge->gatt_table[j] = pte; + writel(pte, agp_bridge->gatt_table+j); } amd64_tlbflush(mem); return 0; @@ -675,4 +675,4 @@ module_exit(agp_amd64_cleanup); MODULE_AUTHOR("Dave Jones , Andi Kleen"); MODULE_PARM(agp_try_unsupported, "1i"); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index bc88d6991..8bf71c182 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -42,11 +42,11 @@ static struct gatt_mask ati_generic_masks[] = typedef struct _ati_page_map { unsigned long *real; - unsigned long *remapped; + unsigned long __iomem *remapped; } ati_page_map; static struct _ati_generic_private { - volatile u8 *registers; + volatile u8 __iomem *registers; ati_page_map **gatt_pages; int num_tables; } ati_generic_private; @@ -76,7 +76,7 @@ static int ati_create_page_map(ati_page_map *page_map) global_cache_flush(); for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) - page_map->remapped[i] = agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, page_map->remapped+i); return 0; } @@ -206,7 +206,7 @@ static void ati_cleanup(void) temp = ((temp & ~(0x0000000f)) | previous_size->size_value); pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp); } - iounmap((void *) ati_generic_private.registers); + iounmap((volatile u8 __iomem *)ati_generic_private.registers); } @@ -217,7 +217,7 @@ static int ati_configure(void) /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp); temp = (temp & 0xfffff000); - ati_generic_private.registers = (volatile u8 *) ioremap(temp, 4096); + ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (is_r200()) pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); @@ -261,7 +261,7 @@ static int ati_insert_memory(struct agp_memory * mem, off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; @@ -276,7 +276,7 @@ static int ati_insert_memory(struct agp_memory * mem, while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - if (!PGE_EMPTY(agp_bridge,cur_gatt[GET_GATT_OFF(addr)])) + if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; j++; } @@ -290,8 +290,7 @@ static int ati_insert_memory(struct agp_memory * mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - agp_bridge->driver->mask_memory(mem->memory[i], mem->type); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } agp_bridge->driver->tlb_flush(mem); return 0; @@ -301,7 +300,7 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, int type) { int i; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) { @@ -310,8 +309,7 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } agp_bridge->driver->tlb_flush(mem); @@ -340,7 +338,7 @@ static int ati_create_gatt_table(void) } agp_bridge->gatt_table_real = (u32 *)page_dir.real; - agp_bridge->gatt_table = (u32 *)page_dir.remapped; + agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_bus(page_dir.real); /* Write out the size register */ @@ -371,9 +369,8 @@ static int ati_create_gatt_table(void) /* Calculate the agp offset */ for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = - virt_to_bus(ati_generic_private.gatt_pages[i]->real); - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + writel(virt_to_bus(ati_generic_private.gatt_pages[i]->real) | 1, + page_dir.remapped+GET_PAGE_DIR_OFF(addr)); } return 0; @@ -384,7 +381,7 @@ static int ati_free_gatt_table(void) ati_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; - page_dir.remapped = (unsigned long *)agp_bridge->gatt_table; + page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; ati_free_gatt_pages(); ati_free_page_map(&page_dir); diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index f65662437..83498820c 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "agp.h" __u32 *agp_gatt_table; @@ -737,7 +738,7 @@ int agp_generic_create_gatt_table(void) /* AK: bogus, should encode addresses > 4GB */ for (i = 0; i < num_entries; i++) - agp_bridge->gatt_table[i] = (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); return 0; } @@ -843,9 +844,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) j = pg_start; while (j < (pg_start + mem->page_count)) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) { + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; - } j++; } @@ -855,9 +855,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - agp_bridge->gatt_table[j] = - agp_bridge->driver->mask_memory( - mem->memory[i], mem->type); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), agp_bridge->gatt_table+j); agp_bridge->driver->tlb_flush(mem); return 0; @@ -875,10 +873,8 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) } /* AK: bogus, should encode addresses > 4GB */ - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - agp_bridge->gatt_table[i] = - (unsigned long) agp_bridge->scratch_page; - } + for (i = pg_start; i < (mem->page_count + pg_start); i++) + writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); agp_bridge->driver->tlb_flush(mem); return 0; diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 5fd2adc96..323a6b68d 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -59,8 +59,8 @@ static struct gatt_mask hp_zx1_masks[] = }; static struct _hp_private { - volatile u8 *ioc_regs; - volatile u8 *lba_regs; + volatile u8 __iomem *ioc_regs; + volatile u8 __iomem *lba_regs; int lba_cap_offset; u64 *io_pdir; // PDIR for entire IOVA u64 *gatt; // PDIR just for GART (subset of above) @@ -97,7 +97,7 @@ static int __init hp_zx1_ioc_shared(void) default: printk(KERN_ERR PFX "Invalid IOTLB page size " "configuration 0x%x\n", hp->io_tlb_ps); - hp->gatt = 0; + hp->gatt = NULL; hp->gatt_entries = 0; return -ENODEV; } @@ -115,7 +115,7 @@ static int __init hp_zx1_ioc_shared(void) if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { /* Normal case when no AGP device in system */ - hp->gatt = 0; + hp->gatt = NULL; hp->gatt_entries = 0; printk(KERN_ERR PFX "No reserved IO PDIR entry found; " "GART disabled\n"); @@ -183,7 +183,7 @@ hp_zx1_ioc_init (u64 hpa) } static int -hp_zx1_lba_find_capability (volatile u8 *hpa, int cap) +hp_zx1_lba_find_capability (volatile u8 __iomem *hpa, int cap) { u16 status; u8 pos, id; @@ -267,10 +267,10 @@ hp_zx1_cleanup (void) if (hp->ioc_regs) { if (hp->io_pdir_owner) OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0); - iounmap((void *) hp->ioc_regs); + iounmap(hp->ioc_regs); } if (hp->lba_regs) - iounmap((void *) hp->lba_regs); + iounmap(hp->lba_regs); } static void @@ -294,7 +294,7 @@ hp_zx1_create_gatt_table (void) if (!hp->io_pdir) { printk(KERN_ERR PFX "Couldn't allocate contiguous " "memory for I/O PDIR\n"); - hp->gatt = 0; + hp->gatt = NULL; hp->gatt_entries = 0; return -ENOMEM; } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index f04527540..7bec505ad 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -69,7 +69,7 @@ static struct gatt_mask intel_i810_masks[] = static struct _intel_i810_private { struct pci_dev *i810_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; int num_dcache_entries; } intel_i810_private; @@ -111,7 +111,7 @@ static int intel_i810_configure(void) pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); temp &= 0xfff80000; - intel_i810_private.registers = (volatile u8 *) ioremap(temp, 128 * 4096); + intel_i810_private.registers = ioremap(temp, 128 * 4096); if (!intel_i810_private.registers) { printk(KERN_ERR PFX "Unable to remap memory.\n"); return -ENOMEM; @@ -142,7 +142,7 @@ static int intel_i810_configure(void) static void intel_i810_cleanup(void) { OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); - iounmap((void *) intel_i810_private.registers); + iounmap(intel_i810_private.registers); } static void intel_i810_tlbflush(struct agp_memory *mem) @@ -162,11 +162,11 @@ static void *i8xx_alloc_pages(void) page = alloc_pages(GFP_KERNEL, 2); if (page == NULL) { - return 0; + return NULL; } if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { - __free_page(page); - return 0; + __free_page(page); + return NULL; } get_page(page); SetPageLocked(page); @@ -180,7 +180,7 @@ static void i8xx_destroy_pages(void *addr) if (addr == NULL) return; - + page = virt_to_page(addr); change_page_attr(page, 4, PAGE_KERNEL); put_page(page); @@ -202,7 +202,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, return -EINVAL; } for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; } @@ -330,7 +330,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr) if (curr->page_count == 4) i8xx_destroy_pages(phys_to_virt(curr->memory[0])); else - agp_bridge->driver->agp_destroy_page( + agp_bridge->driver->agp_destroy_page( phys_to_virt(curr->memory[0])); vfree(curr->memory); } @@ -353,8 +353,8 @@ static struct aper_size_info_fixed intel_i830_sizes[] = static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ - volatile u8 *registers; - volatile u32 *gtt; /* I915G */ + volatile u8 __iomem *registers; + volatile u32 __iomem *gtt; /* I915G */ int gtt_entries; } intel_i830_private; @@ -371,7 +371,7 @@ static void intel_i830_init_gtt_entries(void) /* We obtain the size of the GTT, which is also stored (for some * reason) at the top of stolen memory. Then we add 4KB to that - * for the video BIOS popup, which is also stored in there. */ + * for the video BIOS popup, which is also stored in there. */ size = agp_bridge->driver->fetch_size() + 4; if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || @@ -461,7 +461,7 @@ static int intel_i830_create_gatt_table(void) pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) return (-ENOMEM); @@ -544,7 +544,7 @@ static int intel_i830_configure(void) static void intel_i830_cleanup(void) { - iounmap((void *) intel_i830_private.registers); + iounmap(intel_i830_private.registers); } static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -649,8 +649,8 @@ static int intel_i915_configure(void) static void intel_i915_cleanup(void) { - iounmap((void *) intel_i830_private.gtt); - iounmap((void *) intel_i830_private.registers); + iounmap(intel_i830_private.gtt); + iounmap(intel_i830_private.registers); } static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -746,18 +746,18 @@ static int intel_i915_create_gatt_table(void) size = agp_bridge->current_size; page_order = size->page_order; num_entries = size->num_entries; - agp_bridge->gatt_table_real = 0; + agp_bridge->gatt_table_real = NULL; pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); pci_read_config_dword(intel_i830_private.i830_dev, I915_PTEADDR,&temp2); - intel_i830_private.gtt = (volatile u32 *) ioremap(temp2, 256 * 1024); - if (!intel_i830_private.gtt) + intel_i830_private.gtt = ioremap(temp2, 256 * 1024); + if (!intel_i830_private.gtt) return (-ENOMEM); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) return (-ENOMEM); @@ -921,7 +921,7 @@ static int intel_815_configure(void) /* aperture size */ pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, - current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); @@ -933,7 +933,7 @@ static int intel_815_configure(void) pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* apcont */ pci_read_config_byte(agp_bridge->dev, INTEL_815_APCONT, &temp2); @@ -956,7 +956,7 @@ static void intel_820_cleanup(void) previous_size = A_SIZE_8(agp_bridge->previous_size); pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp); - pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, + pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp & ~(1 << 1)); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value); @@ -966,23 +966,23 @@ static void intel_820_cleanup(void) static int intel_820_configure(void) { u32 temp; - u8 temp2; + u8 temp2; struct aper_size_info_8 *current_size; current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* global enable aperture access */ /* This flag is not accessed through MCHCFG register as in */ @@ -990,7 +990,7 @@ static int intel_820_configure(void) pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp2); pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp2 | (1 << 1)); /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c); return 0; } @@ -1003,23 +1003,23 @@ static int intel_840_configure(void) current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* mcgcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, temp2 | (1 << 9)); /* clear any possible error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000); + pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000); return 0; } @@ -1032,23 +1032,23 @@ static int intel_845_configure(void) current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* agpm */ pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2); pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1)); /* clear any possible error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); return 0; } @@ -1061,23 +1061,23 @@ static int intel_850_configure(void) current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* mcgcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, temp2 | (1 << 9)); /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c); return 0; } @@ -1163,7 +1163,7 @@ static int intel_7505_configure(void) /* mchcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9)); - + return 0; } @@ -1178,7 +1178,7 @@ static struct aper_size_info_8 intel_815_sizes[2] = {64, 16384, 4, 0}, {32, 8192, 3, 8}, }; - + static struct aper_size_info_8 intel_8xx_sizes[7] = { {256, 65536, 6, 0}, @@ -1201,7 +1201,7 @@ static struct aper_size_info_16 intel_generic_sizes[7] = {4, 1024, 0, 63} }; -static struct aper_size_info_8 intel_830mp_sizes[4] = +static struct aper_size_info_8 intel_830mp_sizes[4] = { {256, 65536, 6, 0}, {128, 32768, 5, 32}, @@ -1283,7 +1283,7 @@ static struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 3, + .num_aperture_sizes = 3, .needs_scratch_page = TRUE, .configure = intel_i830_configure, .fetch_size = intel_i830_fetch_size, @@ -1445,7 +1445,7 @@ static struct agp_bridge_driver intel_915_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 3, + .num_aperture_sizes = 3, .needs_scratch_page = TRUE, .configure = intel_i915_configure, .fetch_size = intel_i915_fetch_size, @@ -1489,18 +1489,13 @@ static struct agp_bridge_driver intel_7505_driver = { .agp_destroy_page = agp_generic_destroy_page, }; -static int find_i810(u16 device, const char *name) +static int find_i810(u16 device) { struct pci_dev *i810_dev; i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (!i810_dev) { - printk(KERN_ERR PFX "Detected an Intel %s Chipset, " - "but could not find the secondary device.\n", - name); + if (!i810_dev) return 0; - } - intel_i810_private.i810_dev = i810_dev; return 1; } @@ -1550,29 +1545,29 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, name = "440GX"; break; case PCI_DEVICE_ID_INTEL_82810_MC1: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1, "i810")) + name = "i810"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1)) goto fail; bridge->driver = &intel_810_driver; - name = "i810"; break; case PCI_DEVICE_ID_INTEL_82810_MC3: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3, "i810 DC100")) + name = "i810 DC100"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3)) goto fail; bridge->driver = &intel_810_driver; - name = "i810 DC100"; break; case PCI_DEVICE_ID_INTEL_82810E_MC: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG, "i810 E")) + name = "i810 E"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG)) goto fail; bridge->driver = &intel_810_driver; - name = "i810 E"; break; case PCI_DEVICE_ID_INTEL_82815_MC: /* * The i815 can operate either as an i810 style * integrated device, or as an AGP4X motherboard. */ - if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC, "i815")) + if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC)) bridge->driver = &intel_810_driver; else bridge->driver = &intel_815_driver; @@ -1708,7 +1703,10 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); - fail: + +fail: + printk(KERN_ERR PFX "Detected an Intel %s chipset, " + "but could not find the secondary device.\n", name); agp_put_bridge(bridge); return -ENODEV; } @@ -1724,7 +1722,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - + pci_restore_state(pdev, pdev->saved_config_space); if (bridge->driver == &intel_generic_driver) @@ -1741,7 +1739,7 @@ static int agp_intel_resume(struct pci_dev *pdev) static struct pci_device_id agp_intel_pci_table[] = { #define ID(x) \ - { \ + { \ .class = (PCI_CLASS_BRIDGE_HOST << 8), \ .class_mask = ~0, \ .vendor = PCI_VENDOR_ID_INTEL, \ @@ -1769,7 +1767,8 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82865_HB), ID(PCI_DEVICE_ID_INTEL_82875_HB), ID(PCI_DEVICE_ID_INTEL_7505_0), - ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_82915G_HB), { } }; @@ -1779,7 +1778,7 @@ static struct pci_driver agp_intel_pci_driver = { .name = "agpgart-intel", .id_table = agp_intel_pci_table, .probe = agp_intel_probe, - .remove = agp_intel_remove, + .remove = __devexit_p(agp_intel_remove), .resume = agp_intel_resume, }; diff --git a/drivers/char/agp/intel-mch-agp.c b/drivers/char/agp/intel-mch-agp.c index c8f230acc..fd1d1ac1a 100644 --- a/drivers/char/agp/intel-mch-agp.c +++ b/drivers/char/agp/intel-mch-agp.c @@ -84,7 +84,7 @@ static struct aper_size_info_fixed intel_i830_sizes[] = static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; int gtt_entries; } intel_i830_private; @@ -172,7 +172,7 @@ static int intel_i830_create_gatt_table(void) pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = (volatile u8 __iomem*) ioremap(temp,128 * 4096); if (!intel_i830_private.registers) return (-ENOMEM); @@ -255,7 +255,7 @@ static int intel_i830_configure(void) static void intel_i830_cleanup(void) { - iounmap((void *) intel_i830_private.registers); + iounmap((void __iomem *) intel_i830_private.registers); } static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -633,5 +633,5 @@ module_init(agp_intelmch_init); module_exit(agp_intelmch_cleanup); MODULE_AUTHOR("Dave Jones "); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 28e7fc4bc..16d8bdcb4 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -28,7 +28,7 @@ static struct _nvidia_private { struct pci_dev *dev_1; struct pci_dev *dev_2; struct pci_dev *dev_3; - volatile u32 *aperture; + volatile u32 __iomem *aperture; int num_active_entries; off_t pg_offset; u32 wbc_mask; @@ -154,7 +154,7 @@ static int nvidia_configure(void) /* map aperture */ nvidia_private.aperture = - (volatile u32 *) ioremap(apbase, 33 * PAGE_SIZE); + (volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE); return 0; } @@ -173,7 +173,7 @@ static void nvidia_cleanup(void) pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp & ~(0x11)); /* unmap aperture */ - iounmap((void *) nvidia_private.aperture); + iounmap((void __iomem *) nvidia_private.aperture); /* restore previous aperture size */ previous_size = A_SIZE_8(agp_bridge->previous_size); @@ -206,7 +206,7 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type return -EINVAL; for(j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[nvidia_private.pg_offset + j])) + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+nvidia_private.pg_offset+j))) return -EBUSY; } @@ -215,9 +215,8 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type mem->is_flushed = TRUE; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - agp_bridge->gatt_table[nvidia_private.pg_offset + j] = - agp_bridge->driver->mask_memory(mem->memory[i], mem->type); - + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), + agp_bridge->gatt_table+nvidia_private.pg_offset+j); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -229,11 +228,9 @@ static int nvidia_remove_memory(struct agp_memory *mem, off_t pg_start, int type if ((type != 0) || (mem->type != 0)) return -EINVAL; - - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - agp_bridge->gatt_table[nvidia_private.pg_offset + i] = - (unsigned long) agp_bridge->scratch_page; - } + + for (i = pg_start; i < (mem->page_count + pg_start); i++) + writel(agp_bridge->scratch_page, agp_bridge->gatt_table+nvidia_private.pg_offset+i); agp_bridge->driver->tlb_flush(mem); return 0; @@ -265,9 +262,9 @@ static void nvidia_tlbflush(struct agp_memory *mem) /* flush TLB entries */ for(i = 0; i < 32 + 1; i++) - temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)]; + temp = readl(nvidia_private.aperture+(i * PAGE_SIZE / sizeof(u32))); for(i = 0; i < 32 + 1; i++) - temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)]; + temp = readl(nvidia_private.aperture+(i * PAGE_SIZE / sizeof(u32))); } diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 2a99c738f..019a31c36 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -168,6 +168,10 @@ static struct agp_device_ids sis_agp_device_ids[] __devinitdata = .device_id = PCI_DEVICE_ID_SI_630, .chipset_name = "630", }, + { + .device_id = PCI_DEVICE_ID_SI_635, + .chipset_name = "635", + }, { .device_id = PCI_DEVICE_ID_SI_645, .chipset_name = "645", diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 44e11acbc..ae20fcaa4 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -27,12 +27,12 @@ struct serverworks_page_map { unsigned long *real; - unsigned long *remapped; + unsigned long __iomem *remapped; }; static struct _serverworks_private { struct pci_dev *svrwrks_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; struct serverworks_page_map **gatt_pages; int num_tables; struct serverworks_page_map scratch_dir; @@ -61,9 +61,8 @@ static int serverworks_create_page_map(struct serverworks_page_map *page_map) } global_cache_flush(); - for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { - page_map->remapped[i] = agp_bridge->scratch_page; - } + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) + writel(agp_bridge->scratch_page, page_map->remapped+i); return 0; } @@ -162,10 +161,8 @@ static int serverworks_create_gatt_table(void) } /* Create a fake scratch directory */ for(i = 0; i < 1024; i++) { - serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge->scratch_page; - page_dir.remapped[i] = - virt_to_phys(serverworks_private.scratch_dir.real); - page_dir.remapped[i] |= 0x00000001; + writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i); + writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i); } retval = serverworks_create_gatt_pages(value->num_entries / 1024); @@ -176,7 +173,7 @@ static int serverworks_create_gatt_table(void) } agp_bridge->gatt_table_real = (u32 *)page_dir.real; - agp_bridge->gatt_table = (u32 *)page_dir.remapped; + agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); /* Get the address for the gart region. @@ -189,11 +186,8 @@ static int serverworks_create_gatt_table(void) /* Calculate the agp offset */ - for(i = 0; i < value->num_entries / 1024; i++) { - page_dir.remapped[i] = - virt_to_phys(serverworks_private.gatt_pages[i]->real); - page_dir.remapped[i] |= 0x00000001; - } + for(i = 0; i < value->num_entries / 1024; i++) + writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i); return 0; } @@ -203,7 +197,7 @@ static int serverworks_free_gatt_table(void) struct serverworks_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; - page_dir.remapped = (unsigned long *)agp_bridge->gatt_table; + page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; serverworks_free_gatt_pages(); serverworks_free_page_map(&page_dir); @@ -269,7 +263,7 @@ static int serverworks_configure(void) /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp); temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096); + serverworks_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (!serverworks_private.registers) { printk (KERN_ERR PFX "Unable to ioremap() memory.\n"); return -ENOMEM; @@ -311,14 +305,14 @@ static int serverworks_configure(void) static void serverworks_cleanup(void) { - iounmap((void *) serverworks_private.registers); + iounmap((void __iomem *) serverworks_private.registers); } static int serverworks_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; @@ -334,9 +328,8 @@ static int serverworks_insert_memory(struct agp_memory *mem, while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) { + if (!PGE_EMPTY(agp_bridge, readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; - } j++; } @@ -348,8 +341,7 @@ static int serverworks_insert_memory(struct agp_memory *mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - agp_bridge->driver->mask_memory(mem->memory[i], mem->type); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } serverworks_tlbflush(mem); return 0; @@ -359,7 +351,7 @@ static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { int i; - unsigned long *cur_gatt; + unsigned long __iomem *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) { @@ -372,8 +364,7 @@ static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start, for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge->scratch_page; + writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } serverworks_tlbflush(mem); diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index c619722e5..bcaea8ec3 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -438,6 +438,33 @@ static void __devexit agp_via_remove(struct pci_dev *pdev) agp_put_bridge(bridge); } +#ifdef CONFIG_PM + +static int agp_via_suspend(struct pci_dev *pdev, u32 state) +{ + pci_save_state (pdev, pdev->saved_config_space); + pci_set_power_state (pdev, 3); + + return 0; +} + +static int agp_via_resume(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + pci_set_power_state (pdev, 0); + pci_restore_state(pdev, pdev->saved_config_space); + + if (bridge->driver == &via_agp3_driver) + return via_configure_agp3(); + else if (bridge->driver == &via_driver) + return via_configure(); + + return 0; +} + +#endif /* CONFIG_PM */ + /* must be the same order as name table above */ static struct pci_device_id agp_via_pci_table[] = { #define ID(x) \ @@ -487,6 +514,10 @@ static struct pci_driver agp_via_pci_driver = { .id_table = agp_via_pci_table, .probe = agp_via_probe, .remove = agp_via_remove, +#ifdef CONFIG_PM + .suspend = agp_via_suspend, + .resume = agp_via_resume, +#endif }; @@ -503,5 +534,5 @@ static void __exit agp_via_cleanup(void) module_init(agp_via_init); module_exit(agp_via_cleanup); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dave Jones "); diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 3dc61d41b..f11cf4ea0 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -118,10 +118,6 @@ static struct serial_state rs_table[1]; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -430,7 +426,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)) @@ -557,9 +553,7 @@ static void do_softint(unsigned long private_) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } @@ -1023,9 +1017,7 @@ static void rs_flush_buffer(struct tty_struct *tty) info->xmit.head = info->xmit.tail = 0; local_irq_restore(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1564,8 +1556,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -1610,7 +1602,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (char_time == 0) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); /* * If the transmitter hasn't cleared in twice the approximate * amount of time to send the entire FIFO, it probably won't @@ -2095,7 +2087,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/applicom.c b/drivers/char/applicom.c index 0b2c40e94..148ea2932 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -89,7 +89,7 @@ MODULE_SUPPORTED_DEVICE("ac"); static struct applicom_board { unsigned long PhysIO; - unsigned long RamIO; + void __iomem *RamIO; wait_queue_head_t FlagSleepSend; long irq; spinlock_t mutex; @@ -127,7 +127,7 @@ static struct miscdevice ac_miscdev = { static int dummy; /* dev_id for request_irq() */ -static int ac_register_board(unsigned long physloc, unsigned long loc, +static int ac_register_board(unsigned long physloc, void __iomem *loc, unsigned char boardno) { volatile unsigned char byte_reset_it; @@ -179,11 +179,11 @@ void cleanup_module(void) if (!apbs[i].RamIO) continue; - - iounmap((void *) apbs[i].RamIO); if (apbs[i].irq) free_irq(apbs[i].irq, &dummy); + + iounmap(apbs[i].RamIO); } } @@ -193,7 +193,7 @@ int __init applicom_init(void) { int i, numisa = 0; struct pci_dev *dev = NULL; - void *RamIO; + void __iomem *RamIO; int boardno; printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); @@ -223,8 +223,8 @@ int __init applicom_init(void) applicom_pci_devnames[dev->device-1], dev->resource[0].start, dev->irq); - if (!(boardno = ac_register_board(dev->resource[0].start, - (unsigned long)RamIO,0))) { + boardno = ac_register_board(dev->resource[0].start, RamIO,0); + if (!boardno) { printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); iounmap(RamIO); pci_disable_device(dev); @@ -235,7 +235,7 @@ int __init applicom_init(void) printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); iounmap(RamIO); pci_disable_device(dev); - apbs[boardno - 1].RamIO = 0; + apbs[boardno - 1].RamIO = NULL; continue; } @@ -270,7 +270,7 @@ int __init applicom_init(void) } if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), - (unsigned long)RamIO,i+1))) { + RamIO,i+1))) { iounmap(RamIO); continue; } @@ -280,8 +280,8 @@ int __init applicom_init(void) if (!numisa) { if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &dummy)) { printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq); - iounmap((void *) RamIO); - apbs[boardno - 1].RamIO = 0; + iounmap(RamIO); + apbs[boardno - 1].RamIO = NULL; } else apbs[boardno - 1].irq = irq; @@ -449,7 +449,7 @@ static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, because it works with 2.2 still */ { unsigned char *from = (unsigned char *) &tmpmailbox; - unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC; + void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC; int c; for (c = 0; c < sizeof(struct mailbox); c++) @@ -470,7 +470,7 @@ static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, static int do_ac_read(int IndexCard, char __user *buf, struct st_ram_io *st_loc, struct mailbox *mailbox) { - unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; + void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC; unsigned char *to = (unsigned char *)&mailbox; #ifdef DEBUG int c; @@ -685,7 +685,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un { /* @ ADG ou ATO selon le cas */ int i; unsigned char IndexCard; - unsigned long pmem; + void __iomem *pmem; int ret = 0; volatile unsigned char byte_reset_it; struct st_ram_io *adgl; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e69dc6d00..6ceaee64b 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -682,13 +682,13 @@ static void cy_send_xchar (struct tty_struct *tty, char ch); #define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ - ((cy_readl(&((struct RUNTIME_9060 *) \ + ((cy_readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) -#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 *) \ +#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->mail_box_0)) || \ Z_FPGA_CHECK(card)) && \ - (ZFIRM_ID==cy_readl(&((struct FIRM_ID *) \ + (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \ ((card).base_addr+ID_ADDRESS))->signature))) #ifndef SERIAL_XMIT_SIZE @@ -712,16 +712,16 @@ static struct tty_driver *cy_serial_driver; boot options line. The form is "cyclades=address,address..." */ -static unsigned char *cy_isa_addresses[] = { - (unsigned char *) 0xD0000, - (unsigned char *) 0xD2000, - (unsigned char *) 0xD4000, - (unsigned char *) 0xD6000, - (unsigned char *) 0xD8000, - (unsigned char *) 0xDA000, - (unsigned char *) 0xDC000, - (unsigned char *) 0xDE000, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL +static unsigned int cy_isa_addresses[] = { + 0xD0000, + 0xD2000, + 0xD4000, + 0xD6000, + 0xD8000, + 0xDA000, + 0xDC000, + 0xDE000, + 0,0,0,0,0,0,0,0 }; #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*)) @@ -854,7 +854,7 @@ static void cy_start(struct tty_struct *); static void set_line_char(struct cyclades_port *); static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong); #ifdef CONFIG_ISA -static unsigned detect_isa_irq (volatile ucchar *); +static unsigned detect_isa_irq(void __iomem *); #endif /* CONFIG_ISA */ static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *); @@ -970,10 +970,7 @@ do_softint(void *private_) wake_up_interruptible(&info->delta_msr_wait); } if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } #ifdef Z_WAKE @@ -995,7 +992,7 @@ do_softint(void *private_) This function is only called from inside spinlock-protected code. */ static int -cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index) +cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index) { volatile int i; @@ -1011,7 +1008,7 @@ cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index) if (i == 100) return (-1); /* Issue the new command */ - cy_writeb((u_long)base_addr+(CyCCR< 0)? irq : 0; @@ -1079,7 +1076,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) int status; struct cyclades_card *cinfo; struct cyclades_port *info; - volatile unsigned char *base_addr, *card_base_addr; + void __iomem *base_addr, *card_base_addr; int chip; int save_xir, channel, save_car; char data; @@ -1098,7 +1095,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; /* spurious interrupt */ } - card_base_addr = (unsigned char *)cinfo->base_addr; + card_base_addr = cinfo->base_addr; index = cinfo->bus_index; @@ -1110,8 +1107,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) do{ had_work = 0; for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) { - base_addr = (unsigned char *) - (cinfo->base_addr + (cy_chip_offset[chip]<base_addr + (cy_chip_offset[chip]<last_active = jiffies; save_car = cy_readb(base_addr+(CyCAR<tty == 0){ @@ -1264,8 +1260,8 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) schedule_delayed_work(&tty->flip.work, 1); } /* end of service */ - cy_writeb((u_long)base_addr+(CyRIR<card_lock); } @@ -1284,18 +1280,18 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) channel = (u_short ) (save_xir & CyIRChannel); i = channel + chip * 4 + cinfo->first_line; save_car = cy_readb(base_addr+(CyCAR<last_active = jiffies; if(info->tty == 0){ - cy_writeb((u_long)base_addr+(CySRER<x_char) { /* send special char */ outch = info->x_char; - cy_writeb((u_long)base_addr+(CyTDR<icount.tx++; info->x_char = 0; @@ -1313,14 +1309,14 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (info->breakon || info->breakoff) { if (info->breakon) { - cy_writeb((u_long)base_addr + (CyTDR<breakon = 0; char_count -= 2; } if (info->breakoff) { - cy_writeb((u_long)base_addr + (CyTDR<breakoff = 0; char_count -= 2; } @@ -1329,11 +1325,11 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) while (char_count-- > 0){ if (!info->xmit_cnt){ if (cy_readb(base_addr+(CySRER<xmit_buf == 0){ - cy_writeb((u_long)base_addr+(CySRER<tty->stopped || info->tty->hw_stopped){ - cy_writeb((u_long)base_addr+(CySRER<xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cy_writeb((u_long)base_addr+(CyTDR<icount.tx++; }else{ if(char_count > 1){ info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cy_writeb((u_long)base_addr+(CyTDR<icount.tx++; char_count--; }else{ @@ -1391,9 +1387,9 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) } txend: /* end of service */ - cy_writeb((u_long)base_addr+(CyTIR<card_lock); } @@ -1407,7 +1403,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) + cinfo->first_line]; info->last_active = jiffies; save_car = cy_readb(base_addr+(CyCAR<tty->hw_stopped = 0; - cy_writeb((u_long)base_addr+(CySRER<tty->hw_stopped = 1; - cy_writeb((u_long)base_addr+(CySRER<card_lock); } } /* end while status != 0 */ @@ -1476,7 +1472,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* clear interrupts */ spin_lock(&cinfo->card_lock); - cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<card_lock); return IRQ_HANDLED; @@ -1491,27 +1487,25 @@ static int cyz_fetch_msg( struct cyclades_card *cinfo, uclong *channel, ucchar *cmd, uclong *param) { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; unsigned long loc_doorbell; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)){ return (-1); } - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - loc_doorbell = cy_readl(&((struct RUNTIME_9060 *) + loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->loc_doorbell); if (loc_doorbell){ *cmd = (char)(0xff & loc_doorbell); *channel = cy_readl(&board_ctrl->fwcmd_channel); *param = (uclong)cy_readl(&board_ctrl->fwcmd_param); - cy_writel(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->loc_doorbell, + cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->loc_doorbell, 0xffffffff); return 1; } @@ -1522,40 +1516,38 @@ static int cyz_issue_cmd( struct cyclades_card *cinfo, uclong channel, ucchar cmd, uclong param) { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - volatile uclong *pci_doorbell; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + unsigned long __iomem *pci_doorbell; int index; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)){ return (-1); } - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; index = 0; - pci_doorbell = (uclong *)(&((struct RUNTIME_9060 *) - (cinfo->ctl_addr))->pci_doorbell); + pci_doorbell = &((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->pci_doorbell; while( (cy_readl(pci_doorbell) & 0xff) != 0){ if (index++ == 1000){ return((int)(cy_readl(pci_doorbell) & 0xff)); } udelay(50L); } - cy_writel((u_long)&board_ctrl->hcmd_channel, channel); - cy_writel((u_long)&board_ctrl->hcmd_param , param); - cy_writel((u_long)pci_doorbell, (long)cmd); + cy_writel(&board_ctrl->hcmd_channel, channel); + cy_writel(&board_ctrl->hcmd_param , param); + cy_writel(pci_doorbell, (long)cmd); return(0); } /* cyz_issue_cmd */ static void -cyz_handle_rx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, - volatile struct BUF_CTRL *buf_ctrl) +cyz_handle_rx(struct cyclades_port *info, + volatile struct CH_CTRL __iomem *ch_ctrl, + volatile struct BUF_CTRL __iomem *buf_ctrl) { struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; @@ -1652,8 +1644,9 @@ cyz_handle_rx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, } static void -cyz_handle_tx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, - volatile struct BUF_CTRL *buf_ctrl) +cyz_handle_tx(struct cyclades_port *info, + volatile struct CH_CTRL __iomem *ch_ctrl, + volatile struct BUF_CTRL __iomem *buf_ctrl) { struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; @@ -1740,11 +1733,11 @@ cyz_handle_cmd(struct cyclades_card *cinfo) { struct tty_struct *tty; struct cyclades_port *info; - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct BOARD_CTRL *board_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; + static volatile struct FIRM_ID __iomem *firm_id; + static volatile struct ZFW_CTRL __iomem *zfw_ctrl; + static volatile struct BOARD_CTRL __iomem *board_ctrl; + static volatile struct CH_CTRL __iomem *ch_ctrl; + static volatile struct BUF_CTRL __iomem *buf_ctrl; uclong channel; ucchar cmd; uclong param; @@ -1752,13 +1745,11 @@ cyz_handle_cmd(struct cyclades_card *cinfo) int special_count; int delta_count; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); - board_ctrl = &(zfw_ctrl->board_ctrl); + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; fw_ver = cy_readl(&board_ctrl->fw_version); - hw_ver = cy_readl(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0); + hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->mail_box_0); while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { @@ -1925,10 +1916,8 @@ cyz_poll(unsigned long arg) if (!IS_CYC_Z(*cinfo)) continue; if (!ISZLOADED(*cinfo)) continue; - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &(zfw_ctrl->board_ctrl); /* Skip first polling cycle to avoid racing conditions with the FW */ @@ -1972,7 +1961,7 @@ startup(struct cyclades_port * info) { unsigned long flags; int retval = 0; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; unsigned long page; @@ -2011,8 +2000,7 @@ startup(struct cyclades_port * info) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<default_timeout + cy_writeb(base_addr+(CyRTPR<default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index); - cy_writeb((ulong)base_addr+(CyCAR<flags |= ASYNC_INITIALIZED; @@ -2056,22 +2044,20 @@ startup(struct cyclades_port * info) CY_UNLOCK(info, flags); } else { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = (unsigned char*) (cy_card[card].base_addr); + base_addr = cy_card[card].base_addr; - firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); + firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(cy_card[card])){ return -ENODEV; } - zfw_ctrl = (struct ZFW_CTRL *) - (cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -2163,7 +2149,7 @@ static void start_xmit( struct cyclades_port *info ) { unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; card = info->card; @@ -2172,13 +2158,11 @@ start_xmit( struct cyclades_port *info ) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<flags & ASYNC_INITIALIZED)){ @@ -2219,9 +2203,7 @@ shutdown(struct cyclades_port * info) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<xmit_buf = NULL; free_page((unsigned long) temp); } - cy_writeb((u_long)base_addr+(CyCAR<tty || (info->tty->termios->c_cflag & HUPCL)) { - cy_writeb((u_long)base_addr+(CyMSVR1<flags &= ~ASYNC_INITIALIZED; CY_UNLOCK(info, flags); } else { - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = (unsigned char*) (cy_card[card].base_addr); + base_addr = cy_card[card].base_addr; #ifdef CY_DEBUG_OPEN printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n", card, channel, (long)base_addr); #endif - firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); + firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(cy_card[card])) { return; } - zfw_ctrl = (struct ZFW_CTRL *) - (cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); - board_ctrl = &(zfw_ctrl->board_ctrl); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; CY_LOCK(info, flags); @@ -2293,7 +2273,7 @@ shutdown(struct cyclades_port * info) } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { - cy_writel((u_long)&ch_ctrl[channel].rs_control, + cy_writel(&ch_ctrl[channel].rs_control, (uclong)(cy_readl(&ch_ctrl[channel].rs_control) & ~(C_RS_RTS | C_RS_DTR))); retval = cyz_issue_cmd(&cy_card[info->card], @@ -2337,7 +2317,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, unsigned long flags; int chip, channel,index; int retval; - char *base_addr; + void __iomem *base_addr; cinfo = &cy_card[info->card]; channel = info->line - cinfo->first_line; @@ -2390,15 +2370,14 @@ block_til_ready(struct tty_struct *tty, struct file * filp, chip = channel>>2; channel &= 0x03; index = cinfo->bus_index; - base_addr = (char *)(cinfo->base_addr - + (cy_chip_offset[chip]<base_addr + (cy_chip_offset[chip]<termios->c_cflag & CBAUD)){ - cy_writeb((u_long)base_addr+(CyCAR<flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (cy_readb(base_addr+(CyMSVR1<base_addr); - firm_id = (struct FIRM_ID *) - (base_addr + ID_ADDRESS); + base_addr = cinfo->base_addr; + firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)){ current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); return -EINVAL; } - zfw_ctrl = (struct ZFW_CTRL *) - (base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -2543,11 +2520,10 @@ cy_open(struct tty_struct *tty, struct file * filp) */ if (IS_CYC_Z(cy_card[info->card])) { struct cyclades_card *cinfo = &cy_card[info->card]; - struct FIRM_ID *firm_id = (struct FIRM_ID *) - (cinfo->base_addr + ID_ADDRESS); + struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { - if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 *) + if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->mail_box_0)) && Z_FPGA_CHECK (*cinfo)) && (ZFIRM_HLT == cy_readl (&firm_id->signature))) @@ -2564,12 +2540,10 @@ cy_open(struct tty_struct *tty, struct file * filp) interrupts should be enabled as soon as the first open happens to one of its ports. */ if (!cinfo->intr_enabled) { - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + - (cy_readl (&firm_id->zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cinfo->base_addr + (cy_readl (&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; @@ -2661,7 +2635,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) { struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; unsigned long orig_jiffies; int char_time; @@ -2711,8 +2685,7 @@ cy_wait_until_sent(struct tty_struct *tty, int timeout) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char *) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card])) { int channel = info->line - cy_card[info->card].first_line; int index = cy_card[info->card].bus_index; - unsigned char *base_addr = (unsigned char *) - (cy_card[info->card].base_addr + - (cy_chip_offset[channel>>2] <card].base_addr + (cy_chip_offset[channel>>2] << index); /* Stop accepting input */ channel &= 0x03; - cy_writeb((ulong)base_addr+(CyCAR<flags & ASYNC_INITIALIZED) { /* Waiting for on-board buffers to be empty before closing @@ -2823,12 +2794,10 @@ cy_close(struct tty_struct *tty, struct file *filp) } else { #ifdef Z_WAKE /* Waiting for on-board buffers to be empty before closing the port */ - unsigned char *base_addr = (unsigned char *) - cy_card[info->card].base_addr; - struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); - struct ZFW_CTRL *zfw_ctrl = (struct ZFW_CTRL *) - (base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); - struct CH_CTRL *ch_ctrl = zfw_ctrl->ch_ctrl; + void __iomem *base_addr = cy_card[info->card].base_addr; + struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS; + struct ZFW_CTRL __iomem *zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl; int channel = info->line - cy_card[info->card].first_line; int retval; @@ -2850,8 +2819,7 @@ cy_close(struct tty_struct *tty, struct file *filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); CY_LOCK(info, flags); tty->closing = 0; @@ -3088,10 +3056,8 @@ cy_chars_in_buffer(struct tty_struct *tty) int char_count; volatile uclong tx_put, tx_get, tx_bufsize; - firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); + firm_id = cy_card[card].base_addr + ID_ADDRESS; + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); @@ -3151,7 +3117,7 @@ static void set_line_char(struct cyclades_port * info) { unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; unsigned cflag, iflag; unsigned short chip_number; @@ -3303,76 +3269,74 @@ set_line_char(struct cyclades_port * info) chip = channel>>2; channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<tco); - cy_writeb((u_long)base_addr+(CyTBPR<tbpr); - cy_writeb((u_long)base_addr+(CyRCOR<rco); - cy_writeb((u_long)base_addr+(CyRBPR<rbpr); + cy_writeb(base_addr+(CyTCOR<tco); + cy_writeb(base_addr+(CyTBPR<tbpr); + cy_writeb(base_addr+(CyRCOR<rco); + cy_writeb(base_addr+(CyRBPR<rbpr); /* set line characteristics according configuration */ - cy_writeb((u_long)base_addr+(CySCHR1<tty)); - cy_writeb((u_long)base_addr+(CySCHR2<tty)); - cy_writeb((u_long)base_addr+(CyCOR1<cor1); - cy_writeb((u_long)base_addr+(CyCOR2<cor2); - cy_writeb((u_long)base_addr+(CyCOR3<cor3); - cy_writeb((u_long)base_addr+(CyCOR4<cor4); - cy_writeb((u_long)base_addr+(CyCOR5<cor5); + cy_writeb(base_addr+(CyCOR1<cor1); + cy_writeb(base_addr+(CyCOR2<cor2); + cy_writeb(base_addr+(CyCOR3<cor3); + cy_writeb(base_addr+(CyCOR4<cor4); + cy_writeb(base_addr+(CyCOR5<cor5); cyy_issue_cmd(base_addr, CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index); - cy_writeb((u_long)base_addr+(CyCAR<default_timeout + cy_writeb(base_addr+(CyRTPR<default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ if (C_CLOCAL(info->tty)) { /* without modem intr */ - cy_writeb((u_long)base_addr+(CySRER<0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { - cy_writeb((u_long)base_addr+(CyMCOR1<1 modem transitions */ - cy_writeb((u_long)base_addr+(CyMCOR2<0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { - cy_writeb((u_long)base_addr+(CyMCOR1<1 modem transitions */ - cy_writeb((u_long)base_addr+(CyMCOR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; @@ -3617,7 +3578,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) unsigned char status; unsigned int result; unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; card = info->card; channel = (info->line) - (cy_card[card].first_line); @@ -3625,8 +3586,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char *) - (cy_card[card].base_addr + (cy_chip_offset[chip]<driver_data; int card,chip,channel,index; - unsigned char *base_addr; + void __iomem *base_addr; unsigned long flags; unsigned char status; unsigned long lstatus; unsigned int result; - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; @@ -3663,12 +3623,10 @@ cy_tiocmget(struct tty_struct *tty, struct file *file) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; lstatus = cy_readl(&ch_ctrl[channel].rs_status); @@ -3722,12 +3677,12 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, { struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int card,chip,channel,index; - unsigned char *base_addr; + void __iomem *base_addr; unsigned long flags; - struct FIRM_ID *firm_id; - struct ZFW_CTRL *zfw_ctrl; - struct BOARD_CTRL *board_ctrl; - struct CH_CTRL *ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; int retval; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) @@ -3739,37 +3694,35 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<zfwctrl_addr) & 0xfffff)); + zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -3930,7 +3880,7 @@ get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon) static int set_threshold(struct cyclades_port * info, unsigned long value) { - unsigned char *base_addr; + void __iomem *base_addr; int card,channel,chip,index; unsigned long flags; @@ -3940,15 +3890,13 @@ set_threshold(struct cyclades_port * info, unsigned long value) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<cor3 &= ~CyREC_FIFO; info->cor3 |= value & CyREC_FIFO; CY_LOCK(info, flags); - cy_writeb((u_long)base_addr+(CyCOR3<cor3); + cy_writeb(base_addr+(CyCOR3<cor3); cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index); CY_UNLOCK(info, flags); } else { @@ -3961,7 +3909,7 @@ set_threshold(struct cyclades_port * info, unsigned long value) static int get_threshold(struct cyclades_port * info, unsigned long __user *value) { - unsigned char *base_addr; + void __iomem *base_addr; int card,channel,chip,index; unsigned long tmp; @@ -3971,9 +3919,7 @@ get_threshold(struct cyclades_port * info, unsigned long __user *value) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<driver_data; unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; #ifdef CY_DEBUG_THROTTLE @@ -4359,16 +4301,14 @@ cy_throttle(struct tty_struct * tty) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<driver_data; unsigned long flags; - unsigned char *base_addr; + void __iomem *base_addr; int card,chip,channel,index; #ifdef CY_DEBUG_THROTTLE @@ -4419,16 +4359,14 @@ cy_unthrottle(struct tty_struct * tty) chip = channel>>2; channel &= 0x03; index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr - + (cy_chip_offset[chip]<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<driver_data; - unsigned char *base_addr; + void __iomem *base_addr; int chip,channel,index; unsigned long flags; @@ -4465,14 +4403,12 @@ cy_stop(struct tty_struct *tty) index = cinfo->bus_index; chip = channel>>2; channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[info->card].base_addr - + (cy_chip_offset[chip]<card].base_addr + (cy_chip_offset[chip]<driver_data; - unsigned char *base_addr; + void __iomem *base_addr; int chip,channel,index; unsigned long flags; @@ -4505,14 +4441,12 @@ cy_start(struct tty_struct *tty) if (!IS_CYC_Z(*cinfo)) { chip = channel>>2; channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[info->card].base_addr - + (cy_chip_offset[chip]<card].base_addr + (cy_chip_offset[chip]<write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); } /* cy_flush_buffer */ @@ -4600,20 +4532,19 @@ cy_hangup(struct tty_struct *tty) /* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ static unsigned short __init -cyy_init_card(volatile ucchar *true_base_addr,int index) +cyy_init_card(void __iomem *true_base_addr,int index) { unsigned int chip_number; - volatile ucchar* base_addr; + void __iomem *base_addr; - cy_writeb((u_long)true_base_addr+(Cy_HwReset<= CD1400_REV_J){ /* It is a CD1400 rev. J or later */ /* Impossible to reach 5ms with this chip. Changed to 2ms instead (f = 500 Hz). */ - cy_writeb((u_long)base_addr+(CyPPR<mail_box_0); if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { @@ -5037,7 +4967,7 @@ cy_detect_pci(void) } if (mailbox == ZE_V1) { - cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); + cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ze_win); if (ZeIndex == NR_CARDS) { printk("Cyclades-Ze/PCI found at 0x%lx ", (ulong)cy_pci_phys2); @@ -5055,7 +4985,7 @@ cy_detect_pci(void) i--; continue; } else { - cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Zwin); + cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Zwin); } #ifdef CY_PCI_DEBUG @@ -5082,7 +5012,7 @@ cy_detect_pci(void) */ PAUSE if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel((ulong)(cy_pci_addr2+ID_ADDRESS), 0L); + cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L); /* This must be a Cyclades-8Zo/PCI. The extendable version will have a different device_id and will @@ -5172,7 +5102,7 @@ cy_detect_pci(void) Ze_pdev[j] = Ze_pdev[j+1]; } ZeIndex--; - mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) + mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *) cy_pci_addr0)->mail_box_0); #ifdef CY_PCI_DEBUG printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n", @@ -5413,7 +5343,7 @@ cy_init(void) for (i = 0; i < NR_CARDS; i++) { /* base_addr=0 indicates board not found */ - cy_card[i].base_addr = 0; + cy_card[i].base_addr = NULL; } /* the code below is responsible to find the boards. Each different @@ -5435,7 +5365,7 @@ cy_init(void) for (i = 0 ; i < NR_CARDS ; i++) { if (cy_card[i].base_addr == 0) { cy_card[i].first_line = -1; - cy_card[i].ctl_addr = 0; + cy_card[i].ctl_addr = NULL; cy_card[i].irq = 0; cy_card[i].bus_index = 0; cy_card[i].first_line = 0; @@ -5453,7 +5383,7 @@ cy_init(void) cinfo = &cy_card[board]; if (cinfo->num_chips == -1) { /* Cyclades-Z */ number_z_boards++; - mailbox = cy_readl(&((struct RUNTIME_9060 *) + mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *) cy_card[board].ctl_addr)->mail_box_0); nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; cinfo->intr_enabled = 0; @@ -5623,10 +5553,10 @@ cy_cleanup_module(void) put_tty_driver(cy_serial_driver); for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr != 0) { - iounmap((void *)cy_card[i].base_addr); - if (cy_card[i].ctl_addr != 0) - iounmap((void *)cy_card[i].ctl_addr); + if (cy_card[i].base_addr) { + iounmap(cy_card[i].base_addr); + if (cy_card[i].ctl_addr) + iounmap(cy_card[i].ctl_addr); if (cy_card[i].irq #ifndef CONFIG_CYZ_INTR && cy_card[i].num_chips != -1 /* not a Z card */ diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index 13797ca0c..0f210ceaf 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig @@ -24,14 +24,14 @@ config DRM_TDFX config DRM_GAMMA tristate "3dlabs GMX 2000" - depends on DRM + depends on DRM && BROKEN help This is the old gamma driver, please tell me if it might actually work. config DRM_R128 tristate "ATI Rage 128" - depends on DRM + depends on DRM && PCI help Choose this option if you have an ATI Rage 128 graphics card. If M is selected, the module will be called r128. AGP support for @@ -39,7 +39,7 @@ config DRM_R128 config DRM_RADEON tristate "ATI Radeon" - depends on DRM + depends on DRM && PCI help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to @@ -55,14 +55,29 @@ config DRM_I810 selected, the module will be called i810. AGP support is required for this driver to work. -config DRM_I830 - tristate "Intel 830M, 845G, 852GM, 855GM, 865G" +choice + prompt "Intel 830M, 845G, 852GM, 855GM, 865G" depends on DRM && AGP && AGP_INTEL + optional + +config DRM_I830 + tristate "i830 driver" help Choose this option if you have a system that has Intel 830M, 845G, 852GM, 855GM or 865G integrated graphics. If M is selected, the module will be called i830. AGP support is required for this driver - to work. + to work. This driver will eventually be replaced by the i915 one. + +config DRM_I915 + tristate "i915 driver" + help + Choose this option if you have a system that has Intel 830M, 845G, + 852GM, 855GM 865G or 915G integrated graphics. If M is selected, the + module will be called i915. AGP support is required for this driver + to work. This driver will eventually replace the I830 driver, when + later release of X start to use the new DDX and DRI. + +endchoice config DRM_MGA tristate "Matrox g200/g400" diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index f0acc5e48..d59102e2e 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -8,6 +8,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_ds.o sis_mm.o @@ -19,6 +20,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon.o obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_I830) += i830.o +obj-$(CONFIG_DRM_I915) += i915.o obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_SIS) += sis.o diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 88886cbf9..65351d518 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -73,42 +73,26 @@ #include #include "drm.h" -#include "drm_os_linux.h" +#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) +#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) +#include "drm_os_linux.h" /***********************************************************************/ /** \name DRM template customization defaults */ /*@{*/ -#ifndef __HAVE_AGP -#define __HAVE_AGP 0 -#endif -#ifndef __HAVE_MTRR -#define __HAVE_MTRR 0 -#endif -#ifndef __HAVE_CTX_BITMAP -#define __HAVE_CTX_BITMAP 0 -#endif -#ifndef __HAVE_DMA -#define __HAVE_DMA 0 -#endif -#ifndef __HAVE_IRQ -#define __HAVE_IRQ 0 -#endif -#ifndef __HAVE_DMA_WAITLIST -#define __HAVE_DMA_WAITLIST 0 -#endif -#ifndef __HAVE_DMA_FREELIST -#define __HAVE_DMA_FREELIST 0 -#endif - -#define __REALLY_HAVE_AGP (__HAVE_AGP && (defined(CONFIG_AGP) || \ - defined(CONFIG_AGP_MODULE))) -#define __REALLY_HAVE_MTRR (__HAVE_MTRR && defined(CONFIG_MTRR)) -#define __REALLY_HAVE_SG (__HAVE_SG) - -/*@}*/ - +/* driver capabilities and requirements mask */ +#define DRIVER_USE_AGP 0x1 +#define DRIVER_REQUIRE_AGP 0x2 +#define DRIVER_USE_MTRR 0x4 +#define DRIVER_PCI_DMA 0x8 +#define DRIVER_SG 0x10 +#define DRIVER_HAVE_DMA 0x20 +#define DRIVER_HAVE_IRQ 0x40 +#define DRIVER_IRQ_SHARED 0x80 +#define DRIVER_IRQ_VBL 0x100 +#define DRIVER_DMA_QUEUE 0x200 /***********************************************************************/ /** \name Begin the DRM... */ @@ -265,54 +249,6 @@ static inline struct page * vmalloc_to_page(void * vmalloc_addr) /*@}*/ -/***********************************************************************/ -/** \name Mapping helper macros */ -/*@{*/ - -#define DRM_IOREMAP(map, dev) \ - (map)->handle = DRM(ioremap)( (map)->offset, (map)->size, (dev) ) - -#define DRM_IOREMAP_NOCACHE(map, dev) \ - (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size, (dev)) - -#define DRM_IOREMAPFREE(map, dev) \ - do { \ - if ( (map)->handle && (map)->size ) \ - DRM(ioremapfree)( (map)->handle, (map)->size, (dev) ); \ - } while (0) - -/** - * Find mapping. - * - * \param _map matching mapping if found, untouched otherwise. - * \param _o offset. - * - * Expects the existence of a local variable named \p dev pointing to the - * drm_device structure. - */ -#define DRM_FIND_MAP(_map, _o) \ -do { \ - struct list_head *_list; \ - list_for_each( _list, &dev->maplist->head ) { \ - drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); \ - if ( _entry->map && \ - _entry->map->offset == (_o) ) { \ - (_map) = _entry->map; \ - break; \ - } \ - } \ -} while(0) - -/** - * Drop mapping. - * - * \sa #DRM_FIND_MAP. - */ -#define DRM_DROP_MAP(_map) - -/*@}*/ - - /***********************************************************************/ /** \name Internal types and structures */ /*@{*/ @@ -473,9 +409,7 @@ typedef struct drm_file { struct drm_device *dev; int remove_auth_on_close; unsigned long lock_count; -#ifdef DRIVER_FILE_FIELDS - DRIVER_FILE_FIELDS; -#endif + void *driver_priv; } drm_file_t; /** Wait queue */ @@ -524,16 +458,8 @@ typedef struct drm_device_dma { _DRM_DMA_USE_SG = 0x02 } flags; - /** \name DMA support */ - /*@{*/ - drm_buf_t *this_buffer; /**< Buffer being sent */ - drm_buf_t *next_buffer; /**< Selected buffer to send */ - drm_queue_t *next_queue; /**< Queue from which buffer selected*/ - wait_queue_head_t waiting; /**< Processes waiting on free bufs */ - /*@}*/ } drm_device_dma_t; -#if __REALLY_HAVE_AGP /** * AGP memory entry. Stored as a doubly linked list. */ @@ -562,7 +488,6 @@ typedef struct drm_agp_head { int cant_use_aperture; unsigned long page_mask; } drm_agp_head_t; -#endif /** * Scatter-gather memory. @@ -599,7 +524,6 @@ typedef struct drm_ctx_list { drm_file_t *tag; /**< associated fd private data */ } drm_ctx_list_t; -#ifdef __HAVE_VBL_IRQ typedef struct drm_vbl_sig { struct list_head head; @@ -608,8 +532,40 @@ typedef struct drm_vbl_sig { struct task_struct *task; } drm_vbl_sig_t; -#endif +/** + * DRM device functions structure + */ +struct drm_device; + +struct drm_driver_fn { + int (*preinit)(struct drm_device *); + int (*postinit)(struct drm_device *); + void (*prerelease)(struct drm_device *, struct file *filp); + void (*pretakedown)(struct drm_device *); + int (*postcleanup)(struct drm_device *); + int (*presetup)(struct drm_device *); + int (*postsetup)(struct drm_device *); + int (*open_helper)(struct drm_device *, drm_file_t *); + void (*free_filp_priv)(struct drm_device *, drm_file_t *); + void (*release)(struct drm_device *, struct file *filp); + void (*dma_ready)(struct drm_device *); + int (*dma_quiescent)(struct drm_device *); + int (*context_ctor)(struct drm_device *dev, int context); + int (*context_dtor)(struct drm_device *dev, int context); + int (*kernel_context_switch)(struct drm_device *dev, int old, int new); + void (*kernel_context_switch_unlock)(struct drm_device *dev, drm_lock_t *lock); + int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence); + /* these have to be filled in */ + irqreturn_t (*irq_handler)( DRM_IRQ_ARGS ); + void (*irq_preinstall)(struct drm_device *dev); + void (*irq_postinstall)(struct drm_device *dev); + void (*irq_uninstall)(struct drm_device *dev); + void (*reclaim_buffers)(struct file *filp); + unsigned long (*get_map_ofs)(drm_map_t *map); + unsigned long (*get_reg_ofs)(struct drm_device *dev); + void (*set_version)(struct drm_device *dev, drm_set_version_t *sv); +}; /** * DRM device structure. */ @@ -698,13 +654,13 @@ typedef struct drm_device { struct work_struct work; /** \name VBLANK IRQ support */ /*@{*/ -#ifdef __HAVE_VBL_IRQ + wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ atomic_t vbl_received; spinlock_t vbl_lock; drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ unsigned int vbl_pending; -#endif + /*@}*/ cycles_t ctx_start; cycles_t lck_start; @@ -717,9 +673,7 @@ typedef struct drm_device { wait_queue_head_t buf_readers; /**< Processes waiting to read */ wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ -#if __REALLY_HAVE_AGP drm_agp_head_t *agp; /**< AGP data */ -#endif struct pci_dev *pdev; /**< PCI device structure */ int pci_domain; /**< PCI bus domain number */ @@ -738,8 +692,37 @@ typedef struct drm_device { void *dev_private; /**< device private data */ drm_sigdata_t sigdata; /**< For block_all_signals */ sigset_t sigmask; + + struct drm_driver_fn fn_tbl; + drm_local_map_t *agp_buffer_map; + int dev_priv_size; + u32 driver_features; } drm_device_t; +static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) +{ + return ((dev->driver_features & feature) ? 1 : 0); +} + +#if __OS_HAS_AGP +static inline int drm_core_has_AGP(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_AGP); +} +#else +#define drm_core_has_AGP(dev) (0) +#endif + +#if __OS_HAS_MTRR +static inline int drm_core_has_MTRR(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_MTRR); +} +#else +#define drm_core_has_MTRR(dev) (0) +#endif + +extern void DRM(driver_register_fns)(struct drm_device *dev); /******************************************************************/ /** \name Internal function definitions */ @@ -795,12 +778,10 @@ extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev); extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); -#if __REALLY_HAVE_AGP extern DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type); extern int DRM(free_agp)(DRM_AGP_MEM *handle, int pages); extern int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start); extern int DRM(unbind_agp)(DRM_AGP_MEM *handle); -#endif /* Misc. IOCTL support (drm_ioctl.h) */ extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp, @@ -837,10 +818,8 @@ extern int DRM(rmctx)( struct inode *inode, struct file *filp, extern int DRM(context_switch)(drm_device_t *dev, int old, int new); extern int DRM(context_switch_complete)(drm_device_t *dev, int new); -#if __HAVE_CTX_BITMAP extern int DRM(ctxbitmap_init)( drm_device_t *dev ); extern void DRM(ctxbitmap_cleanup)( drm_device_t *dev ); -#endif extern int DRM(setsareactx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -884,7 +863,6 @@ extern int DRM(addmap)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int DRM(rmmap)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -#if __HAVE_DMA extern int DRM(addbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int DRM(infobufs)( struct inode *inode, struct file *filp, @@ -901,33 +879,22 @@ extern int DRM(dma_setup)(drm_device_t *dev); extern void DRM(dma_takedown)(drm_device_t *dev); extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); extern void DRM(reclaim_buffers)( struct file *filp ); -#endif /* __HAVE_DMA */ /* IRQ support (drm_irq.h) */ -#if __HAVE_IRQ || __HAVE_DMA extern int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -#endif -#if __HAVE_IRQ extern int DRM(irq_install)( drm_device_t *dev ); extern int DRM(irq_uninstall)( drm_device_t *dev ); extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ); extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); -#ifdef __HAVE_VBL_IRQ + extern int DRM(wait_vblank)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); extern void DRM(vbl_send_signals)( drm_device_t *dev ); -#endif -#ifdef __HAVE_IRQ_BH -extern void DRM(irq_immediate_bh)( void *dev ); -#endif -#endif - -#if __REALLY_HAVE_AGP /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *DRM(agp_init)(void); extern void DRM(agp_uninit)(void); @@ -952,7 +919,6 @@ extern DRM_AGP_MEM *DRM(agp_allocate_memory)(size_t pages, u32 type); extern int DRM(agp_free_memory)(DRM_AGP_MEM *handle); extern int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start); extern int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle); -#endif /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, @@ -969,14 +935,12 @@ extern int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root, struct proc_dir_entry *dev_root); -#ifdef __HAVE_SG /* Scatter Gather Support (drm_scatter.h) */ extern void DRM(sg_cleanup)(drm_sg_mem_t *entry); extern int DRM(sg_alloc)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int DRM(sg_free)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -#endif /* ATI PCIGART support (ati_pcigart.h) */ extern int DRM(ati_pcigart_init)(drm_device_t *dev, @@ -986,7 +950,44 @@ extern int DRM(ati_pcigart_cleanup)(drm_device_t *dev, unsigned long addr, dma_addr_t bus_addr); + +/* Inline replacements for DRM_IOREMAP macros */ +static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) +{ + map->handle = DRM(ioremap)( map->offset, map->size, dev ); +} + +static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) +{ + map->handle = DRM(ioremap_nocache)(map->offset, map->size, dev); +} + +static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) +{ + if ( map->handle && map->size ) + DRM(ioremapfree)( map->handle, map->size, dev ); +} + +static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset) +{ + struct list_head *_list; + list_for_each( _list, &dev->maplist->head ) { + drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); + if ( _entry->map && + _entry->map->offset == offset ) { + return _entry->map; + } + } + return NULL; +} + +static __inline__ void drm_core_dropmap(struct drm_map *map) +{ +} /*@}*/ +extern unsigned long DRM(core_get_map_ofs)(drm_map_t *map); +extern unsigned long DRM(core_get_reg_ofs)(struct drm_device *dev); + #endif /* __KERNEL__ */ #endif diff --git a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h index 491c3051c..81b595e0e 100644 --- a/drivers/char/drm/drm_agpsupport.h +++ b/drivers/char/drm/drm_agpsupport.h @@ -34,8 +34,7 @@ #include "drmP.h" #include -#if __REALLY_HAVE_AGP - +#if __OS_HAS_AGP #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") #define DRM_AGP_PUT inter_module_put("drm_agp") @@ -466,4 +465,4 @@ int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle) return drm_agp->unbind_memory(handle); } -#endif /* __REALLY_HAVE_AGP */ +#endif /* __OS_HAS_AGP */ diff --git a/drivers/char/drm/drm_bufs.h b/drivers/char/drm/drm_bufs.h index 6fa862372..19695693f 100644 --- a/drivers/char/drm/drm_bufs.h +++ b/drivers/char/drm/drm_bufs.h @@ -36,26 +36,6 @@ #include #include "drmP.h" -#ifndef __HAVE_PCI_DMA -#define __HAVE_PCI_DMA 0 -#endif - -#ifndef __HAVE_SG -#define __HAVE_SG 0 -#endif - -#ifndef DRIVER_BUF_PRIV_T -#define DRIVER_BUF_PRIV_T u32 -#endif -#ifndef DRIVER_AGP_BUFFERS_MAP -#if __HAVE_AGP && __HAVE_DMA -#error "You must define DRIVER_AGP_BUFFERS_MAP()" -#else -#define DRIVER_AGP_BUFFERS_MAP( dev ) NULL -#endif -#endif - - /** * Compute size order. Returns the exponent of the smaller power of two which * is greater or equal to given number. @@ -142,13 +122,13 @@ int DRM(addmap)( struct inode *inode, struct file *filp, #ifdef __alpha__ map->offset += dev->hose->mem_space->start; #endif -#if __REALLY_HAVE_MTRR - if ( map->type == _DRM_FRAME_BUFFER || - (map->flags & _DRM_WRITE_COMBINING) ) { - map->mtrr = mtrr_add( map->offset, map->size, - MTRR_TYPE_WRCOMB, 1 ); + if (drm_core_has_MTRR(dev)) { + if ( map->type == _DRM_FRAME_BUFFER || + (map->flags & _DRM_WRITE_COMBINING) ) { + map->mtrr = mtrr_add( map->offset, map->size, + MTRR_TYPE_WRCOMB, 1 ); + } } -#endif if (map->type == _DRM_REGISTERS) map->handle = DRM(ioremap)( map->offset, map->size, dev ); @@ -174,15 +154,15 @@ int DRM(addmap)( struct inode *inode, struct file *filp, dev->lock.hw_lock = map->handle; /* Pointer to lock */ } break; -#if __REALLY_HAVE_AGP case _DRM_AGP: + if (drm_core_has_AGP(dev)) { #ifdef __alpha__ - map->offset += dev->hose->mem_space->start; + map->offset += dev->hose->mem_space->start; #endif - map->offset += dev->agp->base; - map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + map->offset += dev->agp->base; + map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + } break; -#endif case _DRM_SCATTER_GATHER: if (!dev->sg) { DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -282,15 +262,15 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if __REALLY_HAVE_MTRR - if (map->mtrr >= 0) { - int retcode; - retcode = mtrr_del(map->mtrr, - map->offset, - map->size); - DRM_DEBUG("mtrr_del = %d\n", retcode); + if (drm_core_has_MTRR(dev)) { + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } } -#endif DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: @@ -306,8 +286,6 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, return 0; } -#if __HAVE_DMA - /** * Cleanup after an error on one of the addbufs() functions. * @@ -348,15 +326,11 @@ static void DRM(cleanup_buf_error)(drm_buf_entry_t *entry) sizeof(*entry->buflist), DRM_MEM_BUFS); -#if __HAVE_DMA_FREELIST - DRM(freelist_destroy)(&entry->freelist); -#endif - entry->buf_count = 0; } } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP /** * Add AGP buffers for DMA transfers (ioctl). * @@ -473,8 +447,8 @@ int DRM(addbufs_agp)( struct inode *inode, struct file *filp, init_waitqueue_head( &buf->dma_wait ); buf->filp = NULL; - buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); - buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = DRM(alloc)( buf->dev_priv_size, DRM_MEM_BUFS ); if(!buf->dev_private) { /* Set count correctly so we free the proper amount. */ @@ -520,12 +494,6 @@ int DRM(addbufs_agp)( struct inode *inode, struct file *filp, DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); -#if __HAVE_DMA_FREELIST - DRM(freelist_create)( &entry->freelist, entry->buf_count ); - for ( i = 0 ; i < entry->buf_count ; i++ ) { - DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); - } -#endif up( &dev->struct_sem ); request.count = entry->buf_count; @@ -539,9 +507,8 @@ int DRM(addbufs_agp)( struct inode *inode, struct file *filp, atomic_dec( &dev->buf_alloc ); return 0; } -#endif /* __REALLY_HAVE_AGP */ +#endif /* __OS_HAS_AGP */ -#if __HAVE_PCI_DMA int DRM(addbufs_pci)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -566,6 +533,7 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp, drm_buf_t **temp_buflist; drm_buf_desc_t __user *argp = (void __user *)arg; + if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL; if ( !dma ) return -EINVAL; if ( copy_from_user( &request, argp, sizeof(request) ) ) @@ -697,8 +665,8 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp, init_waitqueue_head( &buf->dma_wait ); buf->filp = NULL; - buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); - buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = DRM(alloc)( dev->dev_priv_size, DRM_MEM_BUFS ); if(!buf->dev_private) { /* Set count correctly so we free the proper amount. */ @@ -758,12 +726,6 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp, dma->page_count += entry->seg_count << page_order; dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); -#if __HAVE_DMA_FREELIST - DRM(freelist_create)( &entry->freelist, entry->buf_count ); - for ( i = 0 ; i < entry->buf_count ; i++ ) { - DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); - } -#endif up( &dev->struct_sem ); request.count = entry->buf_count; @@ -776,9 +738,7 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp, return 0; } -#endif /* __HAVE_PCI_DMA */ -#if __HAVE_SG int DRM(addbufs_sg)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -801,6 +761,8 @@ int DRM(addbufs_sg)( struct inode *inode, struct file *filp, int i; drm_buf_t **temp_buflist; + if (!drm_core_check_feature(dev, DRIVER_SG)) return -EINVAL; + if ( !dma ) return -EINVAL; if ( copy_from_user( &request, argp, sizeof(request) ) ) @@ -881,8 +843,8 @@ int DRM(addbufs_sg)( struct inode *inode, struct file *filp, init_waitqueue_head( &buf->dma_wait ); buf->filp = NULL; - buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); - buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = DRM(alloc)( dev->dev_priv_size, DRM_MEM_BUFS ); if(!buf->dev_private) { /* Set count correctly so we free the proper amount. */ @@ -929,12 +891,6 @@ int DRM(addbufs_sg)( struct inode *inode, struct file *filp, DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); -#if __HAVE_DMA_FREELIST - DRM(freelist_create)( &entry->freelist, entry->buf_count ); - for ( i = 0 ; i < entry->buf_count ; i++ ) { - DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); - } -#endif up( &dev->struct_sem ); request.count = entry->buf_count; @@ -948,7 +904,6 @@ int DRM(addbufs_sg)( struct inode *inode, struct file *filp, atomic_dec( &dev->buf_alloc ); return 0; } -#endif /* __HAVE_SG */ /** * Add buffers for DMA transfers (ioctl). @@ -968,26 +923,25 @@ int DRM(addbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { drm_buf_desc_t request; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; if ( copy_from_user( &request, (drm_buf_desc_t __user *)arg, sizeof(request) ) ) return -EFAULT; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( request.flags & _DRM_AGP_BUFFER ) return DRM(addbufs_agp)( inode, filp, cmd, arg ); else #endif -#if __HAVE_SG if ( request.flags & _DRM_SG_BUFFER ) return DRM(addbufs_sg)( inode, filp, cmd, arg ); else -#endif -#if __HAVE_PCI_DMA return DRM(addbufs_pci)( inode, filp, cmd, arg ); -#else - return -EINVAL; -#endif } @@ -1019,6 +973,9 @@ int DRM(infobufs)( struct inode *inode, struct file *filp, int i; int count; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; spin_lock( &dev->count_lock ); @@ -1100,6 +1057,9 @@ int DRM(markbufs)( struct inode *inode, struct file *filp, int order; drm_buf_entry_t *entry; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; if ( copy_from_user( &request, @@ -1147,6 +1107,9 @@ int DRM(freebufs)( struct inode *inode, struct file *filp, int idx; drm_buf_t *buf; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; if ( copy_from_user( &request, @@ -1204,6 +1167,9 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp, drm_buf_map_t request; int i; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + if ( !dma ) return -EINVAL; spin_lock( &dev->count_lock ); @@ -1218,9 +1184,9 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp, return -EFAULT; if ( request.count >= dma->buf_count ) { - if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) || - (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) { - drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev ); + if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || + (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG)) ) { + drm_map_t *map = dev->agp_buffer_map; if ( !map ) { retcode = -EINVAL; @@ -1301,4 +1267,3 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp, return retcode; } -#endif /* __HAVE_DMA */ diff --git a/drivers/char/drm/drm_context.h b/drivers/char/drm/drm_context.h index d8000cfbf..b99c99475 100644 --- a/drivers/char/drm/drm_context.h +++ b/drivers/char/drm/drm_context.h @@ -42,11 +42,6 @@ #include "drmP.h" -#if !__HAVE_CTX_BITMAP -#error "__HAVE_CTX_BITMAP must be defined" -#endif - - /******************************************************************/ /** \name Context bitmap support */ /*@{*/ @@ -419,10 +414,13 @@ int DRM(addctx)( struct inode *inode, struct file *filp, /* Should this return -EBUSY instead? */ return -ENOMEM; } -#ifdef DRIVER_CTX_CTOR + if ( ctx.handle != DRM_KERNEL_CONTEXT ) - DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */ -#endif + { + if (dev->fn_tbl.context_ctor) + dev->fn_tbl.context_ctor(dev, ctx.handle); + } + ctx_entry = DRM(alloc)( sizeof(*ctx_entry), DRM_MEM_CTXLIST ); if ( !ctx_entry ) { DRM_DEBUG("out of memory\n"); @@ -554,9 +552,8 @@ int DRM(rmctx)( struct inode *inode, struct file *filp, priv->remove_auth_on_close = 1; } if ( ctx.handle != DRM_KERNEL_CONTEXT ) { -#ifdef DRIVER_CTX_DTOR - DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */ -#endif + if (dev->fn_tbl.context_dtor) + dev->fn_tbl.context_dtor(dev, ctx.handle); DRM(ctxbitmap_free)( dev, ctx.handle ); } @@ -578,3 +575,4 @@ int DRM(rmctx)( struct inode *inode, struct file *filp, } /*@}*/ + diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h new file mode 100644 index 000000000..8ebab5a7e --- /dev/null +++ b/drivers/char/drm/drm_core.h @@ -0,0 +1,40 @@ +/* + * Copyright 2004 Jon Smirl + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "drm_auth.h" +#include "drm_agpsupport.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_irq.h" +#include "drm_drawable.h" +#include "drm_drv.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" +#include "drm_scatter.h" diff --git a/drivers/char/drm/drm_dma.h b/drivers/char/drm/drm_dma.h index 72122754d..5cbdc9315 100644 --- a/drivers/char/drm/drm_dma.h +++ b/drivers/char/drm/drm_dma.h @@ -35,16 +35,6 @@ #include "drmP.h" - -#ifndef __HAVE_DMA_WAITQUEUE -#define __HAVE_DMA_WAITQUEUE 0 -#endif -#ifndef __HAVE_DMA_RECLAIM -#define __HAVE_DMA_RECLAIM 0 -#endif - -#if __HAVE_DMA - /** * Initialize the DMA data. * @@ -116,9 +106,6 @@ void DRM(dma_takedown)(drm_device_t *dev) dma->bufs[i].buf_count * sizeof(*dma->bufs[0].buflist), DRM_MEM_BUFS); -#if __HAVE_DMA_FREELIST - DRM(freelist_destroy)(&dma->bufs[i].freelist); -#endif } } @@ -155,22 +142,11 @@ void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) buf->filp = NULL; buf->used = 0; - if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { + if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && waitqueue_active(&buf->dma_wait)) { wake_up_interruptible(&buf->dma_wait); } -#if __HAVE_DMA_FREELIST - else { - drm_device_dma_t *dma = dev->dma; - /* If processes are waiting, the last one - to wake will put the buffer on the free - list. If no processes are waiting, we - put the buffer on the freelist here. */ - DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf); - } -#endif } -#if !__HAVE_DMA_RECLAIM /** * Reclaim the buffers. * @@ -178,7 +154,7 @@ void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) * * Frees each buffer associated with \p filp not already on the hardware. */ -void DRM(reclaim_buffers)( struct file *filp ) +void DRM(core_reclaim_buffers)( struct file *filp ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -202,29 +178,4 @@ void DRM(reclaim_buffers)( struct file *filp ) } } } -#endif - -#if !__HAVE_IRQ -/* This stub DRM_IOCTL_CONTROL handler is for the drivers that used to require - * IRQs for DMA but no longer do. It maintains compatibility with the X Servers - * that try to use the control ioctl by simply returning success. - */ -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t __user *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - case DRM_UNINST_HANDLER: - return 0; - default: - return -EINVAL; - } -} -#endif -#endif /* __HAVE_DMA */ diff --git a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h index 389fc7ef2..ebba185a7 100644 --- a/drivers/char/drm/drm_drv.h +++ b/drivers/char/drm/drm_drv.h @@ -52,97 +52,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef __MUST_HAVE_AGP -#define __MUST_HAVE_AGP 0 -#endif -#ifndef __HAVE_CTX_BITMAP -#define __HAVE_CTX_BITMAP 0 -#endif -#ifndef __HAVE_IRQ -#define __HAVE_IRQ 0 -#endif -#ifndef __HAVE_DMA_QUEUE -#define __HAVE_DMA_QUEUE 0 -#endif -#ifndef __HAVE_MULTIPLE_DMA_QUEUES -#define __HAVE_MULTIPLE_DMA_QUEUES 0 -#endif -#ifndef __HAVE_DMA_SCHEDULE -#define __HAVE_DMA_SCHEDULE 0 -#endif -#ifndef __HAVE_DMA_FLUSH -#define __HAVE_DMA_FLUSH 0 -#endif -#ifndef __HAVE_DMA_READY -#define __HAVE_DMA_READY 0 -#endif -#ifndef __HAVE_DMA_QUIESCENT -#define __HAVE_DMA_QUIESCENT 0 -#endif -#ifndef __HAVE_RELEASE -#define __HAVE_RELEASE 0 -#endif -#ifndef __HAVE_COUNTERS -#define __HAVE_COUNTERS 0 -#endif -#ifndef __HAVE_SG -#define __HAVE_SG 0 -#endif -/* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm modules in - * the DRI cvs tree, but it is required by the kernel tree's sparc - * driver. - */ -#ifndef __HAVE_KERNEL_CTX_SWITCH -#define __HAVE_KERNEL_CTX_SWITCH 0 -#endif -#ifndef __HAVE_DRIVER_FOPS_READ -#define __HAVE_DRIVER_FOPS_READ 0 -#endif -#ifndef __HAVE_DRIVER_FOPS_POLL -#define __HAVE_DRIVER_FOPS_POLL 0 -#endif - -#ifndef DRIVER_PREINIT -#define DRIVER_PREINIT() -#endif -#ifndef DRIVER_POSTINIT -#define DRIVER_POSTINIT() -#endif -#ifndef DRIVER_PRERELEASE -#define DRIVER_PRERELEASE() -#endif -#ifndef DRIVER_PRETAKEDOWN -#define DRIVER_PRETAKEDOWN() -#endif -#ifndef DRIVER_POSTCLEANUP -#define DRIVER_POSTCLEANUP() -#endif -#ifndef DRIVER_PRESETUP -#define DRIVER_PRESETUP() -#endif -#ifndef DRIVER_POSTSETUP -#define DRIVER_POSTSETUP() -#endif #ifndef DRIVER_IOCTLS #define DRIVER_IOCTLS #endif -#ifndef DRIVER_OPEN_HELPER -#define DRIVER_OPEN_HELPER( priv, dev ) -#endif -#ifndef DRIVER_FOPS -#define DRIVER_FOPS \ -static struct file_operations DRM(fops) = { \ - .owner = THIS_MODULE, \ - .open = DRM(open), \ - .flush = DRM(flush), \ - .release = DRM(release), \ - .ioctl = DRM(ioctl), \ - .mmap = DRM(mmap), \ - .fasync = DRM(fasync), \ - .poll = DRM(poll), \ - .read = DRM(read), \ -} -#endif #ifndef MODULE /** Use an additional macro to avoid preprocessor troubles */ @@ -166,16 +78,24 @@ __setup( DRIVER_NAME "=", DRM_OPTIONS_FUNC ); static drm_device_t DRM(device)[MAX_DEVICES]; static int DRM(numdevs) = 0; -DRIVER_FOPS; +struct file_operations DRM(fops) = { + .owner = THIS_MODULE, + .open = DRM(open), + .flush = DRM(flush), + .release = DRM(release), + .ioctl = DRM(ioctl), + .mmap = DRM(mmap), + .fasync = DRM(fasync), + .poll = DRM(poll), + .read = DRM(read), +}; /** Ioctl table */ -static drm_ioctl_desc_t DRM(ioctls)[] = { +drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, -#if __HAVE_IRQ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 }, -#endif [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, @@ -189,10 +109,8 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, -#if __HAVE_CTX_BITMAP [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, -#endif [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 }, @@ -208,26 +126,18 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, -#if __HAVE_DMA_FLUSH - /* Gamma only, really */ - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, -#else [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(noop), 1, 0 }, -#endif -#if __HAVE_DMA [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ -#endif -#if __HAVE_IRQ || __HAVE_DMA + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, -#endif -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, @@ -238,14 +148,10 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, #endif -#if __HAVE_SG [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 }, -#endif -#ifdef __HAVE_VBL_IRQ [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 }, -#endif DRIVER_IOCTLS }; @@ -264,56 +170,26 @@ MODULE_LICENSE("GPL and additional rights"); static int DRM(setup)( drm_device_t *dev ) { int i; + int ret; + + if (dev->fn_tbl.presetup) + { + ret=dev->fn_tbl.presetup(dev); + if (ret!=0) + return ret; + } - DRIVER_PRESETUP(); atomic_set( &dev->ioctl_count, 0 ); atomic_set( &dev->vma_count, 0 ); dev->buf_use = 0; atomic_set( &dev->buf_alloc, 0 ); -#if __HAVE_DMA - i = DRM(dma_setup)( dev ); - if ( i < 0 ) - return i; -#endif - - dev->counters = 6 + __HAVE_COUNTERS; - dev->types[0] = _DRM_STAT_LOCK; - dev->types[1] = _DRM_STAT_OPENS; - dev->types[2] = _DRM_STAT_CLOSES; - dev->types[3] = _DRM_STAT_IOCTLS; - dev->types[4] = _DRM_STAT_LOCKS; - dev->types[5] = _DRM_STAT_UNLOCKS; -#ifdef __HAVE_COUNTER6 - dev->types[6] = __HAVE_COUNTER6; -#endif -#ifdef __HAVE_COUNTER7 - dev->types[7] = __HAVE_COUNTER7; -#endif -#ifdef __HAVE_COUNTER8 - dev->types[8] = __HAVE_COUNTER8; -#endif -#ifdef __HAVE_COUNTER9 - dev->types[9] = __HAVE_COUNTER9; -#endif -#ifdef __HAVE_COUNTER10 - dev->types[10] = __HAVE_COUNTER10; -#endif -#ifdef __HAVE_COUNTER11 - dev->types[11] = __HAVE_COUNTER11; -#endif -#ifdef __HAVE_COUNTER12 - dev->types[12] = __HAVE_COUNTER12; -#endif -#ifdef __HAVE_COUNTER13 - dev->types[13] = __HAVE_COUNTER13; -#endif -#ifdef __HAVE_COUNTER14 - dev->types[14] = __HAVE_COUNTER14; -#endif -#ifdef __HAVE_COUNTER15 - dev->types[14] = __HAVE_COUNTER14; -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + { + i = DRM(dma_setup)( dev ); + if ( i < 0 ) + return i; + } for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ ) atomic_set( &dev->counts[i], 0 ); @@ -371,7 +247,9 @@ static int DRM(setup)( drm_device_t *dev ) * drm_select_queue fails between the time the interrupt is * initialized and the time the queues are initialized. */ - DRIVER_POSTSETUP(); + if (dev->fn_tbl.postsetup) + dev->fn_tbl.postsetup(dev); + return 0; } @@ -396,10 +274,10 @@ static int DRM(takedown)( drm_device_t *dev ) DRM_DEBUG( "\n" ); - DRIVER_PRETAKEDOWN(); -#if __HAVE_IRQ + if (dev->fn_tbl.pretakedown) + dev->fn_tbl.pretakedown(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)( dev ); -#endif down( &dev->struct_sem ); del_timer( &dev->timer ); @@ -425,9 +303,8 @@ static int DRM(takedown)( drm_device_t *dev ) dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } -#if __REALLY_HAVE_AGP /* Clear AGP information */ - if ( dev->agp ) { + if (drm_core_has_AGP(dev) && dev->agp) { drm_agp_mem_t *entry; drm_agp_mem_t *nexte; @@ -446,7 +323,6 @@ static int DRM(takedown)( drm_device_t *dev ) dev->agp->acquired = 0; dev->agp->enabled = 0; } -#endif /* Clear vma list (only built for debugging) */ if ( dev->vmalist ) { @@ -465,15 +341,15 @@ static int DRM(takedown)( drm_device_t *dev ) switch ( map->type ) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if __REALLY_HAVE_MTRR - if ( map->mtrr >= 0 ) { - int retcode; - retcode = mtrr_del( map->mtrr, - map->offset, - map->size ); - DRM_DEBUG( "mtrr_del=%d\n", retcode ); + if (drm_core_has_MTRR(dev)) { + if ( map->mtrr >= 0 ) { + int retcode; + retcode = mtrr_del( map->mtrr, + map->offset, + map->size ); + DRM_DEBUG( "mtrr_del=%d\n", retcode ); + } } -#endif DRM(ioremapfree)( map->handle, map->size, dev ); break; case _DRM_SHM: @@ -486,15 +362,11 @@ static int DRM(takedown)( drm_device_t *dev ) */ break; case _DRM_SCATTER_GATHER: - /* Handle it, but do nothing, if HAVE_SG - * isn't defined. - */ -#if __HAVE_SG - if(dev->sg) { + /* Handle it */ + if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) { DRM(sg_cleanup)(dev->sg); dev->sg = NULL; } -#endif break; } DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -506,12 +378,8 @@ static int DRM(takedown)( drm_device_t *dev ) dev->maplist = NULL; } -#if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES - if ( dev->queuelist ) { + if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist ) { for ( i = 0 ; i < dev->queue_count ; i++ ) { -#if __HAVE_DMA_WAITLIST - DRM(waitlist_destroy)( &dev->queuelist[i]->waitlist ); -#endif if ( dev->queuelist[i] ) { DRM(free)( dev->queuelist[i], sizeof(*dev->queuelist[0]), @@ -525,11 +393,10 @@ static int DRM(takedown)( drm_device_t *dev ) dev->queuelist = NULL; } dev->queue_count = 0; -#endif -#if __HAVE_DMA - DRM(dma_takedown)( dev ); -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + DRM(dma_takedown)( dev ); + if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ dev->lock.filp = NULL; @@ -540,6 +407,13 @@ static int DRM(takedown)( drm_device_t *dev ) return 0; } +static void DRM(init_fn_table)(struct drm_device *dev) +{ + dev->fn_tbl.reclaim_buffers = DRM(core_reclaim_buffers); + dev->fn_tbl.get_map_ofs = DRM(core_get_map_ofs); + dev->fn_tbl.get_reg_ofs = DRM(core_get_reg_ofs); +} + #include "drm_pciids.h" static struct pci_device_id DRM(pciidlist)[] = { @@ -549,9 +423,7 @@ static struct pci_device_id DRM(pciidlist)[] = { static int DRM(probe)(struct pci_dev *pdev) { drm_device_t *dev; -#if __HAVE_CTX_BITMAP int retcode; -#endif int i; int is_compat = 0; @@ -569,6 +441,9 @@ static int DRM(probe)(struct pci_dev *pdev) if (DRM(numdevs) >= MAX_DEVICES) return -ENODEV; + if ((retcode=pci_enable_device(pdev))) + return retcode; + dev = &(DRM(device)[DRM(numdevs)]); memset( (void *)dev, 0, sizeof(*dev) ); @@ -594,36 +469,51 @@ static int DRM(probe)(struct pci_dev *pdev) dev->pci_func = PCI_FUNC(pdev->devfn); dev->irq = pdev->irq; - DRIVER_PREINIT(); + /* dev_priv_size can be changed by a driver in driver_register_fns */ + dev->dev_priv_size = sizeof(u32); -#if __REALLY_HAVE_AGP - dev->agp = DRM(agp_init)(); -#if __MUST_HAVE_AGP - if ( dev->agp == NULL ) { - DRM_ERROR( "Cannot initialize the agpgart module.\n" ); - DRM(stub_unregister)(dev->minor); - DRM(takedown)( dev ); - return -EINVAL; + /* the DRM has 6 basic counters - drivers add theirs in register_fns */ + dev->counters = 6; + dev->types[0] = _DRM_STAT_LOCK; + dev->types[1] = _DRM_STAT_OPENS; + dev->types[2] = _DRM_STAT_CLOSES; + dev->types[3] = _DRM_STAT_IOCTLS; + dev->types[4] = _DRM_STAT_LOCKS; + dev->types[5] = _DRM_STAT_UNLOCKS; + + DRM(init_fn_table)(dev); + + DRM(driver_register_fns)(dev); + + if (dev->fn_tbl.preinit) + dev->fn_tbl.preinit(dev); + + if (drm_core_has_AGP(dev)) + { + dev->agp = DRM(agp_init)(); + if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) { + DRM_ERROR( "Cannot initialize the agpgart module.\n" ); + DRM(stub_unregister)(dev->minor); + DRM(takedown)( dev ); + return -EINVAL; + } + if (drm_core_has_MTRR(dev)) { + if (dev->agp) + dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size*1024*1024, + MTRR_TYPE_WRCOMB, + 1 ); + } } -#endif -#if __REALLY_HAVE_MTRR - if (dev->agp) - dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, - dev->agp->agp_info.aper_size*1024*1024, - MTRR_TYPE_WRCOMB, - 1 ); -#endif -#endif -#if __HAVE_CTX_BITMAP retcode = DRM(ctxbitmap_init)( dev ); if( retcode ) { DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); DRM(stub_unregister)(dev->minor); DRM(takedown)( dev ); return retcode; - } -#endif + } + DRM(numdevs)++; /* no errors, mark it reserved */ DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n", @@ -635,7 +525,8 @@ static int DRM(probe)(struct pci_dev *pdev) dev->minor, pci_pretty_name(pdev)); - DRIVER_POSTINIT(); + if (dev->fn_tbl.postinit) + dev->fn_tbl.postinit(dev); return 0; } @@ -695,31 +586,30 @@ static void __exit drm_cleanup( void ) DRM_INFO( "Module unloaded\n" ); } } -#if __HAVE_CTX_BITMAP + DRM(ctxbitmap_cleanup)( dev ); -#endif -#if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR - if ( dev->agp && dev->agp->agp_mtrr >= 0) { + if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && + dev->agp && dev->agp->agp_mtrr >= 0) { int retval; retval = mtrr_del( dev->agp->agp_mtrr, dev->agp->agp_info.aper_base, dev->agp->agp_info.aper_size*1024*1024 ); DRM_DEBUG( "mtrr_del=%d\n", retval ); } -#endif DRM(takedown)( dev ); -#if __REALLY_HAVE_AGP - if ( dev->agp ) { + if (drm_core_has_AGP(dev) && dev->agp ) { DRM(agp_uninit)(); DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); dev->agp = NULL; } -#endif + + if (dev->fn_tbl.postcleanup) + dev->fn_tbl.postcleanup(dev); + } - DRIVER_POSTCLEANUP(); DRM(numdevs) = 0; } @@ -834,7 +724,8 @@ int DRM(release)( struct inode *inode, struct file *filp ) DRM_DEBUG( "open_count = %d\n", dev->open_count ); - DRIVER_PRERELEASE(); + if (dev->fn_tbl.prerelease) + dev->fn_tbl.prerelease(dev, filp); /* ======================================================== * Begin inline drm_release @@ -849,9 +740,10 @@ int DRM(release)( struct inode *inode, struct file *filp ) DRM_DEBUG( "File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); -#if __HAVE_RELEASE - DRIVER_RELEASE(); -#endif + + if (dev->fn_tbl.release) + dev->fn_tbl.release(dev, filp); + DRM(lock_free)( dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); @@ -860,14 +752,13 @@ int DRM(release)( struct inode *inode, struct file *filp ) processed via a callback to the X server. */ } -#if __HAVE_RELEASE - else if ( priv->lock_count && dev->lock.hw_lock ) { + else if ( dev->fn_tbl.release && priv->lock_count && dev->lock.hw_lock ) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE( entry, current ); add_wait_queue( &dev->lock.lock_queue, &entry ); for (;;) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); if ( !dev->lock.hw_lock ) { /* Device has been unregistered */ retcode = -EINTR; @@ -887,17 +778,20 @@ int DRM(release)( struct inode *inode, struct file *filp ) break; } } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue( &dev->lock.lock_queue, &entry ); if( !retcode ) { - DRIVER_RELEASE(); + if (dev->fn_tbl.release) + dev->fn_tbl.release(dev, filp); DRM(lock_free)( dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT ); } } -#elif __HAVE_DMA - DRM(reclaim_buffers)( filp ); -#endif + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + { + dev->fn_tbl.reclaim_buffers(filp); + } DRM(fasync)( -1, filp, 0 ); @@ -908,14 +802,14 @@ int DRM(release)( struct inode *inode, struct file *filp ) list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) { if ( pos->tag == priv && pos->handle != DRM_KERNEL_CONTEXT ) { -#ifdef DRIVER_CTX_DTOR - DRIVER_CTX_DTOR(pos->handle); -#endif -#if __HAVE_CTX_BITMAP + if (dev->fn_tbl.context_dtor) + dev->fn_tbl.context_dtor(dev, pos->handle); + DRM(ctxbitmap_free)( dev, pos->handle ); -#endif + list_del( &pos->head ); DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST ); + --dev->ctx_count; } } } @@ -941,6 +835,9 @@ int DRM(release)( struct inode *inode, struct file *filp ) } up( &dev->struct_sem ); + if (dev->fn_tbl.free_filp_priv) + dev->fn_tbl.free_filp_priv(dev, priv); + DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); /* ======================================================== @@ -1039,9 +936,6 @@ int DRM(lock)( struct inode *inode, struct file *filp, DECLARE_WAITQUEUE( entry, current ); drm_lock_t lock; int ret = 0; -#if __HAVE_MULTIPLE_DMA_QUEUES - drm_queue_t *q; -#endif ++priv->lock_count; @@ -1058,83 +952,61 @@ int DRM(lock)( struct inode *inode, struct file *filp, lock.context, current->pid, dev->lock.hw_lock->lock, lock.flags ); -#if __HAVE_DMA_QUEUE - if ( lock.context < 0 ) - return -EINVAL; -#elif __HAVE_MULTIPLE_DMA_QUEUES - if ( lock.context < 0 || lock.context >= dev->queue_count ) - return -EINVAL; - q = dev->queuelist[lock.context]; -#endif + if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) + if ( lock.context < 0 ) + return -EINVAL; -#if __HAVE_DMA_FLUSH - ret = DRM(flush_block_and_flush)( dev, lock.context, lock.flags ); -#endif - if ( !ret ) { - add_wait_queue( &dev->lock.lock_queue, &entry ); - for (;;) { - current->state = TASK_INTERRUPTIBLE; - if ( !dev->lock.hw_lock ) { - /* Device has been unregistered */ - ret = -EINTR; - break; - } - if ( DRM(lock_take)( &dev->lock.hw_lock->lock, - lock.context ) ) { - dev->lock.filp = filp; - dev->lock.lock_time = jiffies; - atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); - break; /* Got lock */ - } - - /* Contention */ - schedule(); - if ( signal_pending( current ) ) { - ret = -ERESTARTSYS; - break; - } - } - current->state = TASK_RUNNING; - remove_wait_queue( &dev->lock.lock_queue, &entry ); - } - -#if __HAVE_DMA_FLUSH - DRM(flush_unblock)( dev, lock.context, lock.flags ); /* cleanup phase */ -#endif - - if ( !ret ) { - sigemptyset( &dev->sigmask ); - sigaddset( &dev->sigmask, SIGSTOP ); - sigaddset( &dev->sigmask, SIGTSTP ); - sigaddset( &dev->sigmask, SIGTTIN ); - sigaddset( &dev->sigmask, SIGTTOU ); - dev->sigdata.context = lock.context; - dev->sigdata.lock = dev->lock.hw_lock; - block_all_signals( DRM(notifier), - &dev->sigdata, &dev->sigmask ); - -#if __HAVE_DMA_READY - if ( lock.flags & _DRM_LOCK_READY ) { - DRIVER_DMA_READY(); + add_wait_queue( &dev->lock.lock_queue, &entry ); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if ( !dev->lock.hw_lock ) { + /* Device has been unregistered */ + ret = -EINTR; + break; } -#endif -#if __HAVE_DMA_QUIESCENT - if ( lock.flags & _DRM_LOCK_QUIESCENT ) { - DRIVER_DMA_QUIESCENT(); + if ( DRM(lock_take)( &dev->lock.hw_lock->lock, + lock.context ) ) { + dev->lock.filp = filp; + dev->lock.lock_time = jiffies; + atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); + break; /* Got lock */ } -#endif - /* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the - * drm modules in the DRI cvs tree, but it is required - * by the Sparc driver. - */ -#if __HAVE_KERNEL_CTX_SWITCH - if ( dev->last_context != lock.context ) { - DRM(context_switch)(dev, dev->last_context, - lock.context); + + /* Contention */ + schedule(); + if ( signal_pending( current ) ) { + ret = -ERESTARTSYS; + break; } -#endif - } - + } + __set_current_state(TASK_RUNNING); + remove_wait_queue( &dev->lock.lock_queue, &entry ); + + sigemptyset( &dev->sigmask ); + sigaddset( &dev->sigmask, SIGSTOP ); + sigaddset( &dev->sigmask, SIGTSTP ); + sigaddset( &dev->sigmask, SIGTTIN ); + sigaddset( &dev->sigmask, SIGTTOU ); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals( DRM(notifier), + &dev->sigdata, &dev->sigmask ); + + if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) + dev->fn_tbl.dma_ready(dev); + + if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) + return dev->fn_tbl.dma_quiescent(dev); + + /* dev->fn_tbl.kernel_context_switch isn't used by any of the x86 + * drivers but is used by the Sparc driver. + */ + + if (dev->fn_tbl.kernel_context_switch && + dev->last_context != lock.context) { + dev->fn_tbl.kernel_context_switch(dev, dev->last_context, + lock.context); + } DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); return ret; @@ -1169,40 +1041,20 @@ int DRM(unlock)( struct inode *inode, struct file *filp, atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] ); - /* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm - * modules in the DRI cvs tree, but it is required by the - * Sparc driver. - */ -#if __HAVE_KERNEL_CTX_SWITCH - /* We no longer really hold it, but if we are the next - * agent to request it then we should just be able to - * take it immediately and not eat the ioctl. + /* kernel_context_switch isn't used by any of the x86 drm + * modules but is required by the Sparc driver. */ - dev->lock.filp = NULL; - { - __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; - unsigned int old, new, prev, ctx; - - ctx = lock.context; - do { - old = *plock; - new = ctx; - prev = cmpxchg(plock, old, new); - } while (prev != old); - } - wake_up_interruptible(&dev->lock.lock_queue); -#else - DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT ); -#if __HAVE_DMA_SCHEDULE - DRM(dma_schedule)( dev, 1 ); -#endif - - if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT ) ) { - DRM_ERROR( "\n" ); + if (dev->fn_tbl.kernel_context_switch_unlock) + dev->fn_tbl.kernel_context_switch_unlock(dev, &lock); + else { + DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT ); + + if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT ) ) { + DRM_ERROR( "\n" ); + } } -#endif /* !__HAVE_KERNEL_CTX_SWITCH */ unblock_all_signals(); return 0; diff --git a/drivers/char/drm/drm_fops.h b/drivers/char/drm/drm_fops.h index 0aa02444a..0e91190a3 100644 --- a/drivers/char/drm/drm_fops.h +++ b/drivers/char/drm/drm_fops.h @@ -53,6 +53,7 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) { int minor = iminor(inode); drm_file_t *priv; + int ret; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ if (!DRM(cpu_valid)()) return -EINVAL; @@ -72,7 +73,11 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) priv->authenticated = capable(CAP_SYS_ADMIN); priv->lock_count = 0; - DRIVER_OPEN_HELPER( priv, dev ); + if (dev->fn_tbl.open_helper) { + ret=dev->fn_tbl.open_helper(dev, priv); + if (ret < 0) + goto out_free; + } down(&dev->struct_sem); if (!dev->file_last) { @@ -104,6 +109,10 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) #endif return 0; +out_free: + DRM(free)(priv, sizeof(*priv), DRM_MEM_FILES); + filp->private_data=NULL; + return ret; } /** No-op. */ @@ -130,19 +139,15 @@ int DRM(fasync)(int fd, struct file *filp, int on) return 0; } -#if !__HAVE_DRIVER_FOPS_POLL /** No-op. */ unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) { return 0; } -#endif -#if !__HAVE_DRIVER_FOPS_READ /** No-op. */ ssize_t DRM(read)(struct file *filp, char __user *buf, size_t count, loff_t *off) { return 0; } -#endif diff --git a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h index ef6532a31..d1271c166 100644 --- a/drivers/char/drm/drm_ioctl.h +++ b/drivers/char/drm/drm_ioctl.h @@ -341,9 +341,9 @@ int DRM(setversion)(DRM_IOCTL_ARGS) if (sv.drm_dd_major != DRIVER_MAJOR || sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR) return EINVAL; -#ifdef DRIVER_SETVERSION - DRIVER_SETVERSION(dev, &sv); -#endif + + if (dev->fn_tbl.set_version) + dev->fn_tbl.set_version(dev, &sv); } return 0; } diff --git a/drivers/char/drm/drm_irq.h b/drivers/char/drm/drm_irq.h index 04bb0ac11..d26c999fe 100644 --- a/drivers/char/drm/drm_irq.h +++ b/drivers/char/drm/drm_irq.h @@ -37,16 +37,6 @@ #include /* For task queue support */ -#ifndef __HAVE_SHARED_IRQ -#define __HAVE_SHARED_IRQ 0 -#endif - -#if __HAVE_SHARED_IRQ -#define DRM_IRQ_TYPE SA_SHIRQ -#else -#define DRM_IRQ_TYPE 0 -#endif - /** * Get interrupt from bus id. * @@ -68,6 +58,9 @@ int DRM(irq_by_busid)(struct inode *inode, struct file *filp, drm_irq_busid_t __user *argp = (void __user *)arg; drm_irq_busid_t p; + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + if (copy_from_user(&p, argp, sizeof(p))) return -EFAULT; @@ -86,8 +79,6 @@ int DRM(irq_by_busid)(struct inode *inode, struct file *filp, return 0; } -#if __HAVE_IRQ - /** * Install IRQ handler. * @@ -101,7 +92,11 @@ int DRM(irq_by_busid)(struct inode *inode, struct file *filp, int DRM(irq_install)( drm_device_t *dev ) { int ret; - + unsigned long sh_flags=0; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + if ( dev->irq == 0 ) return -EINVAL; @@ -122,32 +117,25 @@ int DRM(irq_install)( drm_device_t *dev ) DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); -#if __HAVE_DMA - dev->dma->next_buffer = NULL; - dev->dma->next_queue = NULL; - dev->dma->this_buffer = NULL; -#endif - -#ifdef __HAVE_IRQ_BH - INIT_WORK(&dev->work, DRM(irq_immediate_bh), dev); -#endif - -#ifdef __HAVE_VBL_IRQ - init_waitqueue_head(&dev->vbl_queue); - - spin_lock_init( &dev->vbl_lock ); - - INIT_LIST_HEAD( &dev->vbl_sigs.head ); - - dev->vbl_pending = 0; -#endif + if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { + init_waitqueue_head(&dev->vbl_queue); + + spin_lock_init( &dev->vbl_lock ); + + INIT_LIST_HEAD( &dev->vbl_sigs.head ); + + dev->vbl_pending = 0; + } /* Before installing handler */ - DRM(driver_irq_preinstall)(dev); + dev->fn_tbl.irq_preinstall(dev); /* Install handler */ - ret = request_irq( dev->irq, DRM(irq_handler), - DRM_IRQ_TYPE, dev->devname, dev ); + if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) + sh_flags = SA_SHIRQ; + + ret = request_irq( dev->irq, dev->fn_tbl.irq_handler, + sh_flags, dev->devname, dev ); if ( ret < 0 ) { down( &dev->struct_sem ); dev->irq_enabled = 0; @@ -156,7 +144,7 @@ int DRM(irq_install)( drm_device_t *dev ) } /* After installing handler */ - DRM(driver_irq_postinstall)(dev); + dev->fn_tbl.irq_postinstall(dev); return 0; } @@ -172,6 +160,9 @@ int DRM(irq_uninstall)( drm_device_t *dev ) { int irq_enabled; + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + down( &dev->struct_sem ); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; @@ -182,7 +173,7 @@ int DRM(irq_uninstall)( drm_device_t *dev ) DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); - DRM(driver_irq_uninstall)( dev ); + dev->fn_tbl.irq_uninstall(dev); free_irq( dev->irq, dev ); @@ -206,25 +197,29 @@ int DRM(control)( struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_control_t ctl; + + /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */ if ( copy_from_user( &ctl, (drm_control_t __user *)arg, sizeof(ctl) ) ) return -EFAULT; switch ( ctl.func ) { case DRM_INST_HANDLER: + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && ctl.irq != dev->irq) return -EINVAL; return DRM(irq_install)( dev ); case DRM_UNINST_HANDLER: + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; return DRM(irq_uninstall)( dev ); default: return -EINVAL; } } -#ifdef __HAVE_VBL_IRQ - /** * Wait for VBLANK. * @@ -254,6 +249,9 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS ) int ret = 0; unsigned int flags; + if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL)) + return -EINVAL; + if (!dev->irq) return -EINVAL; @@ -318,7 +316,8 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS ) spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); } else { - ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); + if (dev->fn_tbl.vblank_wait) + ret = dev->fn_tbl.vblank_wait( dev, &vblwait.request.sequence ); do_gettimeofday( &now ); vblwait.reply.tval_sec = now.tv_sec; @@ -366,6 +365,4 @@ void DRM(vbl_send_signals)( drm_device_t *dev ) spin_unlock_irqrestore( &dev->vbl_lock, flags ); } -#endif /* __HAVE_VBL_IRQ */ -#endif /* __HAVE_IRQ */ diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h index 9adfe790d..c68e8d5eb 100644 --- a/drivers/char/drm/drm_memory.h +++ b/drivers/char/drm/drm_memory.h @@ -44,7 +44,7 @@ */ #define DEBUG_MEMORY 0 -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP #include @@ -130,46 +130,56 @@ drm_follow_page (void *vaddr) return pte_pfn(*ptep) << PAGE_SHIFT; } -#endif /* __REALLY_HAVE_AGP */ +#else /* __OS_HAS_AGP */ + +static inline drm_map_t *drm_lookup_map(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + return NULL; +} + +static inline void *agp_remap(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + return NULL; +} + +static inline unsigned long drm_follow_page (void *vaddr) +{ + return 0; +} + +#endif static inline void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) { -#if __REALLY_HAVE_AGP - if (dev->agp && dev->agp->cant_use_aperture) { + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { drm_map_t *map = drm_lookup_map(offset, size, dev); if (map && map->type == _DRM_AGP) return agp_remap(offset, size, dev); } -#endif - return ioremap(offset, size); } static inline void *drm_ioremap_nocache(unsigned long offset, unsigned long size, drm_device_t *dev) { -#if __REALLY_HAVE_AGP - if (dev->agp && dev->agp->cant_use_aperture) { + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { drm_map_t *map = drm_lookup_map(offset, size, dev); if (map && map->type == _DRM_AGP) return agp_remap(offset, size, dev); } -#endif - return ioremap_nocache(offset, size); } static inline void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) { -#if __REALLY_HAVE_AGP /* * This is a bit ugly. It would be much cleaner if the DRM API would use separate * routines for handling mappings in the AGP space. Hopefully this can be done in * a future revision of the interface... */ - if (dev->agp && dev->agp->cant_use_aperture + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture && ((unsigned long) pt >= VMALLOC_START && (unsigned long) pt < VMALLOC_END)) { unsigned long offset; @@ -182,11 +192,11 @@ static inline void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *d return; } } -#endif iounmap(pt); } + #if DEBUG_MEMORY #include "drm_memory_debug.h" #else @@ -331,7 +341,7 @@ void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) drm_ioremapfree(pt, size, dev); } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP /** Wrapper around agp_allocate_memory() */ DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type) { diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 74d3c499e..0053679a8 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -352,7 +352,7 @@ void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) } } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type) { diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 6b69f0aa3..242e311a2 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -16,13 +16,17 @@ #define DRM_CURRENTPID current->pid #define DRM_UDELAY(d) udelay(d) /** Read a byte from a MMIO region */ -#define DRM_READ8(map, offset) readb(((unsigned long)(map)->handle) + (offset)) +#define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset)) +/** Read a word from a MMIO region */ +#define DRM_READ16(map, offset) readw(((void __iomem *)(map)->handle) + (offset)) /** Read a dword from a MMIO region */ -#define DRM_READ32(map, offset) readl(((unsigned long)(map)->handle) + (offset)) +#define DRM_READ32(map, offset) readl(((void __iomem *)(map)->handle) + (offset)) /** Write a byte into a MMIO region */ -#define DRM_WRITE8(map, offset, val) writeb(val, ((unsigned long)(map)->handle) + (offset)) +#define DRM_WRITE8(map, offset, val) writeb(val, ((void __iomem *)(map)->handle) + (offset)) +/** Write a word into a MMIO region */ +#define DRM_WRITE16(map, offset, val) writew(val, ((void __iomem *)(map)->handle) + (offset)) /** Write a dword into a MMIO region */ -#define DRM_WRITE32(map, offset, val) writel(val, ((unsigned long)(map)->handle) + (offset)) +#define DRM_WRITE32(map, offset, val) writel(val, ((void __iomem *)(map)->handle) + (offset)) /** Read memory barrier */ #define DRM_READMEMORYBARRIER() rmb() /** Write memory barrier */ @@ -37,8 +41,34 @@ #define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs /** AGP types */ +#if __OS_HAS_AGP #define DRM_AGP_MEM struct agp_memory #define DRM_AGP_KERN struct agp_kern_info +#else +/* define some dummy types for non AGP supporting kernels */ +struct no_agp_kern { + unsigned long aper_base; + unsigned long aper_size; +}; +#define DRM_AGP_MEM int +#define DRM_AGP_KERN struct no_agp_kern +#endif + +#if !(__OS_HAS_MTRR) +static __inline__ int mtrr_add (unsigned long base, unsigned long size, + unsigned int type, char increment) +{ + return -ENODEV; +} + +static __inline__ int mtrr_del (int reg, unsigned long base, + unsigned long size) +{ + return -ENODEV; +} +#define MTRR_TYPE_WRCOMB 1 + +#endif /** Task queue handler arguments */ #define DRM_TASKQUEUE_ARGS void *arg @@ -104,7 +134,7 @@ do { \ add_wait_queue(&(queue), &entry); \ \ for (;;) { \ - current->state = TASK_INTERRUPTIBLE; \ + __set_current_state(TASK_INTERRUPTIBLE); \ if (condition) \ break; \ if (time_after_eq(jiffies, end)) { \ @@ -117,7 +147,7 @@ do { \ break; \ } \ } \ - current->state = TASK_RUNNING; \ + __set_current_state(TASK_RUNNING); \ remove_wait_queue(&(queue), &entry); \ } while (0) diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 3b5f8d3a2..768c131d2 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -201,3 +201,11 @@ #define ffb_PCI_IDS \ {0, 0, 0} +#define i915_PCI_IDS \ + {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + diff --git a/drivers/char/drm/drm_scatter.h b/drivers/char/drm/drm_scatter.h index e5d829367..436a0170e 100644 --- a/drivers/char/drm/drm_scatter.h +++ b/drivers/char/drm/drm_scatter.h @@ -73,6 +73,9 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, DRM_DEBUG( "%s\n", __FUNCTION__ ); + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; + if ( dev->sg ) return -EINVAL; @@ -206,6 +209,9 @@ int DRM(sg_free)( struct inode *inode, struct file *filp, drm_scatter_gather_t request; drm_sg_mem_t *entry; + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; + if ( copy_from_user( &request, (drm_scatter_gather_t __user *)arg, sizeof(request) ) ) diff --git a/drivers/char/drm/drm_vm.h b/drivers/char/drm/drm_vm.h index d7dce3ae9..1601447d8 100644 --- a/drivers/char/drm/drm_vm.h +++ b/drivers/char/drm/drm_vm.h @@ -46,10 +46,10 @@ * Find the right map and if it's AGP memory find the real physical page to * map, get the page, increment the use count and return it. */ +#if __OS_HAS_AGP static __inline__ struct page *DRM(do_vm_nopage)(struct vm_area_struct *vma, unsigned long address) { -#if __REALLY_HAVE_AGP drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; @@ -59,6 +59,8 @@ static __inline__ struct page *DRM(do_vm_nopage)(struct vm_area_struct *vma, /* * Find the right map */ + if (!drm_core_has_AGP(dev)) + goto vm_nopage_error; if(!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; @@ -107,10 +109,15 @@ static __inline__ struct page *DRM(do_vm_nopage)(struct vm_area_struct *vma, return page; } vm_nopage_error: -#endif /* __REALLY_HAVE_AGP */ - return NOPAGE_SIGBUS; /* Disallow mremap */ } +#else /* __OS_HAS_AGP */ +static __inline__ struct page *DRM(do_vm_nopage)(struct vm_area_struct *vma, + unsigned long address) +{ + return NOPAGE_SIGBUS; +} +#endif /* __OS_HAS_AGP */ /** * \c nopage method for shared virtual memory. @@ -201,15 +208,13 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if __REALLY_HAVE_MTRR - if (map->mtrr >= 0) { + if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { int retcode; retcode = mtrr_del(map->mtrr, map->offset, map->size); DRM_DEBUG("mtrr_del = %d\n", retcode); } -#endif DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: @@ -488,18 +493,19 @@ int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma) return 0; } -#ifndef DRIVER_GET_MAP_OFS -#define DRIVER_GET_MAP_OFS() (map->offset) -#endif +unsigned long DRM(core_get_map_ofs)(drm_map_t *map) +{ + return map->offset; +} -#ifndef DRIVER_GET_REG_OFS +unsigned long DRM(core_get_reg_ofs)(struct drm_device *dev) +{ #ifdef __alpha__ -#define DRIVER_GET_REG_OFS() (dev->hose->dense_mem_base - \ - dev->hose->mem_space->start) + return dev->hose->dense_mem_base - dev->hose->mem_space->start; #else -#define DRIVER_GET_REG_OFS() 0 -#endif + return 0; #endif +} /** * mmap DMA memory. @@ -533,7 +539,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) * --BenH. */ if (!VM_OFFSET(vma) -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) #endif ) @@ -552,7 +558,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) r_list = list_entry(list, drm_map_list_t, head); map = r_list->map; if (!map) continue; - off = DRIVER_GET_MAP_OFS(); + off = dev->fn_tbl.get_map_ofs(map); if (off == VM_OFFSET(vma)) break; } @@ -577,8 +583,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) switch (map->type) { case _DRM_AGP: -#if __REALLY_HAVE_AGP - if (dev->agp->cant_use_aperture) { + if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) { /* * On some platforms we can't talk to bus dma address from the CPU, so for * memory of type DRM_AGP, we'll deal with sorting out the real physical @@ -590,7 +595,6 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &DRM(vm_ops); break; } -#endif /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: @@ -609,7 +613,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) if (map->type != _DRM_AGP) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #endif - offset = DRIVER_GET_REG_OFS(); + offset = dev->fn_tbl.get_reg_ofs(dev); #ifdef __sparc__ if (io_remap_page_range(DRM_RPR_ARG(vma) vma->vm_start, VM_OFFSET(vma) + offset, diff --git a/drivers/char/drm/ffb.h b/drivers/char/drm/ffb.h index af35783b2..3691c8652 100644 --- a/drivers/char/drm/ffb.h +++ b/drivers/char/drm/ffb.h @@ -8,9 +8,5 @@ */ #define DRM(x) ffb_##x -/* General customization: - */ -#define __HAVE_KERNEL_CTX_SWITCH 1 -#define __HAVE_RELEASE 1 #endif diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c index 6fae05c8b..f51812078 100644 --- a/drivers/char/drm/ffb_context.c +++ b/drivers/char/drm/ffb_context.c @@ -354,7 +354,7 @@ static void FFBWait(ffb_fbcPtr ffb) } while (--limit); } -int DRM(context_switch)(drm_device_t *dev, int old, int new) +int ffb_driver_context_switch(drm_device_t *dev, int old, int new) { ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; @@ -380,7 +380,7 @@ int DRM(context_switch)(drm_device_t *dev, int old, int new) return 0; } -int DRM(resctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_resctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_ctx_res_t res; @@ -407,7 +407,7 @@ int DRM(resctx)(struct inode *inode, struct file *filp, unsigned int cmd, } -int DRM(addctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_addctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -428,7 +428,7 @@ int DRM(addctx)(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -int DRM(modctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_modctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -457,7 +457,7 @@ int DRM(modctx)(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -int DRM(getctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_getctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -489,7 +489,7 @@ int DRM(getctx)(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -int DRM(switchctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -499,10 +499,10 @@ int DRM(switchctx)(struct inode *inode, struct file *filp, unsigned int cmd, if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx))) return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); - return DRM(context_switch)(dev, dev->last_context, ctx.handle); + return ffb_driver_context_switch(dev, dev->last_context, ctx.handle); } -int DRM(newctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_newctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_ctx_t ctx; @@ -514,7 +514,7 @@ int DRM(newctx)(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -int DRM(rmctx)(struct inode *inode, struct file *filp, unsigned int cmd, +int ffb_driver_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_ctx_t ctx; @@ -537,3 +537,15 @@ int DRM(rmctx)(struct inode *inode, struct file *filp, unsigned int cmd, } return 0; } + +void ffb_set_context_ioctls(void) +{ + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)].func = ffb_driver_addctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)].func = ffb_driver_rmctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)].func = ffb_driver_modctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)].func = ffb_driver_getctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)].func = ffb_driver_switchctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)].func = ffb_driver_newctx; + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)].func = ffb_driver_resctx; + +} diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c index 765355999..2e1522e7c 100644 --- a/drivers/char/drm/ffb_drv.c +++ b/drivers/char/drm/ffb_drv.c @@ -26,58 +26,6 @@ #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 1 -#define DRIVER_FOPS \ -static struct file_operations DRM(fops) = { \ - .owner = THIS_MODULE, \ - .open = DRM(open), \ - .flush = DRM(flush), \ - .release = DRM(release), \ - .ioctl = DRM(ioctl), \ - .mmap = DRM(mmap), \ - .read = DRM(read), \ - .fasync = DRM(fasync), \ - .poll = DRM(poll), \ - .get_unmapped_area = ffb_get_unmapped_area, \ -} - -#define DRIVER_COUNT_CARDS() ffb_count_card_instances() -/* Allocate private structure and fill it */ -#define DRIVER_PRESETUP() do { \ - int _ret; \ - _ret = ffb_presetup(dev); \ - if (_ret != 0) return _ret; \ -} while(0) - -/* Free private structure */ -#define DRIVER_PRETAKEDOWN() do { \ - if (dev->dev_private) kfree(dev->dev_private); \ -} while(0) - -#define DRIVER_POSTCLEANUP() do { \ - if (ffb_position != NULL) kfree(ffb_position); \ -} while(0) - -/* We have to free up the rogue hw context state holding error or - * else we will leak it. - */ -#define DRIVER_RELEASE() do { \ - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; \ - int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); \ - int idx; \ - \ - idx = context - 1; \ - if (fpriv && \ - context != DRM_KERNEL_CONTEXT && \ - fpriv->hw_state[idx] != NULL) { \ - kfree(fpriv->hw_state[idx]); \ - fpriv->hw_state[idx] = NULL; \ - } \ -} while(0) - -/* For mmap customization */ -#define DRIVER_GET_MAP_OFS() (map->offset & 0xffffffff) -#define DRIVER_GET_REG_OFS() ffb_get_reg_offset(dev) - typedef struct _ffb_position_t { int node; int root; @@ -192,63 +140,6 @@ static int ffb_init_one(drm_device_t *dev, int prom_node, int parent_node, return 0; } -static int __init ffb_count_siblings(int root) -{ - int node, child, count = 0; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) - count++; - - return count; -} - -static int __init ffb_scan_siblings(int root, int instance) -{ - int node, child; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { - ffb_position[instance].node = node; - ffb_position[instance].root = root; - instance++; - } - - return instance; -} - -static int ffb_presetup(drm_device_t *); - -static int __init ffb_count_card_instances(void) -{ - int root, total, instance; - - total = ffb_count_siblings(prom_root_node); - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - total += ffb_count_siblings(root); - - ffb_position = kmalloc(sizeof(ffb_position_t) * total, GFP_KERNEL); - - /* Actual failure will be caught during ffb_presetup b/c we can't catch - * it easily here. - */ - if (!ffb_position) - return -ENOMEM; - - instance = ffb_scan_siblings(prom_root_node, 0); - - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - instance = ffb_scan_siblings(root, instance); - - return total; -} - static drm_map_t *ffb_find_map(struct file *filp, unsigned long off) { drm_file_t *priv = filp->private_data; @@ -275,11 +166,11 @@ static drm_map_t *ffb_find_map(struct file *filp, unsigned long off) return NULL; } -static unsigned long ffb_get_unmapped_area(struct file *filp, - unsigned long hint, - unsigned long len, - unsigned long pgoff, - unsigned long flags) +unsigned long ffb_get_unmapped_area(struct file *filp, + unsigned long hint, + unsigned long len, + unsigned long pgoff, + unsigned long flags) { drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT); unsigned long addr = -ENOMEM; @@ -319,21 +210,7 @@ static unsigned long ffb_get_unmapped_area(struct file *filp, return addr; } -static unsigned long ffb_get_reg_offset(drm_device_t *dev) -{ - ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private; - - if (ffb_priv) - return ffb_priv->card_phys_base; - - return 0; -} - -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" +#include "drm_core.h" /* This functions must be here since it references DRM(numdevs) * which drm_drv.h declares. @@ -372,11 +249,74 @@ static int ffb_presetup(drm_device_t *dev) return ret; } -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +static void ffb_driver_release(drm_device_t *dev, struct file *filp) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; + int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); + int idx; + + idx = context - 1; + if (fpriv && + context != DRM_KERNEL_CONTEXT && + fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } +} + +static void ffb_driver_pretakedown(drm_device_t *dev) +{ + if (dev->dev_private) kfree(dev->dev_private); +} + +static int ffb_driver_postcleanup(drm_device_t *dev) +{ + if (ffb_position != NULL) kfree(ffb_position); + return 0; +} + +static void ffb_driver_kernel_context_switch_unlock(struct drm_device *dev, drm_lock_t *lock) +{ + dev->lock.filp = 0; + { + __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; + unsigned int old, new, prev, ctx; + + ctx = lock->context; + do { + old = *plock; + new = ctx; + prev = cmpxchg(plock, old, new); + } while (prev != old); + } + wake_up_interruptible(&dev->lock.lock_queue); +} + +static unsigned long ffb_driver_get_map_ofs(drm_map_t *map) +{ + return (map->offset & 0xffffffff); +} + +static unsigned long ffb_driver_get_reg_ofs(drm_device_t *dev) +{ + ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private; + + if (ffb_priv) + return ffb_priv->card_phys_base; + + return 0; +} + +void ffb_driver_register_fns(drm_device_t *dev) +{ + ffb_set_context_ioctls(); + DRM(fops).get_unmapped_area = ffb_get_unmapped_area; + dev->fn_tbl.release = ffb_driver_release; + dev->fn_tbl.presetup = ffb_presetup; + dev->fn_tbl.pretakedown = ffb_driver_pretakedown; + dev->fn_tbl.postcleanup = ffb_driver_postcleanup; + dev->fn_tbl.kernel_context_switch = ffb_context_switch; + dev->fn_tbl.kernel_context_switch_unlock = ffb_driver_kernel_context_switch_unlock; + dev->fn_tbl.get_map_ofs = ffb_driver_get_map_ofs; + dev->fn_tbl.get_reg_ofs = ffb_driver_get_reg_ofs; +} diff --git a/drivers/char/drm/ffb_drv.h b/drivers/char/drm/ffb_drv.h index 094bbce09..3b3546715 100644 --- a/drivers/char/drm/ffb_drv.h +++ b/drivers/char/drm/ffb_drv.h @@ -274,3 +274,13 @@ typedef struct ffb_dev_priv { /* Context table. */ struct ffb_hw_context *hw_state[FFB_MAX_CTXS]; } ffb_dev_priv_t; + +extern struct file_operations DRM(fops); +extern unsigned long ffb_get_unmapped_area(struct file *filp, + unsigned long hint, + unsigned long len, + unsigned long pgoff, + unsigned long flags); +extern void ffb_set_context_ioctls(void); +extern drm_ioctl_desc_t DRM(ioctls)[]; + diff --git a/drivers/char/drm/gamma.h b/drivers/char/drm/gamma.h index dcd649048..cabd4b311 100644 --- a/drivers/char/drm/gamma.h +++ b/drivers/char/drm/gamma.h @@ -36,8 +36,6 @@ /* General customization: */ -#define __HAVE_MTRR 1 - #define DRIVER_AUTHOR "VA Linux Systems Inc." #define DRIVER_NAME "gamma" @@ -71,44 +69,9 @@ /* DMA customization: */ -#define __HAVE_DMA 1 -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_OLD_DMA 1 -#define __HAVE_PCI_DMA 1 - -#define __HAVE_DRIVER_FOPS_READ 1 -#define __HAVE_DRIVER_FOPS_POLL 1 - #define __HAVE_MULTIPLE_DMA_QUEUES 1 #define __HAVE_DMA_WAITQUEUE 1 -#define __HAVE_DMA_WAITLIST 1 -#define __HAVE_DMA_FREELIST 1 - -#define __HAVE_DMA_FLUSH 1 -#define __HAVE_DMA_SCHEDULE 1 - -#define __HAVE_DMA_READY 1 -#define DRIVER_DMA_READY() do { \ - gamma_dma_ready(dev); \ -} while (0) - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private; \ - if (dev_priv->num_rast == 2) \ - gamma_dma_quiescent_dual(dev); \ - else gamma_dma_quiescent_single(dev); \ - return 0; \ -} while (0) - -#define __HAVE_IRQ 1 -#define __HAVE_IRQ_BH 1 - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_gamma_private_t *)((dev)->dev_private))->buffers - +/* removed from DRM HAVE_DMA_FREELIST & HAVE_DMA_SCHEDULE */ #endif /* __GAMMA_H__ */ diff --git a/drivers/char/drm/gamma_context.h b/drivers/char/drm/gamma_context.h index d3c8c29c2..d11b507f8 100644 --- a/drivers/char/drm/gamma_context.h +++ b/drivers/char/drm/gamma_context.h @@ -42,7 +42,7 @@ the circular buffer), is based on Alessandro Rubini's LINUX DEVICE DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ -ssize_t DRM(read)(struct file *filp, char __user *buf, size_t count, loff_t *off) +ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -128,7 +128,7 @@ int DRM(write_string)(drm_device_t *dev, const char *s) return 0; } -unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) +unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c index 7802f5156..7e01ca182 100644 --- a/drivers/char/drm/gamma_dma.c +++ b/drivers/char/drm/gamma_dma.c @@ -116,7 +116,7 @@ static inline int gamma_dma_is_ready(drm_device_t *dev) return (!GAMMA_READ(GAMMA_DMACOUNT)); } -irqreturn_t gamma_irq_handler( DRM_IRQ_ARGS ) +irqreturn_t gamma_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *)arg; drm_device_dma_t *dma = dev->dma; @@ -639,12 +639,12 @@ static int gamma_do_init_dma( drm_device_t *dev, drm_gamma_init_t *init ) break; } } - - DRM_FIND_MAP( dev_priv->mmio0, init->mmio0 ); - DRM_FIND_MAP( dev_priv->mmio1, init->mmio1 ); - DRM_FIND_MAP( dev_priv->mmio2, init->mmio2 ); - DRM_FIND_MAP( dev_priv->mmio3, init->mmio3 ); - + + dev_priv->mmio0 = drm_core_findmap(dev, init->mmio0); + dev_priv->mmio1 = drm_core_findmap(dev, init->mmio1); + dev_priv->mmio2 = drm_core_findmap(dev, init->mmio2); + dev_priv->mmio3 = drm_core_findmap(dev, init->mmio3); + dev_priv->sarea_priv = (drm_gamma_sarea_t *) ((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); @@ -661,9 +661,8 @@ static int gamma_do_init_dma( drm_device_t *dev, drm_gamma_init_t *init ) buf = dma->buflist[GLINT_DRI_BUF_COUNT]; } else { - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - - DRM_IOREMAP( dev_priv->buffers, dev ); + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + drm_core_ioremap( dev->agp_buffer_map, dev); buf = dma->buflist[GLINT_DRI_BUF_COUNT]; pgt = buf->address; @@ -690,19 +689,18 @@ int gamma_do_cleanup_dma( drm_device_t *dev ) { DRM_DEBUG( "%s\n", __FUNCTION__ ); -#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + if ( dev->irq_enabled ) + DRM(irq_uninstall)(dev); if ( dev->dev_private ) { - drm_gamma_private_t *dev_priv = dev->dev_private; - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t), DRM_MEM_DRIVER ); @@ -868,7 +866,7 @@ int gamma_setsareactx(struct inode *inode, struct file *filp, return 0; } -void DRM(driver_irq_preinstall)( drm_device_t *dev ) { +void gamma_driver_irq_preinstall( drm_device_t *dev ) { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; @@ -879,7 +877,7 @@ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 ); } -void DRM(driver_irq_postinstall)( drm_device_t *dev ) { +void gamma_driver_irq_postinstall( drm_device_t *dev ) { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; @@ -891,7 +889,7 @@ void DRM(driver_irq_postinstall)( drm_device_t *dev ) { GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00039090 ); } -void DRM(driver_irq_uninstall)( drm_device_t *dev ) { +void gamma_driver_irq_uninstall( drm_device_t *dev ) { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; if (!dev_priv) @@ -904,3 +902,45 @@ void DRM(driver_irq_uninstall)( drm_device_t *dev ) { GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000000 ); GAMMA_WRITE( GAMMA_GINTENABLE, 0x00000000 ); } + +extern drm_ioctl_desc_t DRM(ioctls)[]; + +static int gamma_driver_preinit(drm_device_t *dev) +{ + /* reset the finish ioctl */ + DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_FINISH)].func = DRM(finish); + return 0; +} + +static void gamma_driver_pretakedown(drm_device_t *dev) +{ + gamma_do_cleanup_dma(dev); +} + +static void gamma_driver_dma_ready(drm_device_t *dev) +{ + gamma_dma_ready(dev); +} + +static int gamma_driver_dma_quiescent(drm_device_t *dev) +{ + drm_gamma_private_t *dev_priv = ( + drm_gamma_private_t *)dev->dev_private; + if (dev_priv->num_rast == 2) + gamma_dma_quiescent_dual(dev); + else gamma_dma_quiescent_single(dev); + return 0; +} + +void gamma_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ; + DRM(fops).read = gamma_fops_read; + DRM(fops).poll = gamma_fops_poll; + dev->fn_tbl.preinit = gamma_driver_preinit; + dev->fn_tbl.pretakedown = gamma_driver_pretakedown; + dev->fn_tbl.dma_ready = gamma_driver_dma_ready; + dev->fn_tbl.dma_quiescent = gamma_driver_dma_quiescent; + dev->fn_tbl.dma_flush_block_and_flush = gamma_flush_block_and_flush; + dev->fn_tbl.dma_flush_unblock = gamma_flush_unblock; +} diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c index b1fb05055..e7e64b627 100644 --- a/drivers/char/drm/gamma_drv.c +++ b/drivers/char/drm/gamma_drv.c @@ -56,3 +56,4 @@ #include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" +#include "drm_scatter.h" diff --git a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h index fc78a11a3..146fcc625 100644 --- a/drivers/char/drm/gamma_drv.h +++ b/drivers/char/drm/gamma_drv.h @@ -35,7 +35,6 @@ typedef struct drm_gamma_private { drm_gamma_sarea_t *sarea_priv; drm_map_t *sarea; - drm_map_t *buffers; drm_map_t *mmio0; drm_map_t *mmio1; drm_map_t *mmio2; @@ -91,6 +90,10 @@ extern int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf); extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block); +/* externs for gamma changes to the ops */ +extern struct file_operations DRM(fops); +extern unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait); +extern ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off); #define GLINT_DRI_BUF_COUNT 256 diff --git a/drivers/char/drm/i810.h b/drivers/char/drm/i810.h index aee2efff1..2ea83be82 100644 --- a/drivers/char/drm/i810.h +++ b/drivers/char/drm/i810.h @@ -36,10 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "VA Linux Systems Inc." @@ -78,47 +74,4 @@ [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] = { i810_flip_bufs, 1, 0 } -#define __HAVE_COUNTERS 4 -#define __HAVE_COUNTER6 _DRM_STAT_IRQ -#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY -#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY -#define __HAVE_COUNTER9 _DRM_STAT_DMA - -/* Driver customization: - */ -#define __HAVE_RELEASE 1 -#define DRIVER_RELEASE() do { \ - i810_reclaim_buffers( filp ); \ -} while (0) - -#define DRIVER_PRETAKEDOWN() do { \ - i810_dma_cleanup( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_DMA_QUEUE 1 -#define __HAVE_DMA_WAITLIST 0 -#define __HAVE_DMA_RECLAIM 1 - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - i810_dma_quiescent( dev ); \ -} while (0) - -/* Don't need an irq any more. The template code will make sure that - * a noop stub is generated for compatibility. - */ -/* XXX: Add vblank support? */ -#define __HAVE_IRQ 0 - -/* Buffer customization: - */ - -#define DRIVER_BUF_PRIV_T drm_i810_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_i810_private_t *)((dev)->dev_private))->buffer_map - #endif diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index 42220efe7..d9348ac71 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -232,13 +232,12 @@ int i810_dma_cleanup(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; -#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); -#endif + if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ) && dev->irq_enabled) + DRM(irq_uninstall)(dev); if (dev->dev_private) { int i; @@ -364,15 +363,15 @@ static int i810_dma_initialize(drm_device_t *dev, DRM_ERROR("can not find sarea!\n"); return -EINVAL; } - DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); return -EINVAL; } - DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); - if (!dev_priv->buffer_map) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if (!dev->agp_buffer_map) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not find dma buffer map!\n"); @@ -844,13 +843,10 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev, if (buf_priv->currently_mapped == I810_BUF_MAPPED) { unsigned int prim = (sarea_priv->vertex_prim & PR_MASK); - put_user((GFX_OP_PRIMITIVE | prim | - ((used/4)-2)), - (u32 __user *)buf_priv->virtual); + *(u32 *)buf_priv->kernel_virtual = ((GFX_OP_PRIMITIVE | prim | ((used/4)-2))); if (used & 4) { - put_user(0, - (u32 __user *)((u32)buf_priv->virtual + used)); + *(u32 *)((u32)buf_priv->kernel_virtual + used) = 0; used += 4; } @@ -1391,3 +1387,36 @@ int i810_flip_bufs(struct inode *inode, struct file *filp, i810_dma_dispatch_flip( dev ); return 0; } + +static void i810_driver_pretakedown(drm_device_t *dev) +{ + i810_dma_cleanup( dev ); +} + +static void i810_driver_release(drm_device_t *dev, struct file *filp) +{ + i810_reclaim_buffers(filp); +} + +static int i810_driver_dma_quiescent(drm_device_t *dev) +{ + i810_dma_quiescent( dev ); + return 0; +} + +void i810_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE; + dev->dev_priv_size = sizeof(drm_i810_buf_priv_t); + dev->fn_tbl.pretakedown = i810_driver_pretakedown; + dev->fn_tbl.release = i810_driver_release; + dev->fn_tbl.dma_quiescent = i810_driver_dma_quiescent; + dev->fn_tbl.reclaim_buffers = i810_reclaim_buffers; + + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; +} + diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c index 0bc793864..00ca55166 100644 --- a/drivers/char/drm/i810_drv.c +++ b/drivers/char/drm/i810_drv.c @@ -37,19 +37,4 @@ #include "i810_drm.h" #include "i810_drv.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" - -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index 736c20d76..67c5c88bf 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -53,7 +53,6 @@ typedef struct _drm_i810_ring_buffer{ typedef struct drm_i810_private { drm_map_t *sarea_map; - drm_map_t *buffer_map; drm_map_t *mmio_map; drm_i810_sarea_t *sarea_priv; diff --git a/drivers/char/drm/i830.h b/drivers/char/drm/i830.h index b4a361bf0..85a1ac204 100644 --- a/drivers/char/drm/i830.h +++ b/drivers/char/drm/i830.h @@ -36,10 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "VA Linux Systems Inc." @@ -77,36 +73,6 @@ [DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam, 1, 0 } -#define __HAVE_COUNTERS 4 -#define __HAVE_COUNTER6 _DRM_STAT_IRQ -#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY -#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY -#define __HAVE_COUNTER9 _DRM_STAT_DMA - -/* Driver customization: - */ -#define __HAVE_RELEASE 1 -#define DRIVER_RELEASE() do { \ - i830_reclaim_buffers( filp ); \ -} while (0) - -#define DRIVER_PRETAKEDOWN() do { \ - i830_dma_cleanup( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_DMA_QUEUE 1 -#define __HAVE_DMA_WAITLIST 0 -#define __HAVE_DMA_RECLAIM 1 - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - i830_dma_quiescent( dev ); \ -} while (0) - - /* Driver will work either way: IRQ's save cpu time when waiting for * the card, but are subject to subtle interactions between bios, * hardware and the driver. @@ -114,20 +80,4 @@ /* XXX: Add vblank support? */ #define USE_IRQS 0 -#if USE_IRQS -#define __HAVE_IRQ 1 -#define __HAVE_SHARED_IRQ 1 -#else -#define __HAVE_IRQ 0 -#endif - - -/* Buffer customization: - */ - -#define DRIVER_BUF_PRIV_T drm_i830_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_i830_private_t *)((dev)->dev_private))->buffer_map - #endif diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 856dc81f8..084e9da08 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -233,13 +233,11 @@ int i830_dma_cleanup(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; -#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); -#endif if (dev->dev_private) { int i; @@ -371,15 +369,15 @@ static int i830_dma_initialize(drm_device_t *dev, DRM_ERROR("can not find sarea!\n"); return -EINVAL; } - DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; i830_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); return -EINVAL; } - DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); - if(!dev_priv->buffer_map) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { dev->dev_private = (void *)dev_priv; i830_dma_cleanup(dev); DRM_ERROR("can not find dma buffer map!\n"); @@ -1166,19 +1164,19 @@ static void i830_dma_dispatch_vertex(drm_device_t *dev, DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); if (buf_priv->currently_mapped == I830_BUF_MAPPED) { - u32 __user *vp = buf_priv->virtual; + u32 *vp = buf_priv->kernel_virtual; - put_user( (GFX_OP_PRIMITIVE | - sarea_priv->vertex_prim | - ((used/4)-2)), &vp[0]); + vp[0] = (GFX_OP_PRIMITIVE | + sarea_priv->vertex_prim | + ((used/4)-2)); if (dev_priv->use_mi_batchbuffer_start) { - put_user(MI_BATCH_BUFFER_END, &vp[used/4]); + vp[used/4] = MI_BATCH_BUFFER_END; used += 4; } if (used & 4) { - put_user(0, &vp[used/4]); + vp[used/4] = 0; used += 4; } @@ -1582,3 +1580,45 @@ int i830_setparam( struct inode *inode, struct file *filp, unsigned int cmd, return 0; } + + +static void i830_driver_pretakedown(drm_device_t *dev) +{ + i830_dma_cleanup( dev ); +} + +static void i830_driver_release(drm_device_t *dev, struct file *filp) +{ + i830_reclaim_buffers(filp); +} + +static int i830_driver_dma_quiescent(drm_device_t *dev) +{ + i830_dma_quiescent( dev ); + return 0; +} + +void i830_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE; +#if USE_IRQS + dev->driver_features |= DRIVER_HAVE_IRQ | DRIVER_SHARED_IRQ; +#endif + dev->dev_priv_size = sizeof(drm_i830_buf_priv_t); + dev->fn_tbl.pretakedown = i830_driver_pretakedown; + dev->fn_tbl.release = i830_driver_release; + dev->fn_tbl.dma_quiescent = i830_driver_dma_quiescent; + dev->fn_tbl.reclaim_buffers = i830_reclaim_buffers; +#if USE_IRQS + dev->fn_tbl.irq_preinstall = i830_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = i830_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = i830_driver_irq_uninstall; + dev->fn_tbl.irq_handler = i830_driver_irq_handler; +#endif + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; +} + diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c index 2f4e81572..eb45b2726 100644 --- a/drivers/char/drm/i830_drv.c +++ b/drivers/char/drm/i830_drv.c @@ -39,20 +39,4 @@ #include "i830_drm.h" #include "i830_drv.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" - -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_irq.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index c6d805fc7..c3cab2d83 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -53,7 +53,6 @@ typedef struct _drm_i830_ring_buffer{ typedef struct drm_i830_private { drm_map_t *sarea_map; - drm_map_t *buffer_map; drm_map_t *mmio_map; drm_i830_sarea_t *sarea_priv; @@ -137,6 +136,10 @@ extern int i830_irq_wait( struct inode *inode, struct file *filp, extern int i830_wait_irq(drm_device_t *dev, int irq_nr); extern int i830_emit_irq(drm_device_t *dev); +extern irqreturn_t i830_driver_irq_handler( DRM_IRQ_ARGS ); +extern void i830_driver_irq_preinstall( drm_device_t *dev ); +extern void i830_driver_irq_postinstall( drm_device_t *dev ); +extern void i830_driver_irq_uninstall( drm_device_t *dev ); #define I830_BASE(reg) ((unsigned long) \ dev_priv->mmio_map->handle) diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c index 362d66ef1..6a0e25c26 100644 --- a/drivers/char/drm/i830_irq.c +++ b/drivers/char/drm/i830_irq.c @@ -35,7 +35,7 @@ #include -irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) +irqreturn_t i830_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *)arg; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; @@ -92,7 +92,7 @@ int i830_wait_irq(drm_device_t *dev, int irq_nr) add_wait_queue(&dev_priv->irq_queue, &entry); for (;;) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); if (atomic_read(&dev_priv->irq_received) >= irq_nr) break; if((signed)(end - jiffies) <= 0) { @@ -112,7 +112,7 @@ int i830_wait_irq(drm_device_t *dev, int irq_nr) } } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&dev_priv->irq_queue, &entry); return ret; } @@ -178,7 +178,7 @@ int i830_irq_wait( struct inode *inode, struct file *filp, unsigned int cmd, /* drm_dma.h hooks */ -void DRM(driver_irq_preinstall)( drm_device_t *dev ) { +void i830_driver_irq_preinstall( drm_device_t *dev ) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; @@ -190,14 +190,14 @@ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { init_waitqueue_head(&dev_priv->irq_queue); } -void DRM(driver_irq_postinstall)( drm_device_t *dev ) { +void i830_driver_irq_postinstall( drm_device_t *dev ) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 ); } -void DRM(driver_irq_uninstall)( drm_device_t *dev ) { +void i830_driver_irq_uninstall( drm_device_t *dev ) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; if (!dev_priv) diff --git a/drivers/char/drm/i915.h b/drivers/char/drm/i915.h new file mode 100644 index 000000000..d76d737b4 --- /dev/null +++ b/drivers/char/drm/i915.h @@ -0,0 +1,53 @@ +/* i915.h -- Intel I915 DRM template customization -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef __I915_H__ +#define __I915_H__ + +/* This remains constant for all DRM template files. + */ +#define DRM(x) i915_##x + +/* General customization: + */ + +#define DRIVER_AUTHOR "Tungsten Graphics, Inc." + +#define DRIVER_NAME "i915" +#define DRIVER_DESC "Intel Graphics" +#define DRIVER_DATE "20040405" + +/* Interface history: + * + * 1.1: Original. + */ +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 1 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT)] = { i915_dma_init, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_FLUSH)] = { i915_flush_ioctl, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_FLIP)] = { i915_flip_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_BATCHBUFFER)] = { i915_batchbuffer, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_EMIT)] = { i915_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_WAIT)] = { i915_irq_wait, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_GETPARAM)] = { i915_getparam, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_SETPARAM)] = { i915_setparam, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_ALLOC)] = { i915_mem_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_FREE)] = { i915_mem_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT_HEAP)] = { i915_mem_init_heap, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I915_CMDBUFFER)] = { i915_cmdbuffer, 1, 0 } + +/* We use our own dma mechanisms, not the drm template code. However, + * the shared IRQ code is useful to us: + */ +#define __HAVE_PM 1 + +#endif diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c new file mode 100644 index 000000000..e33853b5a --- /dev/null +++ b/drivers/char/drm/i915_dma.c @@ -0,0 +1,755 @@ +/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +static inline void i915_print_status_page(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 *temp = dev_priv->hw_status_page; + + if (!temp) { + DRM_DEBUG("no status page\n"); + return; + } + + DRM_DEBUG("hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG("hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG("hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG("hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG("hw_status: Driver Counter : %d\n", temp[5]); + +} + +/* Really want an OS-independent resettable timer. Would like to have + * this loop run for (eg) 3 sec, but have the timer reset every time + * the head pointer changes, so that EBUSY only happens if the ring + * actually stalls for (eg) 3 seconds. + */ +int i915_wait_ring(drm_device_t * dev, int n, const char *caller) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + int i; + + for (i = 0; i < 10000; i++) { + ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + if (ring->space >= n) + return 0; + + dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + + if (ring->head != last_head) + i = 0; + + last_head = ring->head; + } + + return DRM_ERR(EBUSY); +} + +void i915_kernel_lost_context(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + + if (ring->head == ring->tail) + dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; +} + +int i915_dma_cleanup(drm_device_t * dev) +{ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if (dev->irq) + DRM(irq_uninstall) (dev); + + if (dev->dev_private) { + drm_i915_private_t *dev_priv = + (drm_i915_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree( &dev_priv->ring.map, dev); + } + + if (dev_priv->hw_status_page) { + pci_free_consistent(dev->pdev, PAGE_SIZE, + dev_priv->hw_status_page, + dev_priv->dma_status_page); + /* Need to rewrite hardware status page */ + I915_WRITE(0x02080, 0x1ffff000); + } + + DRM(free) (dev->dev_private, sizeof(drm_i915_private_t), + DRM_MEM_DRIVER); + + dev->dev_private = NULL; + } + + return 0; +} + +static int i915_initialize(drm_device_t * dev, + drm_i915_private_t * dev_priv, + drm_i915_init_t * init) +{ + memset(dev_priv, 0, sizeof(drm_i915_private_t)); + + DRM_GETSAREA(); + if (!dev_priv->sarea) { + DRM_ERROR("can not find sarea!\n"); + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + return DRM_ERR(EINVAL); + } + + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio_map) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return DRM_ERR(EINVAL); + } + + dev_priv->sarea_priv = (drm_i915_sarea_t *) + ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); + + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + dev_priv->ring.map.offset = init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_core_ioremap( &dev_priv->ring.map, dev ); + + if (dev_priv->ring.map.handle == NULL) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return DRM_ERR(ENOMEM); + } + + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + + dev_priv->back_offset = init->back_offset; + dev_priv->front_offset = init->front_offset; + dev_priv->current_page = 0; + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + + /* We are using separate values as placeholders for mechanisms for + * private backbuffer/depthbuffer usage. + */ + dev_priv->use_mi_batchbuffer_start = 0; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + + /* Program Hardware Status Page */ + dev_priv->hw_status_page = + pci_alloc_consistent(dev->pdev, PAGE_SIZE, + &dev_priv->dma_status_page); + + if (!dev_priv->hw_status_page) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return DRM_ERR(ENOMEM); + } + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + + I915_WRITE(0x02080, dev_priv->dma_status_page); + DRM_DEBUG("Enabled hardware status page\n"); + + dev->dev_private = (void *)dev_priv; + + return 0; +} + +static int i915_resume(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (!dev_priv->sarea) { + DRM_ERROR("can not find sarea!\n"); + return DRM_ERR(EINVAL); + } + + if (!dev_priv->mmio_map) { + DRM_ERROR("can not find mmio map!\n"); + return DRM_ERR(EINVAL); + } + + if (dev_priv->ring.map.handle == NULL) { + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return DRM_ERR(ENOMEM); + } + + /* Program Hardware Status Page */ + if (!dev_priv->hw_status_page) { + DRM_ERROR("Can not find hardware status page\n"); + return DRM_ERR(EINVAL); + } + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + + I915_WRITE(0x02080, dev_priv->dma_status_page); + DRM_DEBUG("Enabled hardware status page\n"); + + return 0; +} + +int i915_dma_init(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv; + drm_i915_init_t init; + int retcode = 0; + + DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data, + sizeof(init)); + + switch (init.func) { + case I915_INIT_DMA: + dev_priv = DRM(alloc) (sizeof(drm_i915_private_t), + DRM_MEM_DRIVER); + if (dev_priv == NULL) + return DRM_ERR(ENOMEM); + retcode = i915_initialize(dev, dev_priv, &init); + break; + case I915_CLEANUP_DMA: + retcode = i915_dma_cleanup(dev); + break; + case I915_RESUME_DMA: + retcode = i915_resume(dev); + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; +} + +/* Implement basically the same security restrictions as hardware does + * for MI_BATCH_NON_SECURE. These can be made stricter at any time. + * + * Most of the calculations below involve calculating the size of a + * particular instruction. It's important to get the size right as + * that tells us where the next instruction to check is. Any illegal + * instruction detected will be given a size of zero, which is a + * signal to abort the rest of the buffer. + */ +static int do_validate_cmd(int cmd) +{ + switch (((cmd >> 29) & 0x7)) { + case 0x0: + switch ((cmd >> 23) & 0x3f) { + case 0x0: + return 1; /* MI_NOOP */ + case 0x4: + return 1; /* MI_FLUSH */ + default: + return 0; /* disallow everything else */ + } + break; + case 0x1: + return 0; /* reserved */ + case 0x2: + return (cmd & 0xff) + 2; /* 2d commands */ + case 0x3: + if (((cmd >> 24) & 0x1f) <= 0x18) + return 1; + + switch ((cmd >> 24) & 0x1f) { + case 0x1c: + return 1; + case 0x1d: + switch ((cmd>>16)&0xff) { + case 0x3: + return (cmd & 0x1f) + 2; + case 0x4: + return (cmd & 0xf) + 2; + default: + return (cmd & 0xffff) + 2; + } + case 0x1e: + if (cmd & (1 << 23)) + return (cmd & 0xffff) + 1; + else + return 1; + case 0x1f: + if ((cmd & (1 << 23)) == 0) /* inline vertices */ + return (cmd & 0x1ffff) + 2; + else if (cmd & (1 << 17)) /* indirect random */ + if ((cmd & 0xffff) == 0) + return 0; /* unknown length, too hard */ + else + return (((cmd & 0xffff) + 1) / 2) + 1; + else + return 2; /* indirect sequential */ + default: + return 0; + } + default: + return 0; + } + + return 0; +} + +static int validate_cmd(int cmd) +{ + int ret = do_validate_cmd(cmd); + +/* printk("validate_cmd( %x ): %d\n", cmd, ret); */ + + return ret; +} + +static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i; + RING_LOCALS; + + for (i = 0; i < dwords;) { + int cmd, sz; + + if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) + return DRM_ERR(EINVAL); + +/* printk("%d/%d ", i, dwords); */ + + if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) + return DRM_ERR(EINVAL); + + BEGIN_LP_RING(sz); + OUT_RING(cmd); + + while (++i, --sz) { + if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], + sizeof(cmd))) { + return DRM_ERR(EINVAL); + } + OUT_RING(cmd); + } + ADVANCE_LP_RING(); + } + + return 0; +} + +static int i915_emit_box(drm_device_t * dev, + drm_clip_rect_t __user * boxes, + int i, int DR1, int DR4) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_clip_rect_t box; + RING_LOCALS; + + if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { + return EFAULT; + } + + if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { + DRM_ERROR("Bad box %d,%d..%d,%d\n", + box.x1, box.y1, box.x2, box.y2); + return DRM_ERR(EINVAL); + } + + BEGIN_LP_RING(6); + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(DR1); + OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); + OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); + OUT_RING(DR4); + OUT_RING(0); + ADVANCE_LP_RING(); + + return 0; +} + +static int i915_dispatch_cmdbuffer(drm_device_t * dev, + drm_i915_cmdbuffer_t * cmd) +{ + int nbox = cmd->num_cliprects; + int i = 0, count, ret; + + if (cmd->sz & 0x3) { + DRM_ERROR("alignment"); + return DRM_ERR(EINVAL); + } + + i915_kernel_lost_context(dev); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + ret = i915_emit_box(dev, cmd->cliprects, i, + cmd->DR1, cmd->DR4); + if (ret) + return ret; + } + + ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); + if (ret) + return ret; + } + + return 0; +} + +static int i915_dispatch_batchbuffer(drm_device_t * dev, + drm_i915_batchbuffer_t * batch) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_clip_rect_t __user *boxes = batch->cliprects; + int nbox = batch->num_cliprects; + int i = 0, count; + RING_LOCALS; + + if ((batch->start | batch->used) & 0x7) { + DRM_ERROR("alignment"); + return DRM_ERR(EINVAL); + } + + i915_kernel_lost_context(dev); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + int ret = i915_emit_box(dev, boxes, i, + batch->DR1, batch->DR4); + if (ret) + return ret; + } + + if (dev_priv->use_mi_batchbuffer_start) { + BEGIN_LP_RING(2); + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + OUT_RING(batch->start + batch->used - 4); + OUT_RING(0); + ADVANCE_LP_RING(); + } + } + + dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; + + BEGIN_LP_RING(4); + OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(20); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); + + return 0; +} + +static int i915_dispatch_flip(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + __FUNCTION__, + dev_priv->current_page, + dev_priv->sarea_priv->pf_current_page); + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(2); + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(0); + ADVANCE_LP_RING(); + + BEGIN_LP_RING(6); + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); + OUT_RING(0); + if (dev_priv->current_page == 0) { + OUT_RING(dev_priv->back_offset); + dev_priv->current_page = 1; + } else { + OUT_RING(dev_priv->front_offset); + dev_priv->current_page = 0; + } + OUT_RING(0); + ADVANCE_LP_RING(); + + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); + OUT_RING(0); + ADVANCE_LP_RING(); + + dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; + + BEGIN_LP_RING(4); + OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(20); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); + + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + return 0; +} + +static int i915_quiescent(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + i915_kernel_lost_context(dev); + return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); +} + +int i915_flush_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_flush_ioctl called without lock held\n"); + return DRM_ERR(EINVAL); + } + + return i915_quiescent(dev); +} + +int i915_batchbuffer(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + dev_priv->sarea_priv; + drm_i915_batchbuffer_t batch; + int ret; + + if (!dev_priv->allow_batchbuffer) { + DRM_ERROR("Batchbuffer ioctl disabled\n"); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data, + sizeof(batch)); + + DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", + batch.start, batch.used, batch.num_cliprects); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_batchbuffer called without lock held\n"); + return DRM_ERR(EINVAL); + } + + if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects, + batch.num_cliprects * + sizeof(drm_clip_rect_t))) + return DRM_ERR(EFAULT); + + ret = i915_dispatch_batchbuffer(dev, &batch); + + sarea_priv->last_dispatch = (int)hw_status[5]; + return ret; +} + +int i915_cmdbuffer(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + dev_priv->sarea_priv; + drm_i915_cmdbuffer_t cmdbuf; + int ret; + + DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data, + sizeof(cmdbuf)); + + DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", + cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_cmdbuffer called without lock held\n"); + return DRM_ERR(EINVAL); + } + + if (cmdbuf.num_cliprects && + DRM_VERIFYAREA_READ(cmdbuf.cliprects, + cmdbuf.num_cliprects * + sizeof(drm_clip_rect_t))) { + DRM_ERROR("Fault accessing cliprects\n"); + return DRM_ERR(EFAULT); + } + + ret = i915_dispatch_cmdbuffer(dev, &cmdbuf); + if (ret) { + DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); + return ret; + } + + sarea_priv->last_dispatch = (int)hw_status[5]; + return 0; +} + +int i915_do_cleanup_pageflip(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + if (dev_priv->current_page != 0) + i915_dispatch_flip(dev); + + return 0; +} + +int i915_flip_bufs(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + DRM_DEBUG("%s\n", __FUNCTION__); + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_flip_buf called without lock held\n"); + return DRM_ERR(EINVAL); + } + + return i915_dispatch_flip(dev); +} + +int i915_getparam(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_getparam_t param; + int value; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data, + sizeof(param)); + + switch (param.param) { + case I915_PARAM_IRQ_ACTIVE: + value = dev->irq ? 1 : 0; + break; + case I915_PARAM_ALLOW_BATCHBUFFER: + value = dev_priv->allow_batchbuffer ? 1 : 0; + break; + default: + DRM_ERROR("Unkown parameter %d\n", param.param); + return DRM_ERR(EINVAL); + } + + if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { + DRM_ERROR("DRM_COPY_TO_USER failed\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +int i915_setparam(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_setparam_t param; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data, + sizeof(param)); + + switch (param.param) { + case I915_SETPARAM_USE_MI_BATCHBUFFER_START: + dev_priv->use_mi_batchbuffer_start = param.value; + break; + case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: + dev_priv->tex_lru_log_granularity = param.value; + break; + case I915_SETPARAM_ALLOW_BATCHBUFFER: + dev_priv->allow_batchbuffer = param.value; + break; + default: + DRM_ERROR("unknown parameter %d\n", param.param); + return DRM_ERR(EINVAL); + } + + return 0; +} + +static void i915_driver_pretakedown(drm_device_t *dev) +{ + if ( dev->dev_private ) { + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_takedown( &(dev_priv->agp_heap) ); + } + i915_dma_cleanup( dev ); +} + +static void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp) +{ + if ( dev->dev_private ) { + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_release( dev, filp, dev_priv->agp_heap ); + } +} + +void i915_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED; + dev->fn_tbl.pretakedown = i915_driver_pretakedown; + dev->fn_tbl.prerelease = i915_driver_prerelease; + dev->fn_tbl.irq_preinstall = i915_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = i915_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = i915_driver_irq_uninstall; + dev->fn_tbl.irq_handler = i915_driver_irq_handler; + + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; +} diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h new file mode 100644 index 000000000..24f4cd622 --- /dev/null +++ b/drivers/char/drm/i915_drm.h @@ -0,0 +1,154 @@ +#ifndef _I915_DRM_H_ +#define _I915_DRM_H_ + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +#include "drm.h" + +/* Each region is a minimum of 16k, and there are at most 255 of them. + */ +#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use + * of chars for next/prev indices */ +#define I915_LOG_MIN_TEX_REGION_SIZE 14 + +typedef struct _drm_i915_init { + enum { + I915_INIT_DMA = 0x01, + I915_CLEANUP_DMA = 0x02, + I915_RESUME_DMA = 0x03 + } func; + unsigned int mmio_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; + unsigned int back_pitch; + unsigned int depth_pitch; + unsigned int cpp; + unsigned int chipset; +} drm_i915_init_t; + +typedef struct _drm_i915_sarea { + drm_tex_region_t texList[I915_NR_TEX_REGIONS + 1]; + int last_upload; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int ctxOwner; /* last context to upload state */ + int texAge; + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ + int perf_boxes; /* performance boxes to be displayed */ +} drm_i915_sarea_t; + +/* Flags for perf_boxes + */ +#define I915_BOX_RING_EMPTY 0x1 +#define I915_BOX_FLIP 0x2 +#define I915_BOX_WAIT 0x4 +#define I915_BOX_TEXTURE_LOAD 0x8 +#define I915_BOX_LOST_CONTEXT 0x10 + +/* I915 specific ioctls + * The device specific ioctl range is 0x40 to 0x79. + */ +#define DRM_IOCTL_I915_INIT DRM_IOW( 0x40, drm_i915_init_t) +#define DRM_IOCTL_I915_FLUSH DRM_IO ( 0x41) +#define DRM_IOCTL_I915_FLIP DRM_IO ( 0x42) +#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( 0x43, drm_i915_batchbuffer_t) +#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(0x44, drm_i915_irq_emit_t) +#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( 0x45, drm_i915_irq_wait_t) +#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(0x46, drm_i915_getparam_t) +#define DRM_IOCTL_I915_SETPARAM DRM_IOW( 0x47, drm_i915_setparam_t) +#define DRM_IOCTL_I915_ALLOC DRM_IOWR(0x48, drm_i915_mem_alloc_t) +#define DRM_IOCTL_I915_FREE DRM_IOW( 0x49, drm_i915_mem_free_t) +#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( 0x4a, drm_i915_mem_init_heap_t) +#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( 0x4b, drm_i915_cmdbuffer_t) + +/* Allow drivers to submit batchbuffers directly to hardware, relying + * on the security mechanisms provided by hardware. + */ +typedef struct _drm_i915_batchbuffer { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */ +} drm_i915_batchbuffer_t; + +/* As above, but pass a pointer to userspace buffer which can be + * validated by the kernel prior to sending to hardware. + */ +typedef struct _drm_i915_cmdbuffer { + char __user *buf; /* pointer to userspace command buffer */ + int sz; /* nr bytes in buf */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */ +} drm_i915_cmdbuffer_t; + +/* Userspace can request & wait on irq's: + */ +typedef struct drm_i915_irq_emit { + int __user *irq_seq; +} drm_i915_irq_emit_t; + +typedef struct drm_i915_irq_wait { + int irq_seq; +} drm_i915_irq_wait_t; + +/* Ioctl to query kernel params: + */ +#define I915_PARAM_IRQ_ACTIVE 1 +#define I915_PARAM_ALLOW_BATCHBUFFER 2 + +typedef struct drm_i915_getparam { + int param; + int __user *value; +} drm_i915_getparam_t; + +/* Ioctl to set kernel params: + */ +#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1 +#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 +#define I915_SETPARAM_ALLOW_BATCHBUFFER 3 + +typedef struct drm_i915_setparam { + int param; + int value; +} drm_i915_setparam_t; + +/* A memory manager for regions of shared memory: + */ +#define I915_MEM_REGION_AGP 1 + +typedef struct drm_i915_mem_alloc { + int region; + int alignment; + int size; + int __user *region_offset; /* offset from start of fb or agp */ +} drm_i915_mem_alloc_t; + +typedef struct drm_i915_mem_free { + int region; + int region_offset; +} drm_i915_mem_free_t; + +typedef struct drm_i915_mem_init_heap { + int region; + int size; + int start; +} drm_i915_mem_init_heap_t; + +#endif /* _I915_DRM_H_ */ diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c new file mode 100644 index 000000000..becce4d70 --- /dev/null +++ b/drivers/char/drm/i915_drv.c @@ -0,0 +1,17 @@ +/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- + */ + +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#include "drm_core.h" diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h new file mode 100644 index 000000000..7564cd090 --- /dev/null +++ b/drivers/char/drm/i915_drv.h @@ -0,0 +1,219 @@ +/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef _I915_DRV_H_ +#define _I915_DRV_H_ + +typedef struct _drm_i915_ring_buffer { + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; + drm_local_map_t map; +} drm_i915_ring_buffer_t; + +struct mem_block { + struct mem_block *next; + struct mem_block *prev; + int start; + int size; + DRMFILE filp; /* 0: free, -1: heap, other: real files */ +}; + +typedef struct drm_i915_private { + drm_local_map_t *sarea; + drm_local_map_t *mmio_map; + + drm_i915_sarea_t *sarea_priv; + drm_i915_ring_buffer_t ring; + + void *hw_status_page; + unsigned long counter; + dma_addr_t dma_status_page; + + int back_offset; + int front_offset; + int current_page; + int page_flipping; + int use_mi_batchbuffer_start; + + wait_queue_head_t irq_queue; + atomic_t irq_received; + atomic_t irq_emitted; + + int tex_lru_log_granularity; + int allow_batchbuffer; + struct mem_block *agp_heap; +} drm_i915_private_t; + + /* i915_dma.c */ +extern int i915_dma_init(DRM_IOCTL_ARGS); +extern int i915_dma_cleanup(drm_device_t * dev); +extern int i915_flush_ioctl(DRM_IOCTL_ARGS); +extern int i915_batchbuffer(DRM_IOCTL_ARGS); +extern int i915_flip_bufs(DRM_IOCTL_ARGS); +extern int i915_getparam(DRM_IOCTL_ARGS); +extern int i915_setparam(DRM_IOCTL_ARGS); +extern int i915_cmdbuffer(DRM_IOCTL_ARGS); +extern void i915_kernel_lost_context(drm_device_t * dev); + +/* i915_irq.c */ +extern int i915_irq_emit(DRM_IOCTL_ARGS); +extern int i915_irq_wait(DRM_IOCTL_ARGS); +extern int i915_wait_irq(drm_device_t * dev, int irq_nr); +extern int i915_emit_irq(drm_device_t * dev); + +extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); +extern void i915_driver_irq_preinstall(drm_device_t *dev); +extern void i915_driver_irq_postinstall(drm_device_t *dev); +extern void i915_driver_irq_uninstall(drm_device_t *dev); + +/* i915_mem.c */ +extern int i915_mem_alloc(DRM_IOCTL_ARGS); +extern int i915_mem_free(DRM_IOCTL_ARGS); +extern int i915_mem_init_heap(DRM_IOCTL_ARGS); +extern void i915_mem_takedown(struct mem_block **heap); +extern void i915_mem_release(drm_device_t * dev, + DRMFILE filp, struct mem_block *heap); + +#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) +#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val) +#define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) +#define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val) + +#define I915_VERBOSE 0 + +#define RING_LOCALS unsigned int outring, ringmask, outcount; \ + volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I915_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i915_wait_ring(dev, n*4, __FUNCTION__); \ + outcount = 0; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define OUT_RING(n) do { \ + if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outcount++; \ + outring += 4; \ + outring &= ringmask; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \ + dev_priv->ring.tail = outring; \ + dev_priv->ring.space -= outcount * 4; \ + I915_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I915REG_HWSTAM 0x02098 +#define I915REG_INT_IDENTITY_R 0x020a4 +#define I915REG_INT_MASK_R 0x020a8 +#define I915REG_INT_ENABLE_R 0x020a0 + +#define SRX_INDEX 0x3c4 +#define SRX_DATA 0x3c5 +#define SR01 1 +#define SR01_SCREEN_OFF (1<<5) + +#define PPCR 0x61204 +#define PPCR_ON (1<<0) + +#define ADPA 0x61100 +#define ADPA_DPMS_MASK (~(3<<10)) +#define ADPA_DPMS_ON (0<<10) +#define ADPA_DPMS_SUSPEND (1<<10) +#define ADPA_DPMS_STANDBY (2<<10) +#define ADPA_DPMS_OFF (3<<10) + +#define NOPID 0x2094 +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x001FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x0xFFFFF000 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) + +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) + +#define MI_BATCH_BUFFER ((0x30<<23)|1) +#define MI_BATCH_BUFFER_START (0x31<<23) +#define MI_BATCH_BUFFER_END (0xA<<23) +#define MI_BATCH_NON_SECURE (1) + +#define MI_WAIT_FOR_EVENT ((0x3<<23)) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) + +#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23)) + +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) + +#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) + +#endif diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c new file mode 100644 index 000000000..de91aba58 --- /dev/null +++ b/drivers/char/drm/i915_irq.c @@ -0,0 +1,165 @@ +/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#define USER_INT_FLAG 0x2 +#define MAX_NOPID ((u32)~0) +#define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) + +irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u16 temp; + + temp = I915_READ16(I915REG_INT_IDENTITY_R); + temp &= USER_INT_FLAG; + + DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); + + if (temp == 0) + return IRQ_NONE; + + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + DRM_WAKEUP(&dev_priv->irq_queue); + + return IRQ_HANDLED; +} + +int i915_emit_irq(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 ret; + RING_LOCALS; + + i915_kernel_lost_context(dev); + + DRM_DEBUG("%s\n", __FUNCTION__); + + ret = dev_priv->counter; + + BEGIN_LP_RING(2); + OUT_RING(0); + OUT_RING(GFX_OP_USER_INTERRUPT); + ADVANCE_LP_RING(); + + return ret; +} + +int i915_wait_irq(drm_device_t * dev, int irq_nr) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int ret = 0; + + DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, + READ_BREADCRUMB(dev_priv)); + + if (READ_BREADCRUMB(dev_priv) >= irq_nr) + return 0; + + dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + + DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, + READ_BREADCRUMB(dev_priv) >= irq_nr); + + if (ret == DRM_ERR(EBUSY)) { + DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", + __FUNCTION__, + READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); + } + + dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + return ret; +} + +/* Needs the lock as it touches the ring. + */ +int i915_irq_emit(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_emit_t emit; + int result; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i915_irq_emit called without lock held\n"); + return DRM_ERR(EINVAL); + } + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data, + sizeof(emit)); + + result = i915_emit_irq(dev); + + if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +/* Doesn't need the hardware lock. + */ +int i915_irq_wait(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_wait_t irqwait; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data, + sizeof(irqwait)); + + return i915_wait_irq(dev, irqwait.irq_seq); +} + +/* drm_dma.h hooks +*/ +void i915_driver_irq_preinstall(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE16(I915REG_HWSTAM, 0xfffe); + I915_WRITE16(I915REG_INT_MASK_R, 0x0); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); +} + +void i915_driver_irq_postinstall(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG); + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); +} + +void i915_driver_irq_uninstall(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!dev_priv) + return; + + I915_WRITE16(I915REG_HWSTAM, 0xffff); + I915_WRITE16(I915REG_INT_MASK_R, 0xffff); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); +} diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c new file mode 100644 index 000000000..42c1e3535 --- /dev/null +++ b/drivers/char/drm/i915_mem.c @@ -0,0 +1,347 @@ +/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*- + */ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915.h" +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* This memory manager is integrated into the global/local lru + * mechanisms used by the clients. Specifically, it operates by + * setting the 'in_use' fields of the global LRU to indicate whether + * this region is privately allocated to a client. + * + * This does require the client to actually respect that field. + * + * Currently no effort is made to allocate 'private' memory in any + * clever way - the LRU information isn't used to determine which + * block to allocate, and the ring is drained prior to allocations -- + * in other words allocation is expensive. + */ +static void mark_block(drm_device_t * dev, struct mem_block *p, int in_use) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_tex_region_t *list; + unsigned shift, nr; + unsigned start; + unsigned end; + unsigned i; + int age; + + shift = dev_priv->tex_lru_log_granularity; + nr = I915_NR_TEX_REGIONS; + + start = p->start >> shift; + end = (p->start + p->size - 1) >> shift; + + age = ++sarea_priv->texAge; + list = sarea_priv->texList; + + /* Mark the regions with the new flag and update their age. Move + * them to head of list to preserve LRU semantics. + */ + for (i = start; i <= end; i++) { + list[i].in_use = in_use; + list[i].age = age; + + /* remove_from_list(i) + */ + list[(unsigned)list[i].next].prev = list[i].prev; + list[(unsigned)list[i].prev].next = list[i].next; + + /* insert_at_head(list, i) + */ + list[i].prev = nr; + list[i].next = list[nr].next; + list[(unsigned)list[nr].next].prev = i; + list[nr].next = i; + } +} + +/* Very simple allocator for agp memory, working on a static range + * already mapped into each client's address space. + */ + +static struct mem_block *split_block(struct mem_block *p, int start, int size, + DRMFILE filp) +{ + /* Maybe cut off the start of an existing block */ + if (start > p->start) { + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = start; + newblock->size = p->size - (start - p->start); + newblock->filp = NULL; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size -= newblock->size; + p = newblock; + } + + /* Maybe cut off the end of an existing block */ + if (size < p->size) { + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = start + size; + newblock->size = p->size - size; + newblock->filp = NULL; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size = size; + } + + out: + /* Our block is in the middle */ + p->filp = filp; + return p; +} + +static struct mem_block *alloc_block(struct mem_block *heap, int size, + int align2, DRMFILE filp) +{ + struct mem_block *p; + int mask = (1 << align2) - 1; + + for (p = heap->next; p != heap; p = p->next) { + int start = (p->start + mask) & ~mask; + if (p->filp == NULL && start + size <= p->start + p->size) + return split_block(p, start, size, filp); + } + + return NULL; +} + +static struct mem_block *find_block(struct mem_block *heap, int start) +{ + struct mem_block *p; + + for (p = heap->next; p != heap; p = p->next) + if (p->start == start) + return p; + + return NULL; +} + +static void free_block(struct mem_block *p) +{ + p->filp = NULL; + + /* Assumes a single contiguous range. Needs a special filp in + * 'heap' to stop it being subsumed. + */ + if (p->next->filp == NULL) { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + DRM_FREE(q, sizeof(*q)); + } + + if (p->prev->filp == NULL) { + struct mem_block *q = p->prev; + q->size += p->size; + q->next = p->next; + q->next->prev = q; + DRM_FREE(p, sizeof(*q)); + } +} + +/* Initialize. How to check for an uninitialized heap? + */ +static int init_heap(struct mem_block **heap, int start, int size) +{ + struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks)); + + if (!blocks) + return -ENOMEM; + + *heap = DRM_MALLOC(sizeof(**heap)); + if (!*heap) { + DRM_FREE(blocks, sizeof(*blocks)); + return -ENOMEM; + } + + blocks->start = start; + blocks->size = size; + blocks->filp = NULL; + blocks->next = blocks->prev = *heap; + + memset(*heap, 0, sizeof(**heap)); + (*heap)->filp = (DRMFILE) - 1; + (*heap)->next = (*heap)->prev = blocks; + return 0; +} + +/* Free all blocks associated with the releasing file. + */ +void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap) +{ + struct mem_block *p; + + if (!heap || !heap->next) + return; + + for (p = heap->next; p != heap; p = p->next) { + if (p->filp == filp) { + p->filp = NULL; + mark_block(dev, p, 0); + } + } + + /* Assumes a single contiguous range. Needs a special filp in + * 'heap' to stop it being subsumed. + */ + for (p = heap->next; p != heap; p = p->next) { + while (p->filp == NULL && p->next->filp == NULL) { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + DRM_FREE(q, sizeof(*q)); + } + } +} + +/* Shutdown. + */ +void i915_mem_takedown(struct mem_block **heap) +{ + struct mem_block *p; + + if (!*heap) + return; + + for (p = (*heap)->next; p != *heap;) { + struct mem_block *q = p; + p = p->next; + DRM_FREE(q, sizeof(*q)); + } + + DRM_FREE(*heap, sizeof(**heap)); + *heap = NULL; +} + +static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) +{ + switch (region) { + case I915_MEM_REGION_AGP: + return &dev_priv->agp_heap; + default: + return NULL; + } +} + +/* IOCTL HANDLERS */ + +int i915_mem_alloc(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_alloc_t alloc; + struct mem_block *block, **heap; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data, + sizeof(alloc)); + + heap = get_heap(dev_priv, alloc.region); + if (!heap || !*heap) + return DRM_ERR(EFAULT); + + /* Make things easier on ourselves: all allocations at least + * 4k aligned. + */ + if (alloc.alignment < 12) + alloc.alignment = 12; + + block = alloc_block(*heap, alloc.size, alloc.alignment, filp); + + if (!block) + return DRM_ERR(ENOMEM); + + mark_block(dev, block, 1); + + if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +int i915_mem_free(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_free_t memfree; + struct mem_block *block, **heap; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data, + sizeof(memfree)); + + heap = get_heap(dev_priv, memfree.region); + if (!heap || !*heap) + return DRM_ERR(EFAULT); + + block = find_block(*heap, memfree.region_offset); + if (!block) + return DRM_ERR(EFAULT); + + if (block->filp != filp) + return DRM_ERR(EPERM); + + mark_block(dev, block, 0); + free_block(block); + return 0; +} + +int i915_mem_init_heap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_init_heap_t initheap; + struct mem_block **heap; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(initheap, + (drm_i915_mem_init_heap_t __user *) data, + sizeof(initheap)); + + heap = get_heap(dev_priv, initheap.region); + if (!heap) + return DRM_ERR(EFAULT); + + if (*heap) { + DRM_ERROR("heap already initialized?"); + return DRM_ERR(EFAULT); + } + + return init_heap(heap, initheap.start, initheap.size); +} diff --git a/drivers/char/drm/mga.h b/drivers/char/drm/mga.h index 702857a32..5356519e5 100644 --- a/drivers/char/drm/mga.h +++ b/drivers/char/drm/mga.h @@ -36,10 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." @@ -64,35 +60,4 @@ [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam, 1, 0 }, -#define __HAVE_COUNTERS 3 -#define __HAVE_COUNTER6 _DRM_STAT_IRQ -#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY -#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY - -/* Driver customization: - */ -#define DRIVER_PRETAKEDOWN() do { \ - mga_do_cleanup_dma( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 - -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - drm_mga_private_t *dev_priv = dev->dev_private; \ - return mga_do_wait_for_idle( dev_priv ); \ -} while (0) - -/* Buffer customization: - */ -#define DRIVER_BUF_PRIV_T drm_mga_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_mga_private_t *)((dev)->dev_private))->buffers - #endif diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 76fbf714b..54b64c782 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -500,7 +500,7 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio) { DRM_ERROR( "failed to find mmio region!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -508,7 +508,7 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->status, init->status_offset ); + dev_priv->status = drm_core_findmap(dev, init->status_offset); if(!dev_priv->status) { DRM_ERROR( "failed to find status page!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -516,8 +516,7 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - - DRM_FIND_MAP( dev_priv->warp, init->warp_offset ); + dev_priv->warp = drm_core_findmap(dev, init->warp_offset); if(!dev_priv->warp) { DRM_ERROR( "failed to find warp microcode region!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -525,7 +524,7 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->primary, init->primary_offset ); + dev_priv->primary = drm_core_findmap(dev, init->primary_offset); if(!dev_priv->primary) { DRM_ERROR( "failed to find primary dma region!\n" ); /* Assign dev_private so we can do cleanup. */ @@ -533,8 +532,8 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) mga_do_cleanup_dma( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - if(!dev_priv->buffers) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { DRM_ERROR( "failed to find dma buffer region!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; @@ -546,13 +545,13 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->warp, dev ); - DRM_IOREMAP( dev_priv->primary, dev ); - DRM_IOREMAP( dev_priv->buffers, dev ); + drm_core_ioremap( dev_priv->warp, dev ); + drm_core_ioremap( dev_priv->primary, dev ); + drm_core_ioremap( dev->agp_buffer_map, dev ); if(!dev_priv->warp->handle || !dev_priv->primary->handle || - !dev_priv->buffers->handle ) { + !dev->agp_buffer_map->handle ) { DRM_ERROR( "failed to ioremap agp regions!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; @@ -631,23 +630,21 @@ int mga_do_cleanup_dma( drm_device_t *dev ) { DRM_DEBUG( "\n" ); -#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); -#endif if ( dev->dev_private ) { drm_mga_private_t *dev_priv = dev->dev_private; if ( dev_priv->warp != NULL ) - DRM_IOREMAPFREE( dev_priv->warp, dev ); + drm_core_ioremapfree( dev_priv->warp, dev ); if ( dev_priv->primary != NULL ) - DRM_IOREMAPFREE( dev_priv->primary, dev ); - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + drm_core_ioremapfree( dev_priv->primary, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); if ( dev_priv->head != NULL ) { mga_freelist_cleanup( dev ); @@ -800,3 +797,31 @@ int mga_dma_buffers( DRM_IOCTL_ARGS ) return ret; } + +static void mga_driver_pretakedown(drm_device_t *dev) +{ + mga_do_cleanup_dma( dev ); +} + +static int mga_driver_dma_quiescent(drm_device_t *dev) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + return mga_do_wait_for_idle( dev_priv ); +} + +void mga_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL; + dev->fn_tbl.pretakedown = mga_driver_pretakedown; + dev->fn_tbl.dma_quiescent = mga_driver_dma_quiescent; + dev->fn_tbl.vblank_wait = mga_driver_vblank_wait; + dev->fn_tbl.irq_preinstall = mga_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = mga_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = mga_driver_irq_uninstall; + dev->fn_tbl.irq_handler = mga_driver_irq_handler; + + dev->counters += 3; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; +} diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 6bcad048f..aa27a2c4b 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -35,19 +35,4 @@ #include "drm.h" #include "mga_drm.h" #include "mga_drv.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_irq.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 65847165c..75dcb0e93 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -130,6 +130,12 @@ extern int mga_getparam( DRM_IOCTL_ARGS ); extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv ); extern int mga_warp_init( drm_mga_private_t *dev_priv ); +extern int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ); +extern void mga_driver_irq_preinstall( drm_device_t *dev ); +extern void mga_driver_irq_postinstall( drm_device_t *dev ); +extern void mga_driver_irq_uninstall( drm_device_t *dev ); + #define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() #if defined(__linux__) && defined(__alpha__) diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c index e486618b2..c3185b0b8 100644 --- a/drivers/char/drm/mga_irq.c +++ b/drivers/char/drm/mga_irq.c @@ -36,7 +36,7 @@ #include "mga_drm.h" #include "mga_drv.h" -irqreturn_t mga_irq_handler( DRM_IRQ_ARGS ) +irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_mga_private_t *dev_priv = @@ -56,7 +56,7 @@ irqreturn_t mga_irq_handler( DRM_IRQ_ARGS ) return IRQ_NONE; } -int mga_vblank_wait(drm_device_t *dev, unsigned int *sequence) +int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { unsigned int cur_vblank; int ret = 0; diff --git a/drivers/char/drm/r128.h b/drivers/char/drm/r128.h index 9dfe18974..1df7042a2 100644 --- a/drivers/char/drm/r128.h +++ b/drivers/char/drm/r128.h @@ -36,13 +36,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 -#define __HAVE_SG 1 -#define __HAVE_PCI_DMA 1 - #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." #define DRIVER_NAME "r128" @@ -79,42 +72,4 @@ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)] = { r128_getparam, 1, 0 }, -/* Driver customization: - */ -#define DRIVER_PRERELEASE() do { \ - if ( dev->dev_private ) { \ - drm_r128_private_t *dev_priv = dev->dev_private; \ - if ( dev_priv->page_flipping ) { \ - r128_do_cleanup_pageflip( dev ); \ - } \ - } \ -} while (0) - -#define DRIVER_PRETAKEDOWN() do { \ - r128_do_cleanup_cce( dev ); \ -} while (0) - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 - -#if 0 -/* GH: Remove this for now... */ -#define __HAVE_DMA_QUIESCENT 1 -#define DRIVER_DMA_QUIESCENT() do { \ - drm_r128_private_t *dev_priv = dev->dev_private; \ - return r128_do_cce_idle( dev_priv ); \ -} while (0) -#endif - -/* Buffer customization: - */ -#define DRIVER_BUF_PRIV_T drm_r128_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_r128_private_t *)((dev)->dev_private))->buffers - #endif diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index 22d38b70c..5fbea8ca6 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -322,7 +322,7 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev, /* The manual (p. 2) says this address is in "VM space". This * means it's an offset from the start of AGP space. */ -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) ring_start = dev_priv->cce_ring->offset - dev->agp->base; else @@ -467,29 +467,29 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->cce_ring, init->ring_offset ); + dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset); if(!dev_priv->cce_ring) { DRM_ERROR("could not find cce ring region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); + dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - if(!dev_priv->buffers) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); @@ -497,8 +497,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) } if ( !dev_priv->is_pci ) { - DRM_FIND_MAP( dev_priv->agp_textures, - init->agp_textures_offset ); + dev_priv->agp_textures = drm_core_findmap(dev, init->agp_textures_offset); if(!dev_priv->agp_textures) { DRM_ERROR("could not find agp texture region!\n"); dev->dev_private = (void *)dev_priv; @@ -511,14 +510,14 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cce_ring, dev ); - DRM_IOREMAP( dev_priv->ring_rptr, dev ); - DRM_IOREMAP( dev_priv->buffers, dev ); + drm_core_ioremap( dev_priv->cce_ring, dev ); + drm_core_ioremap( dev_priv->ring_rptr, dev ); + drm_core_ioremap( dev->agp_buffer_map, dev ); if(!dev_priv->cce_ring->handle || !dev_priv->ring_rptr->handle || - !dev_priv->buffers->handle) { + !dev->agp_buffer_map->handle) { DRM_ERROR("Could not ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); @@ -531,10 +530,10 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) (void *)dev_priv->cce_ring->offset; dev_priv->ring_rptr->handle = (void *)dev_priv->ring_rptr->offset; - dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + dev->agp_buffer_map->handle = (void *)dev->agp_buffer_map->offset; } -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) dev_priv->cce_buffers_offset = dev->agp->base; else @@ -559,7 +558,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) R128_WRITE( R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( dev_priv->is_pci ) { #endif if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, @@ -570,7 +569,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) return DRM_ERR(ENOMEM); } R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP } #endif @@ -587,25 +586,23 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) int r128_do_cleanup_cce( drm_device_t *dev ) { -#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); -#endif if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { if ( dev_priv->cce_ring != NULL ) - DRM_IOREMAPFREE( dev_priv->cce_ring, dev ); + drm_core_ioremapfree( dev_priv->cce_ring, dev ); if ( dev_priv->ring_rptr != NULL ) - DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + drm_core_ioremapfree( dev_priv->ring_rptr, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); } else #endif { diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index 1dee16159..8cfc9966c 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c @@ -37,20 +37,4 @@ #include "r128_drv.h" #include "ati_pcigart.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_irq.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" -#include "drm_scatter.h" +#include "drm_core.h" diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 9df32e566..5b91256c1 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -100,7 +100,6 @@ typedef struct drm_r128_private { drm_local_map_t *mmio; drm_local_map_t *cce_ring; drm_local_map_t *ring_rptr; - drm_local_map_t *buffers; drm_local_map_t *agp_textures; } drm_r128_private_t; @@ -143,6 +142,12 @@ extern int r128_cce_depth( DRM_IOCTL_ARGS ); extern int r128_cce_stipple( DRM_IOCTL_ARGS ); extern int r128_cce_indirect( DRM_IOCTL_ARGS ); +extern int r128_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); + +extern irqreturn_t r128_driver_irq_handler( DRM_IRQ_ARGS ); +extern void r128_driver_irq_preinstall( drm_device_t *dev ); +extern void r128_driver_irq_postinstall( drm_device_t *dev ); +extern void r128_driver_irq_uninstall( drm_device_t *dev ); /* Register definitions, register access macros and drmAddMap constants * for Rage 128 kernel driver. diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c index e77a5538b..be1b9dac6 100644 --- a/drivers/char/drm/r128_irq.c +++ b/drivers/char/drm/r128_irq.c @@ -36,7 +36,7 @@ #include "r128_drm.h" #include "r128_drv.h" -irqreturn_t r128_irq_handler( DRM_IRQ_ARGS ) +irqreturn_t r128_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_r128_private_t *dev_priv = @@ -56,7 +56,7 @@ irqreturn_t r128_irq_handler( DRM_IRQ_ARGS ) return IRQ_NONE; } -int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +int r128_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { unsigned int cur_vblank; int ret = 0; diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 34ebcae1f..adc326698 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -667,7 +667,7 @@ static void r128_cce_dispatch_indirect( drm_device_t *dev, */ if ( dwords & 1 ) { u32 *data = (u32 *) - ((char *)dev_priv->buffers->handle + ((char *)dev->agp_buffer_map->handle + buf->offset + start); data[dwords++] = cpu_to_le32( R128_CCE_PACKET2 ); } @@ -713,7 +713,7 @@ static void r128_cce_dispatch_indices( drm_device_t *dev, drm_r128_buf_priv_t *buf_priv = buf->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; int format = sarea_priv->vc_format; - int offset = dev_priv->buffers->offset - dev_priv->cce_buffers_offset; + int offset = dev->agp_buffer_map->offset - dev_priv->cce_buffers_offset; int prim = buf_priv->prim; u32 *data; int dwords; @@ -733,7 +733,7 @@ static void r128_cce_dispatch_indices( drm_device_t *dev, dwords = (end - start + 3) / sizeof(u32); - data = (u32 *)((char *)dev_priv->buffers->handle + data = (u32 *)((char *)dev->agp_buffer_map->handle + buf->offset + start); data[0] = cpu_to_le32( CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, @@ -857,7 +857,7 @@ static int r128_cce_dispatch_blit( DRMFILE filp, dwords = (blit->width * blit->height) >> dword_shift; - data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); + data = (u32 *)((char *)dev->agp_buffer_map->handle + buf->offset); data[0] = cpu_to_le32( CCE_PACKET3( R128_CNTL_HOSTDATA_BLT, dwords + 6 ) ); data[1] = cpu_to_le32( (R128_GMC_DST_PITCH_OFFSET_CNTL | @@ -1694,3 +1694,31 @@ int r128_getparam( DRM_IOCTL_ARGS ) return 0; } + +static void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp) +{ + if ( dev->dev_private ) { + drm_r128_private_t *dev_priv = dev->dev_private; + if ( dev_priv->page_flipping ) { + r128_do_cleanup_pageflip( dev ); + } + } +} + +static void r128_driver_pretakedown(drm_device_t *dev) +{ + r128_do_cleanup_cce( dev ); +} + +void r128_driver_register_fns(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL; + dev->dev_priv_size = sizeof(drm_r128_buf_priv_t); + dev->fn_tbl.prerelease = r128_driver_prerelease; + dev->fn_tbl.pretakedown = r128_driver_pretakedown; + dev->fn_tbl.vblank_wait = r128_driver_vblank_wait; + dev->fn_tbl.irq_preinstall = r128_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = r128_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = r128_driver_irq_uninstall; + dev->fn_tbl.irq_handler = r128_driver_irq_handler; +} diff --git a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h index 83902f869..43723d53e 100644 --- a/drivers/char/drm/radeon.h +++ b/drivers/char/drm/radeon.h @@ -37,12 +37,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 -#define __HAVE_SG 1 -#define __HAVE_PCI_DMA 1 #define DRIVER_AUTHOR "Gareth Hughes, Keith Whitwell, others." @@ -115,59 +109,4 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, \ -#define DRIVER_FILE_FIELDS \ - int64_t radeon_fb_delta; \ - -#define DRIVER_OPEN_HELPER( filp_priv, dev ) \ -do { \ - drm_radeon_private_t *dev_priv = dev->dev_private; \ - if ( dev_priv ) \ - filp_priv->radeon_fb_delta = dev_priv->fb_location; \ - else \ - filp_priv->radeon_fb_delta = 0; \ -} while( 0 ) - -/* When a client dies: - * - Check for and clean up flipped page state - * - Free any alloced GART memory. - * - * DRM infrastructure takes care of reclaiming dma buffers. - */ -#define DRIVER_PRERELEASE() \ -do { \ - if ( dev->dev_private ) { \ - drm_radeon_private_t *dev_priv = dev->dev_private; \ - if ( dev_priv->page_flipping ) { \ - radeon_do_cleanup_pageflip( dev ); \ - } \ - radeon_mem_release( filp, dev_priv->gart_heap ); \ - radeon_mem_release( filp, dev_priv->fb_heap ); \ - } \ -} while (0) - -/* When the last client dies, shut down the CP and free dev->dev_priv. - */ -/* #define __HAVE_RELEASE 1 */ -#define DRIVER_PRETAKEDOWN() \ -do { \ - radeon_do_release( dev ); \ -} while (0) - - - -/* DMA customization: - */ -#define __HAVE_DMA 1 -#define __HAVE_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 - - -/* Buffer customization: - */ -#define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t - -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_radeon_private_t *)((dev)->dev_private))->buffers - #endif diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index f6964908a..43834b906 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -858,7 +858,7 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 ) | ( dev_priv->fb_location >> 16 ) ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { RADEON_WRITE( RADEON_MC_AGP_LOCATION, (((dev_priv->gart_vm_start - 1 + @@ -885,7 +885,7 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, SET_RING_HEAD( dev_priv, cur_read_ptr ); dev_priv->ring.tail = cur_read_ptr; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset @@ -1118,29 +1118,29 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); + dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset); if(!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); + dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - if(!dev_priv->buffers) { + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if(!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); @@ -1148,7 +1148,7 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) } if ( init->gart_textures_offset ) { - DRM_FIND_MAP( dev_priv->gart_textures, init->gart_textures_offset ); + dev_priv->gart_textures = drm_core_findmap(dev, init->gart_textures_offset); if ( !dev_priv->gart_textures ) { DRM_ERROR("could not find GART texture region!\n"); dev->dev_private = (void *)dev_priv; @@ -1161,14 +1161,14 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cp_ring, dev ); - DRM_IOREMAP( dev_priv->ring_rptr, dev ); - DRM_IOREMAP( dev_priv->buffers, dev ); + drm_core_ioremap( dev_priv->cp_ring, dev ); + drm_core_ioremap( dev_priv->ring_rptr, dev ); + drm_core_ioremap( dev->agp_buffer_map, dev ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || - !dev_priv->buffers->handle) { + !dev->agp_buffer_map->handle) { DRM_ERROR("could not find ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); @@ -1181,14 +1181,14 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) (void *)dev_priv->cp_ring->offset; dev_priv->ring_rptr->handle = (void *)dev_priv->ring_rptr->offset; - dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + dev->agp_buffer_map->handle = (void *)dev->agp_buffer_map->offset; DRM_DEBUG( "dev_priv->cp_ring->handle %p\n", dev_priv->cp_ring->handle ); DRM_DEBUG( "dev_priv->ring_rptr->handle %p\n", dev_priv->ring_rptr->handle ); - DRM_DEBUG( "dev_priv->buffers->handle %p\n", - dev_priv->buffers->handle ); + DRM_DEBUG( "dev->agp_buffer_map->handle %p\n", + dev->agp_buffer_map->handle ); } dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION ) @@ -1211,14 +1211,14 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->gart_vm_start = dev_priv->fb_location + RADEON_READ( RADEON_CONFIG_APER_SIZE ); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) - dev_priv->gart_buffers_offset = (dev_priv->buffers->offset + dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->agp->base + dev_priv->gart_vm_start); else #endif - dev_priv->gart_buffers_offset = (dev_priv->buffers->offset + dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->sg->handle + dev_priv->gart_vm_start); @@ -1240,7 +1240,7 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { /* Turn off PCI GART */ radeon_set_pcigart( dev_priv, 0 ); @@ -1275,25 +1275,23 @@ int radeon_do_cleanup_cp( drm_device_t *dev ) { DRM_DEBUG( "\n" ); -#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); -#endif if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { if ( dev_priv->cp_ring != NULL ) - DRM_IOREMAPFREE( dev_priv->cp_ring, dev ); + drm_core_ioremapfree( dev_priv->cp_ring, dev ); if ( dev_priv->ring_rptr != NULL ) - DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); - if ( dev_priv->buffers != NULL ) - DRM_IOREMAPFREE( dev_priv->buffers, dev ); + drm_core_ioremapfree( dev_priv->ring_rptr, dev ); + if ( dev->agp_buffer_map != NULL ) + drm_core_ioremapfree( dev->agp_buffer_map, dev ); } else #endif { @@ -1329,7 +1327,7 @@ static int radeon_do_resume_cp( drm_device_t *dev ) DRM_DEBUG("Starting radeon_do_resume_cp()\n"); -#if __REALLY_HAVE_AGP +#if __OS_HAS_AGP if ( !dev_priv->is_pci ) { /* Turn off PCI GART */ radeon_set_pcigart( dev_priv, 0 ); diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index 74e32df01..965abc449 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c @@ -38,20 +38,4 @@ #include "radeon_drv.h" #include "ati_pcigart.h" -#include "drm_agpsupport.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_irq.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" -#include "drm_scatter.h" +#include "drm_core.h" diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index e24e0ec09..5df72332e 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -60,6 +60,9 @@ typedef struct drm_radeon_depth_clear_t { u32 se_cntl; } drm_radeon_depth_clear_t; +struct drm_radeon_driver_file_fields { + int64_t radeon_fb_delta; +}; struct mem_block { struct mem_block *next; @@ -138,7 +141,6 @@ typedef struct drm_radeon_private { drm_local_map_t *mmio; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; - drm_local_map_t *buffers; drm_local_map_t *gart_textures; struct mem_block *gart_heap; @@ -203,6 +205,11 @@ extern int radeon_wait_irq(drm_device_t *dev, int swi_nr); extern int radeon_emit_irq(drm_device_t *dev); extern void radeon_do_release(drm_device_t *dev); +extern int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ); +extern void radeon_driver_irq_preinstall( drm_device_t *dev ); +extern void radeon_driver_irq_postinstall( drm_device_t *dev ); +extern void radeon_driver_irq_uninstall( drm_device_t *dev ); /* Flags for stats.boxes */ diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index 51d194935..bdb3cc168 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -54,7 +54,7 @@ * tied to dma at all, this is just a hangover from dri prehistory. */ -irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) +irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_radeon_private_t *dev_priv = @@ -141,7 +141,7 @@ int radeon_emit_and_wait_irq(drm_device_t *dev) } -int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 984d74589..f3cc86eea 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -43,12 +43,14 @@ static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_p drm_file_t *filp_priv, u32 *offset ) { u32 off = *offset; + struct drm_radeon_driver_file_fields *radeon_priv; if ( off >= dev_priv->fb_location && off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) ) return 0; - off += filp_priv->radeon_fb_delta; + radeon_priv = filp_priv->driver_priv; + off += radeon_priv->radeon_fb_delta; DRM_DEBUG( "offset fixed up to 0x%x\n", off ); @@ -1247,7 +1249,7 @@ static void radeon_cp_dispatch_indirect( drm_device_t *dev, */ if ( dwords & 1 ) { u32 *data = (u32 *) - ((char *)dev_priv->buffers->handle + ((char *)dev->agp_buffer_map->handle + buf->offset + start); data[dwords++] = RADEON_CP_PACKET2; } @@ -1301,7 +1303,7 @@ static void radeon_cp_dispatch_indices( drm_device_t *dev, dwords = (prim->finish - prim->start + 3) / sizeof(u32); - data = (u32 *)((char *)dev_priv->buffers->handle + + data = (u32 *)((char *)dev->agp_buffer_map->handle + elt_buf->offset + prim->start); data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 ); @@ -1445,7 +1447,7 @@ static int radeon_cp_dispatch_texture( DRMFILE filp, /* Dispatch the indirect buffer. */ - buffer = (u32*)((char*)dev_priv->buffers->handle + buf->offset); + buffer = (u32*)((char*)dev->agp_buffer_map->handle + buf->offset); dwords = size / 4; buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | @@ -1665,11 +1667,6 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS ) LOCK_TEST_WITH_RETURN( dev, filp ); - if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return DRM_ERR(EINVAL); - } - DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t __user *)data, @@ -2525,6 +2522,7 @@ int radeon_cp_setparam( DRM_IOCTL_ARGS ) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_file_t *filp_priv; drm_radeon_setparam_t sp; + struct drm_radeon_driver_file_fields *radeon_priv; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -2538,7 +2536,8 @@ int radeon_cp_setparam( DRM_IOCTL_ARGS ) { switch( sp.param ) { case RADEON_SETPARAM_FB_LOCATION: - filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; + radeon_priv = filp_priv->driver_priv; + radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; break; default: DRM_DEBUG( "Invalid parameter %d\n", sp.param ); @@ -2547,3 +2546,67 @@ int radeon_cp_setparam( DRM_IOCTL_ARGS ) { return 0; } + +/* When a client dies: + * - Check for and clean up flipped page state + * - Free any alloced GART memory. + * + * DRM infrastructure takes care of reclaiming dma buffers. + */ +static void radeon_driver_prerelease(drm_device_t *dev, DRMFILE filp) +{ + if ( dev->dev_private ) { + drm_radeon_private_t *dev_priv = dev->dev_private; + if ( dev_priv->page_flipping ) { + radeon_do_cleanup_pageflip( dev ); + } + radeon_mem_release( filp, dev_priv->gart_heap ); + radeon_mem_release( filp, dev_priv->fb_heap ); + } +} + +static void radeon_driver_pretakedown(drm_device_t *dev) +{ + radeon_do_release(dev); +} + +static int radeon_driver_open_helper(drm_device_t *dev, drm_file_t *filp_priv) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_driver_file_fields *radeon_priv; + + radeon_priv = (struct drm_radeon_driver_file_fields *)DRM(alloc)(sizeof(*radeon_priv), DRM_MEM_FILES); + + if (!radeon_priv) + return -ENOMEM; + + filp_priv->driver_priv = radeon_priv; + if ( dev_priv ) + radeon_priv->radeon_fb_delta = dev_priv->fb_location; + else + radeon_priv->radeon_fb_delta = 0; + return 0; +} + + +static void radeon_driver_free_filp_priv(drm_device_t *dev, drm_file_t *filp_priv) +{ + struct drm_radeon_driver_file_fields *radeon_priv = filp_priv->driver_priv; + + DRM(free)(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES); +} + +void radeon_driver_register_fns(struct drm_device *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL; + dev->dev_priv_size = sizeof(drm_radeon_buf_priv_t); + dev->fn_tbl.prerelease = radeon_driver_prerelease; + dev->fn_tbl.pretakedown = radeon_driver_pretakedown; + dev->fn_tbl.open_helper = radeon_driver_open_helper; + dev->fn_tbl.free_filp_priv = radeon_driver_free_filp_priv; + dev->fn_tbl.vblank_wait = radeon_driver_vblank_wait; + dev->fn_tbl.irq_preinstall = radeon_driver_irq_preinstall; + dev->fn_tbl.irq_postinstall = radeon_driver_irq_postinstall; + dev->fn_tbl.irq_uninstall = radeon_driver_irq_uninstall; + dev->fn_tbl.irq_handler = radeon_driver_irq_handler; +} diff --git a/drivers/char/drm/sis.h b/drivers/char/drm/sis.h index 7bdc99c0a..838e360df 100644 --- a/drivers/char/drm/sis.h +++ b/drivers/char/drm/sis.h @@ -41,10 +41,6 @@ /* General customization: */ -#define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 0 -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "SIS" #define DRIVER_NAME "sis" @@ -62,17 +58,4 @@ [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_FREE)] = { sis_ioctl_agp_free, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_INIT)] = { sis_fb_init, 1, 1 } -#define __HAVE_COUNTERS 5 - -/* Buffer customization: - */ -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ - ((drm_sis_private_t *)((dev)->dev_private))->buffers - -extern int sis_init_context(int context); -extern int sis_final_context(int context); - -#define DRIVER_CTX_CTOR sis_init_context -#define DRIVER_CTX_DTOR sis_final_context - #endif diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c index 3dd075d30..f05734374 100644 --- a/drivers/char/drm/sis_drv.c +++ b/drivers/char/drm/sis_drv.c @@ -31,18 +31,4 @@ #include "sis_drm.h" #include "sis_drv.h" -#include "drm_auth.h" -#include "drm_agpsupport.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" +#include "drm_core.h" diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h index 40e7f463e..a87001819 100644 --- a/drivers/char/drm/sis_drv.h +++ b/drivers/char/drm/sis_drv.h @@ -31,8 +31,6 @@ #include "sis_ds.h" typedef struct drm_sis_private { - drm_map_t *buffers; - memHeap_t *AGPHeap; memHeap_t *FBHeap; } drm_sis_private_t; diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index 5d29b40be..244471647 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c @@ -90,9 +90,10 @@ int sis_fb_alloc( DRM_IOCTL_ARGS ) { drm_sis_mem_t fb; struct sis_memreq req; + drm_sis_mem_t __user *argp = (void __user *)data; int retval = 0; - DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb)); req.size = fb.size; sis_malloc(&req); @@ -111,7 +112,7 @@ int sis_fb_alloc( DRM_IOCTL_ARGS ) fb.free = 0; } - DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb)); + DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb)); DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset); @@ -123,7 +124,7 @@ int sis_fb_free( DRM_IOCTL_ARGS ) drm_sis_mem_t fb; int retval = 0; - DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *)data, sizeof(fb)); if (!fb.free) return DRM_ERR(EINVAL); @@ -325,7 +326,7 @@ int sis_ioctl_agp_free( DRM_IOCTL_ARGS ) return 0; } -int sis_init_context(int context) +int sis_init_context(struct drm_device *dev, int context) { int i; @@ -357,7 +358,7 @@ int sis_init_context(int context) return 1; } -int sis_final_context(int context) +int sis_final_context(struct drm_device *dev, int context) { int i; @@ -403,3 +404,10 @@ int sis_final_context(int context) return 1; } + +void DRM(driver_register_fns)(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR; + dev->fn_tbl.context_ctor = sis_init_context; + dev->fn_tbl.context_dtor = sis_final_context; +} diff --git a/drivers/char/drm/tdfx.h b/drivers/char/drm/tdfx.h index 6b067db78..a582a3db4 100644 --- a/drivers/char/drm/tdfx.h +++ b/drivers/char/drm/tdfx.h @@ -36,8 +36,6 @@ /* General customization: */ -#define __HAVE_MTRR 1 -#define __HAVE_CTX_BITMAP 1 #define DRIVER_AUTHOR "VA Linux Systems Inc." diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c index fafa1f922..d13144438 100644 --- a/drivers/char/drm/tdfx_drv.c +++ b/drivers/char/drm/tdfx_drv.c @@ -34,18 +34,10 @@ #include "tdfx.h" #include "drmP.h" -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_context.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" +#include "drm_core.h" + +void DRM(driver_register_fns)(drm_device_t *dev) +{ + dev->driver_features = DRIVER_USE_MTRR; +} -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index e2c4ecac7..7def6ad51 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -373,8 +373,7 @@ static int __init ds1620_init(void) th_start.hi = 1; ds1620_write_state(&th_start); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2*HZ); + msleep(2000); ds1620_write_state(&th); diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index b022aca3d..37d664901 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -58,12 +58,6 @@ #define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE) #define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF) -#define wait_some(n) \ -{ \ - set_current_state(TASK_INTERRUPTIBLE); \ - schedule_timeout(n); \ -} - #define handshake(count, maxio, timeout, ENABLE, f) \ { \ long i, t, m; \ @@ -71,13 +65,13 @@ m = min_t(unsigned long, count, maxio); \ for (i = 0; i < m; i++) { \ for (t = 0; t < timeout && !ENABLE; t++) \ - wait_some(HZ/50); \ + msleep(20); \ if(!ENABLE) \ return -EIO; \ f; \ } \ count -= m; \ - if (m == maxio) wait_some(HZ/50); \ + if (m == maxio) msleep(20); \ } \ } @@ -85,7 +79,7 @@ { \ int t; \ for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \ - wait_some(HZ/100); \ + msleep(10); \ if(!DSP56K_TRANSMIT) { \ return -EIO; \ } \ @@ -95,7 +89,7 @@ { \ int t; \ for(t = 0; t < n && !DSP56K_RECEIVE; t++) \ - wait_some(HZ/100); \ + msleep(10); \ if(!DSP56K_RECEIVE) { \ return -EIO; \ } \ diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c index 933282df5..b3289d9d2 100644 --- a/drivers/char/ec3104_keyb.c +++ b/drivers/char/ec3104_keyb.c @@ -412,7 +412,7 @@ static void ec3104_keyb_clear_state(void) k->last_msr = 0; for (;;) { - schedule_timeout(HZ/10); + msleep(100); msr = ctrl_inb(EC3104_SER4_MSR); diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 6d0b81298..1845739ee 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -155,7 +155,7 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, efi_time_t eft; efi_time_cap_t cap; struct rtc_time wtime; - struct rtc_wkalrm *ewp; + struct rtc_wkalrm __user *ewp; unsigned char enabled, pending; switch (cmd) { @@ -189,13 +189,15 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, convert_from_efi_time(&eft, &wtime); - return copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time)) ? - EFAULT : 0; + return copy_to_user((void __user *)arg, &wtime, + sizeof (struct rtc_time)) ? - EFAULT : 0; case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EACCES; - if (copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time)) ) + if (copy_from_user(&wtime, (struct rtc_time __user *)arg, + sizeof(struct rtc_time)) ) return -EFAULT; convert_to_efi_time(&wtime, &eft); @@ -212,19 +214,19 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (!capable(CAP_SYS_TIME)) return -EACCES; - ewp = (struct rtc_wkalrm *)arg; + ewp = (struct rtc_wkalrm __user *)arg; if ( get_user(enabled, &ewp->enabled) || copy_from_user(&wtime, &ewp->time, sizeof(struct rtc_time)) ) return -EFAULT; convert_to_efi_time(&wtime, &eft); - + spin_lock_irqsave(&efi_rtc_lock, flags); /* * XXX Fixme: * As of EFI 0.92 with the firmware I have on my - * machine this call does not seem to work quite + * machine this call does not seem to work quite * right */ status = efi.set_wakeup_time((efi_bool_t)enabled, &eft); @@ -243,14 +245,15 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (status != EFI_SUCCESS) return -EINVAL; - ewp = (struct rtc_wkalrm *)arg; + ewp = (struct rtc_wkalrm __user *)arg; if ( put_user(enabled, &ewp->enabled) || put_user(pending, &ewp->pending)) return -EFAULT; convert_from_efi_time(&eft, &wtime); - return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time)) ? -EFAULT : 0; + return copy_to_user(&ewp->time, &wtime, + sizeof(struct rtc_time)) ? -EFAULT : 0; } return -EINVAL; } diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 854d16a39..0f13bef97 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -74,7 +74,6 @@ #define DIGIINFOMAJOR 35 /* For Digi specific ioctl */ -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAXCARDS 7 #define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg) @@ -551,9 +550,7 @@ static void pc_close(struct tty_struct * tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + tty_ldisc_flush(tty); shutdown(ch); tty->closing = 0; ch->event = 0; @@ -657,10 +654,7 @@ static void pc_hangup(struct tty_struct *tty) cli(); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + tty_ldisc_flush(tty); shutdown(ch); ch->tty = NULL; @@ -826,7 +820,7 @@ static int pc_write(struct tty_struct * tty, int from_user, bytesAvailable will then take on this newly calculated value. ---------------------------------------------------------------------- */ - bytesAvailable = MIN(dataLen, bytesAvailable); + bytesAvailable = min(dataLen, bytesAvailable); /* First we read the data in from the file system into a temp buffer */ @@ -912,7 +906,7 @@ static int pc_write(struct tty_struct * tty, int from_user, space; reduce the amount of data to fit the space. ---------------------------------------------------------------------- */ - bytesAvailable = MIN(remain, bytesAvailable); + bytesAvailable = min(remain, bytesAvailable); txwinon(ch); while (bytesAvailable > 0) @@ -923,7 +917,7 @@ static int pc_write(struct tty_struct * tty, int from_user, data copy fills to the end of card buffer. ------------------------------------------------------------------- */ - dataLen = MIN(bytesAvailable, dataLen); + dataLen = min(bytesAvailable, dataLen); memcpy(ch->txptr + head, buf, dataLen); buf += dataLen; head += dataLen; @@ -1120,8 +1114,7 @@ static void pc_flush_buffer(struct tty_struct *tty) restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* End pc_flush_buffer */ @@ -2262,9 +2255,7 @@ static void doevent(int crd) { /* Begin if LOWWAIT */ ch->statusflags &= ~LOWWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } /* End if LOWWAIT */ @@ -2281,9 +2272,7 @@ static void doevent(int crd) { /* Begin if EMPTYWAIT */ ch->statusflags &= ~EMPTYWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); @@ -3136,6 +3125,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, } else { + /* ldisc lock already held in ioctl */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); } @@ -3307,7 +3297,6 @@ static void do_softint(void *private_) } } /* End EPCA_MAGIC */ - MOD_DEC_USE_COUNT; } /* End do_softint */ /* ------------------------------------------------------------ diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 663a1e24f..d67098c45 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -19,7 +19,7 @@ * * rs_set_termios fixed to look also for changes of the input * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. - * Bernd Anhäupl 05/17/96. + * Bernd Anh�pl 05/17/96. * * --- End of notices from serial.c --- * @@ -140,7 +140,7 @@ static struct esp_struct *ports; static void change_speed(struct esp_struct *info); static void rs_wait_until_sent(struct tty_struct *, int); - + /* * The ESP card has a clock rate of 14.7456 MHz (that is, 2**ESPC_SCALE * times the normal 1.8432 Mhz clock of most serial boards). @@ -150,10 +150,6 @@ static void rs_wait_until_sent(struct tty_struct *, int); /* Standard COM flags (except for COM4, because of the 8514 problem) */ #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs blocks while swapping in a page, @@ -762,10 +758,7 @@ static void do_softint(void *private_) return; if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -1370,10 +1363,7 @@ static void rs_flush_buffer(struct tty_struct *tty) cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -2069,8 +2059,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = NULL; diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c index 34f0e69d3..956b2586e 100644 --- a/drivers/char/ftape/lowlevel/ftape-calibr.c +++ b/drivers/char/ftape/lowlevel/ftape-calibr.c @@ -31,7 +31,10 @@ #include #if defined(__alpha__) # include -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__x86_64__) +# include +# include +#elif defined(__i386__) # include #endif #include @@ -45,7 +48,7 @@ # error Ftape is not implemented for this architecture! #endif -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) static unsigned long ps_per_cycle = 0; #endif @@ -72,7 +75,18 @@ unsigned int ftape_timestamp(void) asm volatile ("rpcc %0" : "=r" (r)); return r; -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__x86_64__) + unsigned long r; + rdtscl(r); + return r; +#elif defined(__i386__) + +/* + * Note that there is some time between counter underflowing and jiffies + * increasing, so the code below won't always give correct output. + * -Vojtech + */ + unsigned long flags; __u16 lo; __u16 hi; @@ -89,9 +103,9 @@ unsigned int ftape_timestamp(void) static unsigned int short_ftape_timestamp(void) { -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) return ftape_timestamp(); -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) unsigned int count; unsigned long flags; @@ -106,9 +120,9 @@ static unsigned int short_ftape_timestamp(void) static unsigned int diff(unsigned int t0, unsigned int t1) { -#if defined(__alpha__) - return (t1 <= t0) ? t1 + (1UL << 32) - t0 : t1 - t0; -#elif defined(__i386__) || defined(__x86_64__) +#if defined(__alpha__) || defined(__x86_64__) + return (t1 - t0); +#elif defined(__i386__) /* * This is tricky: to work for both short and full ftape_timestamps * we'll have to discriminate between these. @@ -122,9 +136,9 @@ static unsigned int diff(unsigned int t0, unsigned int t1) static unsigned int usecs(unsigned int count) { -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) return (ps_per_cycle * count) / 1000000UL; -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); #endif } @@ -163,38 +177,13 @@ static void time_inb(void) static void init_clock(void) { -#if defined(__i386__) || defined(__x86_64__) - unsigned int t; - int i; TRACE_FUN(ft_t_any); - /* Haven't studied on why, but there sometimes is a problem - * with the tick timer readout. The two bytes get swapped. - * This hack solves that problem by doing one extra input. - */ - for (i = 0; i < 1000; ++i) { - t = short_ftape_timestamp(); - if (t > LATCH) { - inb_p(0x40); /* get in sync again */ - TRACE(ft_t_warn, "clock counter fixed"); - break; - } - } +#if defined(__x86_64__) + ps_per_cycle = 1000000000UL / cpu_khz; #elif defined(__alpha__) -#if CONFIG_FT_ALPHA_CLOCK == 0 -#error You must define and set CONFIG_FT_ALPHA_CLOCK in 'make config' ! -#endif extern struct hwrpb_struct *hwrpb; - TRACE_FUN(ft_t_any); - - if (hwrpb->cycle_freq != 0) { - ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; - } else { - /* - * HELP: Linux 2.0.x doesn't set cycle_freq on my noname ! - */ - ps_per_cycle = (1000*1000*1000*1000UL) / CONFIG_FT_ALPHA_CLOCK; - } + ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; #endif TRACE_EXIT; } @@ -213,7 +202,7 @@ void ftape_calibrate(char *name, unsigned int tc = 0; unsigned int count; unsigned int time; -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) unsigned int old_tc = 0; unsigned int old_count = 1; unsigned int old_time = 1; @@ -255,7 +244,7 @@ void ftape_calibrate(char *name, tc = (1000 * time) / (count - 1); TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", usecs(once), count - 1, usecs(multiple), tc); -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) /* * Increase the calibration count exponentially until the * calibration time exceeds 100 ms. @@ -263,7 +252,7 @@ void ftape_calibrate(char *name, if (time >= 100*1000) { break; } -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) /* * increase the count until the resulting time nears 2/HZ, * then the tc will drop sharply because we lose LATCH counts. diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 1027eb7c6..45bc1be63 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -436,9 +436,7 @@ void gs_flush_buffer(struct tty_struct *tty) restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); func_exit (); } @@ -578,9 +576,7 @@ void gs_do_softint(void *private_) if (!tty) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } func_exit (); @@ -694,7 +690,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) { unsigned long flags; struct gs_port *port; - + func_enter (); if (!tty) return; @@ -760,8 +756,8 @@ void gs_close(struct tty_struct * tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5e8c47244..22d46cdac 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -60,8 +60,8 @@ static spinlock_t hpet_task_lock = SPIN_LOCK_UNLOCKED; struct hpet_dev { struct hpets *hd_hpets; - struct hpet *hd_hpet; - struct hpet_timer *hd_timer; + struct hpet __iomem *hd_hpet; + struct hpet_timer __iomem *hd_timer; unsigned long hd_ireqfreq; unsigned long hd_irqdata; wait_queue_head_t hd_waitqueue; @@ -75,7 +75,7 @@ struct hpet_dev { struct hpets { struct hpets *hp_next; - struct hpet *hp_hpet; + struct hpet __iomem *hp_hpet; unsigned long hp_period; unsigned long hp_delta; unsigned int hp_ntimer; @@ -98,14 +98,14 @@ static struct hpets *hpets; #endif #ifndef readq -static unsigned long long __inline readq(void *addr) +static unsigned long long __inline readq(void __iomem *addr) { return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL); } #endif #ifndef writeq -static void __inline writeq(unsigned long long v, void *addr) +static void __inline writeq(unsigned long long v, void __iomem *addr) { writel(v & 0xffffffff, addr); writel(v >> 32, addr + 4); @@ -300,7 +300,7 @@ static int hpet_fasync(int fd, struct file *file, int on) static int hpet_release(struct inode *inode, struct file *file) { struct hpet_dev *devp; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; int irq = 0; devp = file->private_data; @@ -352,8 +352,8 @@ hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int hpet_ioctl_ieon(struct hpet_dev *devp) { - struct hpet_timer *timer; - struct hpet *hpet; + struct hpet_timer __iomem *timer; + struct hpet __iomem *hpet; struct hpets *hpetp; int irq; unsigned long g, v, t, m; @@ -435,8 +435,8 @@ static inline unsigned long hpet_time_div(unsigned long dis) static int hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) { - struct hpet_timer *timer; - struct hpet *hpet; + struct hpet_timer __iomem *timer; + struct hpet __iomem *hpet; struct hpets *hpetp; int err; unsigned long v; @@ -547,7 +547,7 @@ int hpet_register(struct hpet_task *tp, int periodic) { unsigned int i; u64 mask; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; struct hpet_dev *devp; struct hpets *hpetp; @@ -615,7 +615,7 @@ static inline int hpet_tpcheck(struct hpet_task *tp) int hpet_unregister(struct hpet_task *tp) { struct hpet_dev *devp; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; int err; if ((err = hpet_tpcheck(tp))) @@ -662,40 +662,9 @@ int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) #ifdef CONFIG_TIME_INTERPOLATION -static unsigned long hpet_offset, last_wall_hpet; -static long hpet_nsecs_per_cycle, hpet_cycles_per_sec; - -static unsigned long hpet_getoffset(void) -{ - return hpet_offset + (read_counter(&hpets->hp_hpet->hpet_mc) - - last_wall_hpet) * hpet_nsecs_per_cycle; -} - -static void hpet_update(long delta) -{ - unsigned long mc; - unsigned long offset; - - mc = read_counter(&hpets->hp_hpet->hpet_mc); - offset = hpet_offset + (mc - last_wall_hpet) * hpet_nsecs_per_cycle; - - if (delta < 0 || (unsigned long)delta < offset) - hpet_offset = offset - delta; - else - hpet_offset = 0; - last_wall_hpet = mc; -} - -static void hpet_reset(void) -{ - hpet_offset = 0; - last_wall_hpet = read_counter(&hpets->hp_hpet->hpet_mc); -} - static struct time_interpolator hpet_interpolator = { - .get_offset = hpet_getoffset, - .update = hpet_update, - .reset = hpet_reset + .source = TIME_SOURCE_MMIO64, + .shift = 10 }; #endif @@ -745,11 +714,11 @@ static struct ctl_table_header *sysctl_header; static unsigned long __init hpet_calibrate(struct hpets *hpetp) { - struct hpet_timer *timer = NULL; + struct hpet_timer __iomem *timer = NULL; unsigned long t, m, count, i, flags, start; struct hpet_dev *devp; int j; - struct hpet *hpet; + struct hpet __iomem *hpet; for (j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer; j++, devp++) if ((devp->hd_flags & HPET_OPEN) == 0) { @@ -787,8 +756,9 @@ int __init hpet_alloc(struct hpet_data *hdp) u32 i, ntimer; struct hpets *hpetp; size_t siz; - struct hpet *hpet; + struct hpet __iomem *hpet; static struct hpets *last __initdata = (struct hpets *)0; + unsigned long ns; /* * hpet_alloc can be called by platform dependent code. @@ -796,7 +766,7 @@ int __init hpet_alloc(struct hpet_data *hdp) * ACPI also reports hpet, then we catch it here. */ for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address)) + if (hpetp->hp_hpet == hdp->hd_address) return 0; siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) * @@ -810,7 +780,7 @@ int __init hpet_alloc(struct hpet_data *hdp) memset(hpetp, 0, siz); hpetp->hp_which = hpet_nhpet++; - hpetp->hp_hpet = (struct hpet *)hdp->hd_address; + hpetp->hp_hpet = hdp->hd_address; hpetp->hp_ntimer = hdp->hd_nirqs; @@ -840,6 +810,18 @@ int __init hpet_alloc(struct hpet_data *hdp) hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> HPET_COUNTER_CLK_PERIOD_SHIFT; + printk(KERN_INFO "hpet%d: at MMIO 0x%p, IRQ%s", + hpetp->hp_which, hpet, hpetp->hp_ntimer > 1 ? "s" : ""); + for (i = 0; i < hpetp->hp_ntimer; i++) + printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); + printk("\n"); + + ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ + do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */ + printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", + hpetp->hp_which, ns, hpetp->hp_ntimer, + cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); + mcfg = readq(&hpet->hpet_config); if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { write_counter(0L, &hpet->hpet_mc); @@ -850,7 +832,7 @@ int __init hpet_alloc(struct hpet_data *hdp) for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; i++, hpet_ntimer++, devp++) { unsigned long v; - struct hpet_timer *timer; + struct hpet_timer __iomem *timer; timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; v = readq(&timer->hpet_config); @@ -891,11 +873,10 @@ static acpi_status __init hpet_resources(struct acpi_resource *res, void *data) unsigned long size; size = addr.max_address_range - addr.min_address_range + 1; - hdp->hd_address = - (unsigned long)ioremap(addr.min_address_range, size); + hdp->hd_address = ioremap(addr.min_address_range, size); for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address)) + if (hpetp->hp_hpet == hdp->hd_address) return -EBUSY; } else if (res->id == ACPI_RSTYPE_EXT_IRQ) { struct acpi_resource_ext_irq *irqp; @@ -944,9 +925,8 @@ static int __init hpet_acpi_remove(struct acpi_device *device, int type) return 0; } -static struct acpi_driver hpet_acpi_driver __initdata = { +static struct acpi_driver hpet_acpi_driver = { .name = "hpet", - .class = "", .ids = "PNP0103", .ops = { .add = hpet_acpi_add, @@ -971,11 +951,10 @@ static int __init hpet_init(void) struct hpet *hpet; hpet = hpets->hp_hpet; - hpet_cycles_per_sec = hpet_time_div(hpets->hp_period); - hpet_interpolator.frequency = hpet_cycles_per_sec; - hpet_interpolator.drift = hpet_cycles_per_sec * + hpet_interpolator.addr = &hpets->hp_hpet->hpet_mc; + hpet_interpolator.frequency = hpet_time_div(hpets->hp_period); + hpet_interpolator.drift = hpet_interpolator.frequency * HPET_DRIFT / 1000000; - hpet_nsecs_per_cycle = 1000000000 / hpet_cycles_per_sec; register_time_interpolator(&hpet_interpolator); } #endif diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index d4bf205fd..3c0af2cad 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -1,6 +1,11 @@ /* * Copyright (C) 2001 Anton Blanchard , IBM * Copyright (C) 2001 Paul Mackerras , IBM + * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold * * 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 @@ -17,38 +22,51 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include #include +#include +#include +#include +#include +#include #include -#include #include -#include #include #include #include #include -#include -#include #include -#include - -extern int hvc_count(int *); -extern int hvc_get_chars(int index, char *buf, int count); -extern int hvc_put_chars(int index, const char *buf, int count); +#include +#include +#include #define HVC_MAJOR 229 #define HVC_MINOR 0 -#define MAX_NR_HVC_CONSOLES 4 - #define TIMEOUT ((HZ + 99) / 100) +/* + * Wait this long per iteration while trying to push buffered data to the + * hypervisor before allowing the tty to complete a close operation. + */ +#define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ + +/* + * The Linux TTY code does not support dynamic addition of tty derived devices + * so we need to know how many tty devices we might need when space is allocated + * for the tty device. Since this driver supports hotplug of vty adapters we + * need to make sure we have enough allocated. + */ +#define HVC_ALLOC_TTY_ADAPTERS 8 + static struct tty_driver *hvc_driver; -static int hvc_offset; #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; #endif #define N_OUTBUF 16 +#define N_INBUF 16 #define __ALIGNED__ __attribute__((__aligned__(8))) @@ -60,59 +78,249 @@ struct hvc_struct { int do_wakeup; char outbuf[N_OUTBUF] __ALIGNED__; int n_outbuf; + uint32_t vtermno; + int irq_requested; + int irq; + struct list_head next; + struct kobject kobj; /* ref count & hvc_struct lifetime */ + struct vio_dev *vdev; }; -struct hvc_struct hvc_struct[MAX_NR_HVC_CONSOLES]; +/* dynamic list of hvc_struct instances */ +static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); + +/* + * Protect the list of hvc_struct instances from inserts and removals during + * list traversal. + */ +static spinlock_t hvc_structs_lock = SPIN_LOCK_UNLOCKED; + +/* + * Initial console vtermnos for console API usage prior to full console + * initialization. Any vty adapter outside this range will not have usable + * console interfaces but can still be used as a tty device. This has to be + * static because kmalloc will not work during early console init. + */ +static uint32_t vtermnos[MAX_NR_HVC_CONSOLES]; + +/* Used for accounting purposes */ +static int num_vterms = 0; + +static struct task_struct *hvc_task; + +/* + * This value is used to associate a tty->index value to a hvc_struct based + * upon order of exposure via hvc_probe(). + */ +static int hvc_count = -1; + +/* Picks up late kicks after list walk but before schedule() */ +static int hvc_kicked; + +/* Wake the sleeping khvcd */ +static void hvc_kick(void) +{ + hvc_kicked = 1; + wake_up_process(hvc_task); +} + +/* + * NOTE: This API isn't used if the console adapter doesn't support interrupts. + * In this case the console is poll driven. + */ +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + hvc_kick(); + return IRQ_HANDLED; +} + +static void hvc_unthrottle(struct tty_struct *tty) +{ + hvc_kick(); +} + +/* + * Do not call this function with either the hvc_strucst_lock or the hvc_struct + * lock held. If successful, this function increments the kobject reference + * count against the target hvc_struct so it should be released when finished. + */ +struct hvc_struct *hvc_get_by_index(int index) +{ + struct hvc_struct *hp; + unsigned long flags; + + spin_lock(&hvc_structs_lock); + list_for_each_entry(hp, &hvc_structs, next) { + spin_lock_irqsave(&hp->lock, flags); + if (hp->index == index) { + kobject_get(&hp->kobj); + spin_unlock_irqrestore(&hp->lock, flags); + spin_unlock(&hvc_structs_lock); + return hp; + } + spin_unlock_irqrestore(&hp->lock, flags); + } + hp = NULL; + + spin_unlock(&hvc_structs_lock); + return hp; +} + +/* + * The TTY interface won't be used until after the vio layer has exposed the vty + * adapter to the kernel. + */ static int hvc_open(struct tty_struct *tty, struct file * filp) { - int line = tty->index; struct hvc_struct *hp; unsigned long flags; + int irq = NO_IRQ; + int rc = 0; + struct kobject *kobjp; - if (line < 0 || line >= MAX_NR_HVC_CONSOLES) + /* Auto increments kobject reference if found. */ + if (!(hp = hvc_get_by_index(tty->index))) { + printk(KERN_WARNING "hvc_console: tty open failed, no vty associated with tty.\n"); return -ENODEV; - hp = &hvc_struct[line]; + } - tty->driver_data = hp; spin_lock_irqsave(&hp->lock, flags); + /* Check and then increment for fast path open. */ + if (hp->count++ > 0) { + spin_unlock_irqrestore(&hp->lock, flags); + hvc_kick(); + return 0; + } /* else count == 0 */ + + tty->driver_data = hp; hp->tty = tty; - hp->count++; + /* Save for request_irq outside of spin_lock. */ + irq = hp->irq; + if (irq != NO_IRQ) + hp->irq_requested = 1; + + kobjp = &hp->kobj; + spin_unlock_irqrestore(&hp->lock, flags); + /* check error, fallback to non-irq */ + if (irq != NO_IRQ) + rc = request_irq(irq, hvc_handle_interrupt, SA_INTERRUPT, "hvc_console", hp); + + /* + * If the request_irq() fails and we return an error. The tty layer + * will call hvc_close() after a failed open but we don't want to clean + * up there so we'll clean up here and clear out the previously set + * tty fields and return the kobject reference. + */ + if (rc) { + spin_lock_irqsave(&hp->lock, flags); + hp->tty = NULL; + hp->irq_requested = 0; + spin_unlock_irqrestore(&hp->lock, flags); + tty->driver_data = NULL; + kobject_put(kobjp); + } + /* Force wakeup of the polling thread */ + hvc_kick(); - return 0; + return rc; } static void hvc_close(struct tty_struct *tty, struct file * filp) { - struct hvc_struct *hp = tty->driver_data; + struct hvc_struct *hp; + struct kobject *kobjp; + int irq = NO_IRQ; unsigned long flags; if (tty_hung_up_p(filp)) return; + + /* + * No driver_data means that this close was issued after a failed + * hvcs_open by the tty layer's release_dev() function and we can just + * exit cleanly because the kobject reference wasn't made. + */ + if (!tty->driver_data) + return; + + hp = tty->driver_data; spin_lock_irqsave(&hp->lock, flags); - if (--hp->count == 0) + + kobjp = &hp->kobj; + if (--hp->count == 0) { + if (hp->irq_requested) + irq = hp->irq; + hp->irq_requested = 0; + + /* We are done with the tty pointer now. */ hp->tty = NULL; - else if (hp->count < 0) - printk(KERN_ERR "hvc_close %lu: oops, count is %d\n", - hp - hvc_struct, hp->count); - spin_unlock_irqrestore(&hp->lock, flags); + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * Chain calls chars_in_buffer() and returns immediately if + * there is no buffered data otherwise sleeps on a wait queue + * waking periodically to check chars_in_buffer(). + */ + tty_wait_until_sent(tty, HVC_CLOSE_WAIT); + + /* + * Since the line disc doesn't block writes during tty close + * operations we'll set driver_data to NULL and then make sure + * to check tty->driver_data for NULL in hvc_write(). + */ + tty->driver_data = NULL; + + if (irq != NO_IRQ) + free_irq(irq, hp); + + } else { + if (hp->count < 0) + printk(KERN_ERR "hvc_close %X: oops, count is %d\n", + hp->vtermno, hp->count); + spin_unlock_irqrestore(&hp->lock, flags); + } + + kobject_put(kobjp); } static void hvc_hangup(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; + unsigned long flags; + int irq = NO_IRQ; + int temp_open_count; + struct kobject *kobjp; + spin_lock_irqsave(&hp->lock, flags); + kobjp = &hp->kobj; + temp_open_count = hp->count; hp->count = 0; + hp->n_outbuf = 0; hp->tty = NULL; + if (hp->irq_requested) + /* Saved for use outside of spin_lock. */ + irq = hp->irq; + hp->irq_requested = 0; + spin_unlock_irqrestore(&hp->lock, flags); + if (irq != NO_IRQ) + free_irq(irq, hp); + while(temp_open_count) { + --temp_open_count; + kobject_put(kobjp); + } } -/* called with hp->lock held */ +/* + * Push buffered characters whether they were just recently buffered or waiting + * on a blocked hypervisor. Call this function with hp->lock held. + */ static void hvc_push(struct hvc_struct *hp) { int n; - n = hvc_put_chars(hp->index + hvc_offset, hp->outbuf, hp->n_outbuf); + n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); if (n <= 0) { if (n == 0) return; @@ -127,77 +335,126 @@ static void hvc_push(struct hvc_struct *hp) hp->do_wakeup = 1; } -static int hvc_write(struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +static inline int __hvc_write_user(struct hvc_struct *hp, + const unsigned char *buf, int count) { - struct hvc_struct *hp = tty->driver_data; char *tbuf, *p; int tbsize, rsize, written = 0; unsigned long flags; - if (from_user) { - tbsize = min(count, (int)PAGE_SIZE); - if (!(tbuf = kmalloc(tbsize, GFP_KERNEL))) - return -ENOMEM; - - while ((rsize = count - written) > 0) { - int wsize; - if (rsize > tbsize) - rsize = tbsize; - - p = tbuf; - rsize -= copy_from_user(p, buf, rsize); - if (!rsize) { - if (written == 0) - written = -EFAULT; - break; - } - buf += rsize; - written += rsize; - - spin_lock_irqsave(&hp->lock, flags); - for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize; - wsize = N_OUTBUF - hp->n_outbuf) { - if (wsize > rsize) - wsize = rsize; - memcpy(hp->outbuf + hp->n_outbuf, p, wsize); - hp->n_outbuf += wsize; - hvc_push(hp); - rsize -= wsize; - p += wsize; - } - spin_unlock_irqrestore(&hp->lock, flags); - - if (rsize) - break; + tbsize = min(count, (int)PAGE_SIZE); + if (!(tbuf = kmalloc(tbsize, GFP_KERNEL))) + return -ENOMEM; - if (count < tbsize) - tbsize = count; + while ((rsize = count - written) > 0) { + int wsize; + if (rsize > tbsize) + rsize = tbsize; + + p = tbuf; + rsize -= copy_from_user(p, buf, rsize); + if (!rsize) { + if (written == 0) + written = -EFAULT; + break; } + buf += rsize; - kfree(tbuf); - } else { spin_lock_irqsave(&hp->lock, flags); - while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) { - if (rsize > count) - rsize = count; - memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); - count -= rsize; - buf += rsize; - hp->n_outbuf += rsize; - written += rsize; + + /* Push pending writes: make some room in buffer */ + if (hp->n_outbuf > 0) hvc_push(hp); + + for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize; + wsize = N_OUTBUF - hp->n_outbuf) { + if (wsize > rsize) + wsize = rsize; + memcpy(hp->outbuf + hp->n_outbuf, p, wsize); + hp->n_outbuf += wsize; + hvc_push(hp); + rsize -= wsize; + p += wsize; + written += wsize; } spin_unlock_irqrestore(&hp->lock, flags); + + if (rsize) + break; + + if (count < tbsize) + tbsize = count; + } + + kfree(tbuf); + + return written; +} + +static inline int __hvc_write_kernel(struct hvc_struct *hp, + const unsigned char *buf, int count) +{ + unsigned long flags; + int rsize, written = 0; + + spin_lock_irqsave(&hp->lock, flags); + + /* Push pending writes */ + if (hp->n_outbuf > 0) + hvc_push(hp); + + while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) { + if (rsize > count) + rsize = count; + memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); + count -= rsize; + buf += rsize; + hp->n_outbuf += rsize; + written += rsize; + hvc_push(hp); } + spin_unlock_irqrestore(&hp->lock, flags); + + return written; +} +static int hvc_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct hvc_struct *hp = tty->driver_data; + int written; + + /* This write was probably executed during a tty close. */ + if (!hp) + return -EPIPE; + + if (from_user) + written = __hvc_write_user(hp, buf, count); + else + written = __hvc_write_kernel(hp, buf, count); + + /* + * Racy, but harmless, kick thread if there is still pending data. + * There really is nothing wrong with kicking the thread, even if there + * is no buffered data. + */ + if (hp->n_outbuf) + hvc_kick(); return written; } +/* + * This is actually a contract between the driver and the tty layer outlining + * how much write room the driver can guarentee will be sent OR BUFFERED. This + * driver MUST honor the return value. + */ static int hvc_write_room(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; + if (!hp) + return -1; + return N_OUTBUF - hp->n_outbuf; } @@ -205,57 +462,108 @@ static int hvc_chars_in_buffer(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; + if (!hp) + return -1; return hp->n_outbuf; } -static void hvc_poll(int index) +#define HVC_POLL_READ 0x00000001 +#define HVC_POLL_WRITE 0x00000002 +#define HVC_POLL_QUICK 0x00000004 + +static int hvc_poll(struct hvc_struct *hp) { - struct hvc_struct *hp = &hvc_struct[index]; struct tty_struct *tty; - int i, n; - char buf[16] __ALIGNED__; + int i, n, poll_mask = 0; + char buf[N_INBUF] __ALIGNED__; unsigned long flags; + int read_total = 0; spin_lock_irqsave(&hp->lock, flags); + /* Push pending writes */ if (hp->n_outbuf > 0) hvc_push(hp); + /* Reschedule us if still some write pending */ + if (hp->n_outbuf > 0) + poll_mask |= HVC_POLL_WRITE; + /* No tty attached, just skip */ tty = hp->tty; - if (tty) { - for (;;) { - if (TTY_FLIPBUF_SIZE - tty->flip.count < sizeof(buf)) - break; - n = hvc_get_chars(index + hvc_offset, buf, sizeof(buf)); - if (n <= 0) - break; - for (i = 0; i < n; ++i) { -#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ - sysrq_pressed = 1; - continue; - } else if (sysrq_pressed) { - handle_sysrq(buf[i], NULL, tty); - sysrq_pressed = 0; - continue; - } -#endif - tty_insert_flip_char(tty, buf[i], 0); + if (tty == NULL) + goto bail; + + /* Now check if we can get data (are we throttled ?) */ + if (test_bit(TTY_THROTTLED, &tty->flags)) + goto throttled; + + /* If we aren't interrupt driven and aren't throttled, we always + * request a reschedule + */ + if (hp->irq == NO_IRQ) + poll_mask |= HVC_POLL_READ; + + /* Read data if any */ + for (;;) { + int count = N_INBUF; + if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + /* If flip is full, just reschedule a later read */ + if (count == 0) { + poll_mask |= HVC_POLL_READ; + break; + } + + n = hvc_get_chars(hp->vtermno, buf, count); + if (n <= 0) { + /* Hangup the tty when disconnected from host */ + if (n == -EPIPE) { + spin_unlock_irqrestore(&hp->lock, flags); + tty_hangup(tty); + spin_lock_irqsave(&hp->lock, flags); } + break; } + for (i = 0; i < n; ++i) { +#ifdef CONFIG_MAGIC_SYSRQ + /* Handle the SysRq Hack */ + if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ + sysrq_pressed = 1; + continue; + } else if (sysrq_pressed) { + handle_sysrq(buf[i], NULL, tty); + sysrq_pressed = 0; + continue; + } +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(tty, buf[i], 0); + } + if (tty->flip.count) tty_schedule_flip(tty); - if (hp->do_wakeup) { - hp->do_wakeup = 0; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + /* + * Account for the total amount read in one loop, and if above + * 64 bytes, we do a quick schedule loop to let the tty grok the + * data and eventually throttle us. + */ + read_total += n; + if (read_total >= 64) { + poll_mask |= HVC_POLL_QUICK; + break; } } - + throttled: + /* Wakeup write queue if necessary */ + if (hp->do_wakeup) { + hp->do_wakeup = 0; + tty_wakeup(tty); + } + bail: spin_unlock_irqrestore(&hp->lock, flags); + + return poll_mask; } #if defined(CONFIG_XMON) && defined(CONFIG_SMP) @@ -264,21 +572,47 @@ extern cpumask_t cpus_in_xmon; static const cpumask_t cpus_in_xmon = CPU_MASK_NONE; #endif - +/* + * This kthread is either polling or interrupt driven. This is determined by + * calling hvc_poll() who determines whether a console adapter support + * interrupts. + */ int khvcd(void *unused) { - int i; - - daemonize("khvcd"); + int poll_mask; + struct hvc_struct *hp; - for (;;) { + __set_current_state(TASK_RUNNING); + do { + poll_mask = 0; + hvc_kicked = 0; + wmb(); if (cpus_empty(cpus_in_xmon)) { - for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i) - hvc_poll(i); + spin_lock(&hvc_structs_lock); + list_for_each_entry(hp, &hvc_structs, next) { + /*hp = list_entry(node, struct hvc_struct, * next); */ + poll_mask |= hvc_poll(hp); + } + spin_unlock(&hvc_structs_lock); + } else + poll_mask |= HVC_POLL_READ; + if (hvc_kicked) + continue; + if (poll_mask & HVC_POLL_QUICK) { + yield(); + continue; } set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(TIMEOUT); - } + if (!hvc_kicked) { + if (poll_mask == 0) + schedule(); + else + schedule_timeout(TIMEOUT); + } + __set_current_state(TASK_RUNNING); + } while (!kthread_should_stop()); + + return 0; } static struct tty_operations hvc_ops = { @@ -286,19 +620,124 @@ static struct tty_operations hvc_ops = { .close = hvc_close, .write = hvc_write, .hangup = hvc_hangup, + .unthrottle = hvc_unthrottle, .write_room = hvc_write_room, .chars_in_buffer = hvc_chars_in_buffer, }; -int __init hvc_init(void) +char hvc_driver_name[] = "hvc_console"; + +static struct vio_device_id hvc_driver_table[] __devinitdata= { + {"serial", "hvterm1"}, + { 0, } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kobject *kobj) { - int num = hvc_count(&hvc_offset); - int i; + struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); + unsigned long flags; - if (num > MAX_NR_HVC_CONSOLES) - num = MAX_NR_HVC_CONSOLES; + spin_lock(&hvc_structs_lock); - hvc_driver = alloc_tty_driver(num); + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + +static struct kobj_type hvc_kobj_type = { + .release = destroy_hvc_struct, +}; + +static int __devinit hvc_probe( + struct vio_dev *dev, + const struct vio_device_id *id) +{ + struct hvc_struct *hp; + + /* probed with invalid parameters. */ + if (!dev || !id) + return -EPERM; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if (!hp) + return -ENOMEM; + + memset(hp, 0x00, sizeof(*hp)); + hp->vtermno = dev->unit_address; + hp->vdev = dev; + hp->vdev->dev.driver_data = hp; + hp->irq = dev->irq; + + kobject_init(&hp->kobj); + hp->kobj.ktype = &hvc_kobj_type; + + hp->lock = SPIN_LOCK_UNLOCKED; + spin_lock(&hvc_structs_lock); + hp->index = ++hvc_count; + list_add_tail(&(hp->next), &hvc_structs); + spin_unlock(&hvc_structs_lock); + + return 0; +} + +static int __devexit hvc_remove(struct vio_dev *dev) +{ + struct hvc_struct *hp = dev->dev.driver_data; + unsigned long flags; + struct kobject *kobjp; + struct tty_struct *tty; + + spin_lock_irqsave(&hp->lock, flags); + tty = hp->tty; + kobjp = &hp->kobj; + + if (hp->index < MAX_NR_HVC_CONSOLES) + vtermnos[hp->index] = -1; + + /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ + + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * We 'put' the instance that was grabbed when the kobject instance + * was intialized using kobject_init(). Let the last holder of this + * kobject cause it to be removed, which will probably be the tty_hangup + * below. + */ + kobject_put(kobjp); + + /* + * This function call will auto chain call hvc_hangup. The tty should + * always be valid at this time unless a simultaneous tty close already + * cleaned up the hvc_struct. + */ + if (tty) + tty_hangup(tty); + return 0; +} + +static struct vio_driver hvc_vio_driver = { + .name = hvc_driver_name, + .id_table = hvc_driver_table, + .probe = hvc_probe, + .remove = hvc_remove, +}; + +/* Driver initialization. Follow console initialization. This is where the TTY + * interfaces start to become available. */ +int __init hvc_init(void) +{ + int rc; + + /* We need more than num_vterms adapters due to hotplug additions. */ + hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); + /* hvc_driver = alloc_tty_driver(num_vterms); */ if (!hvc_driver) return -ENOMEM; @@ -312,31 +751,73 @@ int __init hvc_init(void) hvc_driver->init_termios = tty_std_termios; hvc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvc_driver, &hvc_ops); - for (i = 0; i < num; i++) { - hvc_struct[i].lock = SPIN_LOCK_UNLOCKED; - hvc_struct[i].index = i; - } if (tty_register_driver(hvc_driver)) panic("Couldn't register hvc console driver\n"); - if (num > 0) - kernel_thread(khvcd, NULL, CLONE_KERNEL); + /* Always start the kthread because there can be hotplug vty adapters + * added later. */ + hvc_task = kthread_run(khvcd, NULL, "khvcd"); + if (IS_ERR(hvc_task)) { + panic("Couldn't create kthread for console.\n"); + put_tty_driver(hvc_driver); + return -EIO; + } + + /* Register as a vio device to receive callbacks */ + rc = vio_register_driver(&hvc_vio_driver); - return 0; + return rc; } +/* This isn't particularily necessary due to this being a console driver but it + * is nice to be thorough */ static void __exit hvc_exit(void) { + kthread_stop(hvc_task); + + vio_unregister_driver(&hvc_vio_driver); + tty_unregister_driver(hvc_driver); + /* return tty_struct instances allocated in hvc_init(). */ + put_tty_driver(hvc_driver); +} + +/* + * Console APIs, NOT TTY. These APIs are available immediately when + * hvc_console_setup() finds adapters. + */ + +/* + * hvc_instantiate() is an early console discovery method which locates consoles + * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT + * get an hvc_instantiate() callback since the appear after early console init. + */ +int hvc_instantiate(uint32_t vtermno, int index) +{ + if (index < 0 || index >= MAX_NR_HVC_CONSOLES) + return -1; + + if (vtermnos[index] != -1) + return -1; + + vtermnos[index] = vtermno; + return 0; } void hvc_console_print(struct console *co, const char *b, unsigned count) { char c[16] __ALIGNED__; - unsigned i, n; + unsigned i = 0, n = 0; int r, donecr = 0; - i = n = 0; + /* Console access attempt outside of acceptable console range. */ + if (co->index >= MAX_NR_HVC_CONSOLES) + return; + + /* This console adapter was removed so it is not useable. */ + if (vtermnos[co->index] < 0) + return; + while (count > 0 || i > 0) { if (count > 0 && i < sizeof(c)) { if (b[n] == '\n' && !donecr) { @@ -348,7 +829,7 @@ void hvc_console_print(struct console *co, const char *b, unsigned count) --count; } } else { - r = hvc_put_chars(co->index + hvc_offset, c, i); + r = hvc_put_chars(vtermnos[co->index], c, i); if (r < 0) { /* throw away chars on error */ i = 0; @@ -369,9 +850,6 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index) static int __init hvc_console_setup(struct console *co, char *options) { - if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES - || co->index >= hvc_count(&hvc_offset)) - return -1; return 0; } @@ -384,8 +862,14 @@ struct console hvc_con_driver = { .index = -1, }; +/* Early console initialization. Preceeds driver initialization. */ static int __init hvc_console_init(void) { + int i; + + for (i=0; i /* - * 1.0.0 -> 1.1.0 Added kernel_thread scheduling methodology to driver to - * replace wait_task constructs. + * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00). + * Removed braces around single statements following conditionals. Removed '= + * 0' after static int declarations since these default to zero. Removed + * list_for_each_safe() and replaced with list_for_each_entry() in + * hvcs_get_by_index(). The 'safe' version is un-needed now that the driver is + * using spinlocks. Changed spin_lock_irqsave() to spin_lock() when locking + * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int + * handler. Initialized hvcs_structs_lock and hvcs_pi_lock to + * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init(). + * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the + * list traversals from a deletion. Removed '= NULL' from pointer declaration + * statements since they are initialized NULL by default. Removed wmb() + * instances from hvcs_try_write(). They probably aren't needed with locking in + * place. Added check and cleanup for hvcs_pi_buff = kmalloc() in + * hvcs_module_init(). Exposed hvcs_struct.index via a sysfs attribute so that + * the coupling between /dev/hvcs* and a vty-server can be automatically + * determined. Moved kobject_put() in hvcs_open outside of the + * spin_unlock_irqrestore(). * - * 1.1.0 -> 1.2.0 Moved pi_buff initialization out of arch code into driver code - * and added locking to share this buffer between hvcs_struct instances. This - * is because the page_size kmalloc can't be done with a spin_lock held. + * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it + * align with how the tty layer always assigns the lowest index available. This + * change resulted in a list of ints that denotes which indexes are available. + * Device additions and removals use the new hvcs_get_index() and + * hvcs_return_index() helper functions. The list is created with + * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list(). + * Without these fixes hotplug vty-server adapter support goes crazy with this + * driver if the user removes a vty-server adapter. Moved free_irq() outside of + * the hvcs_final_close() function in order to get it out of the spinlock. + * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping + * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from + * arch/ppc64/hvcserver.h. * - * Also added sysfs attribute to manually disconnect the vty-server from the vty - * due to stupid firmware behavior when opening the connection then sending data - * then then quickly closing the connection would cause data loss on the - * receiving side. This required some reordering of the termination code. - * - * Fixed the hangup scenario and fixed memory leaks on module_exit. - * - * 1.2.0 -> 1.3.0 Moved from manual kernel thread creation & execution to - * kthread construct which replaced in-kernel IPC for thread termination with - * kthread_stop and kthread_should_stop. Explicit wait_queue handling was - * removed because kthread handles this. Minor bug fix to postpone partner_info - * clearing on hvcs_close until adapter removal to preserve context data for - * printk on partner connection free. Added lock to protect hvcs_structs so - * that hvcs_struct instances aren't added or removed during list traversal. - * Cleaned up comment style, added spaces after commas, and broke function - * declaration lines to be under 80 columns. + * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to + * prevent possible lockup with realtime scheduling as similarily pointed out by + * akpm in hvc_console. Changed resulted in the removal of hvcs_final_close() + * to reorder cleanup operations and prevent discarding of pending data during + * an hvcs_close(). Removed spinlock protection of hvcs_struct data members in + * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed. */ -#define HVCS_DRIVER_VERSION "1.3.0" + +#define HVCS_DRIVER_VERSION "1.3.3" MODULE_AUTHOR("Ryan S. Arnold "); MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(HVCS_DRIVER_VERSION); +/* + * Wait this long per iteration while trying to push buffered data to the + * hypervisor before allowing the tty to complete a close operation. + */ +#define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ + /* * Since the Linux TTY code does not currently (2-04-2004) support dynamic * addition of tty derived devices and we shouldn't allocate thousands of @@ -138,9 +160,9 @@ MODULE_VERSION(HVCS_DRIVER_VERSION); /* * We let Linux assign us a major number and we start the minors at zero. There - * is no intuitive mapping between minor number and the target partition. The - * mapping of minor number is related to the order the vty-servers are exposed - * to this driver via the hvcs_probe function. + * is no intuitive mapping between minor number and the target vty-server + * adapter except that each new vty-server adapter is always assigned to the + * smallest minor number available. */ #define HVCS_MINOR_START 0 @@ -152,9 +174,6 @@ MODULE_VERSION(HVCS_DRIVER_VERSION); */ #define __ALIGNED__ __attribute__((__aligned__(8))) -/* Converged location code string length + 1 null terminator */ -#define CLC_LENGTH 80 - /* * How much data can firmware send with each hvc_put_chars()? Maybe this * should be moved into an architecture specific area. @@ -194,27 +213,41 @@ char hvcs_driver_string[] = "IBM hvcs (Hypervisor Virtual Console Server) Driver"; /* Status of partner info rescan triggered via sysfs. */ -static int hvcs_rescan_status = 0; +static int hvcs_rescan_status; static struct tty_driver *hvcs_tty_driver; /* - * This is used to associate a vty-server, as it is exposed to this driver, with - * a preallocated tty_struct.index. The dev node and hvcs index numbers are not - * re-used after device removal otherwise removing and adding a new one would - * link a /dev/hvcs* entry to a different vty-server than it did before the - * removal. Incidentally, a newly exposed vty-server will always map to an - * incrementally higher /dev/hvcs* entry than the last exposed vty-server. + * In order to be somewhat sane this driver always associates the hvcs_struct + * index element with the numerically equal tty->index. This means that a + * hotplugged vty-server adapter will always map to the lowest index valued + * device node. If vty-servers were hotplug removed from the system and then + * new ones added the new vty-server may have the largest slot number of all + * the vty-server adapters in the partition but it may have the lowest dev node + * index of all the adapters due to the hole left by the hotplug removed + * adapter. There are a set of functions provided to get the lowest index for + * a new device as well as return the index to the list. This list is allocated + * with a number of elements equal to the number of device nodes requested when + * the module was inserted. + */ +static int *hvcs_index_list; + +/* + * How large is the list? This is kept for traversal since the list is + * dynamically created. */ -static int hvcs_struct_count = -1; +static int hvcs_index_count; /* * Used by the khvcsd to pick up I/O operations when the kernel_thread is * already awake but potentially shifted to TASK_INTERRUPTIBLE state. */ -static int hvcs_kicked = 0; +static int hvcs_kicked; -/* Used the the kthread construct for task operations */ +/* + * Use by the kthread construct for task operations like waking the sleeping + * thread and stopping the kthread. + */ static struct task_struct *hvcs_task; /* @@ -223,7 +256,8 @@ static struct task_struct *hvcs_task; */ static unsigned long *hvcs_pi_buff; -static spinlock_t hvcs_pi_lock; +/* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */ +static spinlock_t hvcs_pi_lock = SPIN_LOCK_UNLOCKED; /* One vty-server per hvcs_struct */ struct hvcs_struct { @@ -263,9 +297,9 @@ struct hvcs_struct { */ struct kobject kobj; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ - unsigned int p_unit_address; /* partner unit address */ - unsigned int p_partition_ID; /* partner partition ID */ - char p_location_code[CLC_LENGTH]; + uint32_t p_unit_address; /* partner unit address */ + uint32_t p_partition_ID; /* partner partition ID */ + char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */ struct list_head next; /* list management */ struct vio_dev *vdev; }; @@ -274,7 +308,7 @@ struct hvcs_struct { #define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj) static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs); -static spinlock_t hvcs_structs_lock; +static spinlock_t hvcs_structs_lock = SPIN_LOCK_UNLOCKED; static void hvcs_unthrottle(struct tty_struct *tty); static void hvcs_throttle(struct tty_struct *tty); @@ -297,7 +331,6 @@ static void hvcs_partner_free(struct hvcs_struct *hvcsd); static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, unsigned int irq, struct vio_dev *dev); -static void hvcs_final_close(struct hvcs_struct *hvcsd); static void destroy_hvcs_struct(struct kobject *kobj); static int hvcs_open(struct tty_struct *tty, struct file *filp); @@ -357,12 +390,11 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct hvcs_struct *hvcsd = dev_instance; - unsigned long flags; - spin_lock_irqsave(&hvcsd->lock, flags); + spin_lock(&hvcsd->lock); vio_disable_interrupts(hvcsd->vdev); hvcsd->todo_mask |= HVCS_SCHED_READ; - spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcsd->lock); hvcs_kick(); return IRQ_HANDLED; @@ -371,7 +403,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance, /* This function must be called with the hvcsd->lock held */ static void hvcs_try_write(struct hvcs_struct *hvcsd) { - unsigned int unit_address = hvcsd->vdev->unit_address; + uint32_t unit_address = hvcsd->vdev->unit_address; struct tty_struct *tty = hvcsd->tty; int sent; @@ -382,9 +414,9 @@ static void hvcs_try_write(struct hvcs_struct *hvcsd) hvcsd->chars_in_buffer ); if (sent > 0) { hvcsd->chars_in_buffer = 0; - wmb(); + /* wmb(); */ hvcsd->todo_mask &= ~(HVCS_TRY_WRITE); - wmb(); + /* wmb(); */ /* * We are still obligated to deliver the data to the @@ -393,10 +425,7 @@ static void hvcs_try_write(struct hvcs_struct *hvcsd) * a non-existent tty. */ if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } } @@ -404,11 +433,11 @@ static void hvcs_try_write(struct hvcs_struct *hvcsd) static int hvcs_io(struct hvcs_struct *hvcsd) { - unsigned int unit_address; + uint32_t unit_address; struct tty_struct *tty; char buf[HVCS_BUFF_LEN] __ALIGNED__; unsigned long flags; - int got; + int got = 0; int i; spin_lock_irqsave(&hvcsd->lock, flags); @@ -461,11 +490,8 @@ static int hvcs_io(struct hvcs_struct *hvcsd) static int khvcsd(void *unused) { - struct hvcs_struct *hvcsd = NULL; - struct list_head *element; - struct list_head *safe_temp; + struct hvcs_struct *hvcsd; int hvcs_todo_mask; - unsigned long structs_flags; __set_current_state(TASK_RUNNING); @@ -474,12 +500,11 @@ static int khvcsd(void *unused) hvcs_kicked = 0; wmb(); - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); - list_for_each_safe(element, safe_temp, &hvcs_structs) { - hvcsd = list_entry(element, struct hvcs_struct, next); - hvcs_todo_mask |= hvcs_io(hvcsd); + spin_lock(&hvcs_structs_lock); + list_for_each_entry(hvcsd, &hvcs_structs, next) { + hvcs_todo_mask |= hvcs_io(hvcsd); } - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); /* * If any of the hvcs adapters want to try a write or quick read @@ -506,6 +531,19 @@ static struct vio_device_id hvcs_driver_table[] __devinitdata= { }; MODULE_DEVICE_TABLE(vio, hvcs_driver_table); +static void hvcs_return_index(int index) +{ + /* Paranoia check */ + if (!hvcs_index_list) + return; + if (index < 0 || index >= hvcs_index_count) + return; + if (hvcs_index_list[index] == -1) + return; + else + hvcs_index_list[index] = -1; +} + /* callback when the kboject ref count reaches zero */ static void destroy_hvcs_struct(struct kobject *kobj) { @@ -513,6 +551,7 @@ static void destroy_hvcs_struct(struct kobject *kobj) struct vio_dev *vdev; unsigned long flags; + spin_lock(&hvcs_structs_lock); spin_lock_irqsave(&hvcsd->lock, flags); /* the list_del poisons the pointers */ @@ -524,7 +563,7 @@ static void destroy_hvcs_struct(struct kobject *kobj) " partner vty@%X:%d connection.\n", hvcsd->vdev->unit_address, hvcsd->p_unit_address, - (unsigned int)hvcsd->p_partition_ID); + (uint32_t)hvcsd->p_partition_ID); } printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n", hvcsd->vdev->unit_address); @@ -534,55 +573,60 @@ static void destroy_hvcs_struct(struct kobject *kobj) hvcsd->p_unit_address = 0; hvcsd->p_partition_ID = 0; - memset(&hvcsd->p_location_code[0], 0x00, CLC_LENGTH); + hvcs_return_index(hvcsd->index); + memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1); spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcs_structs_lock); hvcs_remove_device_attrs(vdev); kfree(hvcsd); } -/* This function must be called with hvcsd->lock held. */ -static void hvcs_final_close(struct hvcs_struct *hvcsd) -{ - vio_disable_interrupts(hvcsd->vdev); - free_irq(hvcsd->vdev->irq, hvcsd); - - hvcsd->todo_mask = 0; - - /* These two may be redundant if the operation was a close. */ - if (hvcsd->tty) { - hvcsd->tty->driver_data = NULL; - hvcsd->tty = NULL; - } - - hvcsd->open_count = 0; - - memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); - hvcsd->chars_in_buffer = 0; -} - static struct kobj_type hvcs_kobj_type = { .release = destroy_hvcs_struct, }; +static int hvcs_get_index(void) +{ + int i; + /* Paranoia check */ + if (!hvcs_index_list) { + printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n"); + return -EFAULT; + } + /* Find the numerically lowest first free index. */ + for(i = 0; i < hvcs_index_count; i++) { + if (hvcs_index_list[i] == -1) { + hvcs_index_list[i] = 0; + return i; + } + } + return -1; +} + static int __devinit hvcs_probe( struct vio_dev *dev, const struct vio_device_id *id) { struct hvcs_struct *hvcsd; - unsigned long structs_flags; + int index; if (!dev || !id) { printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); return -EPERM; } + /* early to avoid cleanup on failure */ + index = hvcs_get_index(); + if (index < 0) { + return -EFAULT; + } + hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL); - if (!hvcsd) { + if (!hvcsd) return -ENODEV; - } /* hvcsd->tty is zeroed out with the memset */ memset(hvcsd, 0x00, sizeof(*hvcsd)); @@ -596,7 +640,9 @@ static int __devinit hvcs_probe( hvcsd->vdev = dev; dev->dev.driver_data = hvcsd; - hvcsd->index = ++hvcs_struct_count; + hvcsd->index = index; + + /* hvcsd->index = ++hvcs_struct_count; */ hvcsd->chars_in_buffer = 0; hvcsd->todo_mask = 0; hvcsd->connected = 0; @@ -617,15 +663,15 @@ static int __devinit hvcs_probe( * will get -ENODEV. */ - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); + spin_lock(&hvcs_structs_lock); list_add_tail(&(hvcsd->next), &hvcs_structs); - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); hvcs_create_device_attrs(hvcsd); - printk(KERN_INFO "HVCS: Added vty-server@%X.\n", dev->unit_address); + printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); /* * DON'T enable interrupts here because there is no user to receive the @@ -688,8 +734,8 @@ static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) hvcsd->p_unit_address = pi->unit_address; hvcsd->p_partition_ID = pi->partition_ID; clclength = strlen(&pi->location_code[0]); - if (clclength > CLC_LENGTH - 1) - clclength = CLC_LENGTH - 1; + if (clclength > HVCS_CLC_LENGTH) + clclength = HVCS_CLC_LENGTH; /* copy the null-term char too */ strncpy(&hvcsd->p_location_code[0], @@ -711,20 +757,18 @@ static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) */ static int hvcs_get_pi(struct hvcs_struct *hvcsd) { - /* struct hvcs_partner_info *head_pi = NULL; */ - struct hvcs_partner_info *pi = NULL; - unsigned int unit_address = hvcsd->vdev->unit_address; + struct hvcs_partner_info *pi; + uint32_t unit_address = hvcsd->vdev->unit_address; struct list_head head; - unsigned long flags; int retval; - spin_lock_irqsave(&hvcs_pi_lock, flags); + spin_lock(&hvcs_pi_lock); if (!hvcs_pi_buff) { - spin_unlock_irqrestore(&hvcs_pi_lock, flags); + spin_unlock(&hvcs_pi_lock); return -EFAULT; } retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff); - spin_unlock_irqrestore(&hvcs_pi_lock, flags); + spin_unlock(&hvcs_pi_lock); if (retval) { printk(KERN_ERR "HVCS: Failed to fetch partner" " info for vty-server@%x.\n", unit_address); @@ -748,11 +792,10 @@ static int hvcs_get_pi(struct hvcs_struct *hvcsd) */ static int hvcs_rescan_devices_list(void) { - struct hvcs_struct *hvcsd = NULL; + struct hvcs_struct *hvcsd; unsigned long flags; - unsigned long structs_flags; - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); + spin_lock(&hvcs_structs_lock); list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); @@ -760,7 +803,7 @@ static int hvcs_rescan_devices_list(void) spin_unlock_irqrestore(&hvcsd->lock, flags); } - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); return 0; } @@ -848,13 +891,14 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, unsigned int irq, struct vio_dev *vdev) { unsigned long flags; + int rc; /* * It is possible that the vty-server was removed between the time that * the conn was registered and now. */ - if (!request_irq(irq, &hvcs_handle_interrupt, - SA_INTERRUPT, "ibmhvcs", hvcsd)) { + if (!(rc = request_irq(irq, &hvcs_handle_interrupt, + SA_INTERRUPT, "ibmhvcs", hvcsd))) { /* * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. @@ -874,7 +918,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, hvcs_partner_free(hvcsd); spin_unlock_irqrestore(&hvcsd->lock, flags); - return -ENODEV; + return rc; } @@ -888,22 +932,17 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, struct hvcs_struct *hvcs_get_by_index(int index) { struct hvcs_struct *hvcsd = NULL; - struct list_head *element; - struct list_head *safe_temp; unsigned long flags; - unsigned long structs_flags; - spin_lock_irqsave(&hvcs_structs_lock, structs_flags); + spin_lock(&hvcs_structs_lock); /* We can immediately discard OOB requests */ if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { - list_for_each_safe(element, safe_temp, &hvcs_structs) { - hvcsd = list_entry(element, struct hvcs_struct, next); + list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { kobject_get(&hvcsd->kobj); spin_unlock_irqrestore(&hvcsd->lock, flags); - spin_unlock_irqrestore(&hvcs_structs_lock, - structs_flags); + spin_unlock(&hvcs_structs_lock); return hvcsd; } spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -911,7 +950,7 @@ struct hvcs_struct *hvcs_get_by_index(int index) hvcsd = NULL; } - spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags); + spin_unlock(&hvcs_structs_lock); return hvcsd; } @@ -921,12 +960,13 @@ struct hvcs_struct *hvcs_get_by_index(int index) */ static int hvcs_open(struct tty_struct *tty, struct file *filp) { - struct hvcs_struct *hvcsd = NULL; - int retval = 0; + struct hvcs_struct *hvcsd; + int rc, retval = 0; unsigned long flags; unsigned int irq; struct vio_dev *vdev; unsigned long unit_address; + struct kobject *kobjp; if (tty->driver_data) goto fast_open; @@ -936,7 +976,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * This function increments the kobject index. */ if (!(hvcsd = hvcs_get_by_index(tty->index))) { - printk(KERN_WARNING "HVCS: open failed, no index.\n"); + printk(KERN_WARNING "HVCS: open failed, no device associated" + " with tty->index %d.\n", tty->index); return -ENODEV; } @@ -959,7 +1000,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) */ tty->low_latency = 1; - memset(&hvcsd->buffer[0], 0x3F, HVCS_BUFF_LEN); + memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); /* * Save these in the spinlock for the enable operations that need them @@ -974,12 +1015,12 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) /* * This must be done outside of the spinlock because it requests irqs - * and will grab the spinlcok and free the connection if it fails. + * and will grab the spinlock and free the connection if it fails. */ - if ((hvcs_enable_device(hvcsd, unit_address, irq, vdev))) { + if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { kobject_put(&hvcsd->kobj); printk(KERN_WARNING "HVCS: enable device failed.\n"); - return -ENODEV; + return rc; } goto open_success; @@ -1002,16 +1043,17 @@ fast_open: open_success: hvcs_kick(); - printk(KERN_INFO "HVCS: vty-server@%X opened.\n", + printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", hvcsd->vdev->unit_address ); return 0; error_release: + kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); kobject_put(&hvcsd->kobj); - printk(KERN_WARNING "HVCS: HVCS partner connect failed.\n"); + printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; } @@ -1020,6 +1062,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) struct hvcs_struct *hvcsd; unsigned long flags; struct kobject *kobjp; + int irq = NO_IRQ; /* * Is someone trying to close the file associated with this device after @@ -1039,14 +1082,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); + kobjp = &hvcsd->kobj; if (--hvcsd->open_count == 0) { - /* - * This line is important because it tells hvcs_open that this - * device needs to be re-configured the next time hvcs_open is - * called. - */ - hvcsd->tty->driver_data = NULL; + vio_disable_interrupts(hvcsd->vdev); /* * NULL this early so that the kernel_thread doesn't try to @@ -1055,34 +1094,28 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) */ hvcsd->tty = NULL; - /* - * Block the close until all the buffered data has been - * delivered. - */ - while(hvcsd->chars_in_buffer) { - spin_unlock_irqrestore(&hvcsd->lock, flags); + irq = hvcsd->vdev->irq; + spin_unlock_irqrestore(&hvcsd->lock, flags); - /* - * Give the kernel thread the hvcs_struct so that it can - * try to deliver the remaining data but block the close - * operation by spinning in this function so that other - * tty operations have to wait. - */ - yield(); - spin_lock_irqsave(&hvcsd->lock, flags); - } + tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); - hvcs_final_close(hvcsd); + /* + * This line is important because it tells hvcs_open that this + * device needs to be re-configured the next time hvcs_open is + * called. + */ + tty->driver_data = NULL; + free_irq(irq, hvcsd); + kobject_put(kobjp); + return; } else if (hvcsd->open_count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->open_count); + hvcsd->vdev->unit_address, hvcsd->open_count); } - kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(kobjp); } @@ -1092,6 +1125,7 @@ static void hvcs_hangup(struct tty_struct * tty) unsigned long flags; int temp_open_count; struct kobject *kobjp; + int irq = NO_IRQ; spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kobject refs to put */ @@ -1101,15 +1135,31 @@ static void hvcs_hangup(struct tty_struct * tty) * Don't kobject put inside the spinlock because the destruction * callback may use the spinlock and it may get called before the * spinlock has been released. Get a pointer to the kobject and - * kobject_put on that instead. + * kobject_put on that after releasing the spinlock. */ kobjp = &hvcsd->kobj; - /* Calling this will drop any buffered data on the floor. */ - hvcs_final_close(hvcsd); + vio_disable_interrupts(hvcsd->vdev); + + hvcsd->todo_mask = 0; + + /* I don't think the tty needs the hvcs_struct pointer after a hangup */ + hvcsd->tty->driver_data = NULL; + hvcsd->tty = NULL; + + hvcsd->open_count = 0; + + /* This will drop any buffered data on the floor which is OK in a hangup + * scenario. */ + memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); + hvcsd->chars_in_buffer = 0; + + irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); + free_irq(irq, hvcsd); + /* * We need to kobject_put() for every open_count we have since the * tty_hangup() function doesn't invoke a close per open connection on a @@ -1259,28 +1309,18 @@ static int hvcs_write(struct tty_struct *tty, int from_user, static int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - int retval; if (!hvcsd || hvcsd->open_count <= 0) return 0; - spin_lock_irqsave(&hvcsd->lock, flags); - retval = HVCS_BUFF_LEN - hvcsd->chars_in_buffer; - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; + return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; } static int hvcs_chars_in_buffer(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - int retval; - spin_lock_irqsave(&hvcsd->lock, flags); - retval = hvcsd->chars_in_buffer; - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; + return hvcsd->chars_in_buffer; } static struct tty_operations hvcs_ops = { @@ -1294,6 +1334,28 @@ static struct tty_operations hvcs_ops = { .throttle = hvcs_throttle, }; +static int hvcs_alloc_index_list(int n) +{ + int i; + hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); + if (!hvcs_index_list) + return -ENOMEM; + hvcs_index_count = n; + for(i = 0; i < hvcs_index_count; i++) + hvcs_index_list[i] = -1; + return 0; +} + +static void hvcs_free_index_list(void) +{ + /* Paranoia check to be thorough. */ + if (hvcs_index_list) { + kfree(hvcs_index_list); + hvcs_index_list = NULL; + hvcs_index_count = 0; + } +} + static int __init hvcs_module_init(void) { int rc; @@ -1312,6 +1374,9 @@ static int __init hvcs_module_init(void) if (!hvcs_tty_driver) return -ENOMEM; + if (hvcs_alloc_index_list(num_ttys_to_alloc)) + return -ENOMEM; + hvcs_tty_driver->owner = THIS_MODULE; hvcs_tty_driver->driver_name = hvcs_driver_name; @@ -1342,19 +1407,25 @@ static int __init hvcs_module_init(void) if (tty_register_driver(hvcs_tty_driver)) { printk(KERN_ERR "HVCS: registration " " as a tty driver failed.\n"); + hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); - return rc; + return -EIO; } - hvcs_structs_lock = SPIN_LOCK_UNLOCKED; - - hvcs_pi_lock = SPIN_LOCK_UNLOCKED; hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!hvcs_pi_buff) { + tty_unregister_driver(hvcs_tty_driver); + hvcs_free_index_list(); + put_tty_driver(hvcs_tty_driver); + return -ENOMEM; + } hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); if (IS_ERR(hvcs_task)) { - printk("khvcsd creation failed. Driver not loaded.\n"); + printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); kfree(hvcs_pi_buff); + tty_unregister_driver(hvcs_tty_driver); + hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); return -EIO; } @@ -1374,8 +1445,6 @@ static int __init hvcs_module_init(void) static void __exit hvcs_module_exit(void) { - unsigned long flags; - /* * This driver receives hvcs_remove callbacks for each device upon * module removal. @@ -1387,10 +1456,10 @@ static void __exit hvcs_module_exit(void) */ kthread_stop(hvcs_task); - spin_lock_irqsave(&hvcs_pi_lock, flags); + spin_lock(&hvcs_pi_lock); kfree(hvcs_pi_buff); hvcs_pi_buff = NULL; - spin_unlock_irqrestore(&hvcs_pi_lock, flags); + spin_unlock(&hvcs_pi_lock); hvcs_remove_driver_attrs(); @@ -1398,6 +1467,8 @@ static void __exit hvcs_module_exit(void) tty_unregister_driver(hvcs_tty_driver); + hvcs_free_index_list(); + put_tty_driver(hvcs_tty_driver); printk(KERN_INFO "HVCS: driver module removed.\n"); @@ -1499,7 +1570,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf, " partner vty@%X:%d connection.\n", hvcsd->vdev->unit_address, hvcsd->p_unit_address, - (unsigned int)hvcsd->p_partition_ID); + (uint32_t)hvcsd->p_partition_ID); spin_unlock_irqrestore(&hvcsd->lock, flags); return count; @@ -1520,11 +1591,27 @@ static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf) static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, hvcs_vterm_state_show, hvcs_vterm_state_store); +static ssize_t hvcs_index_show(struct device *dev, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%d\n", hvcsd->index); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} + +static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); + static struct attribute *hvcs_attrs[] = { &dev_attr_partner_vtys.attr, &dev_attr_partner_clcs.attr, &dev_attr_current_vty.attr, &dev_attr_vterm_state.attr, + &dev_attr_index.attr, NULL, }; diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c new file mode 100644 index 000000000..595079c07 --- /dev/null +++ b/drivers/char/hvsi.c @@ -0,0 +1,1319 @@ +/* + * Copyright (C) 2004 Hollis Blanchard , IBM + * + * 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 + */ + +/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS + * and the service processor on IBM pSeries servers. On these servers, there + * are no serial ports under the OS's control, and sometimes there is no other + * console available either. However, the service processor has two standard + * serial ports, so this over-complicated protocol allows the OS to control + * those ports by proxy. + * + * Besides data, the procotol supports the reading/writing of the serial + * port's DTR line, and the reading of the CD line. This is to allow the OS to + * control a modem attached to the service processor's serial port. Note that + * the OS cannot change the speed of the port through this protocol. + */ + +/* TODO: + * test FSP reset + * add udbg support for xmon/kdb + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HVSI_MAJOR 229 +#define HVSI_MINOR 128 +#define MAX_NR_HVSI_CONSOLES 4 + +#define HVSI_TIMEOUT (5*HZ) +#define HVSI_VERSION 1 +#define HVSI_MAX_PACKET 256 +#define HVSI_MAX_READ 16 +#define HVSI_MAX_OUTGOING_DATA 12 +#define N_OUTBUF 12 + +/* + * we pass data via two 8-byte registers, so we would like our char arrays + * properly aligned for those loads. + */ +#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) + +struct hvsi_struct { + struct work_struct writer; + wait_queue_head_t emptyq; /* woken when outbuf is emptied */ + wait_queue_head_t stateq; /* woken when HVSI state changes */ + spinlock_t lock; + int index; + struct tty_struct *tty; + unsigned int count; + uint8_t throttle_buf[128]; + uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ + /* inbuf is for packet reassembly. leave a little room for leftovers. */ + uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ]; + uint8_t *inbuf_end; + int n_throttle; + int n_outbuf; + uint32_t vtermno; + uint32_t virq; + atomic_t seqno; /* HVSI packet sequence number */ + uint16_t mctrl; + uint8_t state; /* HVSI protocol state */ + uint8_t flags; +#ifdef CONFIG_MAGIC_SYSRQ + uint8_t sysrq; +#endif /* CONFIG_MAGIC_SYSRQ */ +}; +static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES]; + +static struct tty_driver *hvsi_driver; +static int hvsi_count; +static int (*hvsi_wait)(struct hvsi_struct *hp, int state); + +enum HVSI_PROTOCOL_STATE { + HVSI_CLOSED, + HVSI_WAIT_FOR_VER_RESPONSE, + HVSI_WAIT_FOR_VER_QUERY, + HVSI_OPEN, + HVSI_WAIT_FOR_MCTRL_RESPONSE, +}; +#define HVSI_CONSOLE 0x1 + +#define VS_DATA_PACKET_HEADER 0xff +#define VS_CONTROL_PACKET_HEADER 0xfe +#define VS_QUERY_PACKET_HEADER 0xfd +#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc + +/* control verbs */ +#define VSV_SET_MODEM_CTL 1 /* to service processor only */ +#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */ +#define VSV_CLOSE_PROTOCOL 3 + +/* query verbs */ +#define VSV_SEND_VERSION_NUMBER 1 +#define VSV_SEND_MODEM_CTL_STATUS 2 + +/* yes, these masks are not consecutive. */ +#define HVSI_TSDTR 0x01 +#define HVSI_TSCD 0x20 + +struct hvsi_header { + uint8_t type; + uint8_t len; + uint16_t seqno; +} __attribute__((packed)); + +struct hvsi_data { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint8_t data[HVSI_MAX_OUTGOING_DATA]; +} __attribute__((packed)); + +struct hvsi_control { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; + /* optional depending on verb: */ + uint32_t word; + uint32_t mask; +} __attribute__((packed)); + +struct hvsi_query { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; +} __attribute__((packed)); + +struct hvsi_query_response { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; + uint16_t query_seqno; + union { + uint8_t version; + uint32_t mctrl_word; + } u; +} __attribute__((packed)); + +static inline int is_open(struct hvsi_struct *hp) +{ + /* if we're waiting for an mctrl then we're already open */ + return (hp->state == HVSI_OPEN) + || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE); +} + +static inline void print_state(struct hvsi_struct *hp) +{ +#ifdef DEBUG + static const char *state_names[] = { + "HVSI_CLOSED", + "HVSI_WAIT_FOR_VER_RESPONSE", + "HVSI_WAIT_FOR_VER_QUERY", + "HVSI_OPEN", + "HVSI_WAIT_FOR_MCTRL_RESPONSE", + }; + const char *name = state_names[hp->state]; + + if (hp->state > (sizeof(state_names)/sizeof(char*))) + name = "UNKNOWN"; + + pr_debug("hvsi%i: state = %s\n", hp->index, name); +#endif /* DEBUG */ +} + +static inline void __set_state(struct hvsi_struct *hp, int state) +{ + hp->state = state; + print_state(hp); + wake_up_all(&hp->stateq); +} + +static inline void set_state(struct hvsi_struct *hp, int state) +{ + unsigned long flags; + + spin_lock_irqsave(&hp->lock, flags); + __set_state(hp, state); + spin_unlock_irqrestore(&hp->lock, flags); +} + +static inline int len_packet(const uint8_t *packet) +{ + return (int)((struct hvsi_header *)packet)->len; +} + +static inline int is_header(const uint8_t *packet) +{ + struct hvsi_header *header = (struct hvsi_header *)packet; + return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER; +} + +static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet) +{ + if (hp->inbuf_end < packet + sizeof(struct hvsi_header)) + return 0; /* don't even have the packet header */ + + if (hp->inbuf_end < (packet + len_packet(packet))) + return 0; /* don't have the rest of the packet */ + + return 1; +} + +/* shift remaining bytes in packetbuf down */ +static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to) +{ + int remaining = (int)(hp->inbuf_end - read_to); + + pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining); + + if (read_to != hp->inbuf) + memmove(hp->inbuf, read_to, remaining); + + hp->inbuf_end = hp->inbuf + remaining; +} + +#ifdef DEBUG +#define dbg_dump_packet(packet) dump_packet(packet) +#define dbg_dump_hex(data, len) dump_hex(data, len) +#else +#define dbg_dump_packet(packet) do { } while (0) +#define dbg_dump_hex(data, len) do { } while (0) +#endif + +static void dump_hex(const uint8_t *data, int len) +{ + int i; + + printk(" "); + for (i=0; i < len; i++) + printk("%.2x", data[i]); + + printk("\n "); + for (i=0; i < len; i++) { + if (isprint(data[i])) + printk("%c", data[i]); + else + printk("."); + } + printk("\n"); +} + +static void dump_packet(uint8_t *packet) +{ + struct hvsi_header *header = (struct hvsi_header *)packet; + + printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len, + header->seqno); + + dump_hex(packet, header->len); +} + +/* can't use hvc_get_chars because that strips CRs */ +static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) +{ + unsigned long got; + + if (plpar_hcall(H_GET_TERM_CHAR, hp->vtermno, 0, 0, 0, &got, + (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) + return got; + return 0; +} + +/* + * we can't call tty_hangup() directly here because we need to call that + * outside of our lock + */ +static struct tty_struct *hvsi_recv_control(struct hvsi_struct *hp, + uint8_t *packet) +{ + struct tty_struct *to_hangup = NULL; + struct hvsi_control *header = (struct hvsi_control *)packet; + + switch (header->verb) { + case VSV_MODEM_CTL_UPDATE: + if ((header->word & HVSI_TSCD) == 0) { + /* CD went away; no more connection */ + pr_debug("hvsi%i: CD dropped\n", hp->index); + hp->mctrl &= TIOCM_CD; + if (!(hp->tty->flags & CLOCAL)) + to_hangup = hp->tty; + } + break; + case VSV_CLOSE_PROTOCOL: + printk(KERN_DEBUG + "hvsi%i: service processor closed connection!\n", hp->index); + __set_state(hp, HVSI_CLOSED); + to_hangup = hp->tty; + hp->tty = NULL; + break; + default: + printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ", + hp->index); + dump_packet(packet); + break; + } + + return to_hangup; +} + +static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet) +{ + struct hvsi_query_response *resp = (struct hvsi_query_response *)packet; + + switch (hp->state) { + case HVSI_WAIT_FOR_VER_RESPONSE: + __set_state(hp, HVSI_WAIT_FOR_VER_QUERY); + break; + case HVSI_WAIT_FOR_MCTRL_RESPONSE: + hp->mctrl = 0; + if (resp->u.mctrl_word & HVSI_TSDTR) + hp->mctrl |= TIOCM_DTR; + if (resp->u.mctrl_word & HVSI_TSCD) + hp->mctrl |= TIOCM_CD; + __set_state(hp, HVSI_OPEN); + break; + default: + printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index); + dump_packet(packet); + break; + } +} + +/* respond to service processor's version query */ +static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) +{ + struct hvsi_query_response packet __ALIGNED__; + int wrote; + + packet.type = VS_QUERY_RESPONSE_PACKET_HEADER; + packet.len = sizeof(struct hvsi_query_response); + packet.seqno = atomic_inc_return(&hp->seqno); + packet.verb = VSV_SEND_VERSION_NUMBER; + packet.u.version = HVSI_VERSION; + packet.query_seqno = query_seqno+1; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't send query response!\n", + hp->index); + return -EIO; + } + + return 0; +} + +static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) +{ + struct hvsi_query *query = (struct hvsi_query *)packet; + + switch (hp->state) { + case HVSI_WAIT_FOR_VER_QUERY: + __set_state(hp, HVSI_OPEN); + hvsi_version_respond(hp, query->seqno); + break; + default: + printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index); + dump_packet(packet); + break; + } +} + +static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +{ + int i; + + for (i=0; i < len; i++) { + char c = buf[i]; +#ifdef CONFIG_MAGIC_SYSRQ + if (c == '\0') { + hp->sysrq = 1; + continue; + } else if (hp->sysrq) { + handle_sysrq(c, NULL, hp->tty); + hp->sysrq = 0; + continue; + } +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(hp->tty, c, 0); + } +} + +/* + * We could get 252 bytes of data at once here. But the tty layer only + * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow + * it. Accordingly we won't send more than 128 bytes at a time to the flip + * buffer, which will give the tty buffer a chance to throttle us. Should the + * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be + * revisited. + */ +#define TTY_THRESHOLD_THROTTLE 128 +static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, + const uint8_t *packet) +{ + const struct hvsi_header *header = (const struct hvsi_header *)packet; + const uint8_t *data = packet + sizeof(struct hvsi_header); + int datalen = header->len - sizeof(struct hvsi_header); + int overflow = datalen - TTY_THRESHOLD_THROTTLE; + + pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); + + if (datalen == 0) + return NULL; + + if (overflow > 0) { + pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__); + datalen = TTY_THRESHOLD_THROTTLE; + } + + hvsi_insert_chars(hp, data, datalen); + + if (overflow > 0) { + /* + * we still have more data to deliver, so we need to save off the + * overflow and send it later + */ + pr_debug("%s: deferring overflow\n", __FUNCTION__); + memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow); + hp->n_throttle = overflow; + } + + return hp->tty; +} + +/* + * Returns true/false indicating data successfully read from hypervisor. + * Used both to get packets for tty connections and to advance the state + * machine during console handshaking (in which case tty = NULL and we ignore + * incoming data). + */ +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, + struct tty_struct **hangup) +{ + uint8_t *packet = hp->inbuf; + int chunklen; + + *flip = NULL; + *hangup = NULL; + + chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); + if (chunklen == 0) + return 0; + + pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen); + dbg_dump_hex(hp->inbuf_end, chunklen); + + hp->inbuf_end += chunklen; + + /* handle all completed packets */ + while ((packet < hp->inbuf_end) && got_packet(hp, packet)) { + struct hvsi_header *header = (struct hvsi_header *)packet; + + if (!is_header(packet)) { + printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index); + /* skip bytes until we find a header or run out of data */ + while ((packet < hp->inbuf_end) && (!is_header(packet))) + packet++; + continue; + } + + pr_debug("%s: handling %i-byte packet\n", __FUNCTION__, + len_packet(packet)); + dbg_dump_packet(packet); + + switch (header->type) { + case VS_DATA_PACKET_HEADER: + if (!is_open(hp)) + break; + if (hp->tty == NULL) + break; /* no tty buffer to put data in */ + *flip = hvsi_recv_data(hp, packet); + break; + case VS_CONTROL_PACKET_HEADER: + *hangup = hvsi_recv_control(hp, packet); + break; + case VS_QUERY_RESPONSE_PACKET_HEADER: + hvsi_recv_response(hp, packet); + break; + case VS_QUERY_PACKET_HEADER: + hvsi_recv_query(hp, packet); + break; + default: + printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n", + hp->index, header->type); + dump_packet(packet); + break; + } + + packet += len_packet(packet); + + if (*hangup) { + pr_debug("%s: hangup\n", __FUNCTION__); + /* + * we need to send the hangup now before receiving any more data. + * If we get "data, hangup, data", we can't deliver the second + * data before the hangup. + */ + break; + } + } + + compact_inbuf(hp, packet); + + return 1; +} + +static void hvsi_send_overflow(struct hvsi_struct *hp) +{ + pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__, + hp->n_throttle); + + hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); + hp->n_throttle = 0; +} + +/* + * must get all pending data because we only get an irq on empty->non-empty + * transition + */ +static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct tty_struct *flip; + struct tty_struct *hangup; + unsigned long flags; + irqreturn_t handled = IRQ_NONE; + int again = 1; + + pr_debug("%s\n", __FUNCTION__); + + while (again) { + spin_lock_irqsave(&hp->lock, flags); + again = hvsi_load_chunk(hp, &flip, &hangup); + handled = IRQ_HANDLED; + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * we have to call tty_flip_buffer_push() and tty_hangup() outside our + * spinlock. But we also have to keep going until we've read all the + * available data. + */ + + if (flip) { + /* there was data put in the tty flip buffer */ + tty_flip_buffer_push(flip); + flip = NULL; + } + + if (hangup) { + tty_hangup(hangup); + } + } + + spin_lock_irqsave(&hp->lock, flags); + if (hp->tty && hp->n_throttle + && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { + /* we weren't hung up and we weren't throttled, so we can deliver the + * rest now */ + flip = hp->tty; + hvsi_send_overflow(hp); + } + spin_unlock_irqrestore(&hp->lock, flags); + + if (flip) { + tty_flip_buffer_push(flip); + } + + return handled; +} + +/* for boot console, before the irq handler is running */ +static int __init poll_for_state(struct hvsi_struct *hp, int state) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + + for (;;) { + hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */ + + if (hp->state == state) + return 0; + + mdelay(5); + if (time_after(jiffies, end_jiffies)) + return -EIO; + } +} + +/* wait for irq handler to change our state */ +static int wait_for_state(struct hvsi_struct *hp, int state) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + unsigned long timeout; + int ret = 0; + + DECLARE_WAITQUEUE(myself, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&hp->stateq, &myself); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (hp->state == state) + break; + timeout = end_jiffies - jiffies; + if (time_after(jiffies, end_jiffies)) { + ret = -EIO; + break; + } + schedule_timeout(timeout); + } + remove_wait_queue(&hp->stateq, &myself); + set_current_state(TASK_RUNNING); + + return ret; +} + +static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) +{ + struct hvsi_query packet __ALIGNED__; + int wrote; + + packet.type = VS_QUERY_PACKET_HEADER; + packet.len = sizeof(struct hvsi_query); + packet.seqno = atomic_inc_return(&hp->seqno); + packet.verb = verb; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index, + wrote); + return -EIO; + } + + return 0; +} + +static int hvsi_get_mctrl(struct hvsi_struct *hp) +{ + int ret; + + set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE); + hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS); + + ret = hvsi_wait(hp, HVSI_OPEN); + if (ret < 0) { + printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index); + set_state(hp, HVSI_OPEN); + return ret; + } + + pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl); + + return 0; +} + +/* note that we can only set DTR */ +static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) +{ + struct hvsi_control packet __ALIGNED__; + int wrote; + + packet.type = VS_CONTROL_PACKET_HEADER, + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = sizeof(struct hvsi_control); + packet.verb = VSV_SET_MODEM_CTL; + packet.mask = HVSI_TSDTR; + + if (mctrl & TIOCM_DTR) + packet.word = HVSI_TSDTR; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index); + return -EIO; + } + + return 0; +} + +static void hvsi_drain_input(struct hvsi_struct *hp) +{ + uint8_t buf[HVSI_MAX_READ] __ALIGNED__; + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + + while (time_before(end_jiffies, jiffies)) + if (0 == hvsi_read(hp, buf, HVSI_MAX_READ)) + break; +} + +static int hvsi_handshake(struct hvsi_struct *hp) +{ + int ret; + + /* + * We could have a CLOSE or other data waiting for us before we even try + * to open; try to throw it all away so we don't get confused. (CLOSE + * is the first message sent up the pipe when the FSP comes online. We + * need to distinguish between "it came up a while ago and we're the first + * user" and "it was just reset before it saw our handshake packet".) + */ + hvsi_drain_input(hp); + + set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE); + ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER); + if (ret < 0) { + printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index); + return ret; + } + + ret = hvsi_wait(hp, HVSI_OPEN); + if (ret < 0) + return ret; + + return 0; +} + +static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) +{ + struct hvsi_data packet __ALIGNED__; + int ret; + + BUG_ON(count > HVSI_MAX_OUTGOING_DATA); + + packet.type = VS_DATA_PACKET_HEADER; + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = count + sizeof(struct hvsi_header); + memcpy(&packet.data, buf, count); + + ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (ret == packet.len) { + /* return the number of chars written, not the packet length */ + return count; + } + return ret; /* return any errors */ +} + +static void hvsi_close_protocol(struct hvsi_struct *hp) +{ + struct hvsi_control packet __ALIGNED__; + + packet.type = VS_CONTROL_PACKET_HEADER; + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = 6; + packet.verb = VSV_CLOSE_PROTOCOL; + + pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); +} + +static int hvsi_open(struct tty_struct *tty, struct file *filp) +{ + struct hvsi_struct *hp; + unsigned long flags; + int line = tty->index; + int ret; + + pr_debug("%s\n", __FUNCTION__); + + if (line < 0 || line >= hvsi_count) + return -ENODEV; + hp = &hvsi_ports[line]; + + tty->driver_data = hp; + tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */ + + spin_lock_irqsave(&hp->lock, flags); + hp->tty = tty; + hp->count++; + atomic_set(&hp->seqno, 0); + h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); + spin_unlock_irqrestore(&hp->lock, flags); + + if (hp->flags & HVSI_CONSOLE) + return 0; /* this has already been handshaked as the console */ + + ret = hvsi_handshake(hp); + if (ret < 0) { + printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name); + return ret; + } + + ret = hvsi_get_mctrl(hp); + if (ret < 0) { + printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name); + return ret; + } + + ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); + if (ret < 0) { + printk(KERN_ERR "%s: couldn't set DTR\n", tty->name); + return ret; + } + + return 0; +} + +/* wait for hvsi_write_worker to empty hp->outbuf */ +static void hvsi_flush_output(struct hvsi_struct *hp) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + unsigned long timeout; + + DECLARE_WAITQUEUE(myself, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&hp->emptyq, &myself); + + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (hp->n_outbuf <= 0) + break; + timeout = end_jiffies - jiffies; + if (time_after(jiffies, end_jiffies)) + break; + schedule_timeout(timeout); + } + remove_wait_queue(&hp->emptyq, &myself); + set_current_state(TASK_RUNNING); + + /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ + cancel_delayed_work(&hp->writer); + flush_scheduled_work(); + + /* + * it's also possible that our timeout expired and hvsi_write_worker + * didn't manage to push outbuf. poof. + */ + hp->n_outbuf = 0; +} + +static void hvsi_close(struct tty_struct *tty, struct file *filp) +{ + struct hvsi_struct *hp = tty->driver_data; + unsigned long flags; + + pr_debug("%s\n", __FUNCTION__); + + if (tty_hung_up_p(filp)) + return; + + spin_lock_irqsave(&hp->lock, flags); + + if (--hp->count == 0) { + hp->tty = NULL; + hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ + + /* only close down connection if it is not the console */ + if (!(hp->flags & HVSI_CONSOLE)) { + h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */ + __set_state(hp, HVSI_CLOSED); + /* + * any data delivered to the tty layer after this will be + * discarded (except for XON/XOFF) + */ + tty->closing = 1; + + spin_unlock_irqrestore(&hp->lock, flags); + + /* let any existing irq handlers finish. no more will start. */ + synchronize_irq(hp->virq); + + /* hvsi_write_worker will re-schedule until outbuf is empty. */ + hvsi_flush_output(hp); + + /* tell FSP to stop sending data */ + hvsi_close_protocol(hp); + + /* + * drain anything FSP is still in the middle of sending, and let + * hvsi_handshake drain the rest on the next open. + */ + hvsi_drain_input(hp); + + spin_lock_irqsave(&hp->lock, flags); + } + } else if (hp->count < 0) + printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", + hp - hvsi_ports, hp->count); + + spin_unlock_irqrestore(&hp->lock, flags); +} + +static void hvsi_hangup(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + + pr_debug("%s\n", __FUNCTION__); + + hp->count = 0; + hp->tty = NULL; +} + +/* called with hp->lock held */ +static void hvsi_push(struct hvsi_struct *hp) +{ + int n; + + if (hp->n_outbuf <= 0) + return; + + n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf); + if (n != 0) { + /* + * either all data was sent or there was an error, and we throw away + * data on error. + */ + hp->n_outbuf = 0; + } +} + +/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ +static void hvsi_write_worker(void *arg) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)arg; + unsigned long flags; +#ifdef DEBUG + static long start_j = 0; + + if (start_j == 0) + start_j = jiffies; +#endif /* DEBUG */ + + spin_lock_irqsave(&hp->lock, flags); + + hvsi_push(hp); + if (hp->n_outbuf > 0) + schedule_delayed_work(&hp->writer, 10); + else { +#ifdef DEBUG + pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__, + jiffies - start_j); + start_j = 0; +#endif /* DEBUG */ + wake_up_all(&hp->emptyq); + if (test_bit(TTY_DO_WRITE_WAKEUP, &hp->tty->flags) + && hp->tty->ldisc.write_wakeup) + hp->tty->ldisc.write_wakeup(hp->tty); + wake_up_interruptible(&hp->tty->write_wait); + } + + spin_unlock_irqrestore(&hp->lock, flags); +} + +static int hvsi_write_room(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + return N_OUTBUF - hp->n_outbuf; +} + +static int hvsi_chars_in_buffer(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + return hp->n_outbuf; +} + +static int hvsi_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct hvsi_struct *hp = tty->driver_data; + const char *source = buf; + char *kbuf = NULL; + unsigned long flags; + int total = 0; + int origcount = count; + + if (from_user) { + kbuf = kmalloc(count, GFP_KERNEL); + if (kbuf == NULL) + return -ENOMEM; + if (copy_from_user(kbuf, buf, count)) { + kfree(kbuf); + return -EFAULT; + } + source = kbuf; + } + + spin_lock_irqsave(&hp->lock, flags); + + if (!is_open(hp)) { + /* we're either closing or not yet open; don't accept data */ + pr_debug("%s: not open\n", __FUNCTION__); + goto out; + } + + /* + * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf + * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls + * will see there is no room in outbuf and return. + */ + while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { + int chunksize = min(count, hvsi_write_room(hp->tty)); + + BUG_ON(hp->n_outbuf < 0); + memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); + hp->n_outbuf += chunksize; + + total += chunksize; + source += chunksize; + count -= chunksize; + hvsi_push(hp); + } + + if (hp->n_outbuf > 0) { + /* + * we weren't able to write it all to the hypervisor. + * schedule another push attempt. + */ + schedule_delayed_work(&hp->writer, 10); + } + +out: + spin_unlock_irqrestore(&hp->lock, flags); + + if (from_user) + kfree(kbuf); + + if (total != origcount) + pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount, + total); + + return total; +} + +/* + * I have never seen throttle or unthrottle called, so this little throttle + * buffering scheme may or may not work. + */ +static void hvsi_throttle(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + pr_debug("%s\n", __FUNCTION__); + + h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); +} + +static void hvsi_unthrottle(struct tty_struct *tty) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + unsigned long flags; + int shouldflip = 0; + + pr_debug("%s\n", __FUNCTION__); + + spin_lock_irqsave(&hp->lock, flags); + if (hp->n_throttle) { + hvsi_send_overflow(hp); + shouldflip = 1; + } + spin_unlock_irqrestore(&hp->lock, flags); + + if (shouldflip) + tty_flip_buffer_push(hp->tty); + + h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); +} + +static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + + hvsi_get_mctrl(hp); + return hp->mctrl; +} + +static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; + unsigned long flags; + uint16_t new_mctrl; + + /* we can only alter DTR */ + clear &= TIOCM_DTR; + set &= TIOCM_DTR; + + spin_lock_irqsave(&hp->lock, flags); + + new_mctrl = (hp->mctrl & ~clear) | set; + + if (hp->mctrl != new_mctrl) { + hvsi_set_mctrl(hp, new_mctrl); + hp->mctrl = new_mctrl; + } + spin_unlock_irqrestore(&hp->lock, flags); + + return 0; +} + + +static struct tty_operations hvsi_ops = { + .open = hvsi_open, + .close = hvsi_close, + .write = hvsi_write, + .hangup = hvsi_hangup, + .write_room = hvsi_write_room, + .chars_in_buffer = hvsi_chars_in_buffer, + .throttle = hvsi_throttle, + .unthrottle = hvsi_unthrottle, + .tiocmget = hvsi_tiocmget, + .tiocmset = hvsi_tiocmset, +}; + +static int __init hvsi_init(void) +{ + int i; + + hvsi_driver = alloc_tty_driver(hvsi_count); + if (!hvsi_driver) + return -ENOMEM; + + hvsi_driver->owner = THIS_MODULE; + hvsi_driver->devfs_name = "hvsi/"; + hvsi_driver->driver_name = "hvsi"; + hvsi_driver->name = "hvsi"; + hvsi_driver->major = HVSI_MAJOR; + hvsi_driver->minor_start = HVSI_MINOR; + hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM; + hvsi_driver->init_termios = tty_std_termios; + hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + hvsi_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(hvsi_driver, &hvsi_ops); + + for (i=0; i < hvsi_count; i++) { + struct hvsi_struct *hp = &hvsi_ports[i]; + int ret = 1; + + ret = request_irq(hp->virq, hvsi_interrupt, SA_INTERRUPT, "hvsi", hp); + if (ret) + printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", + hp->virq, ret); + } + hvsi_wait = wait_for_state; /* irqs active now */ + + if (tty_register_driver(hvsi_driver)) + panic("Couldn't register hvsi console driver\n"); + + printk(KERN_INFO "HVSI: registered %i devices\n", hvsi_count); + + return 0; +} +device_initcall(hvsi_init); + +/***** console (not tty) code: *****/ + +static void hvsi_console_print(struct console *console, const char *buf, + unsigned int count) +{ + struct hvsi_struct *hp = &hvsi_ports[console->index]; + char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__; + unsigned int i = 0, n = 0; + int ret, donecr = 0; + + mb(); + if (!is_open(hp)) + return; + + /* + * ugh, we have to translate LF -> CRLF ourselves, in place. + * copied from hvc_console.c: + */ + while (count > 0 || i > 0) { + if (count > 0 && i < sizeof(c)) { + if (buf[n] == '\n' && !donecr) { + c[i++] = '\r'; + donecr = 1; + } else { + c[i++] = buf[n++]; + donecr = 0; + --count; + } + } else { + ret = hvsi_put_chars(hp, c, i); + if (ret < 0) + i = 0; + i -= ret; + } + } +} + +static struct tty_driver *hvsi_console_device(struct console *console, + int *index) +{ + *index = console->index; + return hvsi_driver; +} + +static int __init hvsi_console_setup(struct console *console, char *options) +{ + struct hvsi_struct *hp = &hvsi_ports[console->index]; + int ret; + + if (console->index < 0 || console->index >= hvsi_count) + return -1; + + /* give the FSP a chance to change the baud rate when we re-open */ + hvsi_close_protocol(hp); + + ret = hvsi_handshake(hp); + if (ret < 0) + return ret; + + ret = hvsi_get_mctrl(hp); + if (ret < 0) + return ret; + + ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); + if (ret < 0) + return ret; + + hp->flags |= HVSI_CONSOLE; + + return 0; +} + +static struct console hvsi_con_driver = { + .name = "hvsi", + .write = hvsi_console_print, + .device = hvsi_console_device, + .setup = hvsi_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int __init hvsi_console_init(void) +{ + struct device_node *vty; + + hvsi_wait = poll_for_state; /* no irqs yet; must poll */ + + /* search device tree for vty nodes */ + for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol"); + vty != NULL; + vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) { + struct hvsi_struct *hp; + uint32_t *vtermno; + uint32_t *irq; + + vtermno = (uint32_t *)get_property(vty, "reg", NULL); + irq = (uint32_t *)get_property(vty, "interrupts", NULL); + if (!vtermno || !irq) + continue; + + if (hvsi_count >= MAX_NR_HVSI_CONSOLES) { + of_node_put(vty); + break; + } + + hp = &hvsi_ports[hvsi_count]; + INIT_WORK(&hp->writer, hvsi_write_worker, hp); + init_waitqueue_head(&hp->emptyq); + init_waitqueue_head(&hp->stateq); + hp->lock = SPIN_LOCK_UNLOCKED; + hp->index = hvsi_count; + hp->inbuf_end = hp->inbuf; + hp->state = HVSI_CLOSED; + hp->vtermno = *vtermno; + hp->virq = virt_irq_create_mapping(irq[0]); + if (hp->virq == NO_IRQ) { + printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", + __FUNCTION__, hp->virq); + continue; + } else + hp->virq = irq_offset_up(hp->virq); + + hvsi_count++; + } + + if (hvsi_count) + register_console(&hvsi_con_driver); + return 0; +} +console_initcall(hvsi_console_init); diff --git a/drivers/char/ip2/ip2types.h b/drivers/char/ip2/ip2types.h index 8d2b37999..9d67b260b 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 ac97e617a..fa3ca6eb5 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/Kconfig b/drivers/char/ipmi/Kconfig index b632538ff..655a17219 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -57,4 +57,11 @@ config IPMI_WATCHDOG help This enables the IPMI watchdog timer. +config IPMI_POWEROFF + tristate 'IPMI Poweroff' + depends on IPMI_HANDLER + help + This enables a function to power off the system with IPMI if + the IPMI management controller is capable of this. + endmenu diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index b7d823072..553f0a408 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o +obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o ipmi_si.o: $(ipmi_si-objs) $(LD) -r -o $@ $(ipmi_si-objs) diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 7295bc559..225b33011 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -31,7 +31,7 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_BT_VERSION "v32" +#define IPMI_BT_VERSION "v33" static int bt_debug = 0x00; /* Production value 0, see following flags */ diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 8d1a08bcc..49d67f538 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -45,7 +45,7 @@ #include #include -#define IPMI_DEVINTF_VERSION "v32" +#define IPMI_DEVINTF_VERSION "v33" struct ipmi_file_private { diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index d155f9a58..48cce2432 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -42,7 +42,7 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_KCS_VERSION "v32" +#define IPMI_KCS_VERSION "v33" /* Set this if you want a printout of why the state machine was hosed when it gets hosed. */ diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 83ae6f530..4191db290 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -46,7 +46,8 @@ #include #include -#define IPMI_MSGHANDLER_VERSION "v32" +#define PFX "IPMI message handler: " +#define IPMI_MSGHANDLER_VERSION "v33" struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -895,6 +896,12 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, return rv; } +void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) +{ + user->intf->handlers->set_run_to_completion(user->intf->send_info, + val); +} + static unsigned char ipmb_checksum(unsigned char *data, int size) { @@ -1686,8 +1693,8 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) intf->curr_channel = IPMI_MAX_CHANNELS; wake_up(&intf->waitq); - printk(KERN_WARNING "ipmi_msghandler: Error sending" - "channel information: %d\n", + printk(KERN_WARNING PFX + "Error sending channel information: %d\n", rv); } } @@ -2351,7 +2358,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, } else { /* There's too many things in the queue, discard this message. */ - printk(KERN_WARNING "ipmi: Event queue full, discarding an" + printk(KERN_WARNING PFX "Event queue full, discarding an" " incoming event\n"); } @@ -2433,10 +2440,34 @@ static int handle_new_recv_msg(ipmi_smi_t intf, #endif if (msg->rsp_size < 2) { /* Message is too small to be correct. */ - requeue = 0; - } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data != NULL)) + printk(KERN_WARNING PFX "BMC returned to small a message" + " for netfn %x cmd %x, got %d bytes\n", + (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); + + /* Generate an error response for the message. */ + msg->rsp[0] = msg->data[0] | (1 << 2); + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = IPMI_ERR_UNSPECIFIED; + msg->rsp_size = 3; + } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */ + || (msg->rsp[1] != msg->data[1])) /* Command */ + { + /* The response is not even marginally correct. */ + printk(KERN_WARNING PFX "BMC returned incorrect response," + " expected netfn %x cmd %x, got netfn %x cmd %x\n", + (msg->data[0] >> 2) | 1, msg->data[1], + msg->rsp[0] >> 2, msg->rsp[1]); + + /* Generate an error response for the message. */ + msg->rsp[0] = msg->data[0] | (1 << 2); + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = IPMI_ERR_UNSPECIFIED; + msg->rsp_size = 3; + } + + if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) + && (msg->rsp[1] == IPMI_SEND_MSG_CMD) + && (msg->user_data != NULL)) { /* It's a response to a response we sent. For this we deliver a send message response to the user. */ @@ -2502,7 +2533,9 @@ static int handle_new_recv_msg(ipmi_smi_t intf, requeue = 0; } - } else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) { + } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) + && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) + { /* It's an asyncronous event. */ requeue = handle_read_event_rsp(intf, msg); } else { @@ -3114,7 +3147,7 @@ static int ipmi_init_msghandler(void) proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { - printk("Unable to create IPMI proc dir"); + printk(KERN_ERR PFX "Unable to create IPMI proc dir"); return -ENOMEM; } @@ -3166,11 +3199,11 @@ static __exit void cleanup_ipmi(void) /* Check for buffer leaks. */ count = atomic_read(&smi_msg_inuse_count); if (count != 0) - printk("ipmi_msghandler: SMI message count %d at exit\n", + printk(KERN_WARNING PFX "SMI message count %d at exit\n", count); count = atomic_read(&recv_msg_inuse_count); if (count != 0) - printk("ipmi_msghandler: recv message count %d at exit\n", + printk(KERN_WARNING PFX "recv message count %d at exit\n", count); } module_exit(cleanup_ipmi); @@ -3207,3 +3240,4 @@ EXPORT_SYMBOL(ipmi_get_my_address); EXPORT_SYMBOL(ipmi_set_my_LUN); EXPORT_SYMBOL(ipmi_get_my_LUN); EXPORT_SYMBOL(ipmi_smi_add_proc_entry); +EXPORT_SYMBOL(ipmi_user_set_run_to_completion); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c new file mode 100644 index 000000000..ade872962 --- /dev/null +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -0,0 +1,543 @@ +/* + * ipmi_poweroff.c + * + * MontaVista IPMI Poweroff extension to sys_reboot + * + * Author: MontaVista Software, Inc. + * Steven Dake + * Corey Minyard + * source@mvista.com + * + * Copyright 2002,2004 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. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include + +#define PFX "IPMI poweroff: " +#define IPMI_POWEROFF_VERSION "v33" + +/* Where to we insert our poweroff function? */ +extern void (*pm_power_off)(void); + +/* Stuff from the get device id command. */ +unsigned int mfg_id; +unsigned int prod_id; +unsigned char capabilities; + +/* We use our own messages for this operation, we don't let the system + allocate them, since we may be in a panic situation. The whole + thing is single-threaded, anyway, so multiple messages are not + required. */ +static void dummy_smi_free(struct ipmi_smi_msg *msg) +{ +} +static void dummy_recv_free(struct ipmi_recv_msg *msg) +{ +} +static struct ipmi_smi_msg halt_smi_msg = +{ + .done = dummy_smi_free +}; +static struct ipmi_recv_msg halt_recv_msg = +{ + .done = dummy_recv_free +}; + + +/* + * Code to send a message and wait for the reponse. + */ + +static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) +{ + struct semaphore *sem = recv_msg->user_msg_data; + + if (sem) + up(sem); +} + +static struct ipmi_user_hndl ipmi_poweroff_handler = +{ + .ipmi_recv_hndl = receive_handler +}; + + +static int ipmi_request_wait_for_response(ipmi_user_t user, + struct ipmi_addr *addr, + struct kernel_ipmi_msg *send_msg) +{ + int rv; + struct semaphore sem; + + sema_init (&sem, 0); + + rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem, + &halt_smi_msg, &halt_recv_msg, 0); + if (rv) + return rv; + + down (&sem); + + return halt_recv_msg.msg.data[0]; +} + +/* We are in run-to-completion mode, no semaphore is desired. */ +static int ipmi_request_in_rc_mode(ipmi_user_t user, + struct ipmi_addr *addr, + struct kernel_ipmi_msg *send_msg) +{ + int rv; + + rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, + &halt_smi_msg, &halt_recv_msg, 0); + if (rv) + return rv; + + return halt_recv_msg.msg.data[0]; +} + +/* + * ATCA Support + */ + +#define IPMI_NETFN_ATCA 0x2c +#define IPMI_ATCA_SET_POWER_CMD 0x11 +#define IPMI_ATCA_GET_ADDR_INFO_CMD 0x01 +#define IPMI_PICMG_ID 0 + +static int ipmi_atca_detect (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[1]; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + /* + * Use get address info to check and see if we are ATCA + */ + send_msg.netfn = IPMI_NETFN_ATCA; + send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD; + data[0] = IPMI_PICMG_ID; + send_msg.data = data; + send_msg.data_len = sizeof(data); + rv = ipmi_request_wait_for_response(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + return !rv; +} + +static void ipmi_poweroff_atca (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[4]; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "Powering down via ATCA power command\n"); + + /* + * Power down + */ + send_msg.netfn = IPMI_NETFN_ATCA; + send_msg.cmd = IPMI_ATCA_SET_POWER_CMD; + data[0] = IPMI_PICMG_ID; + data[1] = 0; /* FRU id */ + data[2] = 0; /* Power Level */ + data[3] = 0; /* Don't change saved presets */ + send_msg.data = data; + send_msg.data_len = sizeof (data); + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) { + printk(KERN_ERR PFX "Unable to send ATCA powerdown message," + " IPMI error 0x%x\n", rv); + goto out; + } + + out: + return; +} + +/* + * CPI1 Support + */ + +#define IPMI_NETFN_OEM_1 0xf8 +#define OEM_GRP_CMD_SET_RESET_STATE 0x84 +#define OEM_GRP_CMD_SET_POWER_STATE 0x82 +#define IPMI_NETFN_OEM_8 0xf8 +#define OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL 0x80 +#define OEM_GRP_CMD_GET_SLOT_GA 0xa3 +#define IPMI_NETFN_SENSOR_EVT 0x10 +#define IPMI_CMD_GET_EVENT_RECEIVER 0x01 + +#define IPMI_CPI1_PRODUCT_ID 0x000157 +#define IPMI_CPI1_MANUFACTURER_ID 0x0108 + +static int ipmi_cpi1_detect (ipmi_user_t user) +{ + return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID) + && (prod_id == IPMI_CPI1_PRODUCT_ID)); +} + +static void ipmi_poweroff_cpi1 (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct ipmi_ipmb_addr ipmb_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[1]; + int slot; + unsigned char hotswap_ipmb; + unsigned char aer_addr; + unsigned char aer_lun; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "Powering down via CPI1 power command\n"); + + /* + * Get IPMI ipmb address + */ + send_msg.netfn = IPMI_NETFN_OEM_8 >> 2; + send_msg.cmd = OEM_GRP_CMD_GET_SLOT_GA; + send_msg.data = NULL; + send_msg.data_len = 0; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + slot = halt_recv_msg.msg.data[1]; + hotswap_ipmb = (slot > 9) ? (0xb0 + 2 * slot) : (0xae + 2 * slot); + + /* + * Get active event receiver + */ + send_msg.netfn = IPMI_NETFN_SENSOR_EVT >> 2; + send_msg.cmd = IPMI_CMD_GET_EVENT_RECEIVER; + send_msg.data = NULL; + send_msg.data_len = 0; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + aer_addr = halt_recv_msg.msg.data[1]; + aer_lun = halt_recv_msg.msg.data[2]; + + /* + * Setup IPMB address target instead of local target + */ + ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE; + ipmb_addr.channel = 0; + ipmb_addr.slave_addr = aer_addr; + ipmb_addr.lun = aer_lun; + + /* + * Send request hotswap control to remove blade from dpv + */ + send_msg.netfn = IPMI_NETFN_OEM_8 >> 2; + send_msg.cmd = OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL; + send_msg.data = &hotswap_ipmb; + send_msg.data_len = 1; + ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &ipmb_addr, + &send_msg); + + /* + * Set reset asserted + */ + send_msg.netfn = IPMI_NETFN_OEM_1 >> 2; + send_msg.cmd = OEM_GRP_CMD_SET_RESET_STATE; + send_msg.data = data; + data[0] = 1; /* Reset asserted state */ + send_msg.data_len = 1; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + + /* + * Power down + */ + send_msg.netfn = IPMI_NETFN_OEM_1 >> 2; + send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE; + send_msg.data = data; + data[0] = 1; /* Power down state */ + send_msg.data_len = 1; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) + goto out; + + out: + return; +} + +/* + * Standard chassis support + */ + +#define IPMI_NETFN_CHASSIS_REQUEST 0 +#define IPMI_CHASSIS_CONTROL_CMD 0x02 + +static int ipmi_chassis_detect (ipmi_user_t user) +{ + /* Chassis support, use it. */ + return (capabilities & 0x80); +} + +static void ipmi_poweroff_chassis (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + unsigned char data[1]; + + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n"); + + /* + * Power down + */ + send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; + send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; + data[0] = 0; /* Power down */ + send_msg.data = data; + send_msg.data_len = sizeof(data); + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) { + printk(KERN_ERR PFX "Unable to send chassis powerdown message," + " IPMI error 0x%x\n", rv); + goto out; + } + + out: + return; +} + + +/* Table of possible power off functions. */ +struct poweroff_function { + char *platform_type; + int (*detect)(ipmi_user_t user); + void (*poweroff_func)(ipmi_user_t user); +}; + +static struct poweroff_function poweroff_functions[] = { + { "ATCA", ipmi_atca_detect, ipmi_poweroff_atca }, + { "CPI1", ipmi_cpi1_detect, ipmi_poweroff_cpi1 }, + /* Chassis should generally be last, other things should override + it. */ + { "chassis", ipmi_chassis_detect, ipmi_poweroff_chassis }, +}; +#define NUM_PO_FUNCS (sizeof(poweroff_functions) \ + / sizeof(struct poweroff_function)) + + +/* Our local state. */ +static int ready = 0; +static ipmi_user_t ipmi_user; +static void (*specific_poweroff_func)(ipmi_user_t user) = NULL; + +/* Holds the old poweroff function so we can restore it on removal. */ +static void (*old_poweroff_func)(void); + + +/* Called on a powerdown request. */ +static void ipmi_poweroff_function (void) +{ + if (!ready) + return; + + /* Use run-to-completion mode, since interrupts may be off. */ + ipmi_user_set_run_to_completion(ipmi_user, 1); + specific_poweroff_func(ipmi_user); + ipmi_user_set_run_to_completion(ipmi_user, 0); +} + +/* Wait for an IPMI interface to be installed, the first one installed + will be grabbed by this code and used to perform the powerdown. */ +static void ipmi_po_new_smi(int if_num) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + int i; + + if (ready) + return; + + 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); + return; + } + + /* + * Do a get device ide and store some results, since this is + * used by several functions. + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + send_msg.netfn = IPMI_NETFN_APP_REQUEST; + send_msg.cmd = IPMI_GET_DEVICE_ID_CMD; + send_msg.data = NULL; + send_msg.data_len = 0; + rv = ipmi_request_wait_for_response(ipmi_user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv) { + printk(KERN_ERR PFX "Unable to send IPMI get device id info," + " IPMI error 0x%x\n", rv); + goto out_err; + } + + if (halt_recv_msg.msg.data_len < 12) { + printk(KERN_ERR PFX "(chassis) IPMI get device id info too," + " short, was %d bytes, needed %d bytes\n", + halt_recv_msg.msg.data_len, 12); + goto out_err; + } + + mfg_id = (halt_recv_msg.msg.data[7] + | (halt_recv_msg.msg.data[8] << 8) + | (halt_recv_msg.msg.data[9] << 16)); + prod_id = (halt_recv_msg.msg.data[10] + | (halt_recv_msg.msg.data[11] << 8)); + capabilities = halt_recv_msg.msg.data[6]; + + + /* Scan for a poweroff method */ + for (i=0; i -#define IPMI_SI_VERSION "v32" +#define IPMI_SI_VERSION "v33" /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -146,6 +146,11 @@ struct smi_info /* The I/O port of an SI interface. */ int port; + /* The space between start addresses of the two ports. For + instance, if the first port is 0xca2 and the spacing is 4, then + the second port is 0xca6. */ + unsigned int spacing; + /* zero if no irq; */ int irq; @@ -452,14 +457,20 @@ static void handle_transaction_done(struct smi_info *smi_info) /* Take off the event flag. */ smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; + handle_flags(smi_info); } else { spin_lock(&smi_info->count_lock); smi_info->events++; spin_unlock(&smi_info->count_lock); + /* Do this before we deliver the message + because delivering the message releases the + lock and something else can mess with the + state. */ + handle_flags(smi_info); + deliver_recv_msg(smi_info, msg); } - handle_flags(smi_info); break; } @@ -482,14 +493,20 @@ static void handle_transaction_done(struct smi_info *smi_info) /* Take off the msg flag. */ smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL; + handle_flags(smi_info); } else { spin_lock(&smi_info->count_lock); smi_info->incoming_messages++; spin_unlock(&smi_info->count_lock); + /* Do this before we deliver the message + because delivering the message releases the + lock and something else can mess with the + state. */ + handle_flags(smi_info); + deliver_recv_msg(smi_info, msg); } - handle_flags(smi_info); break; } @@ -568,6 +585,9 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, smi_info->hosed_count++; spin_unlock(&smi_info->count_lock); + /* Do the before return_hosed_msg, because that + releases the lock. */ + smi_info->si_state = SI_NORMAL; if (smi_info->curr_msg != NULL) { /* If we were handling a user message, format a response to send to the upper layer to @@ -575,7 +595,6 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, return_hosed_msg(smi_info); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - smi_info->si_state = SI_NORMAL; } /* We prefer handling attn over new messages. */ @@ -872,9 +891,10 @@ static struct smi_info *smi_infos[SI_MAX_DRIVERS] = #define DEVICE_NAME "ipmi_si" -#define DEFAULT_KCS_IO_PORT 0xca2 -#define DEFAULT_SMIC_IO_PORT 0xca9 -#define DEFAULT_BT_IO_PORT 0xe4 +#define DEFAULT_KCS_IO_PORT 0xca2 +#define DEFAULT_SMIC_IO_PORT 0xca9 +#define DEFAULT_BT_IO_PORT 0xe4 +#define DEFAULT_REGSPACING 1 static int si_trydefaults = 1; static char *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL }; @@ -886,6 +906,12 @@ static unsigned int ports[SI_MAX_PARMS] = { 0, 0, 0, 0 }; static int num_ports = 0; static int irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 }; static int num_irqs = 0; +static int regspacings[SI_MAX_PARMS] = { 0, 0, 0, 0 }; +static int num_regspacings = 0; +static int regsizes[SI_MAX_PARMS] = { 0, 0, 0, 0 }; +static int num_regsizes = 0; +static int regshifts[SI_MAX_PARMS] = { 0, 0, 0, 0 }; +static int num_regshifts = 0; module_param_named(trydefaults, si_trydefaults, bool, 0); @@ -912,6 +938,23 @@ MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the" " addresses separated by commas. Only use if an interface" " has an interrupt. Otherwise, set it to zero or leave" " it blank."); +module_param_array(regspacings, int, num_regspacings, 0); +MODULE_PARM_DESC(regspacings, "The number of bytes between the start address" + " and each successive register used by the interface. For" + " instance, if the start address is 0xca2 and the spacing" + " is 2, then the second address is at 0xca4. Defaults" + " to 1."); +module_param_array(regsizes, int, num_regsizes, 0); +MODULE_PARM_DESC(regsizes, "The size of the specific IPMI register in bytes." + " This should generally be 1, 2, 4, or 8 for an 8-bit," + " 16-bit, 32-bit, or 64-bit register. Use this if you" + " the 8-bit IPMI register has to be read from a larger" + " register."); +module_param_array(regshifts, int, num_regshifts, 0); +MODULE_PARM_DESC(regshifts, "The amount to shift the data read from the." + " IPMI register, in bits. For instance, if the data" + " is read from a 32-bit word and the IPMI data is in" + " bit 8-15, then the shift would be 8"); #define IPMI_MEM_ADDR_SPACE 1 #define IPMI_IO_ADDR_SPACE 2 @@ -977,7 +1020,7 @@ static unsigned char port_inb(struct si_sm_io *io, unsigned int offset) { unsigned int *addr = io->info; - return inb((*addr)+offset); + return inb((*addr)+(offset*io->regspacing)); } static void port_outb(struct si_sm_io *io, unsigned int offset, @@ -985,30 +1028,97 @@ static void port_outb(struct si_sm_io *io, unsigned int offset, { unsigned int *addr = io->info; - outb(b, (*addr)+offset); + outb(b, (*addr)+(offset * io->regspacing)); } -static int port_setup(struct smi_info *info) +static unsigned char port_inw(struct si_sm_io *io, unsigned int offset) { - unsigned int *addr = info->io.info; + unsigned int *addr = io->info; - if (!addr || (!*addr)) - return -ENODEV; + return (inw((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; +} - if (request_region(*addr, info->io_size, DEVICE_NAME) == NULL) - return -EIO; - return 0; +static void port_outw(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int *addr = io->info; + + outw(b << io->regshift, (*addr)+(offset * io->regspacing)); +} + +static unsigned char port_inl(struct si_sm_io *io, unsigned int offset) +{ + unsigned int *addr = io->info; + + return (inl((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; +} + +static void port_outl(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int *addr = io->info; + + outl(b << io->regshift, (*addr)+(offset * io->regspacing)); } static void port_cleanup(struct smi_info *info) { unsigned int *addr = info->io.info; + int mapsize; - if (addr && (*addr)) - release_region (*addr, info->io_size); + if (addr && (*addr)) { + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + release_region (*addr, mapsize); + } kfree(info); } +static int port_setup(struct smi_info *info) +{ + unsigned int *addr = info->io.info; + int mapsize; + + if (!addr || (!*addr)) + return -ENODEV; + + info->io_cleanup = port_cleanup; + + /* Figure out the actual inb/inw/inl/etc routine to use based + upon the register size. */ + switch (info->io.regsize) { + case 1: + info->io.inputb = port_inb; + info->io.outputb = port_outb; + break; + case 2: + info->io.inputb = port_inw; + info->io.outputb = port_outw; + break; + case 4: + info->io.inputb = port_inl; + info->io.outputb = port_outl; + break; + default: + printk("ipmi_si: Invalid register size: %d\n", + info->io.regsize); + return -EINVAL; + } + + /* Calculate the total amount of memory to claim. This is an + * unusual looking calculation, but it avoids claiming any + * more memory than it has to. It will claim everything + * between the first address to the end of the last full + * register. */ + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + if (request_region(*addr, mapsize, DEVICE_NAME) == NULL) + return -EIO; + return 0; +} + static int try_init_port(int intf_num, struct smi_info **new_info) { struct smi_info *info; @@ -1028,11 +1138,15 @@ static int try_init_port(int intf_num, struct smi_info **new_info) memset(info, 0, sizeof(*info)); info->io_setup = port_setup; - info->io_cleanup = port_cleanup; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); info->io.addr = NULL; + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = regsizes[intf_num]; + if (!info->io.regsize) + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; info->irq = 0; info->irq_setup = NULL; *new_info = info; @@ -1047,44 +1161,125 @@ static int try_init_port(int intf_num, struct smi_info **new_info) static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset) { - return readb((io->addr)+offset); + return readb((io->addr)+(offset * io->regspacing)); } static void mem_outb(struct si_sm_io *io, unsigned int offset, unsigned char b) { - writeb(b, (io->addr)+offset); + writeb(b, (io->addr)+(offset * io->regspacing)); } -static int mem_setup(struct smi_info *info) +static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset) { - unsigned long *addr = info->io.info; + return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) + && 0xff; +} - if (!addr || (!*addr)) - return -ENODEV; +static void mem_outw(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} - if (request_mem_region(*addr, info->io_size, DEVICE_NAME) == NULL) - return -EIO; +static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset) +{ + return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) + && 0xff; +} - info->io.addr = ioremap(*addr, info->io_size); - if (info->io.addr == NULL) { - release_mem_region(*addr, info->io_size); - return -EIO; - } - return 0; +static void mem_outl(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); } +#ifdef readq +static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) +{ + return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) + && 0xff; +} + +static void mem_outq(struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} +#endif + static void mem_cleanup(struct smi_info *info) { unsigned long *addr = info->io.info; + int mapsize; if (info->io.addr) { iounmap(info->io.addr); - release_mem_region(*addr, info->io_size); + + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + release_mem_region(*addr, mapsize); } kfree(info); } +static int mem_setup(struct smi_info *info) +{ + unsigned long *addr = info->io.info; + int mapsize; + + if (!addr || (!*addr)) + return -ENODEV; + + info->io_cleanup = mem_cleanup; + + /* Figure out the actual readb/readw/readl/etc routine to use based + upon the register size. */ + switch (info->io.regsize) { + case 1: + info->io.inputb = mem_inb; + info->io.outputb = mem_outb; + break; + case 2: + info->io.inputb = mem_inw; + info->io.outputb = mem_outw; + break; + case 4: + info->io.inputb = mem_inl; + info->io.outputb = mem_outl; + break; +#ifdef readq + case 8: + info->io.inputb = mem_inq; + info->io.outputb = mem_outq; + break; +#endif + default: + printk("ipmi_si: Invalid register size: %d\n", + info->io.regsize); + return -EINVAL; + } + + /* Calculate the total amount of memory to claim. This is an + * unusual looking calculation, but it avoids claiming any + * more memory than it has to. It will claim everything + * between the first address to the end of the last full + * register. */ + mapsize = ((info->io_size * info->io.regspacing) + - (info->io.regspacing - info->io.regsize)); + + if (request_mem_region(*addr, mapsize, DEVICE_NAME) == NULL) + return -EIO; + + info->io.addr = ioremap(*addr, mapsize); + if (info->io.addr == NULL) { + release_mem_region(*addr, mapsize); + return -EIO; + } + return 0; +} + static int try_init_mem(int intf_num, struct smi_info **new_info) { struct smi_info *info; @@ -1104,11 +1299,15 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) memset(info, 0, sizeof(*info)); info->io_setup = mem_setup; - info->io_cleanup = mem_cleanup; - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; info->io.info = (void *) addrs[intf_num]; info->io.addr = NULL; + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = regsizes[intf_num]; + if (!info->io.regsize) + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; info->irq = 0; info->irq_setup = NULL; *new_info = info; @@ -1132,7 +1331,7 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) static int acpi_failure = 0; /* For GPE-type interrupts. */ -void ipmi_acpi_gpe(void *context) +u32 ipmi_acpi_gpe(void *context) { struct smi_info *smi_info = context; unsigned long flags; @@ -1156,6 +1355,8 @@ void ipmi_acpi_gpe(void *context) smi_event_handler(smi_info, 0); out: spin_unlock_irqrestore(&(smi_info->si_lock), flags); + + return ACPI_INTERRUPT_HANDLED; } static int acpi_gpe_irq_setup(struct smi_info *info) @@ -1182,7 +1383,6 @@ static int acpi_gpe_irq_setup(struct smi_info *info) printk(" Using ACPI GPE %d\n", info->irq); return 0; } - } static void acpi_gpe_irq_cleanup(struct smi_info *info) @@ -1310,21 +1510,22 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) info->irq_setup = NULL; } + regspacings[intf_num] = spmi->addr.register_bit_width / 8; + info->io.regspacing = spmi->addr.register_bit_width / 8; + regsizes[intf_num] = regspacings[intf_num]; + info->io.regsize = regsizes[intf_num]; + regshifts[intf_num] = spmi->addr.register_bit_offset; + info->io.regshift = regshifts[intf_num]; + if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { io_type = "memory"; info->io_setup = mem_setup; - info->io_cleanup = mem_cleanup; addrs[intf_num] = spmi->addr.address; - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; info->io.info = &(addrs[intf_num]); } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) { io_type = "I/O"; info->io_setup = port_setup; - info->io_cleanup = port_cleanup; ports[intf_num] = spmi->addr.address; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); } else { kfree(info); @@ -1348,6 +1549,7 @@ typedef struct dmi_ipmi_data u8 addr_space; unsigned long base_addr; u8 irq; + u8 offset; }dmi_ipmi_data_t; typedef struct dmi_header @@ -1361,6 +1563,7 @@ static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data) { u8 *data = (u8 *)dm; unsigned long base_addr; + u8 reg_spacing; ipmi_data->type = data[0x04]; @@ -1375,7 +1578,27 @@ static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data) ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE; } - ipmi_data->base_addr = base_addr; + /* The top two bits of byte 0x10 hold the register spacing. */ + reg_spacing = (data[0x10] & 0xC0) >> 6; + switch(reg_spacing){ + case 0x00: /* Byte boundaries */ + ipmi_data->offset = 1; + break; + case 0x01: /* 32-bit boundaries */ + ipmi_data->offset = 4; + break; + case 0x02: /* 16-bit boundaries */ + ipmi_data->offset = 2; + default: + printk("ipmi_si: Unknown SMBIOS IPMI Base Addr" + " Modifier: 0x%x\n", reg_spacing); + return -EIO; + } + + /* If bit 4 of byte 0x10 is set, then the lsb for the address + is odd. */ + ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); + ipmi_data->irq = data[0x11]; if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) @@ -1500,18 +1723,12 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info) if (ipmi_data.addr_space == 1) { io_type = "memory"; info->io_setup = mem_setup; - info->io_cleanup = mem_cleanup; addrs[intf_num] = ipmi_data.base_addr; - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; info->io.info = &(addrs[intf_num]); } else if (ipmi_data.addr_space == 2) { io_type = "I/O"; info->io_setup = port_setup; - info->io_cleanup = port_cleanup; ports[intf_num] = ipmi_data.base_addr; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); } else { kfree(info); @@ -1519,6 +1736,13 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info) return -EIO; } + regspacings[intf_num] = ipmi_data.offset; + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; + irqs[intf_num] = ipmi_data.irq; *new_info = info; @@ -1596,11 +1820,13 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) memset(info, 0, sizeof(*info)); info->io_setup = port_setup; - info->io_cleanup = port_cleanup; ports[intf_num] = base_addr; - info->io.inputb = port_inb; - info->io.outputb = port_outb; info->io.info = &(ports[intf_num]); + info->io.regspacing = regspacings[intf_num]; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshifts[intf_num]; *new_info = info; @@ -1860,6 +2086,13 @@ static int init_one_smi(int intf_num, struct smi_info **smi) new_smi->timer_stopped = 0; new_smi->stop_operation = 0; + /* Start clearing the flags before we enable interrupts or the + timer to avoid racing with the timer. */ + start_clear_flags(new_smi); + /* IRQ is defined to be set when non-zero. */ + if (new_smi->irq) + new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; + /* The ipmi_register_smi() code does some operations to determine the channel information, so we must be ready to handle operations before it is called. This means we have @@ -1903,12 +2136,6 @@ static int init_one_smi(int intf_num, struct smi_info **smi) goto out_err_stop_timer; } - start_clear_flags(new_smi); - - /* IRQ is defined to be set when non-zero. */ - if (new_smi->irq) - new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; - *smi = new_smi; printk(" IPMI %s interface initialized\n", si_type[intf_num]); @@ -2052,6 +2279,13 @@ void __exit cleanup_one_si(struct smi_info *to_clean) schedule_timeout(1); } + /* Interrupts and timeouts are stopped, now make sure the + interface is in a clean state. */ + while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) { + poll(to_clean); + schedule_timeout(1); + } + rv = ipmi_unregister_smi(to_clean->intf); if (rv) { printk(KERN_ERR diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index f3506552c..a0212b004 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -52,6 +52,9 @@ struct si_sm_io state machine shouldn't touch these. */ void *info; void *addr; + int regspacing; + int regsize; + int regshift; }; /* Results of SMI events. */ diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index b5c08d6e0..ae18747e6 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -46,7 +46,7 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_SMIC_VERSION "v32" +#define IPMI_SMIC_VERSION "v33" /* smic_debug is a bit-field * SMIC_DEBUG_ENABLE - turned on for now diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index fb8492490..db2cf9cb5 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -51,7 +51,9 @@ #include #endif -#define IPMI_WATCHDOG_VERSION "v32" +#define PFX "IPMI Watchdog: " + +#define IPMI_WATCHDOG_VERSION "v33" /* * The IPMI command/response information for the watchdog timer. @@ -160,6 +162,7 @@ static char data_to_read = 0; static DECLARE_WAIT_QUEUE_HEAD(read_q); static struct fasync_struct *fasync_q = NULL; static char pretimeout_since_last_heartbeat = 0; +static char expect_close; /* If true, the driver will start running as soon as it is configured and ready. */ @@ -191,7 +194,7 @@ static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; static int ipmi_ignore_heartbeat = 0; /* Is someone using the watchdog? Only one user is allowed. */ -static int ipmi_wdog_open = 0; +static unsigned long ipmi_wdog_open = 0; /* If set to 1, the heartbeat command will set the state to reset and start the timer. The timer doesn't normally run when the driver is @@ -287,7 +290,7 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, recv_msg, 1); if (rv) { - printk(KERN_WARNING "IPMI Watchdog, set timeout error: %d\n", + printk(KERN_WARNING PFX "set timeout error: %d\n", rv); } @@ -464,7 +467,7 @@ static int ipmi_heartbeat(void) 1); if (rv) { up(&heartbeat_lock); - printk(KERN_WARNING "IPMI Watchdog, heartbeat failure: %d\n", + printk(KERN_WARNING PFX "heartbeat failure: %d\n", rv); return rv; } @@ -599,6 +602,21 @@ static ssize_t ipmi_write(struct file *file, int rv; if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } rv = ipmi_heartbeat(); if (rv) return rv; @@ -662,11 +680,9 @@ static int ipmi_open(struct inode *ino, struct file *filep) switch (iminor(ino)) { case WATCHDOG_MINOR: - if (ipmi_wdog_open) + if(test_and_set_bit(0, &ipmi_wdog_open)) return -EBUSY; - ipmi_wdog_open = 1; - /* Don't start the timer now, let it start on the first heartbeat. */ ipmi_start_timer_on_heartbeat = 1; @@ -704,14 +720,18 @@ static int ipmi_close(struct inode *ino, struct file *filep) { if (iminor(ino)==WATCHDOG_MINOR) { - if (!nowayout) { + if (expect_close == 42) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); + clear_bit(0, &ipmi_wdog_open); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + ipmi_heartbeat(); } - ipmi_wdog_open = 0; } ipmi_fasync (-1, filep, 0); + expect_close = 0; return 0; } @@ -739,7 +759,7 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) { if (msg->msg.data[0] != 0) { - printk(KERN_ERR "IPMI Watchdog response: Error %x on cmd %x\n", + printk(KERN_ERR PFX "response: Error %x on cmd %x\n", msg->msg.data[0], msg->msg.cmd); } @@ -784,7 +804,7 @@ static void ipmi_register_watchdog(int ipmi_intf) rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); if (rv < 0) { - printk("IPMI watchdog: Unable to register with ipmi\n"); + printk(KERN_CRIT PFX "Unable to register with ipmi\n"); goto out; } @@ -796,7 +816,7 @@ static void ipmi_register_watchdog(int ipmi_intf) if (rv < 0) { ipmi_destroy_user(watchdog_user); watchdog_user = NULL; - printk("IPMI watchdog: Unable to register misc device\n"); + printk(KERN_CRIT PFX "Unable to register misc device\n"); } out: @@ -807,7 +827,7 @@ static void ipmi_register_watchdog(int ipmi_intf) start_now = 0; /* Disable this function after first startup. */ ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); - printk("Starting IPMI Watchdog now!\n"); + printk(KERN_INFO PFX "Starting now!\n"); } } @@ -818,7 +838,7 @@ ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) /* If no one else handled the NMI, we assume it was the IPMI watchdog. */ if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) - panic("IPMI watchdog pre-timeout"); + panic(PFX "pre-timeout"); /* On some machines, the heartbeat will give an error and not work unless we re-enable @@ -924,7 +944,7 @@ static int __init ipmi_wdog_init(void) { int rv; - printk(KERN_INFO "IPMI watchdog driver version " + printk(KERN_INFO PFX "driver version " IPMI_WATCHDOG_VERSION "\n"); if (strcmp(action, "reset") == 0) { @@ -937,7 +957,7 @@ static int __init ipmi_wdog_init(void) action_val = WDOG_TIMEOUT_POWER_DOWN; } else { action_val = WDOG_TIMEOUT_RESET; - printk("ipmi_watchdog: Unknown action '%s', defaulting to" + printk(KERN_INFO PFX "Unknown action '%s', defaulting to" " reset\n", action); } @@ -953,7 +973,7 @@ static int __init ipmi_wdog_init(void) preaction_val = WDOG_PRETIMEOUT_MSG_INT; } else { preaction_val = WDOG_PRETIMEOUT_NONE; - printk("ipmi_watchdog: Unknown preaction '%s', defaulting to" + printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to" " none\n", preaction); } @@ -965,23 +985,21 @@ static int __init ipmi_wdog_init(void) preop_val = WDOG_PREOP_GIVE_DATA; } else { preop_val = WDOG_PREOP_NONE; - printk("ipmi_watchdog: Unknown preop '%s', defaulting to" + printk(KERN_INFO PFX "Unknown preop '%s', defaulting to" " none\n", preop); } #ifdef HAVE_NMI_HANDLER if (preaction_val == WDOG_PRETIMEOUT_NMI) { if (preop_val == WDOG_PREOP_GIVE_DATA) { - printk(KERN_WARNING - "ipmi_watchdog: Pretimeout op is to give data" + printk(KERN_WARNING PFX "Pretimeout op is to give data" " but NMI pretimeout is enabled, setting" " pretimeout op to none\n"); preop_val = WDOG_PREOP_NONE; } #ifdef CONFIG_X86_LOCAL_APIC if (nmi_watchdog == NMI_IO_APIC) { - printk(KERN_WARNING - "ipmi_watchdog: nmi_watchdog is set to IO APIC" + printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" " mode (value is %d), that is incompatible" " with using NMI in the IPMI watchdog." " Disabling IPMI nmi pretimeout.\n", @@ -991,8 +1009,7 @@ static int __init ipmi_wdog_init(void) #endif rv = request_nmi(&ipmi_nmi_handler); if (rv) { - printk(KERN_WARNING - "ipmi_watchdog: Can't register nmi handler\n"); + printk(KERN_WARNING PFX "Can't register nmi handler\n"); return rv; } #ifdef CONFIG_X86_LOCAL_APIC @@ -1007,8 +1024,7 @@ static int __init ipmi_wdog_init(void) if (preaction_val == WDOG_PRETIMEOUT_NMI) release_nmi(&ipmi_nmi_handler); #endif - printk(KERN_WARNING - "ipmi_watchdog: can't register smi watcher\n"); + printk(KERN_WARNING PFX "can't register smi watcher\n"); return rv; } @@ -1053,8 +1069,7 @@ static __exit void ipmi_unregister_watchdog(void) /* Disconnect from IPMI. */ rv = ipmi_destroy_user(watchdog_user); if (rv) { - printk(KERN_WARNING - "IPMI Watchdog, error unlinking from IPMI: %d\n", + printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", rv); } watchdog_user = NULL; diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index e8650449f..b454bf208 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -389,7 +390,7 @@ static void isicom_tx(unsigned long _data) tty = port->tty; save_flags(flags); cli(); - txcount = MIN(TX_SIZE, port->xmit_cnt); + txcount = min_t(short, TX_SIZE, port->xmit_cnt); if ((txcount <= 0) || tty->stopped || tty->hw_stopped) { restore_flags(flags); continue; @@ -421,7 +422,7 @@ static void isicom_tx(unsigned long _data) residue = NO; wrd = 0; while (1) { - cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); + cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); if (residue == YES) { residue = NO; if (cnt > 0) { @@ -484,10 +485,8 @@ static void isicom_bottomhalf(void * data) if (!tty) return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -650,7 +649,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, } } else { /* Data Packet */ - count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); + count = min_t(unsigned short, byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n", count, byte_count); @@ -1119,8 +1118,8 @@ static void isicom_close(struct tty_struct * tty, struct file * filp) isicom_shutdown_port(port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; port->tty = NULL; if (port->blocked_open) { @@ -1163,8 +1162,8 @@ static int isicom_write(struct tty_struct * tty, int from_user, save_flags(flags); while(1) { cli(); - cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); if (cnt <= 0) break; @@ -1180,8 +1179,8 @@ static int isicom_write(struct tty_struct * tty, int from_user, return -EFAULT; } cli(); - cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + cnt = min_t(int, cnt, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt); } else @@ -1563,9 +1562,7 @@ static void isicom_flush_buffer(struct tty_struct * tty) restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } @@ -1906,8 +1903,7 @@ int init_module(void) void cleanup_module(void) { re_schedule = 0; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep(1000); #ifdef ISICOM_DEBUG printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 4a8b7d51e..9460f6d0b 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -749,17 +749,13 @@ static void stli_stalreset(stlibrd_t *brdp); static stliport_t *stli_getport(int brdnr, int panelnr, int portnr); -static inline int stli_initbrds(void); -static inline int stli_initecp(stlibrd_t *brdp); -static inline int stli_initonb(stlibrd_t *brdp); -static inline int stli_findeisabrds(void); -static inline int stli_eisamemprobe(stlibrd_t *brdp); -static inline int stli_initports(stlibrd_t *brdp); -static inline int stli_getbrdnr(void); +static int stli_initecp(stlibrd_t *brdp); +static int stli_initonb(stlibrd_t *brdp); +static int stli_eisamemprobe(stlibrd_t *brdp); +static int stli_initports(stlibrd_t *brdp); #ifdef CONFIG_PCI -static inline int stli_findpcibrds(void); -static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp); +static int stli_initpcibrd(int brdtype, struct pci_dev *devp); #endif /*****************************************************************************/ @@ -2751,7 +2747,7 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, * more chars to unload. */ -static inline void stli_read(stlibrd_t *brdp, stliport_t *portp) +static void stli_read(stlibrd_t *brdp, stliport_t *portp) { volatile cdkasyrq_t *rp; volatile char *shbuf; @@ -2819,7 +2815,7 @@ static inline void stli_read(stlibrd_t *brdp, stliport_t *portp) * difficult to deal with them here. */ -static inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp) +static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp) { int cmd; @@ -2867,7 +2863,7 @@ static inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp) * then port is still busy, otherwise no longer busy. */ -static inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) +static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) { volatile cdkasy_t *ap; volatile cdkctrl_t *cp; @@ -3026,7 +3022,7 @@ static inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) * at the cdk header structure. */ -static inline void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp) +static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp) { stliport_t *portp; unsigned char hostbits[(STL_MAXCHANS / 8) + 1]; @@ -3299,7 +3295,7 @@ static long stli_mktiocm(unsigned long sigvalue) * we need to do here is set up the appropriate per port data structures. */ -static inline int stli_initports(stlibrd_t *brdp) +static int stli_initports(stlibrd_t *brdp) { stliport_t *portp; int i, panelnr, panelport; @@ -3911,7 +3907,7 @@ static void stli_stalreset(stlibrd_t *brdp) * board types. */ -static inline int stli_initecp(stlibrd_t *brdp) +static int stli_initecp(stlibrd_t *brdp) { cdkecpsig_t sig; cdkecpsig_t *sigsp; @@ -4072,7 +4068,7 @@ static inline int stli_initecp(stlibrd_t *brdp) * This handles only these board types. */ -static inline int stli_initonb(stlibrd_t *brdp) +static int stli_initonb(stlibrd_t *brdp) { cdkonbsig_t sig; cdkonbsig_t *sigsp; @@ -4414,7 +4410,7 @@ static int __init stli_brdinit(stlibrd_t *brdp) * might be. This is a bit if hack, but it is the best we can do. */ -static inline int stli_eisamemprobe(stlibrd_t *brdp) +static int stli_eisamemprobe(stlibrd_t *brdp) { cdkecpsig_t ecpsig, *ecpsigp; cdkonbsig_t onbsig, *onbsigp; @@ -4506,7 +4502,7 @@ static inline int stli_eisamemprobe(stlibrd_t *brdp) return(0); } -static inline int stli_getbrdnr(void) +static int stli_getbrdnr(void) { int i; @@ -4532,7 +4528,7 @@ static inline int stli_getbrdnr(void) * do is go probing around in the usual places hoping we can find it. */ -static inline int stli_findeisabrds(void) +static int stli_findeisabrds(void) { stlibrd_t *brdp; unsigned int iobase, eid; @@ -4616,7 +4612,7 @@ static inline int stli_findeisabrds(void) * configuration space. */ -static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp) +static int stli_initpcibrd(int brdtype, struct pci_dev *devp) { stlibrd_t *brdp; @@ -4662,7 +4658,7 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp) * one as it is found. */ -static inline int stli_findpcibrds(void) +static int stli_findpcibrds(void) { struct pci_dev *dev = NULL; int rc; @@ -4711,7 +4707,7 @@ static stlibrd_t *stli_allocbrd(void) * can find. */ -static inline int stli_initbrds(void) +static int stli_initbrds(void) { stlibrd_t *brdp, *nxtbrdp; stlconf_t *confp; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 3ad30ba46..313789840 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -123,7 +123,7 @@ int shift_state = 0; */ static struct input_handler kbd_handler; -static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; static int npadch = -1; /* -1 or number assembled on pad */ @@ -142,7 +142,7 @@ static struct ledptr { /* Simple translation table for the SysRq keys */ #ifdef CONFIG_MAGIC_SYSRQ -unsigned char kbd_sysrq_xlate[128] = +unsigned char kbd_sysrq_xlate[KEY_MAX] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -941,6 +941,9 @@ void kbd_refresh_leds(struct input_handle *handle) #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) +#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ + ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) + static unsigned short x86_keycodes[256] = { 0, 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, 29, 30, 31, @@ -1007,6 +1010,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #else +#define HW_RAW(dev) 0 + #warning "Cannot generate rawmode keyboard for your architecture yet." static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) @@ -1019,7 +1024,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u } #endif -void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) +void kbd_rawcode(unsigned char data) +{ + struct vc_data *vc = vc_cons[fg_console].d; + kbd = kbd_table + fg_console; + if (kbd->kbdmode == VC_RAW) + put_queue(vc, data); +} + +void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1053,7 +1066,7 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) return; #endif /* CONFIG_MAC_EMUMOUSEBTN */ - if ((raw_mode = (kbd->kbdmode == VC_RAW))) + if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); @@ -1119,6 +1132,9 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) return; } + if (keycode > NR_KEYS) + return; + keysym = key_map[keycode]; type = KTYP(keysym); @@ -1148,11 +1164,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) } static void kbd_event(struct input_handle *handle, unsigned int event_type, - unsigned int keycode, int down) + unsigned int event_code, int value) { - if (event_type != EV_KEY) - return; - kbd_keycode(keycode, down, handle->dev->regs); + if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) + kbd_rawcode(value); + if (event_type == EV_KEY) + kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs); tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 3274c3a73..9d8dbded2 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -31,9 +31,6 @@ # include #endif -#ifdef CONFIG_FB -extern void fbmem_init(void); -#endif #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) extern void tapechar_init(void); #endif @@ -86,7 +83,7 @@ static inline int uncached_access(struct file *file, unsigned long addr) * above the IO hole... Ah, and of course, XFree86 doesn't pass * O_SYNC when mapping us to tap IO space. Surprised ? */ - return !page_is_ram(addr); + return !page_is_ram(addr >> PAGE_SHIFT); #else /* * Accessing memory above the top the kernel knows about or through a file pointer @@ -416,7 +413,7 @@ static inline size_t read_zero_pagealigned(char __user * buf, size_t size) if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0) goto out_up; - if (vma->vm_flags & VM_SHARED) + if (vma->vm_flags & (VM_SHARED | VM_HUGETLB)) break; count = vma->vm_end - addr; if (count > size) @@ -730,9 +727,6 @@ static int __init chr_dev_init(void) S_IFCHR | devlist[i].mode, devlist[i].name); } -#if defined (CONFIG_FB) - fbmem_init(); -#endif return 0; } diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c new file mode 100644 index 000000000..20aa170db --- /dev/null +++ b/drivers/char/mmtimer.c @@ -0,0 +1,216 @@ +/* + * Intel Multimedia Timer device implementation for SGI SN platforms. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. + * + * This driver exports an API that should be supportable by any HPET or IA-PC + * multimedia timer. The code below is currently specific to the SGI Altix + * SHub RTC, however. + * + * 11/01/01 - jbarnes - initial revision + * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jesse Barnes "); +MODULE_DESCRIPTION("Multimedia timer support"); +MODULE_LICENSE("GPL"); + +/* name of the device, usually in /dev */ +#define MMTIMER_NAME "mmtimer" +#define MMTIMER_DESC "IA-PC Multimedia Timer" +#define MMTIMER_VERSION "1.0" + +#define RTC_BITS 55 /* 55 bits for this implementation */ + +static int mmtimer_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma); + +/* + * Period in femtoseconds (10^-15 s) + */ +static unsigned long mmtimer_femtoperiod = 0; + +static struct file_operations mmtimer_fops = { + .owner = THIS_MODULE, + .mmap = mmtimer_mmap, + .ioctl = mmtimer_ioctl, +}; + +/** + * mmtimer_ioctl - ioctl interface for /dev/mmtimer + * @inode: inode of the device + * @file: file structure for the device + * @cmd: command to execute + * @arg: optional argument to command + * + * Executes the command specified by @cmd. Returns 0 for success, < 0 for + * failure. + * + * Valid commands: + * + * %MMTIMER_GETOFFSET - Should return the offset (relative to the start + * of the page where the registers are mapped) for the counter in question. + * + * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15) + * seconds + * + * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address + * specified by @arg + * + * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter + * + * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace + * + * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it + * in the address specified by @arg. + */ +static int mmtimer_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case MMTIMER_GETOFFSET: /* offset of the counter */ + /* + * SN RTC registers are on their own 64k page + */ + if(PAGE_SIZE <= (1 << 16)) + ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8; + else + ret = -ENOSYS; + break; + + case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */ + if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod, + sizeof(unsigned long))) + return -EFAULT; + break; + + case MMTIMER_GETFREQ: /* frequency in Hz */ + if(copy_to_user((unsigned long *)arg, + &sn_rtc_cycles_per_second, + sizeof(unsigned long))) + return -EFAULT; + ret = 0; + break; + + case MMTIMER_GETBITS: /* number of bits in the clock */ + ret = RTC_BITS; + break; + + case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */ + ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0; + break; + + case MMTIMER_GETCOUNTER: + if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR, + sizeof(unsigned long))) + return -EFAULT; + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +/** + * mmtimer_mmap - maps the clock's registers into userspace + * @file: file structure for the device + * @vma: VMA to map the registers into + * + * Calls remap_page_range() to map the clock's registers into + * the calling process' address space. + */ +static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long mmtimer_addr; + + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) + return -EPERM; + + if (PAGE_SIZE > (1 << 16)) + return -ENOSYS; + + vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED ); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + mmtimer_addr = __pa(RTC_COUNTER_ADDR); + mmtimer_addr &= ~(PAGE_SIZE - 1); + mmtimer_addr &= 0xfffffffffffffffUL; + + if (remap_page_range(vma, vma->vm_start, mmtimer_addr, PAGE_SIZE, + vma->vm_page_prot)) { + printk(KERN_ERR "remap_page_range failed in mmtimer.c\n"); + return -EAGAIN; + } + + return 0; +} + +static struct miscdevice mmtimer_miscdev = { + SGI_MMTIMER, + MMTIMER_NAME, + &mmtimer_fops +}; + +/** + * mmtimer_init - device initialization routine + * + * Does initial setup for the mmtimer device. + */ +static int __init mmtimer_init(void) +{ + if (!ia64_platform_is("sn2")) + return -1; + + /* + * Sanity check the cycles/sec variable + */ + if (sn_rtc_cycles_per_second < 100000) { + printk(KERN_ERR "%s: unable to determine clock frequency\n", + MMTIMER_NAME); + return -1; + } + + mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / + 2) / sn_rtc_cycles_per_second; + + strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME); + if (misc_register(&mmtimer_miscdev)) { + printk(KERN_ERR "%s: failed to register device\n", + MMTIMER_NAME); + return -1; + } + + printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION, + sn_rtc_cycles_per_second/(unsigned long)1E6); + + return 0; +} + +module_init(mmtimer_init); + diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 0e75a0dc9..d45d381d4 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -618,8 +618,8 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; ch->event = 0; ch->tty = NULL; @@ -693,9 +693,7 @@ static void moxa_flush_buffer(struct tty_struct *tty) if (ch == NULL) return; MoxaPortFlushData(ch->port, 1); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -954,9 +952,7 @@ static void moxa_poll(unsigned long ignored) if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { if (!tp->stopped) { ch->statusflags &= ~LOWWAIT; - if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tp->ldisc.write_wakeup) - (tp->ldisc.write_wakeup) (tp); + tty_wakeup(tp); wake_up_interruptible(&tp->write_wait); } } @@ -1123,9 +1119,7 @@ static void check_xmit_empty(unsigned long data) if (ch->tty && (ch->statusflags & EMPTYWAIT)) { if (MoxaPortTxQueue(ch->port) == 0) { ch->statusflags &= ~EMPTYWAIT; - if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - ch->tty->ldisc.write_wakeup) - (ch->tty->ldisc.write_wakeup) (ch->tty); + tty_wakeup(ch->tty); wake_up_interruptible(&ch->tty->write_wait); return; } diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index d4ba62a29..147c1ba2e 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -101,10 +101,6 @@ #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * Define the Moxa PCI vendor and device IDs. */ @@ -349,10 +345,10 @@ static void mxser_set_termios(struct tty_struct *, struct termios *); static void mxser_stop(struct tty_struct *); static void mxser_start(struct tty_struct *); static void mxser_hangup(struct tty_struct *); -static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); static inline void mxser_receive_chars(struct mxser_struct *, int *); static inline void mxser_transmit_chars(struct mxser_struct *); static inline void mxser_check_modem_status(struct mxser_struct *, int); +static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *); static int mxser_startup(struct mxser_struct *); static void mxser_shutdown(struct mxser_struct *); @@ -678,9 +674,7 @@ static void mxser_do_softint(void *private_) tty = info->tty; if (tty) { if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) { @@ -817,8 +811,8 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) mxser_shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; info->event = 0; info->tty = NULL; @@ -849,7 +843,7 @@ static int mxser_write(struct tty_struct *tty, int from_user, if (from_user) { down(&mxvar_tmp_buf_sem); while (1) { - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -862,7 +856,7 @@ static int mxser_write(struct tty_struct *tty, int from_user, } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); @@ -877,7 +871,7 @@ static int mxser_write(struct tty_struct *tty, int from_user, } else { while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { restore_flags(flags); @@ -976,9 +970,7 @@ static void mxser_flush_buffer(struct tty_struct *tty) info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); } static int mxser_ioctl(struct tty_struct *tty, struct file *file, @@ -1307,69 +1299,6 @@ void mxser_hangup(struct tty_struct *tty) wake_up_interruptible(&info->open_wait); } -/* - * This is the serial driver's generic interrupt routine - */ -static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int status, i; - struct mxser_struct *info; - struct mxser_struct *port; - int max, irqbits, bits, msr; - int pass_counter = 0; - int handled = 0; - - port = NULL; - for (i = 0; i < MXSER_BOARDS; i++) { - if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { - port = dev_id; - break; - } - } - - if (i == MXSER_BOARDS) - return IRQ_NONE; - if (port == 0) - return IRQ_NONE; - max = mxser_numports[mxsercfg[i].board_type]; - - while (1) { - irqbits = inb(port->vector) & port->vectormask; - if (irqbits == port->vectormask) - break; - handled = 1; - for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { - if (irqbits == port->vectormask) - break; - if (bits & irqbits) - continue; - info = port + i; - if (!info->tty || - (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) - continue; - status = inb(info->base + UART_LSR) & info->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(info, &status); - msr = inb(info->base + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(info, msr); - if (status & UART_LSR_THRE) { -/* 8-2-99 by William - if ( info->x_char || (info->xmit_cnt > 0) ) - */ - mxser_transmit_chars(info); - } - } - if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { -#if 0 - printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - } - return IRQ_RETVAL(handled); -} - static inline void mxser_receive_chars(struct mxser_struct *info, int *status) { @@ -1490,6 +1419,69 @@ static inline void mxser_check_modem_status(struct mxser_struct *info, } } +/* + * This is the serial driver's generic interrupt routine + */ +static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status, i; + struct mxser_struct *info; + struct mxser_struct *port; + int max, irqbits, bits, msr; + int pass_counter = 0; + int handled = 0; + + port = NULL; + for (i = 0; i < MXSER_BOARDS; i++) { + if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { + port = dev_id; + break; + } + } + + if (i == MXSER_BOARDS) + return IRQ_NONE; + if (port == 0) + return IRQ_NONE; + max = mxser_numports[mxsercfg[i].board_type]; + + while (1) { + irqbits = inb(port->vector) & port->vectormask; + if (irqbits == port->vectormask) + break; + handled = 1; + for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { + if (irqbits == port->vectormask) + break; + if (bits & irqbits) + continue; + info = port + i; + if (!info->tty || + (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) + continue; + status = inb(info->base + UART_LSR) & info->read_status_mask; + if (status & UART_LSR_DR) + mxser_receive_chars(info, &status); + msr = inb(info->base + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(info, msr); + if (status & UART_LSR_THRE) { +/* 8-2-99 by William + if ( info->x_char || (info->xmit_cnt > 0) ) + */ + mxser_transmit_chars(info); + } + } + if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { +#if 0 + printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + } + return IRQ_RETVAL(handled); +} + static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_struct *info) { diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 072197462..5a3be050e 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -99,11 +99,18 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) spin_unlock_irqrestore(&tty->read_lock, flags); } -/* - * Check whether to call the driver.unthrottle function. - * We test the TTY_THROTTLED bit first so that it always - * indicates the current state. +/** + * check_unthrottle - allow new receive data + * @tty; tty device + * + * Check whether to call the driver.unthrottle function. + * We test the TTY_THROTTLED bit first so that it always + * indicates the current state. The decision about whether + * it is worth allowing more input has been taken by the caller. + * Can sleep, may be called under the atomic_read semaphore but + * this is not guaranteed. */ + static void check_unthrottle(struct tty_struct * tty) { if (tty->count && @@ -112,10 +119,13 @@ static void check_unthrottle(struct tty_struct * tty) tty->driver->unthrottle(tty); } -/* - * Reset the read buffer counters, clear the flags, - * and make sure the driver is unthrottled. Called - * from n_tty_open() and n_tty_flush_buffer(). +/** + * reset_buffer_flags - reset buffer state + * @tty: terminal to reset + * + * Reset the read buffer counters, clear the flags, + * and make sure the driver is unthrottled. Called + * from n_tty_open() and n_tty_flush_buffer(). */ static void reset_buffer_flags(struct tty_struct *tty) { @@ -129,9 +139,19 @@ static void reset_buffer_flags(struct tty_struct *tty) check_unthrottle(tty); } -/* - * Flush the input buffer +/** + * n_tty_flush_buffer - clean input queue + * @tty: terminal device + * + * Flush the input buffer. Called when the line discipline is + * being closed, when the tty layer wants the buffer flushed (eg + * at hangup) or when the N_TTY line discipline internally has to + * clean the pending queue (for example some signals). + * + * FIXME: tty->ctrl_status is not spinlocked and relies on + * lock_kernel() still. */ + void n_tty_flush_buffer(struct tty_struct * tty) { /* clear everything and unthrottle the driver */ @@ -146,9 +166,14 @@ void n_tty_flush_buffer(struct tty_struct * tty) } } -/* - * Return number of characters buffered to be delivered to user +/** + * n_tty_chars_in_buffer - report available bytes + * @tty: tty device + * + * Report the number of characters buffered to be delivered to user + * at this instant in time. */ + ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { unsigned long flags; @@ -166,20 +191,47 @@ ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) return n; } +/** + * is_utf8_continuation - utf8 multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character. We use this to correctly compute the on screen size + * of the character when printing + */ + static inline int is_utf8_continuation(unsigned char c) { return (c & 0xc0) == 0x80; } +/** + * is_continuation - multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character and the terminal is in unicode mode. + */ + static inline int is_continuation(unsigned char c, struct tty_struct *tty) { return I_IUTF8(tty) && is_utf8_continuation(c); } -/* - * Perform OPOST processing. Returns -1 when the output device is - * full and the character must be retried. +/** + * opost - output post processor + * @c: character (or partial unicode symbol) + * @tty: terminal device + * + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. Note that Linux currently + * ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't + * relevant in the world today. If you ever need them, add them here. + * + * Called from both the receive and transmit sides and can be called + * re-entrantly. Relies on lock_kernel() still. */ + static int opost(unsigned char c, struct tty_struct *tty) { int space, spaces; @@ -239,10 +291,20 @@ static int opost(unsigned char c, struct tty_struct *tty) return 0; } -/* - * opost_block --- to speed up block console writes, among other - * things. +/** + * opost_block - block postprocess + * @tty: terminal device + * @inbuf: user buffer + * @nr: number of bytes + * + * This path is used to speed up block console writes, among other + * things when processing blocks of output data. It handles only + * the simple cases normally found and helps to generate blocks of + * symbols for the console driver and thus improve performance. + * + * Called from write_chan under the tty layer write lock. */ + static ssize_t opost_block(struct tty_struct * tty, const unsigned char __user * inbuf, unsigned int nr) { @@ -304,13 +366,27 @@ break_out: } - +/** + * put_char - write character to driver + * @c: character (or part of unicode symbol) + * @tty: terminal device + * + * Queue a byte to the driver layer for output + */ + static inline void put_char(unsigned char c, struct tty_struct *tty) { tty->driver->put_char(tty, c); } -/* Must be called only when L_ECHO(tty) is true. */ +/** + * echo_char - echo characters + * @c: unicode byte to echo + * @tty: terminal device + * + * Echo user input back onto the screen. This must be called only when + * L_ECHO(tty) is true. Called from the driver receive_buf path. + */ static void echo_char(unsigned char c, struct tty_struct *tty) { @@ -331,6 +407,16 @@ static inline void finish_erasing(struct tty_struct *tty) } } +/** + * eraser - handle erase function + * @c: character input + * @tty: terminal device + * + * Perform erase and neccessary output when an erase character is + * present in the stream from the driver layer. Handles the complexities + * of UTF-8 multibyte symbols. + */ + static void eraser(unsigned char c, struct tty_struct *tty) { enum { ERASE, WERASE, KILL } kill_type; @@ -463,6 +549,18 @@ static void eraser(unsigned char c, struct tty_struct *tty) finish_erasing(tty); } +/** + * isig - handle the ISIG optio + * @sig: signal + * @tty: terminal + * @flush: force flush + * + * Called when a signal is being sent due to terminal input. This + * may caus terminal flushing to take place according to the termios + * settings and character used. Called from the driver receive_buf + * path so serialized. + */ + static inline void isig(int sig, struct tty_struct *tty, int flush) { if (tty->pgrp > 0) @@ -474,6 +572,16 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) } } +/** + * n_tty_receive_break - handle break + * @tty: terminal + * + * An RS232 break event has been hit in the incoming bitstream. This + * can cause a variety of events depending upon the termios settings. + * + * Called from the receive_buf path so single threaded. + */ + static inline void n_tty_receive_break(struct tty_struct *tty) { if (I_IGNBRK(tty)) @@ -490,19 +598,40 @@ static inline void n_tty_receive_break(struct tty_struct *tty) wake_up_interruptible(&tty->read_wait); } +/** + * n_tty_receive_overrun - handle overrun reporting + * @tty: terminal + * + * Data arrived faster than we could process it. While the tty + * driver has flagged this the bits that were missed are gone + * forever. + * + * Called from the receive_buf path so single threaded. Does not + * need locking as num_overrun and overrun_time are function + * private. + */ + static inline void n_tty_receive_overrun(struct tty_struct *tty) { char buf[64]; tty->num_overrun++; if (time_before(tty->overrun_time, jiffies - HZ)) { - printk("%s: %d input overrun(s)\n", tty_name(tty, buf), + printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), tty->num_overrun); tty->overrun_time = jiffies; tty->num_overrun = 0; } } +/** + * n_tty_receive_parity_error - error notifier + * @tty: terminal device + * @c: character + * + * Process a parity error and queue the right data to indicate + * the error case if neccessary. Locking as per n_tty_receive_buf. + */ static inline void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { @@ -520,6 +649,16 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, wake_up_interruptible(&tty->read_wait); } +/** + * n_tty_receive_char - perform processing + * @tty: terminal device + * @c: character + * + * Process an individual character of input received from the driver. + * This is serialized with respect to itself by the rules for the + * driver above. + */ + static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { unsigned long flags; @@ -711,6 +850,16 @@ send_signal: put_tty_queue(c, tty); } +/** + * n_tty_receive_room - receive space + * @tty: terminal + * + * Called by the driver to find out how much data it is + * permitted to feed to the line discipline without any being lost + * and thus to manage flow control. Not serialized. Answers for the + * "instant". + */ + static int n_tty_receive_room(struct tty_struct *tty) { int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; @@ -729,10 +878,13 @@ static int n_tty_receive_room(struct tty_struct *tty) return 0; } -/* - * Required for the ptys, serial driver etc. since processes - * that attach themselves to the master and rely on ASYNC - * IO must be woken up +/** + * n_tty_write_wakeup - asynchronous I/O notifier + * @tty: tty device + * + * Required for the ptys, serial driver etc. since processes + * that attach themselves to the master and rely on ASYNC + * IO must be woken up */ static void n_tty_write_wakeup(struct tty_struct *tty) @@ -745,6 +897,19 @@ static void n_tty_write_wakeup(struct tty_struct *tty) return; } +/** + * n_tty_receive_buf - data receive + * @tty: terminal device + * @cp: buffer + * @fp: flag buffer + * @count: characters + * + * Called by the terminal driver when a block of characters has + * been received. This function must be called from soft contexts + * not from interrupt context. The driver is responsible for making + * calls one at a time and in order (or using flush_to_ldisc) + */ + static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { @@ -828,6 +993,18 @@ int is_ignored(int sig) current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); } +/** + * n_tty_set_termios - termios data changed + * @tty: terminal + * @old: previous data + * + * Called by the tty layer when the user changes termios flags so + * that the line discipline can plan ahead. This function cannot sleep + * and is protected from re-entry by the tty layer. The user is + * guaranteed that this function will not be re-entered or in progress + * when the ldisc is closed. + */ + static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) { if (!tty) @@ -843,7 +1020,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - local_irq_disable(); // FIXME: is this safe? memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) @@ -879,7 +1055,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); - local_irq_enable(); // FIXME: is this safe? tty->raw = 0; tty->real_raw = 0; } else { @@ -893,6 +1068,16 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) } } +/** + * n_tty_close - close the ldisc for this tty + * @tty: device + * + * Called from the terminal layer when this line discipline is + * being shut down, either because of a close or becsuse of a + * discipline change. The function will not be called while other + * ldisc methods are in progress. + */ + static void n_tty_close(struct tty_struct *tty) { n_tty_flush_buffer(tty); @@ -902,11 +1087,22 @@ static void n_tty_close(struct tty_struct *tty) } } +/** + * n_tty_open - open an ldisc + * @tty: terminal to open + * + * Called when this line discipline is being attached to the + * terminal device. Can sleep. Called serialized so that no + * other events will occur in parallel. No further open will occur + * until a close. + */ + static int n_tty_open(struct tty_struct *tty) { if (!tty) return -EINVAL; + /* This one is ugly. Currently a malloc failure here can panic */ if (!tty->read_buf) { tty->read_buf = alloc_buf(); if (!tty->read_buf) @@ -932,14 +1128,23 @@ static inline int input_available_p(struct tty_struct *tty, int amt) return 0; } -/* - * Helper function to speed up read_chan. It is only called when - * ICANON is off; it copies characters straight from the tty queue to - * user space directly. It can be profitably called twice; once to - * drain the space from the tail pointer to the (physical) end of the - * buffer, and once to drain the space from the (physical) beginning of - * the buffer to head pointer. +/** + * copy_from_read_buf - copy read data directly + * @tty: terminal device + * @b: user data + * @nr: size of data + * + * Helper function to speed up read_chan. It is only called when + * ICANON is off; it copies characters straight from the tty queue to + * user space directly. It can be profitably called twice; once to + * drain the space from the tail pointer to the (physical) end of the + * buffer, and once to drain the space from the (physical) beginning of + * the buffer to head pointer. + * + * Called under the tty->atomic_read sem and with TTY_DONT_FLIP set + * */ + static inline int copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr) @@ -970,25 +1175,18 @@ static inline int copy_from_read_buf(struct tty_struct *tty, extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); -static ssize_t read_chan(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) +/** + * job_control - check job control + * @tty: tty + * @file: file handle + * + * Perform job control management checks on this file/tty descriptor + * and if appropriate send any needed signals and return a negative + * error code if action should be taken. + */ + +static int job_control(struct tty_struct *tty, struct file *file) { - unsigned char __user *b = buf; - DECLARE_WAITQUEUE(wait, current); - int c; - int minimum, time; - ssize_t retval = 0; - ssize_t size; - long timeout; - unsigned long flags; - -do_it_again: - - if (!tty->read_buf) { - printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); - return -EIO; - } - /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough @@ -1006,7 +1204,48 @@ do_it_again: return -ERESTARTSYS; } } + return 0; +} + + +/** + * read_chan - read function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Perform reads for the line discipline. We are guaranteed that the + * line discipline will not be closed under us but we may get multiple + * parallel readers and must handle this ourselves. We may also get + * a hangup. Always called in user context, may sleep. + * + * This code must be sure never to sleep through a hangup. + */ + +static ssize_t read_chan(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) +{ + unsigned char __user *b = buf; + DECLARE_WAITQUEUE(wait, current); + int c; + int minimum, time; + ssize_t retval = 0; + ssize_t size; + long timeout; + unsigned long flags; + +do_it_again: + + if (!tty->read_buf) { + printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); + return -EIO; + } + c = job_control(tty, file); + if(c < 0) + return c; + minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; if (!tty->icanon) { @@ -1028,6 +1267,9 @@ do_it_again: } } + /* + * Internal serialization of reads. + */ if (file->f_flags & O_NONBLOCK) { if (down_trylock(&tty->atomic_read)) return -EAGAIN; @@ -1177,6 +1419,21 @@ do_it_again: return retval; } +/** + * write_chan - write function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Write function of the terminal device. This is serialized with + * respect to other write callers but not to termios changes, reads + * and other such events. We must be careful with N_TTY as the receive + * code will echo characters, thus calling driver write methods. + * + * This code must be sure never to sleep through a hangup. + */ + static ssize_t write_chan(struct tty_struct * tty, struct file * file, const unsigned char __user * buf, size_t nr) { @@ -1246,7 +1503,25 @@ break_out: return (b - buf) ? b - buf : retval; } -/* Called without the kernel lock held - fine */ +/** + * normal_poll - poll method for N_TTY + * @tty: terminal device + * @file: file accessing it + * @wait: poll table + * + * Called when the line discipline is asked to poll() for data or + * for special events. This code is not serialized with respect to + * other events save open/close. + * + * This code must be sure never to sleep through a hangup. + * Called without the kernel lock held - fine + * + * FIXME: if someone changes the VMIN or discipline settings for the + * terminal while another process is in poll() the poll does not + * recompute the new limits. Possibly set_termios should issue + * a read wakeup to fix this bug. + */ + static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) { unsigned int mask = 0; @@ -1287,6 +1562,7 @@ struct tty_ldisc tty_ldisc_N_TTY = { n_tty_ioctl, /* ioctl */ n_tty_set_termios, /* set_termios */ normal_poll, /* poll */ + NULL, /* hangup */ n_tty_receive_buf, /* receive_buf */ n_tty_receive_room, /* receive_room */ n_tty_write_wakeup /* write_wakeup */ diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index e75381ec1..f344ed315 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -60,15 +60,6 @@ static DECLARE_MUTEX(nwflash_sem); extern spinlock_t gpio_lock; -/* - * the delay routine - it is often required to let the flash "breeze"... - */ -void flash_wait(int timeout) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(timeout); -} - static int get_flash_id(void) { volatile unsigned int c1, c2; @@ -401,7 +392,7 @@ static int erase_block(int nBlock) /* * wait 10 ms */ - flash_wait(HZ / 100); + msleep(10); /* * wait while erasing in process (up to 10 sec) @@ -409,7 +400,7 @@ static int erase_block(int nBlock) timeout = jiffies + 10 * HZ; c1 = 0; while (!(c1 & 0x80) && time_before(jiffies, timeout)) { - flash_wait(HZ / 100); + msleep(10); /* * read any address */ @@ -440,7 +431,7 @@ static int erase_block(int nBlock) /* * just to make sure - verify if erased OK... */ - flash_wait(HZ / 100); + msleep(10); pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + (nBlock << 16))); @@ -587,7 +578,7 @@ static int write_block(unsigned long p, const char __user *buf, int count) /* * wait couple ms */ - flash_wait(HZ / 100); + msleep(10); /* * red LED == write */ @@ -612,7 +603,7 @@ static int write_block(unsigned long p, const char __user *buf, int count) leds_event(led_amber_off); leds_event(led_green_on); - flash_wait(HZ / 100); + msleep(10); pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index cb1cfb0af..5d7f21542 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. @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #include #include #include +#include #include #include @@ -76,12 +78,8 @@ #include #include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#ifdef CONFIG_HDLC_MODULE +#define CONFIG_HDLC 1 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -239,12 +237,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 +259,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 +395,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); @@ -453,8 +444,6 @@ static int tx_abort(MGSLPC_INFO *info); static int set_rxenable(MGSLPC_INFO *info, int enable); static int wait_events(MGSLPC_INFO *info, int __user *mask); -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) - static MGSLPC_INFO *mgslpc_device_list = NULL; static int mgslpc_device_count = 0; @@ -494,7 +483,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; @@ -504,10 +493,6 @@ static struct tty_driver *serial_driver; static void mgslpc_change_params(MGSLPC_INFO *info); static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* PCMCIA prototypes */ static void mgslpc_config(dev_link_t *link); @@ -531,6 +516,40 @@ static void* mgslpc_get_text_ptr(void) return mgslpc_get_text_ptr; } +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_flush_buffer - flush line discipline receive buffers + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_flush_buffer(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } +} + +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + static dev_link_t *mgslpc_attach(void) { MGSLPC_INFO *info; @@ -984,13 +1003,7 @@ void bh_transmit(MGSLPC_INFO *info) printk("bh_transmit() entry on %s\n", info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):calling ldisc.write_wakeup on %s\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } @@ -1163,9 +1176,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 { @@ -1201,7 +1214,7 @@ void tx_ready(MGSLPC_INFO *info) return; while (info->tx_count && fifo_count) { - c = MIN(2, MIN(fifo_count, MIN(info->tx_count, TXBUFSIZE - info->tx_get))); + c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); if (c == 1) { write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); @@ -1271,13 +1284,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); @@ -1764,8 +1777,8 @@ static int mgslpc_write(struct tty_struct * tty, int from_user, } for (;;) { - c = MIN(count, - MIN(TXBUFSIZE - info->tx_count - 1, + c = min(count, + min(TXBUFSIZE - info->tx_count - 1, TXBUFSIZE - info->tx_put)); if (c <= 0) break; @@ -1875,11 +1888,9 @@ static void mgslpc_flush_buffer(struct tty_struct *tty) info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); spin_unlock_irqrestore(&info->lock,flags); - + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* Send a high-priority XON/XOFF character @@ -2588,9 +2599,8 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + ldisc_flush_buffer(tty); shutdown(info); @@ -2651,7 +2661,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if (info->params.mode == MGSL_MODE_HDLC) { while (info->tx_active) { @@ -2876,7 +2886,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 +2941,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 +3080,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 +3096,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); @@ -3669,7 +3674,7 @@ void tx_start(MGSLPC_INFO *info) } else { info->tx_active = 1; tx_ready(info); - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } } @@ -4021,9 +4026,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,18 +4060,12 @@ 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 - { - /* Call the line discipline receive callback directly. */ - if (tty && tty->ldisc.receive_buf) - tty->ldisc.receive_buf(tty, buf->data, info->flag_buf, framesize); - } + ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); } } @@ -4128,7 +4130,7 @@ BOOLEAN irq_test(MGSLPC_INFO *info) end_time=100; while(end_time-- && !info->irq_occurred) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); } info->testing_irq = FALSE; @@ -4215,88 +4217,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 +4352,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); } -void mgslpc_sppp_rx_done(MGSLPC_INFO *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(MGSLPC_INFO *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(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/pcxx.c b/drivers/char/pcxx.c index e804fdc73..061237bb0 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -130,7 +130,6 @@ static struct channel *digi_channels; int pcxx_ncook=sizeof(pcxx_cook); int pcxx_nbios=sizeof(pcxx_bios); -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define pcxxassert(x, msg) if(!(x)) pcxx_error(__LINE__, msg) #define FEPTIMEOUT 200000 @@ -206,7 +205,7 @@ static void __exit pcxe_cleanup(void) { unsigned long flags; - int e1, e2; + int e1; printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION); @@ -223,12 +222,6 @@ static void __exit pcxe_cleanup(void) restore_flags(flags); } -/* - * pcxe_init() is our init_module(): - */ -module_init(pcxe_init); -module_cleanup(pcxe_cleanup); - static inline struct channel *chan(register struct tty_struct *tty) { if (tty) { @@ -538,28 +531,11 @@ static void pcxe_close(struct tty_struct * tty, struct file * filp) if(tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if(tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); shutdown(info); tty->closing = 0; info->event = 0; info->tty = NULL; -#ifndef MODULE -/* ldiscs[] is not available in a MODULE -** worth noting that while I'm not sure what this hunk of code is supposed -** to do, it is not present in the serial.c driver. Hmmm. If you know, -** please send me a note. brian@ilinx.com -** Don't know either what this is supposed to do christoph@lameter.com. -*/ - if(tty->ldisc.num != ldiscs[N_TTY].num) { - if(tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if(tty->ldisc.open) - (tty->ldisc.open)(tty); - } -#endif if(info->blocked_open) { if(info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -626,7 +602,7 @@ static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned cha tail &= (size - 1); stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); - count = MIN(stlen, count); + count = min(stlen, count); memoff(ch); restore_flags(flags); @@ -658,11 +634,11 @@ static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned cha remain = tail - head - 1; stlen = remain; } - count = MIN(remain, count); + count = min(remain, count); txwinon(ch); while (count > 0) { - stlen = MIN(count, stlen); + stlen = min(count, stlen); memcpy(ch->txptr + head, buf, stlen); buf += stlen; count -= stlen; @@ -800,9 +776,7 @@ static void pcxe_flush_buffer(struct tty_struct *tty) memoff(ch); restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } static void pcxe_flush_chars(struct tty_struct *tty) @@ -1013,9 +987,6 @@ void __init pcxx_setup(char *str, int *ints) } #endif -module_init(pcxe_init) -module_exit(pcxe_exit) - static struct tty_operations pcxe_ops = { .open = pcxe_open, .close = pcxe_close, @@ -1561,6 +1532,8 @@ cleanup_boards: return ret; } +module_init(pcxe_init) +module_exit(pcxe_cleanup) static void pcxxpoll(unsigned long dummy) { @@ -1675,10 +1648,7 @@ static void doevent(int crd) if (event & LOWTX_IND) { if (ch->statusflags & LOWWAIT) { ch->statusflags &= ~LOWWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -1686,10 +1656,7 @@ static void doevent(int crd) ch->statusflags &= ~TXBUSY; if (ch->statusflags & EMPTYWAIT) { ch->statusflags &= ~EMPTYWAIT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } } @@ -1995,6 +1962,7 @@ static int pcxe_tiocmget(struct tty_struct *tty, struct file *file) volatile struct board_chan *bc; unsigned long flags; int mflag = 0; + int mstat; if(ch) bc = ch->brdchan; @@ -2069,6 +2037,7 @@ static int pcxe_tiocmset(struct tty_struct *tty, struct file *file, pcxxparam(tty,ch); memoff(ch); restore_flags(flags); + return 0; } @@ -2165,8 +2134,7 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file, tty_wait_until_sent(tty, 0); } else { - if(tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); } /* Fall Thru */ diff --git a/drivers/char/pty.c b/drivers/char/pty.c index fcbb32547..9826bbd0f 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -32,12 +32,6 @@ #include #include -#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; @@ -91,10 +85,7 @@ static void pty_unthrottle(struct tty_struct * tty) if (!o_tty) return; - if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - o_tty->ldisc.write_wakeup) - (o_tty->ldisc.write_wakeup)(o_tty); - wake_up_interruptible(&o_tty->write_wait); + tty_wakeup(o_tty); set_bit(TTY_THROTTLED, &tty->flags); } @@ -107,6 +98,10 @@ static void pty_unthrottle(struct tty_struct * tty) * (2) avoid redundant copying for cases where count >> receive_room * N.B. Calls from user space may now return an error code instead of * a count. + * + * FIXME: Our pty_write method is called with our ldisc lock held but + * not our partners. We can't just take the other one blindly without + * risking deadlocks. There is also the small matter of TTY_DONT_FLIP */ static int pty_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -205,19 +200,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 +213,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 +269,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 +331,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 +429,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 e39179f50..295e3f718 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); @@ -781,9 +781,9 @@ static void batch_entropy_process(void *private_) /* There is one of these per entropy source */ struct timer_rand_state { - __u32 last_time; - __s32 last_delta,last_delta2; - int dont_count_entropy:1; + cycles_t last_time; + long last_delta,last_delta2; + unsigned dont_count_entropy:1; }; static struct timer_rand_state keyboard_timer_state; @@ -799,37 +799,31 @@ static struct timer_rand_state *irq_timer_state[NR_IRQS]; * The number "num" is also added to the pool - it should somehow describe * the type of event which just happened. This is currently 0-255 for * keyboard scan codes, and 256 upwards for interrupts. - * On the i386, this is assumed to be at most 16 bits, and the high bits - * are used for a high-resolution timer. * */ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) { - __u32 time; - __s32 delta, delta2, delta3; + cycles_t time; + long delta, delta2, delta3; int entropy = 0; + preempt_disable(); /* if over the trickle threshold, use only 1 in 4096 samples */ if ( random_state->entropy_count > trickle_thresh && (__get_cpu_var(trickle_count)++ & 0xfff)) - return; + goto out; -#if defined (__i386__) || defined (__x86_64__) - if (cpu_has_tsc) { - __u32 high; - rdtsc(time, high); - num ^= high; + /* + * Use get_cycles() if implemented, otherwise fall back to + * jiffies. + */ + time = get_cycles(); + if (time != 0) { + if (sizeof(time) > 4) + num ^= (u32)(time >> 32); } else { time = jiffies; } -#elif defined (__sparc_v9__) - unsigned long tick = tick_ops->get_tick(); - - time = (unsigned int) tick; - num ^= (tick >> 32UL); -#else - time = jiffies; -#endif /* * Calculate number of bits of randomness we probably added. @@ -868,6 +862,8 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) entropy = int_ln_12bits(delta); } batch_entropy_store(num, time, entropy); +out: + preempt_enable(); } void add_keyboard_randomness(unsigned char scancode) @@ -1328,8 +1324,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 +1368,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 +1381,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 +1471,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,15 +1529,22 @@ 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); + init_std_data(urandom_state); #ifdef CONFIG_SYSCTL sysctl_init_random(random_state); #endif @@ -1674,9 +1677,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 @@ -1730,10 +1739,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: @@ -1754,40 +1762,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; @@ -1884,7 +1858,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, @@ -2212,7 +2187,7 @@ static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) #undef K3 /* This should not be decreased so low that ISNs wrap too fast. */ -#define REKEY_INTERVAL 300 +#define REKEY_INTERVAL (300*HZ) /* * Bit layout of the tcp sequence numbers (before adding current time): * bit 24-31: increased after every key exchange @@ -2238,43 +2213,55 @@ static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) #define HASH_MASK ( (1<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)<secret, sizeof(keyptr->secret)); + keyptr->count = (ip_cnt&COUNT_MASK)<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { - keyptr = __check_and_rekey(time); - } + smp_rmb(); return keyptr; } +static __init int seqgen_init(void) +{ + rekey_seq_generator(NULL); + return 0; +} +late_initcall(seqgen_init); + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, __u16 sport, __u16 dport) @@ -2282,14 +2269,12 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, struct timeval tv; __u32 seq; __u32 hash[12]; - struct keydata *keyptr; + struct keydata *keyptr = get_keyptr(); /* The procedure is the same as for IPv4, but addresses are longer. * Thus we must use twothirdsMD4Transform. */ - do_gettimeofday(&tv); /* We need the usecs below... */ - keyptr = check_and_rekey(tv.tv_sec); memcpy(hash, saddr, 16); hash[4]=(sport << 16) + dport; @@ -2297,38 +2282,22 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; seq += keyptr->count; + + do_gettimeofday(&tv); seq += tv.tv_usec + tv.tv_sec*1000000; return seq; } EXPORT_SYMBOL(secure_tcpv6_sequence_number); - -__u32 secure_ipv6_id(__u32 *daddr) -{ - struct keydata *keyptr; - - keyptr = check_and_rekey(get_seconds()); - - return halfMD4Transform(daddr, keyptr->secret); -} - -EXPORT_SYMBOL(secure_ipv6_id); #endif - __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { struct timeval tv; __u32 seq; __u32 hash[4]; - struct keydata *keyptr; - - /* - * Pick a random secret every REKEY_INTERVAL seconds. - */ - do_gettimeofday(&tv); /* We need the usecs below... */ - keyptr = check_and_rekey(tv.tv_sec); + struct keydata *keyptr = get_keyptr(); /* * Pick a unique starting offset for each TCP connection endpoints @@ -2351,6 +2320,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, * That's funny, Linux has one built in! Use it! * (Networks are faster now - should this be increased?) */ + do_gettimeofday(&tv); seq += tv.tv_usec + tv.tv_sec*1000000; #if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", @@ -2369,7 +2339,7 @@ __u32 secure_ip_id(__u32 daddr) struct keydata *keyptr; __u32 hash[4]; - keyptr = check_and_rekey(get_seconds()); + keyptr = get_keyptr(); /* * Pick a unique starting offset for each IP destination. diff --git a/drivers/char/rio/linux_compat.h b/drivers/char/rio/linux_compat.h index 26063cb6a..d53843abe 100644 --- a/drivers/char/rio/linux_compat.h +++ b/drivers/char/rio/linux_compat.h @@ -16,7 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include #define disable(oldspl) save_flags (oldspl) diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index a11fafbab..0cc02371a 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -1138,8 +1138,8 @@ static int __init rio_init(void) hp->Ivec = pdev->irq; if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0; - hp->CardP = (struct DpRam *) hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN); + hp->CardP = (struct DpRam *) hp->Caddr; hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; @@ -1196,8 +1196,8 @@ static int __init rio_init(void) if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0; hp->Ivec |= 0x8000; /* Mark as non-sharable */ - hp->CardP = (struct DpRam *) hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN); + hp->CardP = (struct DpRam *) hp->Caddr; hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; @@ -1242,8 +1242,8 @@ static int __init rio_init(void) hp->PaddrP = rio_probe_addrs[i]; /* There was something about the IRQs of these cards. 'Forget what.--REW */ hp->Ivec = 0; - hp->CardP = (struct DpRam *) hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN); + hp->CardP = (struct DpRam *) hp->Caddr; hp->Type = RIO_AT; hp->Copy = rio_pcicopy; /* AT card PCI???? - PVDL * -- YES! this is now a normal copy. Only the diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 69108ceea..a35ea03a3 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -75,10 +75,6 @@ ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \ ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #define RS_EVENT_WRITE_WAKEUP 0 static struct riscom_board * IRQ_to_board[16]; @@ -107,7 +103,7 @@ static struct riscom_board rc_board[RC_NBOARD] = { }; static struct riscom_port rc_port[RC_NBOARD * RC_NPORT]; - + /* RISCom/8 I/O ports addresses (without address translation) */ static unsigned short rc_ioport[] = { #if 1 @@ -483,7 +479,7 @@ static inline void rc_transmit(struct riscom_board const * bp) rc_out(bp, CD180_TDR, CD180_C_SBRK); port->COR2 &= ~COR2_ETC; } - count = MIN(port->break_length, 0xff); + count = min_t(int, port->break_length, 0xff); rc_out(bp, CD180_TDR, CD180_C_ESC); rc_out(bp, CD180_TDR, CD180_C_DELAY); rc_out(bp, CD180_TDR, count); @@ -1127,8 +1123,8 @@ static void rc_close(struct tty_struct * tty, struct file * filp) rc_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; port->event = 0; port->tty = NULL; @@ -1165,8 +1161,8 @@ static int rc_write(struct tty_struct * tty, int from_user, down(&tmp_buf_sem); while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) break; @@ -1178,8 +1174,8 @@ static int rc_write(struct tty_struct * tty, int from_user, } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + c = min_t(int, c, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; @@ -1193,8 +1189,8 @@ static int rc_write(struct tty_struct * tty, int from_user, } else { while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { restore_flags(flags); break; @@ -1301,9 +1297,7 @@ static void rc_flush_buffer(struct tty_struct *tty) restore_flags(flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } static int rc_tiocmget(struct tty_struct *tty, struct file *file) @@ -1644,9 +1638,7 @@ static void do_softint(void *private_) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 129b8ccd8..72af1bec9 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -250,12 +250,16 @@ static void rp_do_receive(struct r_port *info, CHANNEL_t * cp, unsigned int ChanStatus) { unsigned int CharNStat; - int ToRecv, wRecv, space, count; + int ToRecv, wRecv, space = 0, count; unsigned char *cbuf; char *fbuf; + struct tty_ldisc *ld; + + ld = tty_ldisc_ref(tty); ToRecv = sGetRxCnt(cp); - space = tty->ldisc.receive_room(tty); + if (ld) + space = ld->receive_room(tty); if (space > 2 * TTY_FLIPBUF_SIZE) space = 2 * TTY_FLIPBUF_SIZE; cbuf = tty->flip.char_buf; @@ -354,7 +358,8 @@ static void rp_do_receive(struct r_port *info, count += ToRecv; } /* Push the data up to the tty layer */ - tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); + ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); + tty_ldisc_deref(ld); } /* @@ -389,7 +394,7 @@ static void rp_do_transmit(struct r_port *info) while (1) { if (tty->stopped || tty->hw_stopped) break; - c = MIN(info->xmit_fifo_room, MIN(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); + c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); if (c <= 0 || info->xmit_fifo_room <= 0) break; sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); @@ -408,8 +413,7 @@ static void rp_do_transmit(struct r_port *info) clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); @@ -1022,7 +1026,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp) unsigned long flags; int timeout; CHANNEL_t *cp; - + if (rocket_paranoia_check(info, "rp_close")) return; @@ -1101,8 +1105,8 @@ static void rp_close(struct tty_struct *tty, struct file *filp) if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty)) TTY_DRIVER_FLUSH_BUFFER(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); @@ -1283,11 +1287,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; @@ -1662,7 +1662,7 @@ static int rp_write(struct tty_struct *tty, int from_user, * into FIFO. Use the write queue for temp storage. */ if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { - c = MIN(count, info->xmit_fifo_room); + c = min(count, info->xmit_fifo_room); b = buf; if (from_user) { if (copy_from_user(info->xmit_buf, buf, c)) { @@ -1672,7 +1672,7 @@ static int rp_write(struct tty_struct *tty, int from_user, if (info->tty == 0) goto end; b = info->xmit_buf; - c = MIN(c, info->xmit_fifo_room); + c = min(c, info->xmit_fifo_room); } /* Push data into FIFO, 2 bytes at a time */ @@ -1700,7 +1700,7 @@ static int rp_write(struct tty_struct *tty, int from_user, if (info->tty == 0) /* Seemingly obligatory check... */ goto end; - c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); + c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); if (c <= 0) break; @@ -1731,8 +1731,7 @@ end_intr: end: if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); @@ -1806,8 +1805,7 @@ static void rp_flush_buffer(struct tty_struct *tty) #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); #endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); cp = &info->channel; sFlushTxFIFO(cp); diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 9380ff53f..802687290 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -1241,10 +1241,6 @@ struct r_port { #define TTY_ROCKET_MAJOR 46 #define CUA_ROCKET_MAJOR 47 -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #ifdef PCI_VENDOR_ID_RP #undef PCI_VENDOR_ID_RP #undef PCI_DEVICE_ID_RP8OCTA diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 598f60110..4675eda44 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -26,10 +26,6 @@ #include #include -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') @@ -281,12 +277,15 @@ int paste_selection(struct tty_struct *tty) { struct vt_struct *vt = (struct vt_struct *) tty->driver_data; int pasted = 0, count; + struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); acquire_console_sem(); poke_blanked_console(); release_console_sem(); + ld = tty_ldisc_ref_wait(tty); + add_wait_queue(&vt->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); @@ -295,12 +294,14 @@ int paste_selection(struct tty_struct *tty) continue; } count = sel_buffer_lth - pasted; - count = MIN(count, tty->ldisc.receive_room(tty)); + count = min(count, tty->ldisc.receive_room(tty)); tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } remove_wait_queue(&vt->paste_wait, &wait); current->state = TASK_RUNNING; + + tty_ldisc_deref(ld); return 0; } diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index f0b966876..6b4e9d155 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -599,10 +599,7 @@ int ch, err, n, p; /* WakeUp if output buffer runs low */ if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){ - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - } - wake_up_interruptible(&port->gs.tty->write_wait); + tty_wakeup(port->gs.tty); } } // if the port is used } // for every port on the board diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 1b51eecfb..885621edb 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -83,10 +83,6 @@ #undef CYCLOM_16Y_HACK #define CYCLOM_ENABLE_MONITORING -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #define WAKEUP_CHARS 256 #define STD_COM_FLAGS (0) @@ -760,11 +756,7 @@ do_softint(void *private_) wake_up_interruptible(&info->open_wait); } if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } /* do_softint */ @@ -1238,8 +1230,8 @@ cy_write(struct tty_struct * tty, int from_user, if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -1251,8 +1243,8 @@ cy_write(struct tty_struct * tty, int from_user, } local_irq_save(flags); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt += c; @@ -1266,8 +1258,8 @@ cy_write(struct tty_struct * tty, int from_user, } else { while (1) { local_irq_save(flags); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { local_irq_restore(flags); break; @@ -1343,10 +1335,7 @@ cy_flush_buffer(struct tty_struct *tty) local_irq_save(flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; local_irq_restore(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* cy_flush_buffer */ @@ -1846,18 +1835,9 @@ cy_close(struct tty_struct * tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); info->event = 0; info->tty = 0; - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -2379,7 +2359,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/serial_tx3912.c b/drivers/char/serial_tx3912.c index 39717ed68..50ed6dfec 100644 --- a/drivers/char/serial_tx3912.c +++ b/drivers/char/serial_tx3912.c @@ -191,12 +191,9 @@ static inline void transmit_char_pio(struct rs_port *port) } if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + tty_wakeup(port->gs.tty); rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); - wake_up_interruptible(&port->gs.tty->write_wait); } } diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c new file mode 100644 index 000000000..25917e08e --- /dev/null +++ b/drivers/char/snsc.c @@ -0,0 +1,456 @@ +/* + * SN Platform system controller communication support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * System controller communication driver + * + * This driver allows a user process to communicate with the system + * controller (a.k.a. "IRouter") network in an SGI SN system. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "snsc.h" + +#define SYSCTL_BASENAME "snsc" + +#define SCDRV_BUFSZ 2048 +#define SCDRV_TIMEOUT 1000 + +static irqreturn_t +scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs) +{ + struct subch_data_s *sd = subch_data; + unsigned long flags; + int status; + + spin_lock_irqsave(&sd->sd_rlock, flags); + spin_lock(&sd->sd_wlock); + status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); + + if (status > 0) { + if (status & SAL_IROUTER_INTR_RECV) { + wake_up(&sd->sd_rq); + } + if (status & SAL_IROUTER_INTR_XMIT) { + ia64_sn_irtr_intr_disable + (sd->sd_nasid, sd->sd_subch, + SAL_IROUTER_INTR_XMIT); + wake_up(&sd->sd_wq); + } + } + spin_unlock(&sd->sd_wlock); + spin_unlock_irqrestore(&sd->sd_rlock, flags); + return IRQ_HANDLED; +} + +/* + * scdrv_open + * + * Reserve a subchannel for system controller communication. + */ + +static int +scdrv_open(struct inode *inode, struct file *file) +{ + struct sysctl_data_s *scd; + struct subch_data_s *sd; + int rv; + + /* look up device info for this device file */ + scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev); + + /* allocate memory for subchannel data */ + sd = kmalloc(sizeof (struct subch_data_s), GFP_KERNEL); + if (sd == NULL) { + printk("%s: couldn't allocate subchannel data\n", + __FUNCTION__); + return -ENOMEM; + } + + /* initialize subch_data_s fields */ + memset(sd, 0, sizeof (struct subch_data_s)); + sd->sd_nasid = scd->scd_nasid; + sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid); + + if (sd->sd_subch < 0) { + kfree(sd); + printk("%s: couldn't allocate subchannel\n", __FUNCTION__); + return -EBUSY; + } + + spin_lock_init(&sd->sd_rlock); + spin_lock_init(&sd->sd_wlock); + init_waitqueue_head(&sd->sd_rq); + init_waitqueue_head(&sd->sd_wq); + sema_init(&sd->sd_rbs, 1); + sema_init(&sd->sd_wbs, 1); + + file->private_data = sd; + + /* hook this subchannel up to the system controller interrupt */ + rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, + SA_SHIRQ | SA_INTERRUPT, + SYSCTL_BASENAME, sd); + if (rv) { + ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); + kfree(sd); + printk("%s: irq request failed (%d)\n", __FUNCTION__, rv); + return -EBUSY; + } + + return 0; +} + +/* + * scdrv_release + * + * Release a previously-reserved subchannel. + */ + +static int +scdrv_release(struct inode *inode, struct file *file) +{ + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + int rv; + + /* free the interrupt */ + free_irq(SGI_UART_VECTOR, sd); + + /* ask SAL to close the subchannel */ + rv = ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); + + kfree(sd); + return rv; +} + +/* + * scdrv_read + * + * Called to read bytes from the open IRouter pipe. + * + */ + +static inline int +read_status_check(struct subch_data_s *sd, int *len) +{ + return ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, sd->sd_rb, len); +} + +static ssize_t +scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) +{ + int status; + int len; + unsigned long flags; + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + + /* try to get control of the read buffer */ + if (down_trylock(&sd->sd_rbs)) { + /* somebody else has it now; + * if we're non-blocking, then exit... + */ + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + /* ...or if we want to block, then do so here */ + if (down_interruptible(&sd->sd_rbs)) { + /* something went wrong with wait */ + return -ERESTARTSYS; + } + } + + /* anything to read? */ + len = CHUNKSIZE; + spin_lock_irqsave(&sd->sd_rlock, flags); + status = read_status_check(sd, &len); + + /* if not, and we're blocking I/O, loop */ + while (status < 0) { + DECLARE_WAITQUEUE(wait, current); + + if (file->f_flags & O_NONBLOCK) { + spin_unlock_irqrestore(&sd->sd_rlock, flags); + up(&sd->sd_rbs); + return -EAGAIN; + } + + len = CHUNKSIZE; + add_wait_queue(&sd->sd_rq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&sd->sd_rlock, flags); + + schedule_timeout(SCDRV_TIMEOUT); + + remove_wait_queue(&sd->sd_rq, &wait); + if (signal_pending(current)) { + /* wait was interrupted */ + up(&sd->sd_rbs); + return -ERESTARTSYS; + } + + spin_lock_irqsave(&sd->sd_rlock, flags); + status = read_status_check(sd, &len); + } + spin_unlock_irqrestore(&sd->sd_rlock, flags); + + if (len > 0) { + /* we read something in the last read_status_check(); copy + * it out to user space + */ + if (count < len) { + pr_debug("%s: only accepting %d of %d bytes\n", + __FUNCTION__, (int) count, len); + } + len = min((int) count, len); + if (copy_to_user(buf, sd->sd_rb, len)) + len = -EFAULT; + } + + /* release the read buffer and wake anyone who might be + * waiting for it + */ + up(&sd->sd_rbs); + + /* return the number of characters read in */ + return len; +} + +/* + * scdrv_write + * + * Writes a chunk of an IRouter packet (or other system controller data) + * to the system controller. + * + */ +static inline int +write_status_check(struct subch_data_s *sd, int count) +{ + return ia64_sn_irtr_send(sd->sd_nasid, sd->sd_subch, sd->sd_wb, count); +} + +static ssize_t +scdrv_write(struct file *file, const char __user *buf, + size_t count, loff_t *f_pos) +{ + unsigned long flags; + int status; + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + + /* try to get control of the write buffer */ + if (down_trylock(&sd->sd_wbs)) { + /* somebody else has it now; + * if we're non-blocking, then exit... + */ + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + /* ...or if we want to block, then do so here */ + if (down_interruptible(&sd->sd_wbs)) { + /* something went wrong with wait */ + return -ERESTARTSYS; + } + } + + count = min((int) count, CHUNKSIZE); + if (copy_from_user(sd->sd_wb, buf, count)) { + up(&sd->sd_wbs); + return -EFAULT; + } + + /* try to send the buffer */ + spin_lock_irqsave(&sd->sd_wlock, flags); + status = write_status_check(sd, count); + + /* if we failed, and we want to block, then loop */ + while (status <= 0) { + DECLARE_WAITQUEUE(wait, current); + + if (file->f_flags & O_NONBLOCK) { + spin_unlock(&sd->sd_wlock); + up(&sd->sd_wbs); + return -EAGAIN; + } + + add_wait_queue(&sd->sd_wq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&sd->sd_wlock, flags); + + schedule_timeout(SCDRV_TIMEOUT); + + remove_wait_queue(&sd->sd_wq, &wait); + if (signal_pending(current)) { + /* wait was interrupted */ + up(&sd->sd_wbs); + return -ERESTARTSYS; + } + + spin_lock_irqsave(&sd->sd_wlock, flags); + status = write_status_check(sd, count); + } + spin_unlock_irqrestore(&sd->sd_wlock, flags); + + /* release the write buffer and wake anyone who's waiting for it */ + up(&sd->sd_wbs); + + /* return the number of characters accepted (should be the complete + * "chunk" as requested) + */ + if ((status >= 0) && (status < count)) { + pr_debug("Didn't accept the full chunk; %d of %d\n", + status, (int) count); + } + return status; +} + +static unsigned int +scdrv_poll(struct file *file, struct poll_table_struct *wait) +{ + unsigned int mask = 0; + int status = 0; + struct subch_data_s *sd = (struct subch_data_s *) file->private_data; + unsigned long flags; + + poll_wait(file, &sd->sd_rq, wait); + poll_wait(file, &sd->sd_wq, wait); + + spin_lock_irqsave(&sd->sd_rlock, flags); + spin_lock(&sd->sd_wlock); + status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); + spin_unlock(&sd->sd_wlock); + spin_unlock_irqrestore(&sd->sd_rlock, flags); + + if (status > 0) { + if (status & SAL_IROUTER_INTR_RECV) { + mask |= POLLIN | POLLRDNORM; + } + if (status & SAL_IROUTER_INTR_XMIT) { + mask |= POLLOUT | POLLWRNORM; + } + } + + return mask; +} + +static struct file_operations scdrv_fops = { + .owner = THIS_MODULE, + .read = scdrv_read, + .write = scdrv_write, + .poll = scdrv_poll, + .open = scdrv_open, + .release = scdrv_release, +}; + +/* + * scdrv_init + * + * Called at boot time to initialize the system controller communication + * facility. + */ +int __init +scdrv_init(void) +{ + geoid_t geoid; + cmoduleid_t cmod; + int i; + char devname[32]; + char *devnamep; + module_t *m; + struct sysctl_data_s *scd; + void *salbuf; + struct class_simple *snsc_class; + dev_t first_dev, dev; + + if (alloc_chrdev_region(&first_dev, 0, (MAX_SLABS*nummodules), + SYSCTL_BASENAME) < 0) { + printk("%s: failed to register SN system controller device\n", + __FUNCTION__); + return -ENODEV; + } + snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME); + + for (cmod = 0; cmod < nummodules; cmod++) { + m = sn_modules[cmod]; + for (i = 0; i <= MAX_SLABS; i++) { + + if (m->nodes[i] == -1) { + /* node is not alive in module */ + continue; + } + + geoid = m->geoid[i]; + devnamep = devname; + format_module_id(devnamep, geo_module(geoid), + MODULE_FORMAT_BRIEF); + devnamep = devname + strlen(devname); + sprintf(devnamep, "#%d", geo_slab(geoid)); + + /* allocate sysctl device data */ + scd = kmalloc(sizeof (struct sysctl_data_s), + GFP_KERNEL); + if (!scd) { + printk("%s: failed to allocate device info" + "for %s/%s\n", __FUNCTION__, + SYSCTL_BASENAME, devname); + continue; + } + memset(scd, 0, sizeof (struct sysctl_data_s)); + + /* initialize sysctl device data fields */ + scd->scd_nasid = cnodeid_to_nasid(m->nodes[i]); + if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) { + printk("%s: failed to allocate driver buffer" + "(%s%s)\n", __FUNCTION__, + SYSCTL_BASENAME, devname); + kfree(scd); + continue; + } + + if (ia64_sn_irtr_init(scd->scd_nasid, salbuf, + SCDRV_BUFSZ) < 0) { + printk + ("%s: failed to initialize SAL for" + " system controller communication" + " (%s/%s): outdated PROM?\n", + __FUNCTION__, SYSCTL_BASENAME, devname); + kfree(scd); + kfree(salbuf); + continue; + } + + dev = first_dev + m->nodes[i]; + cdev_init(&scd->scd_cdev, &scdrv_fops); + if (cdev_add(&scd->scd_cdev, dev, 1)) { + printk("%s: failed to register system" + " controller device (%s%s)\n", + __FUNCTION__, SYSCTL_BASENAME, devname); + kfree(scd); + kfree(salbuf); + continue; + } + + class_simple_device_add(snsc_class, dev, NULL, + "%s", devname); + + ia64_sn_irtr_intr_enable(scd->scd_nasid, + 0 /*ignored */ , + SAL_IROUTER_INTR_RECV); + } + } + return 0; +} + +module_init(scdrv_init); diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h new file mode 100644 index 000000000..c22c6c55e --- /dev/null +++ b/drivers/char/snsc.h @@ -0,0 +1,50 @@ +/* + * SN Platform system controller communication support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * This file contains macros and data types for communication with the + * system controllers in SGI SN systems. + */ + +#ifndef _SN_SYSCTL_H_ +#define _SN_SYSCTL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHUNKSIZE 127 + +/* This structure is used to track an open subchannel. */ +struct subch_data_s { + nasid_t sd_nasid; /* node on which the subchannel was opened */ + int sd_subch; /* subchannel number */ + spinlock_t sd_rlock; /* monitor lock for rsv */ + spinlock_t sd_wlock; /* monitor lock for wsv */ + wait_queue_head_t sd_rq; /* wait queue for readers */ + wait_queue_head_t sd_wq; /* wait queue for writers */ + struct semaphore sd_rbs; /* semaphore for read buffer */ + struct semaphore sd_wbs; /* semaphore for write buffer */ + + char sd_rb[CHUNKSIZE]; /* read buffer */ + char sd_wb[CHUNKSIZE]; /* write buffer */ +}; + +struct sysctl_data_s { + struct cdev scd_cdev; /* Character device info */ + nasid_t scd_nasid; /* Node on which subchannels are opened. */ +}; + +#endif /* _SN_SYSCTL_H_ */ diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 28418d57f..aa7c91d6f 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -50,12 +50,13 @@ #include #include +static int verbose; /* = 0 */ + #include "sonypi.h" #include static struct sonypi_device sonypi_device; static int minor = -1; -static int verbose; /* = 0 */ static int fnkeyinit; /* = 0 */ static int camera; /* = 0 */ static int compat; /* = 0 */ @@ -66,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/sonypi.h b/drivers/char/sonypi.h index 0eb8f46ab..58bbf385b 100644 --- a/drivers/char/sonypi.h +++ b/drivers/char/sonypi.h @@ -401,8 +401,6 @@ struct sonypi_device { #define SONYPI_ACPI_ACTIVE 0 #endif /* CONFIG_ACPI */ -extern int verbose; - static inline int sonypi_ec_write(u8 addr, u8 value) { #ifdef CONFIG_ACPI_EC if (SONYPI_ACPI_ACTIVE) diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 0d3763dc6..bf82f06d4 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -135,10 +135,6 @@ ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \ ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - #undef RS_EVENT_WRITE_WAKEUP #define RS_EVENT_WRITE_WAKEUP 0 @@ -159,7 +155,7 @@ static struct specialix_board sx_board[SX_NBOARD] = { }; static struct specialix_port sx_port[SX_NBOARD * SX_NPORT]; - + #ifdef SPECIALIX_TIMER static struct timer_list missed_irq_timer; @@ -715,7 +711,7 @@ static inline void sx_transmit(struct specialix_board * bp) sx_out(bp, CD186x_TDR, CD186x_C_SBRK); port->COR2 &= ~COR2_ETC; } - count = MIN(port->break_length, 0xff); + count = min_t(int, port->break_length, 0xff); sx_out(bp, CD186x_TDR, CD186x_C_ESC); sx_out(bp, CD186x_TDR, CD186x_C_DELAY); sx_out(bp, CD186x_TDR, count); @@ -1468,8 +1464,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) sx_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; port->tty = NULL; @@ -1506,7 +1501,7 @@ static int sx_write(struct tty_struct * tty, int from_user, if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) break; @@ -1519,7 +1514,7 @@ static int sx_write(struct tty_struct * tty, int from_user, } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min_t(int, c, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); @@ -1534,7 +1529,7 @@ static int sx_write(struct tty_struct * tty, int from_user, } else { while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { restore_flags(flags); @@ -1646,10 +1641,8 @@ static void sx_flush_buffer(struct tty_struct *tty) port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; restore_flags(flags); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); } @@ -2052,12 +2045,8 @@ static void do_softint(void *private_) if(!(tty = port->tty)) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) + tty_wakeup(tty); } static struct tty_operations sx_ops = { diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index a0b3ba7b0..90018ce17 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -1197,8 +1197,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) portp->tx.tail = (char *) NULL; } set_bit(TTY_IO_ERROR, &tty->flags); - if (tty->ldisc.flush_buffer) - (tty->ldisc.flush_buffer)(tty); + tty_ldisc_flush(tty); tty->closing = 0; portp->tty = (struct tty_struct *) NULL; @@ -1809,10 +1808,7 @@ static void stl_flushbuffer(struct tty_struct *tty) return; stl_flush(portp); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /*****************************************************************************/ @@ -2193,10 +2189,7 @@ static void stl_offintr(void *private) lock_kernel(); if (test_bit(ASYI_TXLOW, &portp->istate)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { clear_bit(ASYI_DCDCHANGE, &portp->istate); diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 1ca3d2543..a990eb7aa 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1046,12 +1046,9 @@ static void sx_transmit_chars (struct sx_port *port) } if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + tty_wakeup(port->gs.tty); sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); - wake_up_interruptible(&port->gs.tty->write_wait); } clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 78d4efe6f..0a1cc1d36 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 #include #include +#include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#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 /* @@ -863,8 +851,6 @@ static int mgsl_rxenable(struct mgsl_struct * info, int enable); static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); static int mgsl_loopmode_send_done( struct mgsl_struct * info ); -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) - /* set non-zero on successful registration with PCI subsystem */ static int pci_registered; @@ -911,7 +897,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); @@ -942,10 +928,6 @@ static struct tty_driver *serial_driver; static void mgsl_change_params(struct mgsl_struct *info); static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * 1st function defined in .text section. Calling this function in * init_module() followed by a breakpoint allows a remote debugger @@ -993,6 +975,29 @@ static inline int mgsl_paranoia_check(struct mgsl_struct *info, return 0; } +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + /* mgsl_stop() throttle (stop) transmitter * * Arguments: tty pointer to tty info structure @@ -1153,13 +1158,7 @@ void mgsl_bh_transmit(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):calling ldisc.write_wakeup on %s\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -1289,9 +1288,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 +1351,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) { @@ -2258,8 +2257,8 @@ static int mgsl_write(struct tty_struct * tty, int from_user, if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, + min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -2272,7 +2271,7 @@ static int mgsl_write(struct tty_struct * tty, int from_user, break; } spin_lock_irqsave(&info->irq_spinlock,flags); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); info->xmit_head = ((info->xmit_head + c) & @@ -2287,8 +2286,8 @@ static int mgsl_write(struct tty_struct * tty, int from_user, } else { while (1) { spin_lock_irqsave(&info->irq_spinlock,flags); - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + c = min_t(int, count, + min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -2415,11 +2414,8 @@ static void mgsl_flush_buffer(struct tty_struct *tty) spin_unlock_irqrestore(&info->irq_spinlock,flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - -} /* end of mgsl_flush_buffer() */ + tty_wakeup(tty); +} /* mgsl_send_xchar() * @@ -3253,9 +3249,8 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); shutdown(info); @@ -3326,7 +3321,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if ( info->params.mode == MGSL_MODE_HDLC || info->params.mode == MGSL_MODE_RAW ) { @@ -3592,7 +3587,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--; } @@ -4187,7 +4182,7 @@ int load_next_tx_holding_buffer(struct mgsl_struct *info) info->get_tx_holding_index=0; /* restart transmit timer */ - mod_timer(&info->tx_timer, jiffies + jiffies_from_ms(5000)); + mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); ret = 1; } @@ -4415,12 +4410,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 +4568,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; @@ -5819,7 +5811,7 @@ void usc_start_transmitter( struct mgsl_struct *info ) usc_TCmd( info, TCmd_SendFrame ); - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } info->tx_active = 1; @@ -6750,9 +6742,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; @@ -6779,7 +6774,7 @@ int mgsl_get_rx_frame(struct mgsl_struct *info) if ( debug_level >= DEBUG_LEVEL_DATA ) mgsl_trace_block(info,info->rx_buffer_list[StartIndex].virt_addr, - MIN(framesize,DMABUFFERSIZE),0); + min_t(int, framesize, DMABUFFERSIZE),0); if (framesize) { if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && @@ -6823,18 +6818,12 @@ 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 - { - /* Call the line discipline receive callback directly. */ - if ( tty && tty->ldisc.receive_buf ) - tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); - } + ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } } /* Free the buffers used by this frame. */ @@ -6996,7 +6985,7 @@ int mgsl_get_raw_rx_frame(struct mgsl_struct *info) if ( debug_level >= DEBUG_LEVEL_DATA ) mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, - MIN(framesize,DMABUFFERSIZE),0); + min_t(int, framesize, DMABUFFERSIZE),0); if (framesize) { /* copy dma buffer(s) to contiguous intermediate buffer */ @@ -7006,9 +6995,7 @@ int mgsl_get_raw_rx_frame(struct mgsl_struct *info) memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); info->icount.rxok++; - /* Call the line discipline receive callback directly. */ - if ( tty && tty->ldisc.receive_buf ) - tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } /* Free the buffers used by this frame. */ @@ -7056,7 +7043,7 @@ void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, const char *Buffer, DMABUFFERENTRY *pBufEntry; if ( debug_level >= DEBUG_LEVEL_DATA ) - mgsl_trace_block(info,Buffer, MIN(BufferSize,DMABUFFERSIZE), 1); + mgsl_trace_block(info,Buffer, min_t(int, BufferSize, DMABUFFERSIZE), 1); if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { /* set CMR:13 to start transmit when @@ -7214,7 +7201,7 @@ BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) EndTime=100; while( EndTime-- && !info->irq_occurred ) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); } spin_lock_irqsave(&info->irq_spinlock,flags); @@ -7353,7 +7340,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) /*************************************************************/ /* Wait 100ms for interrupt. */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); for(;;) { if (time_after(jiffies, EndTime)) { @@ -7409,7 +7396,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) /**********************************/ /* Wait 100ms */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); for(;;) { if (time_after(jiffies, EndTime)) { @@ -7451,7 +7438,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) /******************************/ /* Wait 100ms */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); /* While timer not expired wait for transmit complete */ @@ -7482,7 +7469,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) /* WAIT FOR RECEIVE COMPLETE */ /* Wait 100ms */ - EndTime = jiffies + jiffies_from_ms(100); + EndTime = jiffies + msecs_to_jiffies(100); /* Wait for 16C32 to write receive status to buffer entry. */ status=info->rx_buffer_list[0].status; @@ -7736,9 +7723,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 +7806,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 +7932,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); +} + +/** + * 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); } -void mgsl_sppp_rx_done(struct mgsl_struct *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(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 1361ea041..5648ed355 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.29 2004/08/27 20:06:41 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -67,13 +67,10 @@ #include #include #include +#include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#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 @@ -462,8 +453,6 @@ typedef struct _synclinkmp_info { #define CRCE BIT2 -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) - /* * Global linked list of SyncLink devices */ @@ -498,7 +487,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.29 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -524,10 +513,6 @@ static struct tty_driver *serial_driver; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* tty callbacks */ @@ -553,20 +538,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 */ @@ -668,7 +645,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x0080002d; +static u32 lcr1_brdr_value = 0x00800029; static u32 read_ahead_count = 8; @@ -722,6 +699,29 @@ static inline int sanity_check(SLMP_INFO *info, return 0; } +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + /* tty callbacks */ /* Called when a port is opened. Init and enable port. @@ -800,7 +800,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--; } @@ -869,8 +869,7 @@ static void close(struct tty_struct *tty, struct file *filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); shutdown(info); @@ -1017,8 +1016,8 @@ static int write(struct tty_struct *tty, int from_user, } for (;;) { - c = MIN(count, - MIN(info->max_frame_size - info->tx_count - 1, + c = min_t(int, count, + min(info->max_frame_size - info->tx_count - 1, info->max_frame_size - info->tx_put)); if (c <= 0) break; @@ -1161,7 +1160,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if ( info->params.mode == MGSL_MODE_HDLC ) { while (info->tx_active) { @@ -1275,9 +1274,7 @@ static void flush_buffer(struct tty_struct *tty) spin_unlock_irqrestore(&info->lock,flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* throttle (stop) transmitter @@ -1627,79 +1624,125 @@ static void set_break(struct tty_struct *tty, int break_state) spin_unlock_irqrestore(&info->lock,flags); } -#ifdef CONFIG_SYNCLINK_SYNCPPP +#ifdef CONFIG_HDLC -/* syncppp support and callbacks */ - -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 +1750,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. @@ -1941,13 +2143,7 @@ void bh_transmit(SLMP_INFO *info) __FILE__,__LINE__,info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s calling ldisc.write_wakeup\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } @@ -1994,16 +2190,15 @@ void isr_rxint(SLMP_INFO * info) { struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; - unsigned char status = read_reg(info, SR1); - unsigned char status2 = read_reg(info, SR2); + unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); + unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; /* clear status bits */ - if ( status & (FLGD + IDLD + CDCD + BRKD) ) - write_reg(info, SR1, - (unsigned char)(status & (FLGD + IDLD + CDCD + BRKD))); + if (status) + write_reg(info, SR1, status); - if ( status2 & OVRN ) - write_reg(info, SR2, (unsigned char)(status2 & OVRN)); + if (status2) + write_reg(info, SR2, status2); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_rxint status=%02X %02x\n", @@ -2140,15 +2335,22 @@ void isr_txeom(SLMP_INFO * info, unsigned char status) printk("%s(%d):%s isr_txeom status=%02x\n", __FILE__,__LINE__,info->device_name,status); - /* disable and clear MSCI interrupts */ - info->ie1_value &= ~(IDLE + UDRN); - write_reg(info, IE1, info->ie1_value); - write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); - write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + if (status & UDRN) { + write_reg(info, CMD, TXRESET); + write_reg(info, CMD, TXENABLE); + } else + write_reg(info, CMD, TXBUFCLR); + + /* disable and clear tx interrupts */ + info->ie0_value &= ~TXRDYE; + info->ie1_value &= ~(IDLE + UDRN); + write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); + write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); + if ( info->tx_active ) { if (info->params.mode != MGSL_MODE_ASYNC) { if (status & UDRN) @@ -2168,9 +2370,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 { @@ -2189,10 +2391,10 @@ void isr_txeom(SLMP_INFO * info, unsigned char status) */ void isr_txint(SLMP_INFO * info) { - unsigned char status = read_reg(info, SR1); + unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); /* clear status bits */ - write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS))); + write_reg(info, SR1, status); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txint status=%02x\n", @@ -2221,6 +2423,14 @@ void isr_txrdy(SLMP_INFO * info) printk("%s(%d):%s isr_txrdy() tx_count=%d\n", __FILE__,__LINE__,info->device_name,info->tx_count); + if (info->params.mode != MGSL_MODE_ASYNC) { + /* disable TXRDY IRQ, enable IDLE IRQ */ + info->ie0_value &= ~TXRDYE; + info->ie1_value |= IDLE; + write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); + return; + } + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { tx_stop(info); return; @@ -2275,13 +2485,6 @@ void isr_rxdmaerror(SLMP_INFO * info) void isr_txdmaok(SLMP_INFO * info) { - /* BIT7 = EOT (end of transfer, used for async mode) - * BIT6 = EOM (end of message/frame, used for sync mode) - * - * We don't look at DMA status because only EOT is enabled - * and we always clear and disable all tx DMA IRQs. - */ -// unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0; unsigned char status_reg1 = read_reg(info, SR1); write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ @@ -2292,19 +2495,10 @@ void isr_txdmaok(SLMP_INFO * info) printk("%s(%d):%s isr_txdmaok(), status=%02x\n", __FILE__,__LINE__,info->device_name,status_reg1); - /* If transmitter already idle, do end of frame processing, - * otherwise enable interrupt for tx IDLE. - */ - if (status_reg1 & IDLE) - isr_txeom(info, IDLE); - else { - /* disable and clear underrun IRQ, enable IDLE interrupt */ - info->ie1_value |= IDLE; - info->ie1_value &= ~UDRN; - write_reg(info, IE1, info->ie1_value); - - write_reg(info, SR1, UDRN); - } + /* program TXRDY as FIFO empty flag, enable TXRDY IRQ */ + write_reg16(info, TRC0, 0); + info->ie0_value |= TXRDYE; + write_reg(info, IE0, info->ie0_value); } void isr_txdmaerror(SLMP_INFO * info) @@ -2358,12 +2552,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) { @@ -2577,7 +2771,7 @@ static int startup(SLMP_INFO * info) change_params(info); - info->status_timer.expires = jiffies + jiffies_from_ms(10); + info->status_timer.expires = jiffies + msecs_to_jiffies(10); add_timer(&info->status_timer); if (info->tty) @@ -2988,7 +3182,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) unsigned char oldval = info->ie1_value; unsigned char newval = oldval + (mask & MgslEvent_ExitHuntMode ? FLGD:0) + - (mask & MgslEvent_IdleReceived ? IDLE:0); + (mask & MgslEvent_IdleReceived ? IDLD:0); if ( oldval != newval ) { info->ie1_value = newval; write_reg(info, IE1, info->ie1_value); @@ -3055,7 +3249,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) spin_lock_irqsave(&info->lock,flags); if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ - info->ie1_value &= ~(FLGD|IDLE); + info->ie1_value &= ~(FLGD|IDLD); write_reg(info, IE1, info->ie1_value); } spin_unlock_irqrestore(&info->lock,flags); @@ -3449,9 +3643,10 @@ void free_tmp_rx_buf(SLMP_INFO *info) int claim_resources(SLMP_INFO *info) { - if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else @@ -3460,22 +3655,25 @@ int claim_resources(SLMP_INFO *info) if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else info->lcr_mem_requested = 1; - if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else info->sca_base_requested = 1; - if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else @@ -3485,33 +3683,41 @@ int claim_resources(SLMP_INFO *info) if (!info->memory_base) { printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } - if ( !memory_test(info) ) { - printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - goto errout; - } - - info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; + info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE); if (!info->lcr_base) { printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } + info->lcr_base += info->lcr_offset; - info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset; + info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE); if (!info->sca_base) { printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } + info->sca_base += info->sca_offset; - info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset; + info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE); if (!info->statctrl_base) { printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); + info->init_error = DiagStatus_CantAssignPciResources; + goto errout; + } + info->statctrl_base += info->statctrl_offset; + + if ( !memory_test(info) ) { + printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + info->init_error = DiagStatus_MemoryError; goto errout; } @@ -3534,7 +3740,7 @@ void release_resources(SLMP_INFO *info) } if ( info->shared_mem_requested ) { - release_mem_region(info->phys_memory_base,0x40000); + release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); info->shared_mem_requested = 0; } if ( info->lcr_mem_requested ) { @@ -3542,11 +3748,11 @@ void release_resources(SLMP_INFO *info) info->lcr_mem_requested = 0; } if ( info->sca_base_requested ) { - release_mem_region(info->phys_sca_base + info->sca_offset,512); + release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); info->sca_base_requested = 0; } if ( info->sca_statctrl_requested ) { - release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16); + release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); info->sca_statctrl_requested = 0; } @@ -3616,9 +3822,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 } @@ -3788,7 +3993,6 @@ static struct tty_operations ops = { static void synclinkmp_cleanup(void) { - unsigned long flags; int rc; SLMP_INFO *info; SLMP_INFO *tmp; @@ -3802,34 +4006,24 @@ static void synclinkmp_cleanup(void) put_tty_driver(serial_driver); } + /* reset devices */ info = synclinkmp_device_list; while(info) { -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - sppp_delete(info); -#endif reset_port(info); - if ( info->port_num == 0 ) { - if ( info->irq_requested ) { - free_irq(info->irq_level, info); - info->irq_requested = 0; - } - } info = info->next_device; } - /* port 0 of each adapter originally claimed - * all resources, release those now - */ + /* release devices */ info = synclinkmp_device_list; while(info) { +#ifdef CONFIG_HDLC + hdlcdev_exit(info); +#endif free_dma_bufs(info); free_tmp_rx_buf(info); if ( info->port_num == 0 ) { - spin_lock_irqsave(&info->lock,flags); - reset_adapter(info); - write_reg(info, LPR, 1); /* set low power mode */ - spin_unlock_irqrestore(&info->lock,flags); + if (info->sca_base) + write_reg(info, LPR, 1); /* set low power mode */ release_resources(info); } tmp = info; @@ -4112,6 +4306,9 @@ void tx_start(SLMP_INFO *info) } } + write_reg16(info, TRC0, + (unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level)); + write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ @@ -4123,17 +4320,16 @@ void tx_start(SLMP_INFO *info) write_reg16(info, TXDMA + EDA, info->tx_buf_list_ex[info->last_tx_buf].phys_entry); - /* clear IDLE and UDRN status bit */ - info->ie1_value &= ~(IDLE + UDRN); - if (info->params.mode != MGSL_MODE_ASYNC) - info->ie1_value |= UDRN; /* HDLC, IRQ on underrun */ - write_reg(info, IE1, info->ie1_value); /* enable MSCI interrupts */ + /* enable underrun IRQ */ + info->ie1_value &= ~IDLE; + info->ie1_value |= UDRN; + write_reg(info, IE1, info->ie1_value); write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */ - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } else { @@ -4823,10 +5019,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 } @@ -4836,7 +5034,7 @@ CheckAgain: if ( debug_level >= DEBUG_LEVEL_DATA ) trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr, - MIN(framesize,SCABUFSIZE),0); + min_t(int, framesize,SCABUFSIZE),0); if (framesize) { if (framesize > info->max_frame_size) @@ -4851,7 +5049,7 @@ CheckAgain: info->icount.rxok++; while(copy_count) { - int partial_count = MIN(copy_count,SCABUFSIZE); + int partial_count = min(copy_count,SCABUFSIZE); memcpy( ptmp, info->rx_buf_list_ex[index].virt_addr, partial_count ); @@ -4862,22 +5060,13 @@ 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 - { - if ( tty && tty->ldisc.receive_buf ) { - /* Call the line discipline receive callback directly. */ - tty->ldisc.receive_buf(tty, - info->tmp_rx_buf, - info->flag_buf, - framesize); - } - } + ldisc_receive_buf(tty,info->tmp_rx_buf, + info->flag_buf, framesize); } } /* Free the buffers used by this frame. */ @@ -4910,14 +5099,14 @@ void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) SCADESC_EX *desc_ex; if ( debug_level >= DEBUG_LEVEL_DATA ) - trace_block(info,buf, MIN(count,SCABUFSIZE), 1); + trace_block(info,buf, min_t(int, count,SCABUFSIZE), 1); /* Copy source buffer to one or more DMA buffers, starting with * the first transmit dma buffer. */ for(i=0;;) { - copy_count = MIN(count,SCABUFSIZE); + copy_count = min_t(unsigned short,count,SCABUFSIZE); desc = &info->tx_buf_list[i]; desc_ex = &info->tx_buf_list_ex[i]; @@ -5021,7 +5210,7 @@ int irq_test(SLMP_INFO *info) timeout=100; while( timeout-- && !info->irq_occurred ) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); } spin_lock_irqsave(&info->lock,flags); @@ -5172,7 +5361,7 @@ int loopback_test(SLMP_INFO *info) /* Set a timeout for waiting for interrupt. */ for ( timeout = 100; timeout; --timeout ) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + schedule_timeout(msecs_to_jiffies(10)); if (rx_get_frame(info)) { rc = TRUE; @@ -5384,9 +5573,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); @@ -5428,7 +5617,7 @@ void status_timeout(unsigned long context) info->status_timer.data = (unsigned long)info; info->status_timer.function = status_timeout; - info->status_timer.expires = jiffies + jiffies_from_ms(10); + info->status_timer.expires = jiffies + msecs_to_jiffies(10); add_timer(&info->status_timer); } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 91f530c61..89457cc2e 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -92,6 +92,7 @@ #include #include #include +#include #include #include @@ -120,10 +121,14 @@ struct termios tty_std_termios = { /* for the benefit of tty drivers */ EXPORT_SYMBOL(tty_std_termios); +/* This list gets poked at by procfs and various bits of boot up code. This + could do with some rationalisation such as pulling the tty proc function + into this file */ + LIST_HEAD(tty_drivers); /* linked list of tty drivers */ -struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ -/* Semaphore to protect creating and releasing a tty */ +/* Semaphore to protect creating and releasing a tty. This is shared with + vt.c for deeply disgusting hack reasons */ DECLARE_MUTEX(tty_sem); #ifdef CONFIG_UNIX98_PTYS @@ -142,6 +147,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); @@ -223,65 +229,323 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) return 0; } +/* + * This is probably overkill for real world processors but + * they are not on hot paths so a little discipline won't do + * any harm. + */ + +static void tty_set_termios_ldisc(struct tty_struct *tty, int num) +{ + down(&tty->termios_sem); + tty->termios->c_line = num; + up(&tty->termios_sem); +} + +/* + * This guards the refcounted line discipline lists. The lock + * must be taken with irqs off because there are hangup path + * callers who will do ldisc lookups and cannot sleep. + */ + +static spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); +static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ + int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { + unsigned long flags; + int ret = 0; + if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; + spin_lock_irqsave(&tty_ldisc_lock, flags); if (new_ldisc) { - ldiscs[disc] = *new_ldisc; - ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - ldiscs[disc].num = disc; - } else - memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); + tty_ldiscs[disc] = *new_ldisc; + tty_ldiscs[disc].num = disc; + tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + tty_ldiscs[disc].refcount = 0; + } else { + if(tty_ldiscs[disc].refcount) + ret = -EBUSY; + else + tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return 0; + return ret; } EXPORT_SYMBOL(tty_register_ldisc); -/* Set the discipline of a tty line. */ +struct tty_ldisc *tty_ldisc_get(int disc) +{ + unsigned long flags; + struct tty_ldisc *ld; + + if (disc < N_TTY || disc >= NR_LDISCS) + return NULL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + + ld = &tty_ldiscs[disc]; + /* Check the entry is defined */ + if(ld->flags & LDISC_FLAG_DEFINED) + { + /* If the module is being unloaded we can't use it */ + if (!try_module_get(ld->owner)) + ld = NULL; + else /* lock it */ + ld->refcount++; + } + else + ld = NULL; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return ld; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_get); + +void tty_ldisc_put(int disc) +{ + struct tty_ldisc *ld; + unsigned long flags; + + if (disc < N_TTY || disc >= NR_LDISCS) + BUG(); + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld = &tty_ldiscs[disc]; + if(ld->refcount == 0) + BUG(); + ld->refcount --; + module_put(ld->owner); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} + +EXPORT_SYMBOL_GPL(tty_ldisc_put); + +void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) +{ + tty->ldisc = *ld; + tty->ldisc.refcount = 0; +} + +/** + * tty_ldisc_try - internal helper + * @tty: the tty + * + * Make a single attempt to grab and bump the refcount on + * the tty ldisc. Return 0 on failure or 1 on success. This is + * used to implement both the waiting and non waiting versions + * of tty_ldisc_ref + */ + +static int tty_ldisc_try(struct tty_struct *tty) +{ + unsigned long flags; + struct tty_ldisc *ld; + int ret = 0; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld = &tty->ldisc; + if(test_bit(TTY_LDISC, &tty->flags)) + { + ld->refcount++; + ret = 1; + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return ret; +} + +/** + * tty_ldisc_ref_wait - wait for the tty ldisc + * @tty: tty device + * + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then + * wait patiently until it changes. + * + * Note: Must not be called from an IRQ/timer context. The caller + * must also be careful not to hold other locks that will deadlock + * against a discipline change, such as an existing ldisc reference + * (which we check for) + */ + +struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) +{ + /* wait_event is a macro */ + wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); + if(tty->ldisc.refcount == 0) + printk(KERN_ERR "tty_ldisc_ref_wait\n"); + return &tty->ldisc; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); + +/** + * tty_ldisc_ref - get the tty ldisc + * @tty: tty device + * + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then + * return NULL. Can be called from IRQ and timer functions. + */ + +struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) +{ + if(tty_ldisc_try(tty)) + return &tty->ldisc; + return NULL; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_ref); + +/** + * tty_ldisc_deref - free a tty ldisc reference + * @ld: reference to free up + * + * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May + * be called in IRQ context. + */ + +void tty_ldisc_deref(struct tty_ldisc *ld) +{ + unsigned long flags; + + if(ld == NULL) + BUG(); + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if(ld->refcount == 0) + printk(KERN_ERR "tty_ldisc_deref: no references.\n"); + else + ld->refcount--; + if(ld->refcount == 0) + wake_up(&tty_ldisc_wait); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} + +EXPORT_SYMBOL_GPL(tty_ldisc_deref); + +/** + * tty_ldisc_enable - allow ldisc use + * @tty: terminal to activate ldisc on + * + * Set the TTY_LDISC flag when the line discipline can be called + * again. Do neccessary wakeups for existing sleepers. + * + * Note: nobody should set this bit except via this function. Clearing + * directly is allowed. + */ + +static void tty_ldisc_enable(struct tty_struct *tty) +{ + set_bit(TTY_LDISC, &tty->flags); + wake_up(&tty_ldisc_wait); +} + +/** + * tty_set_ldisc - set line discipline + * @tty: the terminal to set + * @ldisc: the line discipline + * + * Set the discipline of a tty line. Must be called from a process + * context. + */ + static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval = 0; struct tty_ldisc o_ldisc; char buf[64]; + int work; + unsigned long flags; + struct tty_ldisc *ld; if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; + +restart: + + if (tty->ldisc.num == ldisc) + return 0; /* We are already in the desired discipline */ + + ld = tty_ldisc_get(ldisc); /* Eduardo Blanco */ /* Cyrus Durgin */ - if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { + if (ld == NULL) { request_module("tty-ldisc-%d", ldisc); + ld = tty_ldisc_get(ldisc); } - if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) + if (ld == NULL) return -EINVAL; - if (tty->ldisc.num == ldisc) - return 0; /* We are already in the desired discipline */ - - if (!try_module_get(ldiscs[ldisc].owner)) - return -EINVAL; - o_ldisc = tty->ldisc; tty_wait_until_sent(tty, 0); + + /* + * Make sure we don't change while someone holds a + * reference to the line discipline. The TTY_LDISC bit + * prevents anyone taking a reference once it is clear. + * We need the lock to avoid racing reference takers. + */ + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if(tty->ldisc.refcount) + { + /* Free the new ldisc we grabbed. Must drop the lock + first. */ + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + /* + * There are several reasons we may be busy, including + * random momentary I/O traffic. We must therefore + * retry. We could distinguish between blocking ops + * and retries if we made tty_ldisc_wait() smarter. That + * is up for discussion. + */ + if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + clear_bit(TTY_LDISC, &tty->flags); + clear_bit(TTY_DONT_FLIP, &tty->flags); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + /* + * From this point on we know nobody has an ldisc + * usage reference, nor can they obtain one until + * we say so later on. + */ + + work = cancel_delayed_work(&tty->flip.work); + /* + * Wait for ->hangup_work and ->flip.work handlers to terminate + */ + + flush_scheduled_work(); /* Shutdown the current discipline. */ if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Now set up the new line discipline. */ - tty->ldisc = ldiscs[ldisc]; - tty->termios->c_line = ldisc; + tty_ldisc_assign(tty, ld); + tty_set_termios_ldisc(tty, ldisc); if (tty->ldisc.open) retval = (tty->ldisc.open)(tty); if (retval < 0) { - tty->ldisc = o_ldisc; - tty->termios->c_line = tty->ldisc.num; + tty_ldisc_put(ldisc); + /* There is an outstanding reference here so this is safe */ + tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); + tty_set_termios_ldisc(tty, tty->ldisc.num); if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; + tty_ldisc_put(o_ldisc.num); + /* This driver is always present */ + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(tty, N_TTY); if (tty->ldisc.open) { int r = tty->ldisc.open(tty); @@ -291,12 +555,27 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_name(tty, buf), r); } } - } else { - module_put(o_ldisc.owner); } + /* At this point we hold a reference to the new ldisc and a + a reference to the old ldisc. If we ended up flipping back + to the existing ldisc we have two references to it */ if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) tty->driver->set_ldisc(tty); + + tty_ldisc_put(o_ldisc.num); + + /* + * Allow ldisc referencing to occur as soon as the driver + * ldisc callback completes. + */ + + tty_ldisc_enable(tty); + + /* Restart it in case no characters kick it off. Safe if + already running */ + if(work) + schedule_delayed_work(&tty->flip.work, 1); return retval; } @@ -377,6 +656,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, @@ -399,6 +691,53 @@ static struct file_operations hung_up_tty_fops = { static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED; static struct file *redirect; + +/** + * tty_wakeup - request more data + * @tty: terminal + * + * Internal and external helper for wakeups of tty. This function + * informs the line discipline if present that the driver is ready + * to receive more output data. + */ + +void tty_wakeup(struct tty_struct *tty) +{ + struct tty_ldisc *ld; + + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { + ld = tty_ldisc_ref(tty); + if(ld) { + if(ld->write_wakeup) + ld->write_wakeup(tty); + tty_ldisc_deref(ld); + } + } + wake_up_interruptible(&tty->write_wait); +} + +EXPORT_SYMBOL_GPL(tty_wakeup); + +/** + * tty_ldisc_flush - flush line discipline queue + * @tty: tty + * + * Flush the line discipline queue (if any) for this tty. If there + * is no line discipline active this is a no-op. + */ + +void tty_ldisc_flush(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if(ld) { + if(ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } +} + +EXPORT_SYMBOL_GPL(tty_ldisc_flush); + /* * This can be called by the "eventd" kernel thread. That is process synchronous, * but doesn't hold any locks, so we need to make sure we have the appropriate @@ -410,7 +749,7 @@ void do_tty_hangup(void *data) struct file * cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; - struct pid *pid; + struct tty_ldisc *ld; int closecount = 0, n; if (!tty) @@ -428,6 +767,7 @@ void do_tty_hangup(void *data) check_tty_count(tty, "do_tty_hangup"); file_list_lock(); + /* This breaks for file handles being sent over AF_UNIX sockets ? */ list_for_each_entry(filp, &tty->tty_files, f_list) { if (filp->f_op->write == redirected_tty_write) cons_filp = filp; @@ -440,21 +780,25 @@ void do_tty_hangup(void *data) file_list_unlock(); /* FIXME! What are the locking issues here? This may me overdoing things.. - * this question is especially important now that we've removed the irqlock. */ - { - unsigned long flags; + * this question is especially important now that we've removed the irqlock. */ - local_irq_save(flags); // FIXME: is this safe? - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + ld = tty_ldisc_ref(tty); + if(ld != NULL) /* We may have no line discipline at this point */ + { + if (ld->flush_buffer) + ld->flush_buffer(tty); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - local_irq_restore(flags); // FIXME: is this safe? + ld->write_wakeup) + ld->write_wakeup(tty); + if (ld->hangup) + ld->hangup(tty); } + /* FIXME: Once we trust the LDISC code better we can wait here for + ldisc completion and fix the driver call race */ + wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); @@ -463,26 +807,21 @@ void do_tty_hangup(void *data) * N_TTY. */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + { + down(&tty->termios_sem); *tty->termios = tty->driver->init_termios; - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - module_put(tty->ldisc.owner); - - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) { - int i = (tty->ldisc.open)(tty); - if (i < 0) - printk(KERN_ERR "do_tty_hangup: N_TTY open: " - "error %d\n", -i); - } + up(&tty->termios_sem); } + /* Defer ldisc switch */ + /* tty_deferred_ldisc_switch(N_TTY); + + This should get done automatically when the port closes and + tty_release is called */ + read_lock(&tasklist_lock); if (tty->session > 0) { - struct list_head *l; - for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) { + do_each_task_pid(tty->session, PIDTYPE_SID, p) { if (p->signal->tty == tty) p->signal->tty = NULL; if (!p->signal->leader) @@ -491,7 +830,7 @@ void do_tty_hangup(void *data) send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p); if (tty->pgrp > 0) p->signal->tty_old_pgrp = tty->pgrp; - } + } while_each_task_pid(tty->session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); @@ -511,6 +850,17 @@ void do_tty_hangup(void *data) tty->driver->close(tty, cons_filp); } else if (tty->driver->hangup) (tty->driver->hangup)(tty); + + /* We don't want to have driver/ldisc interactions beyond + the ones we did here. The driver layer expects no + calls after ->hangup() from the ldisc side. However we + can't yet guarantee all that */ + + set_bit(TTY_HUPPED, &tty->flags); + if (ld) { + tty_ldisc_enable(tty); + tty_ldisc_deref(ld); + } unlock_kernel(); if (f) fput(f); @@ -563,8 +913,6 @@ void disassociate_ctty(int on_exit) { struct tty_struct *tty; struct task_struct *p; - struct list_head *l; - struct pid *pid; int tty_pgrp = -1; lock_kernel(); @@ -593,8 +941,9 @@ void disassociate_ctty(int on_exit) tty->pgrp = -1; read_lock(&tasklist_lock); - for_each_task_pid(current->signal->session, PIDTYPE_SID, p, l, pid) + do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); unlock_kernel(); } @@ -627,9 +976,9 @@ void start_tty(struct tty_struct *tty) } if (tty->driver->start) (tty->driver->start)(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + + /* If we have a running line discipline it may need kicking */ + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } @@ -641,6 +990,7 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count, int i; struct tty_struct * tty; struct inode *inode; + struct tty_ldisc *ld; tty = (struct tty_struct *)file->private_data; inode = file->f_dentry->d_inode; @@ -649,11 +999,15 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count, if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; + /* We want to wait for the line discipline to sort out in this + situation */ + ld = tty_ldisc_ref_wait(tty); lock_kernel(); - if (tty->ldisc.read) - i = (tty->ldisc.read)(tty,file,buf,count); + if (ld->read) + i = (ld->read)(tty,file,buf,count); else i = -EIO; + tty_ldisc_deref(ld); unlock_kernel(); if (i > 0) inode->i_atime = CURRENT_TIME; @@ -715,16 +1069,23 @@ static ssize_t tty_write(struct file * file, const char __user * buf, size_t cou { struct tty_struct * tty; struct inode *inode = file->f_dentry->d_inode; - + ssize_t ret; + struct tty_ldisc *ld; + tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; - if (!tty->ldisc.write) - return -EIO; - return do_tty_write(tty->ldisc.write, tty, file, + + ld = tty_ldisc_ref_wait(tty); + if (!ld->write) + ret = -EIO; + else + ret = do_tty_write(ld->write, tty, file, (const unsigned char __user *)buf, count); + tty_ldisc_deref(ld); + return ret; } ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count, @@ -749,6 +1110,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); @@ -910,6 +1282,7 @@ static int init_dev(struct tty_driver *driver, int idx, * If we fail here just call release_mem to clean up. No need * to decrement the use counts, as release_mem doesn't care. */ + if (tty->ldisc.open) { retval = (tty->ldisc.open)(tty); if (retval) @@ -922,7 +1295,9 @@ static int init_dev(struct tty_driver *driver, int idx, (tty->ldisc.close)(tty); goto release_mem_out; } + tty_ldisc_enable(o_tty); } + tty_ldisc_enable(tty); goto success; /* @@ -951,6 +1326,9 @@ fast_track: tty->count++; tty->driver = driver; /* N.B. why do this every time?? */ + /* FIXME */ + if(!test_bit(TTY_LDISC, &tty->flags)) + printk(KERN_ERR "init_dev but no ldisc\n"); success: *ret_tty = tty; @@ -1054,6 +1432,7 @@ static void release_dev(struct file * filp) int devpts_master, devpts; int idx; char buf[64]; + unsigned long flags; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev")) @@ -1130,7 +1509,6 @@ static void release_dev(struct file * filp) } } #endif - if (tty->driver->close) tty->driver->close(tty, filp); @@ -1235,15 +1613,15 @@ static void release_dev(struct file * filp) */ if (tty_closing || o_tty_closing) { struct task_struct *p; - struct list_head *l; - struct pid *pid; read_lock(&tasklist_lock); - for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) + do_each_task_pid(tty->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); if (o_tty) - for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid) + do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); } @@ -1254,36 +1632,58 @@ static void release_dev(struct file * filp) #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "freeing tty structure..."); #endif - /* * Prevent flush_to_ldisc() from rescheduling the work for later. Then - * kill any delayed work. + * kill any delayed work. As this is the final close it does not + * race with the set_ldisc code path. */ + clear_bit(TTY_LDISC, &tty->flags); clear_bit(TTY_DONT_FLIP, &tty->flags); cancel_delayed_work(&tty->flip.work); /* * Wait for ->hangup_work and ->flip.work handlers to terminate */ + flush_scheduled_work(); - + + /* + * Wait for any short term users (we know they are just driver + * side waiters as the file is closing so user count on the file + * side is zero. + */ + spin_lock_irqsave(&tty_ldisc_lock, flags); + while(tty->ldisc.refcount) + { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); + spin_lock_irqsave(&tty_ldisc_lock, flags); + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); /* * Shutdown the current line discipline, and reset it to N_TTY. * N.B. why reset ldisc when we're releasing the memory?? + * + * FIXME: this MUST get fixed for the new reflocking */ if (tty->ldisc.close) (tty->ldisc.close)(tty); - module_put(tty->ldisc.owner); + tty_ldisc_put(tty->ldisc.num); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; + /* + * Switch the line discipline back + */ + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(tty,N_TTY); if (o_tty) { + /* FIXME: could o_tty be in setldisc here ? */ + clear_bit(TTY_LDISC, &o_tty->flags); if (o_tty->ldisc.close) (o_tty->ldisc.close)(o_tty); - module_put(o_tty->ldisc.owner); - o_tty->ldisc = ldiscs[N_TTY]; + tty_ldisc_put(o_tty->ldisc.num); + tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(o_tty,N_TTY); } - /* * The release_mem function takes care of the details of clearing * the slots and preserving the termios structure. @@ -1323,6 +1723,7 @@ static int tty_open(struct inode * inode, struct file * filp) unsigned short saved_flags = filp->f_flags; nonseekable_open(inode, filp); + retry_open: noctty = filp->f_flags & O_NOCTTY; index = -1; @@ -1358,53 +1759,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 +1792,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 +1819,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(); @@ -1479,14 +1887,18 @@ static int tty_release(struct inode * inode, struct file * filp) static unsigned int tty_poll(struct file * filp, poll_table * wait) { struct tty_struct * tty; + struct tty_ldisc *ld; + int ret = 0; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll")) return 0; - - if (tty->ldisc.poll) - return (tty->ldisc.poll)(tty, filp, wait); - return 0; + + ld = tty_ldisc_ref_wait(tty); + if (ld->poll) + ret = (ld->poll)(tty, filp, wait); + tty_ldisc_deref(ld); + return ret; } static int tty_fasync(int fd, struct file * filp, int on) @@ -1518,12 +1930,15 @@ static int tty_fasync(int fd, struct file * filp, int on) static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; - + struct tty_ldisc *ld; + if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ch, p)) return -EFAULT; - tty->ldisc.receive_buf(tty, &ch, &mbz, 1); + ld = tty_ldisc_ref_wait(tty); + ld->receive_buf(tty, &ch, &mbz, 1); + tty_ldisc_deref(ld); return 0; } @@ -1606,8 +2021,6 @@ static int fionbio(struct file *file, int __user *p) static int tiocsctty(struct tty_struct *tty, int arg) { - struct list_head *l; - struct pid *pid; task_t *p; if (current->signal->leader && @@ -1630,8 +2043,9 @@ static int tiocsctty(struct tty_struct *tty, int arg) */ read_lock(&tasklist_lock); - for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) + do_each_task_pid(tty->session, PIDTYPE_SID, p) { p->signal->tty = NULL; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); } else return -EPERM; @@ -1772,6 +2186,7 @@ int tty_ioctl(struct inode * inode, struct file * file, struct tty_struct *tty, *real_tty; void __user *p = (void __user *)arg; int retval; + struct tty_ldisc *ld; tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) @@ -1861,6 +2276,7 @@ int tty_ioctl(struct inode * inode, struct file * file, case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: + /* FIXME: check this is ok */ return put_user(tty->ldisc.num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); @@ -1899,16 +2315,19 @@ int tty_ioctl(struct inode * inode, struct file * file, return tty_tiocmset(tty, file, cmd, p); } if (tty->driver->ioctl) { - int retval = (tty->driver->ioctl)(tty, file, cmd, arg); + retval = (tty->driver->ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } - if (tty->ldisc.ioctl) { - int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); - if (retval != -ENOIOCTLCMD) - return retval; + ld = tty_ldisc_ref_wait(tty); + retval = -EINVAL; + if (ld->ioctl) { + retval = ld->ioctl(tty, file, cmd, arg); + if (retval == -ENOIOCTLCMD) + retval = -EINVAL; } - return -EINVAL; + tty_ldisc_deref(ld); + return retval; } @@ -1938,21 +2357,26 @@ static void __do_SAK(void *arg) #else struct tty_struct *tty = arg; struct task_struct *p; - struct list_head *l; - struct pid *pid; int session; int i; struct file *filp; + struct tty_ldisc *disc; if (!tty) return; session = tty->session; - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + /* We don't want an ldisc switch during this */ + disc = tty_ldisc_ref(tty); + if (disc && disc->flush_buffer) + disc->flush_buffer(tty); + tty_ldisc_deref(disc); + if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); + read_lock(&tasklist_lock); - for_each_task_pid(session, PIDTYPE_SID, p, l, pid) { + do_each_task_pid(session, PIDTYPE_SID, p) { if (p->signal->tty == tty || session > 0) { printk(KERN_NOTICE "SAK: killed process %d" " (%s): p->signal->session==tty->session\n", @@ -1979,7 +2403,7 @@ static void __do_SAK(void *arg) spin_unlock(&p->files->file_lock); } task_unlock(p); - } + } while_each_task_pid(session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); #endif } @@ -2002,24 +2426,29 @@ EXPORT_SYMBOL(do_SAK); /* * This routine is called out of the software interrupt to flush data - * from the flip buffer to the line discipline. + * from the flip buffer to the line discipline. */ + static void flush_to_ldisc(void *private_) { struct tty_struct *tty = (struct tty_struct *) private_; unsigned char *cp; char *fp; int count; - unsigned long flags; + unsigned long flags; + struct tty_ldisc *disc; + + disc = tty_ldisc_ref(tty); + if (disc == NULL) /* !TTY_LDISC */ + return; if (test_bit(TTY_DONT_FLIP, &tty->flags)) { /* * Do it after the next timer tick: */ schedule_delayed_work(&tty->flip.work, 1); - return; + goto out; } - spin_lock_irqsave(&tty->read_lock, flags); if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; @@ -2038,7 +2467,31 @@ static void flush_to_ldisc(void *private_) tty->flip.count = 0; spin_unlock_irqrestore(&tty->read_lock, flags); - tty->ldisc.receive_buf(tty, cp, fp, count); + disc->receive_buf(tty, cp, fp, count); +out: + tty_ldisc_deref(disc); +} + +/* + * Call the ldisc flush directly from a driver. This function may + * return an error and need retrying by the user. + */ + +int tty_push_data(struct tty_struct *tty, unsigned char *cp, unsigned char *fp, int count) +{ + int ret = 0; + struct tty_ldisc *disc; + + disc = tty_ldisc_ref(tty); + if(test_bit(TTY_DONT_FLIP, &tty->flags)) + ret = -EAGAIN; + else if(disc == NULL) + ret = -EIO; + else + disc->receive_buf(tty, cp, fp, count); + tty_ldisc_deref(disc); + return ret; + } /* @@ -2060,9 +2513,20 @@ static int baud_table[] = { static int n_baud_table = ARRAY_SIZE(baud_table); +/** + * tty_termios_baud_rate + * @termios: termios structure + * + * Convert termios baud rate data into a speed. This should be called + * with the termios lock held if this termios is a terminal termios + * structure. May change the termios data. + */ + int tty_termios_baud_rate(struct termios *termios) { - unsigned int cbaud = termios->c_cflag & CBAUD; + unsigned int cbaud; + + cbaud = termios->c_cflag & CBAUD; if (cbaud & CBAUDEX) { cbaud &= ~CBAUDEX; @@ -2072,12 +2536,20 @@ int tty_termios_baud_rate(struct termios *termios) else cbaud += 15; } - return baud_table[cbaud]; } EXPORT_SYMBOL(tty_termios_baud_rate); +/** + * tty_get_baud_rate - get tty bit rates + * @tty: tty to query + * + * Returns the baud rate as an integer for this terminal. The + * termios lock must be held by the caller and the terminal bit + * flags may be updated. + */ + int tty_get_baud_rate(struct tty_struct *tty) { int baud = tty_termios_baud_rate(tty->termios); @@ -2096,6 +2568,17 @@ int tty_get_baud_rate(struct tty_struct *tty) EXPORT_SYMBOL(tty_get_baud_rate); +/** + * tty_flip_buffer_push - terminal + * @tty: tty to push + * + * Queue a push of the terminal flip buffers to the line discipline. This + * function must not be called from IRQ context if tty->low_latency is set. + * + * In the event of the queue being busy for flipping the work will be + * held off and retried later. + */ + void tty_flip_buffer_push(struct tty_struct *tty) { if (tty->low_latency) @@ -2113,12 +2596,13 @@ static void initialize_tty_struct(struct tty_struct *tty) { memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; - tty->ldisc = ldiscs[N_TTY]; + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); tty->pgrp = -1; tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; INIT_WORK(&tty->flip.work, flush_to_ldisc, tty); init_MUTEX(&tty->flip.pty_sem); + init_MUTEX(&tty->termios_sem); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); @@ -2154,6 +2638,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 +2650,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 +2924,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/tty_ioctl.c b/drivers/char/tty_ioctl.c index ae924c7cb..830c665a3 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -98,8 +98,17 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios { int canon_change; struct termios old_termios = *tty->termios; + struct tty_ldisc *ld; + + /* + * Perform the actual termios internal changes under lock. + */ + + + /* FIXME: we need to decide on some locking/ordering semantics + for the set_termios notification eventually */ + down(&tty->termios_sem); - local_irq_disable(); // FIXME: is this safe? *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -109,12 +118,13 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios tty->canon_data = 0; tty->erasing = 0; } - local_irq_enable(); // FIXME: is this safe? + + if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ wake_up_interruptible(&tty->read_wait); - /* see if packet mode change of state */ + /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { int old_flow = ((old_termios.c_iflag & IXON) && @@ -132,17 +142,23 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios wake_up_interruptible(&tty->link->read_wait); } } - + if (tty->driver->set_termios) (*tty->driver->set_termios)(tty, &old_termios); - if (tty->ldisc.set_termios) - (*tty->ldisc.set_termios)(tty, &old_termios); + ld = tty_ldisc_ref(tty); + if (ld != NULL) { + if (ld->set_termios) + (ld->set_termios)(tty, &old_termios); + tty_ldisc_deref(ld); + } + up(&tty->termios_sem); } static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { struct termios tmp_termios; + struct tty_ldisc *ld; int retval = tty_check_change(tty); if (retval) @@ -159,9 +175,14 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) return -EFAULT; } - if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + ld = tty_ldisc_ref(tty); + + if (ld != NULL) { + if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } + if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) @@ -226,11 +247,14 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { struct sgttyb tmp; + down(&tty->termios_sem); tmp.sg_ispeed = 0; tmp.sg_ospeed = 0; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); + up(&tty->termios_sem); + return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -269,12 +293,16 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) retval = tty_check_change(tty); if (retval) return retval; - termios = *tty->termios; + if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; + + down(&tty->termios_sem); + termios = *tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); + up(&tty->termios_sem); change_termios(tty, &termios); return 0; } @@ -365,6 +393,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, struct tty_struct * real_tty; void __user *p = (void __user *)arg; int retval; + struct tty_ldisc *ld; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -443,22 +472,26 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, retval = tty_check_change(tty); if (retval) return retval; + + ld = tty_ldisc_ref(tty); switch (arg) { case TCIFLUSH: - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (ld->flush_buffer) + ld->flush_buffer(tty); break; case TCIOFLUSH: - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (ld->flush_buffer) + ld->flush_buffer(tty); /* fall through */ case TCOFLUSH: if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); break; default: + tty_ldisc_deref(ld); return -EINVAL; } + tty_ldisc_deref(ld); return 0; case TIOCOUTQ: return put_user(tty->driver->chars_in_buffer ? @@ -504,9 +537,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; + down(&tty->termios_sem); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); + up(&tty->termios_sem); return 0; default: return -ENOIOCTLCMD; diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index df9d4de9b..dcfcef4be 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -422,10 +422,7 @@ static void send_buffers(struct port_info *pi) pi->overflowMessage = 0; if (pi->tty) { - if ((pi->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - (pi->tty->ldisc.write_wakeup)) - (pi->tty->ldisc.write_wakeup)(pi->tty); - wake_up_interruptible(&pi->tty->write_wait); + tty_wakeup(pi->tty); } } diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 6f7833417..19ba83635 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -544,12 +544,8 @@ static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp) SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ port->gs.flags &= ~GS_TX_INTEN; } - if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - wake_up_interruptible(&port->gs.tty->write_wait); - } + if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) + tty_wakeup(port->gs.tty); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index a204572f5..31da37da5 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -136,9 +136,6 @@ extern void prom_con_init(void); #ifdef CONFIG_MDA_CONSOLE extern int mda_console_init(void); #endif -#ifdef CONFIG_FRAMEBUFFER_CONSOLE -extern int fb_console_init(void); -#endif struct vc vc_cons [MAX_NR_CONSOLES]; @@ -600,6 +597,17 @@ static inline void save_screen(int currcons) * Redrawing of screen */ +static void clear_buffer_attributes(int currcons) +{ + unsigned short *p = (unsigned short *) origin; + int count = screenbuf_size/2; + int mask = hi_font_mask | 0xff; + + for (; count > 0; count--, p++) { + scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); + } +} + void redraw_screen(int new_console, int is_switch) { int redraw = 1; @@ -637,9 +645,21 @@ void redraw_screen(int new_console, int is_switch) if (redraw) { int update; + int old_was_color = vc_cons[currcons].d->vc_can_do_color; + set_origin(currcons); update = sw->con_switch(vc_cons[currcons].d); set_palette(currcons); + /* + * If console changed from mono<->color, the best we can do + * is to clear the buffer attributes. As it currently stands, + * rebuilding new attributes from the old buffer is not doable + * without overly complex code. + */ + if (old_was_color != vc_cons[currcons].d->vc_can_do_color) { + update_attr(currcons); + clear_buffer_attributes(currcons); + } if (update && vcmode != KD_GRAPHICS) do_update_region(currcons, origin, screenbuf_size/2); } @@ -1865,7 +1885,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) * since console_init (and thus con_init) are called before any * kernel memory allocation is available. */ -char con_buf[PAGE_SIZE]; +char con_buf[CON_BUF_SIZE]; DECLARE_MUTEX(con_buf_sem); /* acquires console_sem */ @@ -1958,12 +1978,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) { @@ -2063,7 +2087,7 @@ again: continue; } FLUSH - do_con_trol(tty, currcons, c); + do_con_trol(tty, currcons, orig); } FLUSH console_conditional_schedule(); @@ -2645,25 +2669,11 @@ int __init vty_init(void) #ifdef CONFIG_MDA_CONSOLE mda_console_init(); #endif -#ifdef CONFIG_FRAMEBUFFER_CONSOLE - fb_console_init(); -#endif return 0; } #ifndef VT_SINGLE_DRIVER -static void clear_buffer_attributes(int currcons) -{ - unsigned short *p = (unsigned short *) origin; - int count = screenbuf_size/2; - int mask = hi_font_mask | 0xff; - - for (; count > 0; count--, p++) { - scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); - } -} - /* * If we support more console drivers, this function is used * when a driver wants to take over some existing consoles diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 682b44e9d..dd8e2f781 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -536,8 +536,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, default: return -EINVAL; } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); return 0; case KDGKBMODE: diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index a9dec9e98..4f109b7d7 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 c5f99d332..c43e9990c 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/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index 7e7b653a2..2865dac0a 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c @@ -134,7 +134,7 @@ static int cpu5wdt_open(struct inode *inode, struct file *file) if ( test_and_set_bit(0, &cpu5wdt_device.inuse) ) return -EBUSY; - return 0; + return nonseekable_open(inode, file); } static int cpu5wdt_release(struct inode *inode, struct file *file) @@ -198,6 +198,7 @@ static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t c static struct file_operations cpu5wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .ioctl = cpu5wdt_ioctl, .open = cpu5wdt_open, .write = cpu5wdt_write, diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c index cd6467eb4..d974f16e8 100644 --- a/drivers/char/watchdog/ib700wdt.c +++ b/drivers/char/watchdog/ib700wdt.c @@ -263,6 +263,7 @@ ibwdt_notify_sys(struct notifier_block *this, unsigned long code, static struct file_operations ibwdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = ibwdt_write, .ioctl = ibwdt_ioctl, .open = ibwdt_open, diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c index 4e9093b4a..6af2c799b 100644 --- a/drivers/char/watchdog/indydog.c +++ b/drivers/char/watchdog/indydog.c @@ -162,6 +162,7 @@ static int indydog_notify_sys(struct notifier_block *this, unsigned long code, v static struct file_operations indydog_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = indydog_write, .ioctl = indydog_ioctl, .open = indydog_open, diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index b8e3d91d3..a6781dede 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -170,6 +170,7 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file) static struct file_operations ixp4xx_wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = ixp4xx_wdt_write, .ioctl = ixp4xx_wdt_ioctl, .open = ixp4xx_wdt_open, diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index 3782930e6..6e14abbb4 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c @@ -425,6 +425,7 @@ static int zf_notify_sys(struct notifier_block *this, unsigned long code, static struct file_operations zf_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = zf_write, .ioctl = zf_ioctl, .open = zf_open, diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index 15a3547f2..3143e4a07 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -197,6 +197,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, static struct file_operations mixcomwd_fops= { .owner = THIS_MODULE, + .llseek = no_llseek, .write = mixcomwd_write, .ioctl = mixcomwd_ioctl, .open = mixcomwd_open, diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c new file mode 100644 index 000000000..56d62ba7c --- /dev/null +++ b/drivers/char/watchdog/mpc8xx_wdt.c @@ -0,0 +1,164 @@ +/* + * mpc8xx_wdt.c - MPC8xx watchdog userspace interface + * + * Author: Florian Schirmer + * + * 2002 (c) Florian Schirmer 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("MPC8xx watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index 88bdbda92..592dca108 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -859,8 +859,7 @@ static int __init pcwd_checkcard(int base_addr) /* Not an 'ff' from a floating bus, so must be a card! */ for (i = 0; i < 4; ++i) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); + msleep(500); last_port0 = port0; last_port1 = port1; diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c index 1adf09f83..394ee7ac7 100644 --- a/drivers/char/watchdog/sa1100_wdt.c +++ b/drivers/char/watchdog/sa1100_wdt.c @@ -27,6 +27,10 @@ #include #include +#ifdef CONFIG_ARCH_PXA +#include +#endif + #include #include #include @@ -162,6 +166,7 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file, static struct file_operations sa1100dog_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = sa1100dog_write, .ioctl = sa1100dog_ioctl, .open = sa1100dog_open, diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index 9ddebaebe..d17d485fb 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -301,6 +301,7 @@ static struct notifier_block sc1200wdt_notifier = static struct file_operations sc1200wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = sc1200wdt_write, .ioctl = sc1200wdt_ioctl, .open = sc1200wdt_open, diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c index ed1800cff..983e9e980 100644 --- a/drivers/char/watchdog/scx200_wdt.c +++ b/drivers/char/watchdog/scx200_wdt.c @@ -201,6 +201,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file, static struct file_operations scx200_wdt_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = scx200_wdt_write, .ioctl = scx200_wdt_ioctl, .open = scx200_wdt_open, diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c index d3fced33d..52825a1f1 100644 --- a/drivers/char/watchdog/wdt285.c +++ b/drivers/char/watchdog/wdt285.c @@ -180,6 +180,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static struct file_operations watchdog_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .write = watchdog_write, .ioctl = watchdog_ioctl, .open = watchdog_open, diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c index 388c548c2..072e9b214 100644 --- a/drivers/char/watchdog/wdt977.c +++ b/drivers/char/watchdog/wdt977.c @@ -392,6 +392,7 @@ static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, static struct file_operations wdt977_fops= { .owner = THIS_MODULE, + .llseek = no_llseek, .write = wdt977_write, .ioctl = wdt977_ioctl, .open = wdt977_open, diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c index 9d5b5f4e5..7651deda9 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 331b5156d..889f243fb 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 1eebf3c6e..50291abb4 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.c b/drivers/cpufreq/cpufreq.c index a7fa79f5b..3e14a3a44 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -99,6 +99,85 @@ static void cpufreq_cpu_put(struct cpufreq_policy *data) module_put(cpufreq_driver->owner); } +/********************************************************************* + * EXTERNALLY AFFECTING FREQUENCY CHANGES * + *********************************************************************/ + +/** + * adjust_jiffies - adjust the system "loops_per_jiffy" + * + * This function alters the system "loops_per_jiffy" for the clock + * speed change. Note that loops_per_jiffy cannot be updated on SMP + * systems as each CPU might be scaled differently. So, use the arch + * per-CPU loops_per_jiffy value wherever possible. + */ +#ifndef CONFIG_SMP +static unsigned long l_p_j_ref; +static unsigned int l_p_j_ref_freq; + +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) +{ + if (ci->flags & CPUFREQ_CONST_LOOPS) + return; + + if (!l_p_j_ref_freq) { + l_p_j_ref = loops_per_jiffy; + l_p_j_ref_freq = ci->old; + } + if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || + (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || + (val == CPUFREQ_RESUMECHANGE)) + loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); +} +#else +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } +#endif + + +/** + * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition + * + * This function calls the transition notifiers and the "adjust_jiffies" function. It is called + * twice on all CPU frequency changes that have external effects. + */ +void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) +{ + BUG_ON(irqs_disabled()); + + freqs->flags = cpufreq_driver->flags; + + down_read(&cpufreq_notifier_rwsem); + switch (state) { + case CPUFREQ_PRECHANGE: + /* detect if the driver reported a value as "old frequency" which + * is not equal to what the cpufreq core thinks is "old frequency". + */ + if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { + if ((likely(cpufreq_cpu_data[freqs->cpu])) && + (likely(cpufreq_cpu_data[freqs->cpu]->cur)) && + (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) + { + printk(KERN_WARNING "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); + freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; + } + } + notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); + adjust_jiffies(CPUFREQ_PRECHANGE, freqs); + break; + case CPUFREQ_POSTCHANGE: + adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); + notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); + if (likely(cpufreq_cpu_data[freqs->cpu])) + cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; + break; + } + up_read(&cpufreq_notifier_rwsem); +} +EXPORT_SYMBOL_GPL(cpufreq_notify_transition); + + + /********************************************************************* * SYSFS INTERFACE * *********************************************************************/ @@ -521,9 +600,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne { struct cpufreq_freqs freqs; - if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); @@ -614,11 +690,8 @@ static int cpufreq_resume(struct sys_device * sysdev) if (unlikely(cur_freq != cpu_policy->cur)) { struct cpufreq_freqs freqs; - if (cpufreq_driver->flags & CPUFREQ_PANIC_RESUME_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing" - "core thinks of %u, is %u kHz.\n", cpu_policy->cur, cur_freq); + printk(KERN_WARNING "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); freqs.cpu = cpu; freqs.old = cpu_policy->cur; @@ -626,6 +699,8 @@ static int cpufreq_resume(struct sys_device * sysdev) notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); + + cpu_policy->cur = cur_freq; } } @@ -1005,87 +1080,6 @@ int cpufreq_update_policy(unsigned int cpu) EXPORT_SYMBOL(cpufreq_update_policy); -/********************************************************************* - * EXTERNALLY AFFECTING FREQUENCY CHANGES * - *********************************************************************/ - -/** - * adjust_jiffies - adjust the system "loops_per_jiffy" - * - * This function alters the system "loops_per_jiffy" for the clock - * speed change. Note that loops_per_jiffy cannot be updated on SMP - * systems as each CPU might be scaled differently. So, use the arch - * per-CPU loops_per_jiffy value wherever possible. - */ -#ifndef CONFIG_SMP -static unsigned long l_p_j_ref; -static unsigned int l_p_j_ref_freq; - -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) -{ - if (ci->flags & CPUFREQ_CONST_LOOPS) - return; - - if (!l_p_j_ref_freq) { - l_p_j_ref = loops_per_jiffy; - l_p_j_ref_freq = ci->old; - } - if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || - (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || - (val == CPUFREQ_RESUMECHANGE)) - loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); -} -#else -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } -#endif - - -/** - * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition - * - * This function calls the transition notifiers and the "adjust_jiffies" function. It is called - * twice on all CPU frequency changes that have external effects. - */ -void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) -{ - BUG_ON(irqs_disabled()); - - freqs->flags = cpufreq_driver->flags; - - down_read(&cpufreq_notifier_rwsem); - switch (state) { - case CPUFREQ_PRECHANGE: - /* detect if the driver reported a value as "old frequency" which - * is not equal to what the cpufreq core thinks is "old frequency". - */ - if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) && - (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) - { - if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - - printk(KERN_WARNING "Warning: CPU frequency out of sync: " - "cpufreq and timing core thinks of %u, is %u kHz.\n", - cpufreq_cpu_data[freqs->cpu]->cur, freqs->old); - freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; - } - } - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); - adjust_jiffies(CPUFREQ_PRECHANGE, freqs); - break; - case CPUFREQ_POSTCHANGE: - adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); - cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; - break; - } - up_read(&cpufreq_notifier_rwsem); -} -EXPORT_SYMBOL_GPL(cpufreq_notify_transition); - - - /********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************/ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c new file mode 100644 index 000000000..a9320ae41 --- /dev/null +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -0,0 +1,437 @@ +/* + * drivers/cpufreq/cpufreq_ondemand.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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))?1:((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_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(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[] = { + &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 total_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 */ + total_idle_ticks = kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + idle_ticks = total_idle_ticks - + this_dbs_info->prev_cpu_idle_up; + this_dbs_info->prev_cpu_idle_up = total_idle_ticks; + + /* Scale idle ticks by 100 and compare with up and down ticks */ + idle_ticks *= 100; + up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) * + sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate); + + 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 = total_idle_ticks; + return; + } + + /* Check for frequency decrease */ + down_skip[cpu]++; + if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) + return; + + idle_ticks = total_idle_ticks - + this_dbs_info->prev_cpu_idle_down; + /* Scale idle ticks by 100 and compare with up and down ticks */ + idle_ticks *= 100; + down_skip[cpu] = 0; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + + 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); + + if (idle_ticks > down_idle_ticks ) { + freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100; + + /* max freq cannot be less than 100. But who knows.... */ + if (unlikely(freq_down_step == 0)) + freq_down_step = 5; + + __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 + + kstat_cpu(cpu).cpustat.iowait; + this_dbs_info->prev_cpu_idle_down = + kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + 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) { + unsigned int latency; + /* policy latency is in nS. Convert it to uS first */ + + latency = policy->cpuinfo.transition_latency; + if (latency < 1000) + latency = 1000; + + def_sampling_rate = (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 "); +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/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 161e8a27c..558cc9dd0 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -82,6 +82,13 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, { struct cpufreq_freqs *freq = data; + /* Don't update cur_freq if CPU is managed and we're + * waking up: else we won't remember what frequency + * we need to set the CPU to. + */ + if (cpu_is_managed[freq->cpu] && (val == CPUFREQ_RESUMECHANGE)) + return 0; + cpu_cur_freq[freq->cpu] = freq->new; return 0; @@ -147,6 +154,9 @@ EXPORT_SYMBOL_GPL(cpufreq_setmax); #ifdef CONFIG_CPU_FREQ_24_API +#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01 + +static unsigned int warning_print = 0; /*********************** cpufreq_sysctl interface ********************/ static int @@ -162,6 +172,13 @@ cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, return 0; } + if (!warning_print) { + warning_print++; + printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and " + "will be removed from (new) 2.6. kernels soon " + "after 2005-01-01\n"); + } + if (write) { unsigned int freq; @@ -197,6 +214,13 @@ cpufreq_sysctl(ctl_table *table, int __user *name, int nlen, if (!cpu_online(cpu)) return -EINVAL; + if (!warning_print) { + warning_print++; + printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and " + "will be removed from (new) 2.6. kernels soon " + "after 2005-01-01\n"); + } + if (oldval && oldlenp) { size_t oldlen; @@ -522,6 +546,9 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, else if (policy->min > cpu_cur_freq[cpu]) __cpufreq_driver_target(¤t_policy[cpu], policy->min, CPUFREQ_RELATION_L); + else + __cpufreq_driver_target(¤t_policy[cpu], cpu_cur_freq[cpu], + CPUFREQ_RELATION_L); memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); up(&userspace_sem); break; diff --git a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c index a0eaf6f1d..673977899 100644 --- a/drivers/cpufreq/proc_intf.c +++ b/drivers/cpufreq/proc_intf.c @@ -12,9 +12,12 @@ #include #include +#warning This module will be removed from the 2.6. kernel series soon after 2005-01-01 #define CPUFREQ_ALL_CPUS ((NR_CPUS)) +static unsigned int warning_print = 0; + /** * cpufreq_parse_policy - parse a policy string * @input_string: the string to parse. @@ -110,6 +113,13 @@ static int cpufreq_proc_read ( if (off != 0) goto end; + if (!warning_print) { + warning_print++; + printk(KERN_INFO "Access to /proc/cpufreq is deprecated and " + "will be removed from (new) 2.6. kernels soon " + "after 2005-01-01\n"); + } + p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n"); for (i=0;iimask = (i); \ * That's why here are the following inline functions... */ -typedef unsigned long xram_p; +typedef void __iomem *xram_p; /* Get 32bit number from XRAM */ -static inline u32 xram_get_32 (xram_p x) +static inline u32 xram_get_32(xram_p x) { return ((sbus_readw(x + 0x00UL) << 16) | (sbus_readw(x + 0x02UL))); } /* Like the above, but when we don't care about the high 16 bits */ -static inline u32 xram_get_32low (xram_p x) +static inline u32 xram_get_32low(xram_p x) { return (u32) sbus_readw(x + 0x02UL); } -static inline u16 xram_get_16 (xram_p x) +static inline u16 xram_get_16(xram_p x) { return sbus_readw(x); } -static inline u8 xram_get_8 (xram_p x) +static inline u8 xram_get_8(xram_p x) { - if (x & (xram_p)0x1) { + if ((unsigned long)x & 0x1UL) { x = x - 1; return (u8) sbus_readw(x); } else { @@ -111,7 +111,7 @@ static inline u8 xram_get_8 (xram_p x) } } -static inline void xram_copy_from (void *p, xram_p x, int len) +static inline void xram_copy_from(void *p, xram_p x, int len) { for (len >>= 2; len > 0; len--, x += sizeof(u32)) { u32 val, *p32 = p; @@ -123,7 +123,7 @@ static inline void xram_copy_from (void *p, xram_p x, int len) } } -static inline void xram_copy_to (xram_p x, void *p, int len) +static inline void xram_copy_to(xram_p x, void *p, int len) { for (len >>= 2; len > 0; len--, x += sizeof(u32)) { u32 tmp, *p32 = p; @@ -135,7 +135,7 @@ static inline void xram_copy_to (xram_p x, void *p, int len) } } -static inline void xram_bzero (xram_p x, int len) +static inline void xram_bzero(xram_p x, int len) { for (len >>= 1; len > 0; len--, x += sizeof(u16)) sbus_writew(0, x); @@ -274,7 +274,7 @@ struct soc { soc_cq req[2]; /* Request CQs */ soc_cq rsp[2]; /* Response CQs */ int soc_no; - unsigned long regs; + void __iomem *regs; xram_p xram; fc_wwn wwn; u32 imask; /* Our copy of regs->imask */ diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index e158d7d26..5ee4dda53 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -60,7 +60,7 @@ static char *version = #define for_each_socal(s) for (s = socals; s; s = s->next) struct socal *socals = NULL; -static void socal_copy_from_xram(void *d, unsigned long xram, long size) +static void socal_copy_from_xram(void *d, void __iomem *xram, long size) { u32 *dp = (u32 *) d; while (size) { @@ -70,7 +70,7 @@ static void socal_copy_from_xram(void *d, unsigned long xram, long size) } } -static void socal_copy_to_xram(unsigned long xram, void *s, long size) +static void socal_copy_to_xram(void __iomem *xram, void *s, long size) { u32 *sp = (u32 *) s; while (size) { diff --git a/drivers/fc4/socal.h b/drivers/fc4/socal.h index a853fad92..2ff386b9f 100644 --- a/drivers/fc4/socal.h +++ b/drivers/fc4/socal.h @@ -295,9 +295,9 @@ struct socal { socal_cq req[4]; /* Request CQs */ socal_cq rsp[4]; /* Response CQs */ int socal_no; - unsigned long regs; - unsigned long xram; - unsigned long eeprom; + void __iomem *regs; + void __iomem *xram; + void __iomem *eeprom; fc_wwn wwn; u32 imask; /* Our copy of regs->imask */ u32 cfg; /* Our copy of regs->cfg */ diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index a6504dbd3..4607ddd46 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -14,8 +14,9 @@ config EDD Services real mode BIOS calls to determine which disk BIOS tries boot from. This information is then exported via sysfs. - This option is experimental, but believed to be safe, - and most disk controller BIOS vendors do not yet implement this feature. + This option is experimental and is known to fail to boot on some + obscure configurations. Most disk controller BIOS vendors do + not yet implement this feature. config EFI_VARS tristate "EFI Variable Support via sysfs" diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 2b48079f5..cd170395a 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -7,6 +7,9 @@ obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o obj-y += busses/ chips/ algos/ +i2c-sensor-objs := i2c-sensor-detect.o i2c-sensor-vid.o + + ifeq ($(CONFIG_I2C_DEBUG_CORE),y) EXTRA_CFLAGS += -DDEBUG endif diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index 88982cd31..cf9832bdc 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -27,6 +27,17 @@ config I2C_ALGOPCF This support is also available as a module. If so, the module will be called i2c-algo-pcf. +config I2C_ALGOPCA + tristate "I2C PCA 9564 interfaces" + depends on I2C + help + This allows you to use a range of I2C adapters called PCA adapters. + Say Y if you own an I2C adapter belonging to this class and then say + Y to the specific driver for you adapter below. + + This support is also available as a module. If so, the module + will be called i2c-algo-pca. + config I2C_ALGOITE tristate "ITE I2C Algorithm" depends on MIPS_ITE8172 && I2C diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile index df88f3f01..3545644be 100644 --- a/drivers/i2c/algos/Makefile +++ b/drivers/i2c/algos/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o +obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index afbd48fe8..4ea4c7928 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -565,8 +565,8 @@ MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(bit_test, "i"); -MODULE_PARM(i2c_debug,"i"); +module_param(bit_test, bool, 0); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); MODULE_PARM_DESC(i2c_debug, diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c index acc7ab6a9..7405aac67 100644 --- a/drivers/i2c/algos/i2c-algo-ite.c +++ b/drivers/i2c/algos/i2c-algo-ite.c @@ -52,21 +52,15 @@ #define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04 #define GPIO_CCR IT8172_PCI_IO_BASE + IT_GPCCR -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x #define DEB2(x) if (i2c_debug>=2) x #define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ -#define DEBPROTO(x) if (i2c_debug>=9) x; - /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 -/* ----- global variables --------------------------------------------- */ - /* module parameters: */ -static int i2c_debug=1; -static int iic_test=0; /* see if the line-setting functions work */ +static int i2c_debug; +static int iic_test; /* see if the line-setting functions work */ /* --- setting states on the bus with the right timing: --------------- */ @@ -804,8 +798,8 @@ MODULE_AUTHOR("MontaVista Software "); MODULE_DESCRIPTION("ITE iic algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(iic_test, "i"); -MODULE_PARM(i2c_debug,"i"); +module_param(iic_test, bool, 0); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available"); MODULE_PARM_DESC(i2c_debug, diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c new file mode 100644 index 000000000..38092b7a7 --- /dev/null +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -0,0 +1,395 @@ +/* + * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters + * Copyright (C) 2004 Arcom Control Systems + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-algo-pca.h" + +#define DRIVER "i2c-algo-pca" + +#define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0) +#define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) +#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0) + +static int i2c_debug=0; + +#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val) +#define pca_inw(adap, reg) adap->read_byte(adap, reg) + +#define pca_status(adap) pca_inw(adap, I2C_PCA_STA) +#define pca_clock(adap) adap->get_clock(adap) +#define pca_own(adap) adap->get_own(adap) +#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) +#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) +#define pca_wait(adap) adap->wait_for_interrupt(adap) + +/* + * Generate a start condition on the i2c bus. + * + * returns after the start condition has occured + */ +static void pca_start(struct i2c_algo_pca_data *adap) +{ + int sta = pca_get_con(adap); + DEB2("=== START\n"); + sta |= I2C_PCA_CON_STA; + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + pca_wait(adap); +} + +/* + * Generate a repeated start condition on the i2c bus + * + * return after the repeated start condition has occured + */ +static void pca_repeated_start(struct i2c_algo_pca_data *adap) +{ + int sta = pca_get_con(adap); + DEB2("=== REPEATED START\n"); + sta |= I2C_PCA_CON_STA; + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + pca_wait(adap); +} + +/* + * Generate a stop condition on the i2c bus + * + * returns after the stop condition has been generated + * + * STOPs do not generate an interrupt or set the SI flag, since the + * part returns the the idle state (0xf8). Hence we don't need to + * pca_wait here. + */ +static void pca_stop(struct i2c_algo_pca_data *adap) +{ + int sta = pca_get_con(adap); + DEB2("=== STOP\n"); + sta |= I2C_PCA_CON_STO; + sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI); + pca_set_con(adap, sta); +} + +/* + * Send the slave address and R/W bit + * + * returns after the address has been sent + */ +static void pca_address(struct i2c_algo_pca_data *adap, + struct i2c_msg *msg) +{ + int sta = pca_get_con(adap); + int addr; + + addr = ( (0x7f & msg->addr) << 1 ); + if (msg->flags & I2C_M_RD ) + addr |= 1; + DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n", + msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr); + + pca_outw(adap, I2C_PCA_DAT, addr); + + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + + pca_wait(adap); +} + +/* + * Transmit a byte. + * + * Returns after the byte has been transmitted + */ +static void pca_tx_byte(struct i2c_algo_pca_data *adap, + __u8 b) +{ + int sta = pca_get_con(adap); + DEB2("=== WRITE %#04x\n", b); + pca_outw(adap, I2C_PCA_DAT, b); + + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); + pca_set_con(adap, sta); + + pca_wait(adap); +} + +/* + * Receive a byte + * + * returns immediately. + */ +static void pca_rx_byte(struct i2c_algo_pca_data *adap, + __u8 *b, int ack) +{ + *b = pca_inw(adap, I2C_PCA_DAT); + DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK"); +} + +/* + * Setup ACK or NACK for next received byte and wait for it to arrive. + * + * Returns after next byte has arrived. + */ +static void pca_rx_ack(struct i2c_algo_pca_data *adap, + int ack) +{ + int sta = pca_get_con(adap); + + sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA); + + if ( ack ) + sta |= I2C_PCA_CON_AA; + + pca_set_con(adap, sta); + pca_wait(adap); +} + +/* + * Reset the i2c bus / SIO + */ +static void pca_reset(struct i2c_algo_pca_data *adap) +{ + /* apparently only an external reset will do it. not a lot can be done */ + printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n"); +} + +static int pca_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], + int num) +{ + struct i2c_algo_pca_data *adap = i2c_adap->algo_data; + struct i2c_msg *msg = NULL; + int curmsg; + int numbytes = 0; + int state; + + state = pca_status(adap); + if ( state != 0xF8 ) { + printk(KERN_ERR DRIVER ": bus is not idle. status is %#04x\n", state ); + /* FIXME: what to do. Force stop ? */ + return -EREMOTEIO; + } + + DEB1("{{{ XFER %d messages\n", num); + + if (i2c_debug>=2) { + for (curmsg = 0; curmsg < num; curmsg++) { + int addr, i; + msg = &msgs[curmsg]; + + addr = (0x7f & msg->addr) ; + + if (msg->flags & I2C_M_RD ) + printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n", + curmsg, msg->len, addr, (addr<<1) | 1); + else { + printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s", + curmsg, msg->len, addr, addr<<1, + msg->len == 0 ? "" : ", "); + for(i=0; i < msg->len; i++) + printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", "); + printk("]\n"); + } + } + } + + curmsg = 0; + while (curmsg < num) { + state = pca_status(adap); + + DEB3("STATE is 0x%02x\n", state); + msg = &msgs[curmsg]; + + switch (state) { + case 0xf8: /* On reset or stop the bus is idle */ + pca_start(adap); + break; + + case 0x08: /* A START condition has been transmitted */ + case 0x10: /* A repeated start condition has been transmitted */ + pca_address(adap, msg); + break; + + case 0x18: /* SLA+W has been transmitted; ACK has been received */ + case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */ + if (numbytes < msg->len) { + pca_tx_byte(adap, msg->buf[numbytes]); + numbytes++; + break; + } + curmsg++; numbytes = 0; + if (curmsg == num) + pca_stop(adap); + else + pca_repeated_start(adap); + break; + + case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */ + DEB2("NOT ACK recieved after SLA+W\n"); + pca_stop(adap); + return -EREMOTEIO; + + case 0x40: /* SLA+R has been transmitted; ACK has been received */ + pca_rx_ack(adap, msg->len > 1); + break; + + case 0x50: /* Data bytes has been received; ACK has been returned */ + if (numbytes < msg->len) { + pca_rx_byte(adap, &msg->buf[numbytes], 1); + numbytes++; + pca_rx_ack(adap, numbytes < msg->len - 1); + break; + } + curmsg++; numbytes = 0; + if (curmsg == num) + pca_stop(adap); + else + pca_repeated_start(adap); + break; + + case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */ + DEB2("NOT ACK received after SLA+R\n"); + pca_stop(adap); + return -EREMOTEIO; + + case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */ + DEB2("NOT ACK recieved after data byte\n"); + return -EREMOTEIO; + + case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */ + DEB2("Arbitration lost\n"); + return -EREMOTEIO; + + case 0x58: /* Data byte has been received; NOT ACK has been returned */ + if ( numbytes == msg->len - 1 ) { + pca_rx_byte(adap, &msg->buf[numbytes], 0); + curmsg++; numbytes = 0; + if (curmsg == num) + pca_stop(adap); + else + pca_repeated_start(adap); + } else { + DEB2("NOT ACK sent after data byte received. " + "Not final byte. numbytes %d. len %d\n", + numbytes, msg->len); + pca_stop(adap); + return -EREMOTEIO; + } + break; + case 0x70: /* Bus error - SDA stuck low */ + DEB2("BUS ERROR - SDA Stuck low\n"); + pca_reset(adap); + return -EREMOTEIO; + case 0x90: /* Bus error - SCL stuck low */ + DEB2("BUS ERROR - SCL Stuck low\n"); + pca_reset(adap); + return -EREMOTEIO; + case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */ + DEB2("BUS ERROR - Illegal START or STOP\n"); + pca_reset(adap); + return -EREMOTEIO; + default: + printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state); + break; + } + + } + + DEB1(KERN_CRIT "}}} transfered %d messages. " + "status is %#04x. control is %#04x\n", + num, pca_status(adap), + pca_get_con(adap)); + return curmsg; +} + +static u32 pca_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static int pca_init(struct i2c_algo_pca_data *adap) +{ + static int freqs[] = {330,288,217,146,88,59,44,36}; + int own, clock; + + own = pca_own(adap); + clock = pca_clock(adap); + DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own); + DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]); + + pca_outw(adap, I2C_PCA_ADR, own << 1); + + pca_set_con(adap, I2C_PCA_CON_ENSIO | clock); + udelay(500); /* 500 µs for oscilator to stabilise */ + + return 0; +} + +static struct i2c_algorithm pca_algo = { + .name = "PCA9564 algorithm", + .id = I2C_ALGO_PCA, + .master_xfer = pca_xfer, + .functionality = pca_func, +}; + +/* + * registering functions to load algorithms at runtime + */ +int i2c_pca_add_bus(struct i2c_adapter *adap) +{ + struct i2c_algo_pca_data *pca_adap = adap->algo_data; + int rval; + + /* register new adapter to i2c module... */ + + adap->id |= pca_algo.id; + adap->algo = &pca_algo; + + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + + rval = pca_init(pca_adap); + + if (!rval) + i2c_add_adapter(adap); + + return rval; +} + +int i2c_pca_del_bus(struct i2c_adapter *adap) +{ + return i2c_del_adapter(adap); +} + +EXPORT_SYMBOL(i2c_pca_add_bus); +EXPORT_SYMBOL(i2c_pca_del_bus); + +MODULE_AUTHOR("Ian Campbell "); +MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); +MODULE_LICENSE("GPL"); + +module_param(i2c_debug, int, 0); diff --git a/drivers/i2c/algos/i2c-algo-pca.h b/drivers/i2c/algos/i2c-algo-pca.h new file mode 100644 index 000000000..2fee07e05 --- /dev/null +++ b/drivers/i2c/algos/i2c-algo-pca.h @@ -0,0 +1,26 @@ +#ifndef I2C_PCA9564_H +#define I2C_PCA9564_H 1 + +#define I2C_PCA_STA 0x00 /* STATUS Read Only */ +#define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */ +#define I2C_PCA_DAT 0x01 /* DATA Read/Write */ +#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */ +#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */ + +#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */ +#define I2C_PCA_CON_ENSIO 0x40 /* Enable */ +#define I2C_PCA_CON_STA 0x20 /* Start */ +#define I2C_PCA_CON_STO 0x10 /* Stop */ +#define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */ +#define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */ + +#define I2C_PCA_CON_330kHz 0x00 +#define I2C_PCA_CON_288kHz 0x01 +#define I2C_PCA_CON_217kHz 0x02 +#define I2C_PCA_CON_146kHz 0x03 +#define I2C_PCA_CON_88kHz 0x04 +#define I2C_PCA_CON_59kHz 0x05 +#define I2C_PCA_CON_44kHz 0x06 +#define I2C_PCA_CON_36kHz 0x07 + +#endif /* I2C_PCA9564_H */ diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index b53f65a12..6dc807abc 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -38,8 +38,6 @@ #include "i2c-algo-pcf.h" -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x #define DEB2(x) if (i2c_debug>=2) x #define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ #define DEBPROTO(x) if (i2c_debug>=9) x; @@ -48,7 +46,7 @@ /* module parameters: */ -static int i2c_debug=0; +static int i2c_debug; /* --- setting states on the bus with the right timing: --------------- */ @@ -101,12 +99,6 @@ static int wait_for_bb(struct i2c_algo_pcf_data *adap) { } -static inline void pcf_sleep(unsigned long timeout) -{ - schedule_timeout( timeout * HZ); -} - - static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { int timeout = DEF_TIMEOUT; @@ -472,6 +464,6 @@ MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); MODULE_LICENSE("GPL"); -MODULE_PARM(i2c_debug,"i"); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3628b099f..166b9174a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -164,6 +164,17 @@ config I2C_IXP4XX This support is also available as a module. If so, the module will be called i2c-ixp4xx. +config I2C_IXP2000 + tristate "IXP2000 GPIO-Based I2C Interface" + depends on I2C && ARCH_IXP2000 + select I2C_ALGOBIT + help + Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based + system and are using GPIO lines for an I2C bus. + + This support is also available as a module. If so, the module + will be called i2c-ixp2000. + config I2C_KEYWEST tristate "Powermac Keywest I2C interface" depends on I2C && PPC_PMAC @@ -174,6 +185,18 @@ config I2C_KEYWEST This support is also available as a module. If so, the module will be called i2c-keywest. +config I2C_MPC + tristate "MPC107/824x/85xx/52xx" + depends on I2C && FSL_OCP + help + If you say yes to this option, support will be included for the + built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and + MPC85xx family processors. The driver may also work on 52xx + family processors, though interrupts are known not to work. + + This driver can also be built as a module. If so, the module + will be called i2c-mpc. + config I2C_NFORCE2 tristate "Nvidia Nforce2" depends on I2C && PCI && EXPERIMENTAL @@ -396,4 +419,15 @@ config I2C_VOODOO3 This driver can also be built as a module. If so, the module will be called i2c-voodoo3. +config I2C_PCA_ISA + tristate "PCA9564 on an ISA bus" + depends on I2C + select I2C_ALGOPCA + help + This driver supports ISA boards using the Philips PCA 9564 + Parallel bus to I2C bus controller + + This driver can also be built as a module. If so, the module + will be called i2c-pca-isa. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 83391986c..932b00fb6 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -15,11 +15,14 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_ISA) += i2c-isa.o obj-$(CONFIG_I2C_ITE) += i2c-ite.o +obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o +obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o +obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index f77ae846e..ef6dd420d 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -395,7 +395,7 @@ static struct pci_device_id __devinitdata ali1563_id_table[] = { }; static struct pci_driver ali1563_pci_driver = { - .name = "i2c-ali1563", + .name = "ali1563_i2c", .id_table = ali1563_id_table, .probe = ali1563_probe, .remove = ali1563_remove, diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index ef4a62524..4e3dfd787 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -126,8 +126,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static u16 force_addr = 0; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); @@ -509,7 +509,7 @@ static void __devexit ali15x3_remove(struct pci_dev *dev) } static struct pci_driver ali15x3_driver = { - .name = "ali15x3 smbus", + .name = "ali15x3_smbus", .id_table = ali15x3_ids, .probe = ali15x3_probe, .remove = __devexit_p(ali15x3_remove), diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 4b1151373..22c4a9948 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -394,7 +394,7 @@ static void __devexit amd756_remove(struct pci_dev *dev) } static struct pci_driver amd756_driver = { - .name = "amd756 smbus", + .name = "amd756_smbus", .id_table = amd756_ids, .probe = amd756_probe, .remove = __devexit_p(amd756_remove), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index b0e597049..c0ea19e41 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -392,7 +392,7 @@ static void __devexit amd8111_remove(struct pci_dev *dev) } static struct pci_driver amd8111_driver = { - .name = "amd8111 smbus 2", + .name = "amd8111_smbus2", .id_table = amd8111_ids, .probe = amd8111_probe, .remove = __devexit_p(amd8111_remove), diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 768c901a8..f6bd38b06 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -269,11 +269,11 @@ MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_LICENSE("GPL"); -MODULE_PARM(base, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(clock, "i"); -MODULE_PARM(own, "i"); -MODULE_PARM(mmapped, "i"); +module_param(base, int, 0); +module_param(irq, int, 0); +module_param(clock, int, 0); +module_param(own, int, 0); +module_param(mmapped, int, 0); module_init(i2c_pcfisa_init); module_exit(i2c_pcfisa_exit); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index 7d6d69182..275da79e3 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -158,7 +158,7 @@ static void __devexit hydra_remove(struct pci_dev *dev) static struct pci_driver hydra_driver = { - .name = "hydra smbus", + .name = "hydra_smbus", .id_table = hydra_ids, .probe = hydra_probe, .remove = __devexit_p(hydra_remove), diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 4689bd01d..e873ba001 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -98,8 +98,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the I801 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static u16 force_addr; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Forcibly enable the I801 at the given address. " "EXTREMELY DANGEROUS!"); @@ -623,7 +623,7 @@ static void __devexit i801_remove(struct pci_dev *dev) } static struct pci_driver i801_driver = { - .name = "i801 smbus", + .name = "i801_smbus", .id_table = i801_ids, .probe = i801_probe, .remove = __devexit_p(i801_remove), diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index fd11366cc..46bd56660 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -231,7 +231,7 @@ static void __devexit i810_remove(struct pci_dev *dev) } static struct pci_driver i810_driver = { - .name = "i810 smbus", + .name = "i810_smbus", .id_table = i810_ids, .probe = i810_probe, .remove = __devexit_p(i810_remove), diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index a25218dba..fcb525296 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -50,12 +50,12 @@ MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); MODULE_LICENSE("GPL"); -static int iic_force_poll = 0; -MODULE_PARM(iic_force_poll, "i"); +static int iic_force_poll; +module_param(iic_force_poll, bool, 0); MODULE_PARM_DESC(iic_force_poll, "Force polling mode"); -static int iic_force_fast = 0; -MODULE_PARM(iic_force_fast, "i"); +static int iic_force_fast; +module_param(iic_force_fast, bool, 0); MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)"); #define DBG_LEVEL 0 diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c index 917759c42..da926a619 100644 --- a/drivers/i2c/busses/i2c-ite.c +++ b/drivers/i2c/busses/i2c-ite.c @@ -54,10 +54,10 @@ #define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */ #define DEFAULT_OWN 0x55 -static int base = 0; -static int irq = 0; -static int clock = 0; -static int own = 0; +static int base; +static int irq; +static int clock; +static int own; static struct iic_ite gpi; static wait_queue_head_t iic_wait; @@ -102,14 +102,6 @@ static int iic_ite_getclock(void *data) } -#if 0 -static void iic_ite_sleep(unsigned long timeout) -{ - schedule_timeout( timeout * HZ); -} -#endif - - /* Put this process to sleep. We will wake up when the * IIC controller interrupts. */ @@ -254,10 +246,10 @@ MODULE_AUTHOR("MontaVista Software "); MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter"); MODULE_LICENSE("GPL"); -MODULE_PARM(base, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(clock, "i"); -MODULE_PARM(own, "i"); +module_param(base, int, 0); +module_param(irq, int, 0); +module_param(clock, int, 0); +module_param(own, int, 0); /* Called when module is loaded or when kernel is initialized. diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c new file mode 100644 index 000000000..21cd54d02 --- /dev/null +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -0,0 +1,171 @@ +/* + * drivers/i2c/busses/i2c-ixp2000.c + * + * I2C adapter for IXP2000 systems using GPIOs for I2C bus + * + * Author: Deepak Saxena + * Based on IXDP2400 code by: Naeem M. Afzal + * Made generic by: Jeff Daly + * + * Copyright (c) 2003-2004 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 Jeff Daly: + * + * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any + * IXP2000 platform if it uses the HW GPIO in the same manner. Basically, + * SDA and SCL GPIOs have external pullups. Setting the respective GPIO to + * an input will make the signal a '1' via the pullup. Setting them to + * outputs will pull them down. + * + * The GPIOs are open drain signals and are used as configuration strap inputs + * during power-up so there's generally a buffer on the board that needs to be + * 'enabled' to drive the GPIOs. + */ + +#include +#ifdef CONFIG_I2C_DEBUG_BUS +#define DEBUG 1 +#endif + +#include +#include +#include +#include +#include +#include + +#include /* Pick up IXP42000-specific bits */ + +static inline int ixp2000_scl_pin(void *data) +{ + return ((struct ixp2000_i2c_pins*)data)->scl_pin; +} + +static inline int ixp2000_sda_pin(void *data) +{ + return ((struct ixp2000_i2c_pins*)data)->sda_pin; +} + + +static void ixp2000_bit_setscl(void *data, int val) +{ + int i = 5000; + + if (val) { + gpio_line_config(ixp2000_scl_pin(data), GPIO_IN); + while(!gpio_line_get(ixp2000_scl_pin(data)) && i--); + } else { + gpio_line_config(ixp2000_scl_pin(data), GPIO_OUT); + } +} + +static void ixp2000_bit_setsda(void *data, int val) +{ + if (val) { + gpio_line_config(ixp2000_sda_pin(data), GPIO_IN); + } else { + gpio_line_config(ixp2000_sda_pin(data), GPIO_OUT); + } +} + +static int ixp2000_bit_getscl(void *data) +{ + return gpio_line_get(ixp2000_scl_pin(data)); +} + +static int ixp2000_bit_getsda(void *data) +{ + return gpio_line_get(ixp2000_sda_pin(data)); +} + +struct ixp2000_i2c_data { + struct ixp2000_i2c_pins *gpio_pins; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo_data; +}; + +static int ixp2000_i2c_remove(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct ixp2000_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev); + + dev_set_drvdata(&plat_dev->dev, NULL); + + i2c_bit_del_bus(&drv_data->adapter); + + kfree(drv_data); + + return 0; +} + +static int ixp2000_i2c_probe(struct device *dev) +{ + int err; + struct platform_device *plat_dev = to_platform_device(dev); + struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data; + struct ixp2000_i2c_data *drv_data = + kmalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL); + + if (!drv_data) + return -ENOMEM; + memzero(drv_data, sizeof(*drv_data)); + drv_data->gpio_pins = gpio; + + drv_data->algo_data.data = gpio; + drv_data->algo_data.setsda = ixp2000_bit_setsda; + drv_data->algo_data.setscl = ixp2000_bit_setscl; + drv_data->algo_data.getsda = ixp2000_bit_getsda; + drv_data->algo_data.getscl = ixp2000_bit_getscl; + drv_data->algo_data.udelay = 6; + drv_data->algo_data.mdelay = 6; + drv_data->algo_data.timeout = 100; + + drv_data->adapter.id = I2C_HW_B_IXP2000, + drv_data->adapter.algo_data = &drv_data->algo_data, + + drv_data->adapter.dev.parent = &plat_dev->dev; + + gpio_line_config(gpio->sda_pin, GPIO_IN); + gpio_line_config(gpio->scl_pin, GPIO_IN); + gpio_line_set(gpio->scl_pin, 0); + gpio_line_set(gpio->sda_pin, 0); + + if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) { + dev_err(dev, "Could not install, error %d\n", err); + kfree(drv_data); + return err; + } + + dev_set_drvdata(&plat_dev->dev, drv_data); + + return 0; +} + +static struct device_driver ixp2000_i2c_driver = { + .name = "IXP2000-I2C", + .bus = &platform_bus_type, + .probe = ixp2000_i2c_probe, + .remove = ixp2000_i2c_remove, +}; + +static int __init ixp2000_i2c_init(void) +{ + return driver_register(&ixp2000_i2c_driver); +} + +static void __exit ixp2000_i2c_exit(void) +{ + driver_unregister(&ixp2000_i2c_driver); +} + +module_init(ixp2000_i2c_init); +module_exit(ixp2000_i2c_exit); + +MODULE_AUTHOR ("Deepak Saxena "); +MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 0b606e88d..a5a8c1e79 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -88,12 +88,12 @@ static const char *__kw_state_names[] = { }; #endif /* DEBUG */ +static int probe; + MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); MODULE_LICENSE("GPL"); -MODULE_PARM(probe, "i"); - -static int probe = 0; +module_param(probe, bool, 0); #ifdef POLLED_MODE /* Don't schedule, the g5 fan controller is too @@ -662,8 +662,7 @@ dispose_iface(struct device *dev) spin_lock_irq(&iface->lock); while (iface->state != state_idle) { spin_unlock_irq(&iface->lock); - set_task_state(current,TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); spin_lock_irq(&iface->lock); } #endif /* POLLED_MODE */ diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c new file mode 100644 index 000000000..f77245e56 --- /dev/null +++ b/drivers/i2c/busses/i2c-mpc.c @@ -0,0 +1,392 @@ +/* + * (C) Copyright 2003-2004 + * Humboldt Solutions Ltd, adrian@humboldt.co.uk. + + * This is a combined i2c adapter and algorithm driver for the + * MPC107/Tsi107 PowerPC northbridge and processors that include + * the same I2C unit (8240, 8245, 85xx). + * + * Release 0.6 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPC_I2C_ADDR 0x00 +#define MPC_I2C_FDR 0x04 +#define MPC_I2C_CR 0x08 +#define MPC_I2C_SR 0x0c +#define MPC_I2C_DR 0x10 +#define MPC_I2C_DFSRR 0x14 +#define MPC_I2C_REGION 0x20 + +#define CCR_MEN 0x80 +#define CCR_MIEN 0x40 +#define CCR_MSTA 0x20 +#define CCR_MTX 0x10 +#define CCR_TXAK 0x08 +#define CCR_RSTA 0x04 + +#define CSR_MCF 0x80 +#define CSR_MAAS 0x40 +#define CSR_MBB 0x20 +#define CSR_MAL 0x10 +#define CSR_SRW 0x04 +#define CSR_MIF 0x02 +#define CSR_RXAK 0x01 + +struct mpc_i2c { + char *base; + struct ocp_def *ocpdef; + u32 interrupt; + wait_queue_head_t queue; + struct i2c_adapter adap; +}; + +static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x) +{ + writeb(x, i2c->base + MPC_I2C_CR); +} + +static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mpc_i2c *i2c = dev_id; + if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) { + /* Read again to allow register to stabilise */ + i2c->interrupt = readb(i2c->base + MPC_I2C_SR); + writeb(0, i2c->base + MPC_I2C_SR); + wake_up_interruptible(&i2c->queue); + } + return IRQ_HANDLED; +} + +static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long orig_jiffies = jiffies; + u32 x; + int result = 0; + + if (i2c->ocpdef->irq == OCP_IRQ_NA) { + while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { + schedule(); + if (time_after(jiffies, orig_jiffies + timeout)) { + pr_debug("I2C: timeout\n"); + result = -EIO; + break; + } + } + x = readb(i2c->base + MPC_I2C_SR); + writeb(0, i2c->base + MPC_I2C_SR); + } else { + add_wait_queue(&i2c->queue, &wait); + while (!(i2c->interrupt & CSR_MIF)) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + pr_debug("I2C: Interrupted\n"); + result = -EINTR; + break; + } + if (time_after(jiffies, orig_jiffies + timeout)) { + pr_debug("I2C: timeout\n"); + result = -EIO; + break; + } + schedule_timeout(timeout); + } + current->state = TASK_RUNNING; + remove_wait_queue(&i2c->queue, &wait); + x = i2c->interrupt; + i2c->interrupt = 0; + } + + if (result < -0) + return result; + + if (!(x & CSR_MCF)) { + pr_debug("I2C: unfinished\n"); + return -EIO; + } + + if (x & CSR_MAL) { + pr_debug("I2C: MAL\n"); + return -EIO; + } + + if (writing && (x & CSR_RXAK)) { + pr_debug("I2C: No RXAK\n"); + /* generate stop */ + writeccr(i2c, CCR_MEN); + return -EIO; + } + return 0; +} + +static void mpc_i2c_setclock(struct mpc_i2c *i2c) +{ + struct ocp_fs_i2c_data *i2c_data = i2c->ocpdef->additions; + /* Set clock and filters */ + if (i2c_data && (i2c_data->flags & FS_I2C_SEPARATE_DFSRR)) { + writeb(0x31, i2c->base + MPC_I2C_FDR); + writeb(0x10, i2c->base + MPC_I2C_DFSRR); + } else if (i2c_data && (i2c_data->flags & FS_I2C_CLOCK_5200)) + writeb(0x3f, i2c->base + MPC_I2C_FDR); + else + writel(0x1031, i2c->base + MPC_I2C_FDR); +} + +static void mpc_i2c_start(struct mpc_i2c *i2c) +{ + /* Clear arbitration */ + writeb(0, i2c->base + MPC_I2C_SR); + /* Start with MEN */ + writeccr(i2c, CCR_MEN); +} + +static void mpc_i2c_stop(struct mpc_i2c *i2c) +{ + writeccr(i2c, CCR_MEN); +} + +static int mpc_write(struct mpc_i2c *i2c, int target, + const u8 * data, int length, int restart) +{ + int i; + unsigned timeout = HZ; + u32 flags = restart ? CCR_RSTA : 0; + + /* Start with MEN */ + if (!restart) + writeccr(i2c, CCR_MEN); + /* Start as master */ + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); + /* Write target byte */ + writeb((target << 1), i2c->base + MPC_I2C_DR); + + if (i2c_wait(i2c, timeout, 1) < 0) + return -1; + + for (i = 0; i < length; i++) { + /* Write data byte */ + writeb(data[i], i2c->base + MPC_I2C_DR); + + if (i2c_wait(i2c, timeout, 1) < 0) + return -1; + } + + return 0; +} + +static int mpc_read(struct mpc_i2c *i2c, int target, + u8 * data, int length, int restart) +{ + unsigned timeout = HZ; + int i; + u32 flags = restart ? CCR_RSTA : 0; + + /* Start with MEN */ + if (!restart) + writeccr(i2c, CCR_MEN); + /* Switch to read - restart */ + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); + /* Write target address byte - this time with the read flag set */ + writeb((target << 1) | 1, i2c->base + MPC_I2C_DR); + + if (i2c_wait(i2c, timeout, 1) < 0) + return -1; + + if (length) { + if (length == 1) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); + else + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); + /* Dummy read */ + readb(i2c->base + MPC_I2C_DR); + } + + for (i = 0; i < length; i++) { + if (i2c_wait(i2c, timeout, 0) < 0) + return -1; + + /* Generate txack on next to last byte */ + if (i == length - 2) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); + /* Generate stop on last byte */ + if (i == length - 1) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK); + data[i] = readb(i2c->base + MPC_I2C_DR); + } + + return length; +} + +static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + int i; + int ret = 0; + unsigned long orig_jiffies = jiffies; + struct mpc_i2c *i2c = i2c_get_adapdata(adap); + + mpc_i2c_start(i2c); + + /* Allow bus up to 1s to become not busy */ + while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { + if (signal_pending(current)) { + pr_debug("I2C: Interrupted\n"); + return -EINTR; + } + if (time_after(jiffies, orig_jiffies + HZ)) { + pr_debug("I2C: timeout\n"); + return -EIO; + } + schedule(); + } + + for (i = 0; ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, pmsg->addr, i + 1, num); + if (pmsg->flags & I2C_M_RD) + ret = + mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); + else + ret = + mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); + } + mpc_i2c_stop(i2c); + return (ret < 0) ? ret : num; +} + +static u32 mpc_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm mpc_algo = { + .name = "MPC algorithm", + .id = I2C_ALGO_MPC107, + .master_xfer = mpc_xfer, + .functionality = mpc_functionality, +}; + +static struct i2c_adapter mpc_ops = { + .owner = THIS_MODULE, + .name = "MPC adapter", + .id = I2C_ALGO_MPC107 | I2C_HW_MPC107, + .algo = &mpc_algo, + .class = I2C_CLASS_HWMON, + .timeout = 1, + .retries = 1 +}; + +static int __devinit mpc_i2c_probe(struct ocp_device *ocp) +{ + int result = 0; + struct mpc_i2c *i2c; + + if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) { + return -ENOMEM; + } + i2c->ocpdef = ocp->def; + init_waitqueue_head(&i2c->queue); + + if (!request_mem_region(ocp->def->paddr, MPC_I2C_REGION, "i2c-mpc")) { + printk(KERN_ERR "i2c-mpc - resource unavailable\n"); + return -ENODEV; + } + + i2c->base = ioremap(ocp->def->paddr, MPC_I2C_REGION); + + if (!i2c->base) { + printk(KERN_ERR "i2c-mpc - failed to map controller\n"); + result = -ENOMEM; + goto fail_map; + } + + if (ocp->def->irq != OCP_IRQ_NA) + if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, + 0, "i2c-mpc", i2c)) < 0) { + printk(KERN_ERR + "i2c-mpc - failed to attach interrupt\n"); + goto fail_irq; + } + + i2c->adap = mpc_ops; + i2c_set_adapdata(&i2c->adap, i2c); + if ((result = i2c_add_adapter(&i2c->adap)) < 0) { + printk(KERN_ERR "i2c-mpc - failed to add adapter\n"); + goto fail_add; + } + + mpc_i2c_setclock(i2c); + ocp_set_drvdata(ocp, i2c); + return result; + + fail_add: + if (ocp->def->irq != OCP_IRQ_NA) + free_irq(ocp->def->irq, 0); + fail_irq: + iounmap(i2c->base); + fail_map: + release_mem_region(ocp->def->paddr, MPC_I2C_REGION); + kfree(i2c); + return result; +} +static void __devexit mpc_i2c_remove(struct ocp_device *ocp) +{ + struct mpc_i2c *i2c = ocp_get_drvdata(ocp); + ocp_set_drvdata(ocp, NULL); + i2c_del_adapter(&i2c->adap); + + if (ocp->def->irq != OCP_IRQ_NA) + free_irq(i2c->ocpdef->irq, i2c); + iounmap(i2c->base); + release_mem_region(i2c->ocpdef->paddr, MPC_I2C_REGION); + kfree(i2c); +} + +static struct ocp_device_id mpc_iic_ids[] __devinitdata = { + {.vendor = OCP_VENDOR_FREESCALE,.function = OCP_FUNC_IIC}, + {.vendor = OCP_VENDOR_INVALID} +}; + +MODULE_DEVICE_TABLE(ocp, mpc_iic_ids); + +static struct ocp_driver mpc_iic_driver = { + .name = "iic", + .id_table = mpc_iic_ids, + .probe = mpc_i2c_probe, + .remove = __devexit_p(mpc_i2c_remove) +}; + +static int __init iic_init(void) +{ + return ocp_register_driver(&mpc_iic_driver); +} + +static void __exit iic_exit(void) +{ + ocp_unregister_driver(&mpc_iic_driver); +} + +module_init(iic_init); +module_exit(iic_exit); + +MODULE_AUTHOR("Adrian Cox "); +MODULE_DESCRIPTION + ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 774a7ef52..0cf6a2686 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -244,8 +244,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, temp = inb_p(NVIDIA_SMB_STS); } if (~temp & NVIDIA_SMB_STS_DONE) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/100); + msleep(10); temp = inb_p(NVIDIA_SMB_STS); } @@ -384,7 +383,7 @@ static void __devexit nforce2_remove(struct pci_dev *dev) } static struct pci_driver nforce2_driver = { - .name = "nForce2 SMBus", + .name = "nForce2_smbus", .id_table = nforce2_ids, .probe = nforce2_probe, .remove = __devexit_p(nforce2_remove), diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 6798954f0..cb5e72230 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -36,8 +36,8 @@ #define DEFAULT_BASE 0x378 -static int base; -MODULE_PARM(base, "i"); +static u16 base; +module_param(base, ushort, 0); MODULE_PARM_DESC(base, "Base I/O address"); /* ----- Low-level parallel port access ----------------------------------- */ diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index 284d3f5d3..f63a53779 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -83,7 +83,7 @@ static struct adapter_parm adapter_parm[] = { }; static int type; -MODULE_PARM(type, "i"); +module_param(type, int, 0); MODULE_PARM_DESC(type, "Type of adapter:\n" " 0 = Philips adapter\n" diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c new file mode 100644 index 000000000..9c611134d --- /dev/null +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -0,0 +1,184 @@ +/* + * i2c-pca-isa.c driver for PCA9564 on ISA boards + * Copyright (C) 2004 Arcom Control Systems + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "../algos/i2c-algo-pca.h" + +#define IO_SIZE 4 + +#undef DEBUG_IO +//#define DEBUG_IO + +static unsigned long base = 0x330; +static int irq = 10; + +/* Data sheet recommends 59kHz for 100kHz operation due to variation + * in the actual clock rate */ +static int clock = I2C_PCA_CON_59kHz; + +static int own = 0x55; + +static wait_queue_head_t pca_wait; + +static int pca_isa_getown(struct i2c_algo_pca_data *adap) +{ + return (own); +} + +static int pca_isa_getclock(struct i2c_algo_pca_data *adap) +{ + return (clock); +} + +static void +pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val) +{ +#ifdef DEBUG_IO + static char *names[] = { "T/O", "DAT", "ADR", "CON" }; + printk("*** write %s at %#lx <= %#04x\n", names[reg], base+reg, val); +#endif + outb(val, base+reg); +} + +static int +pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg) +{ + int res = inb(base+reg); +#ifdef DEBUG_IO + { + static char *names[] = { "STA", "DAT", "ADR", "CON" }; + printk("*** read %s => %#04x\n", names[reg], res); + } +#endif + return res; +} + +static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap) +{ + int ret = 0; + + if (irq > -1) { + ret = wait_event_interruptible(pca_wait, + pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI); + } else { + while ((pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) + udelay(100); + } + return ret; +} + +static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) { + wake_up_interruptible(&pca_wait); + return IRQ_HANDLED; +} + +static struct i2c_algo_pca_data pca_isa_data = { + .get_own = pca_isa_getown, + .get_clock = pca_isa_getclock, + .write_byte = pca_isa_writebyte, + .read_byte = pca_isa_readbyte, + .wait_for_interrupt = pca_isa_waitforinterrupt, +}; + +static struct i2c_adapter pca_isa_ops = { + .owner = THIS_MODULE, + .id = I2C_HW_A_ISA, + .algo_data = &pca_isa_data, + .name = "PCA9564 ISA Adapter", +}; + +static int __init pca_isa_init(void) +{ + + init_waitqueue_head(&pca_wait); + + printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq); + + if (!request_region(base, IO_SIZE, "i2c-pca-isa")) { + printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base); + goto out; + } + + if (irq > -1) { + if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) { + printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq); + goto out_region; + } + } + + if (i2c_pca_add_bus(&pca_isa_ops) < 0) { + printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n"); + goto out_irq; + } + + return 0; + + out_irq: + if (irq > -1) + free_irq(irq, &pca_isa_ops); + out_region: + release_region(base, IO_SIZE); + out: + return -ENODEV; +} + +static void pca_isa_exit(void) +{ + i2c_pca_del_bus(&pca_isa_ops); + + if (irq > 0) { + disable_irq(irq); + free_irq(irq, &pca_isa_ops); + } + release_region(base, IO_SIZE); +} + +MODULE_AUTHOR("Ian Campbell "); +MODULE_DESCRIPTION("ISA base PCA9564 driver"); +MODULE_LICENSE("GPL"); + +module_param(base, ulong, 0); +MODULE_PARM_DESC(base, "I/O base address"); + +module_param(irq, int, 0); +MODULE_PARM_DESC(irq, "IRQ"); +module_param(clock, int, 0); +MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet"); + +module_param(own, int, 0); /* the driver can't do slave mode, so there's no real point in this */ + +module_init(pca_isa_init); +module_exit(pca_isa_exit); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index e7c0262b0..6dd156fce 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -493,7 +493,7 @@ static void __devexit piix4_remove(struct pci_dev *dev) } static struct pci_driver piix4_driver = { - .name = "piix4-smbus", + .name = "piix4_smbus", .id_table = piix4_ids, .probe = piix4_probe, .remove = __devexit_p(piix4_remove), diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 0aabe49e5..9552e53a3 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -314,7 +314,7 @@ static struct pci_device_id prosavage_pci_tbl[] = { }; static struct pci_driver prosavage_driver = { - .name = "prosavage-smbus", + .name = "prosavage_smbus", .id_table = prosavage_pci_tbl, .probe = prosavage_probe, .remove = prosavage_remove, diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 33972a779..52d51948a 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -178,7 +178,7 @@ static void __devexit savage4_remove(struct pci_dev *dev) } static struct pci_driver savage4_driver = { - .name = "savage4 smbus", + .name = "savage4_smbus", .id_table = savage4_ids, .probe = savage4_probe, .remove = __devexit_p(savage4_remove), diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index a5040cca3..9469ebf16 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -124,8 +124,8 @@ static int blacklist[] = { /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static u16 force_addr = 0; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); static unsigned short sis5595_base = 0; @@ -393,7 +393,7 @@ static void __devexit sis5595_remove(struct pci_dev *dev) } static struct pci_driver sis5595_driver = { - .name = "sis5595 smbus", + .name = "sis5595_smbus", .id_table = sis5595_ids, .probe = sis5595_probe, .remove = __devexit_p(sis5595_remove), diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 437ee28d3..20e3fb42b 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -94,11 +94,11 @@ #define SIS630_BLOCK_DATA 0x05 /* insmod parameters */ -static int high_clock = 0; -static int force = 0; -MODULE_PARM(high_clock, "i"); +static int high_clock; +static int force; +module_param(high_clock, bool, 0); MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); -MODULE_PARM(force, "i"); +module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); /* acpi base address */ @@ -145,7 +145,7 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock); /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ - if (high_clock > 0) + if (high_clock) sis630_write(SMB_CNT, 0x20); else sis630_write(SMB_CNT, (*oldclock & ~0x40)); @@ -210,7 +210,7 @@ static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock) * restore old Host Master Clock if high_clock is set * and oldclock was not 56KHz */ - if (high_clock > 0 && !(oldclock & 0x20)) + if (high_clock && !(oldclock & 0x20)) sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20)); dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); @@ -401,7 +401,7 @@ static int sis630_setup(struct pci_dev *sis630_dev) if (dummy) { pci_dev_put(dummy); } - else if (force > 0) { + else if (force) { dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but " "loading because of force option enabled\n"); } @@ -464,6 +464,7 @@ static struct i2c_adapter sis630_adapter = { static struct pci_device_id sis630_ids[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, + { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { 0, } }; @@ -494,7 +495,7 @@ static void __devexit sis630_remove(struct pci_dev *dev) static struct pci_driver sis630_driver = { - .name = "sis630 smbus", + .name = "sis630_smbus", .id_table = sis630_ids, .probe = sis630_probe, .remove = __devexit_p(sis630_remove), diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index c71daa347..d605dee4d 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -339,7 +339,7 @@ static void __devexit sis96x_remove(struct pci_dev *dev) } static struct pci_driver sis96x_driver = { - .name = "sis96x smbus", + .name = "sis96x_smbus", .id_table = sis96x_ids, .probe = sis96x_probe, .remove = __devexit_p(sis96x_remove), diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index fba8f0eae..0497b9d0c 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -158,7 +158,7 @@ static void __devexit vt586b_remove(struct pci_dev *dev) static struct pci_driver vt586b_driver = { - .name = "vt586b smbus", + .name = "vt586b_smbus", .id_table = vt586b_ids, .probe = vt586b_probe, .remove = __devexit_p(vt586b_remove), diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index fbd4a15d8..396b5ebf1 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -92,13 +92,13 @@ static unsigned short smb_cf_hstcfg = 0xD2; /* If force is set to anything different from 0, we forcibly enable the VT596. DANGEROUS! */ static int force; -MODULE_PARM(force, "i"); +module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); /* If force_addr is set to anything different from 0, we forcibly enable the VT596 at the given address. VERY DANGEROUS! */ -static int force_addr; -MODULE_PARM(force_addr, "i"); +static u16 force_addr; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Forcibly enable the SMBus at the given address. " "EXTREMELY DANGEROUS!"); @@ -455,7 +455,7 @@ static struct pci_device_id vt596_ids[] = { }; static struct pci_driver vt596_driver = { - .name = "vt596 smbus", + .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, .remove = __devexit_p(vt596_remove), diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index efb677d24..b91456108 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -224,7 +224,7 @@ static void __devexit voodoo3_remove(struct pci_dev *dev) } static struct pci_driver voodoo3_driver = { - .name = "voodoo3 smbus", + .name = "voodoo3_smbus", .id_table = voodoo3_ids, .probe = voodoo3_probe, .remove = __devexit_p(voodoo3_remove), diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index b3cbbb9ea..62b7614e5 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,8 @@ MODULE_LICENSE("GPL"); #define MAX_DEVICES 4 static int base[MAX_DEVICES] = { 0x820, 0x840 }; -MODULE_PARM(base, "1-4i"); +static int num_base; +module_param_array(base, int, num_base, 0); MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers"); #ifdef DEBUG @@ -254,7 +256,7 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) scx200_acb_machine(iface, status); return; } - schedule_timeout(HZ/100+1); + msleep(10); } scx200_acb_timeout(iface); diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index b472fe81a..294ffa2f7 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -38,14 +38,14 @@ MODULE_AUTHOR("Christer Weinigel "); MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(scl, "i"); -MODULE_PARM_DESC(scl, "GPIO line for SCL"); -MODULE_PARM(sda, "i"); -MODULE_PARM_DESC(sda, "GPIO line for SDA"); - static int scl = CONFIG_SCx200_I2C_SCL; static int sda = CONFIG_SCx200_I2C_SDA; +module_param(scl, int, 0); +MODULE_PARM_DESC(scl, "GPIO line for SCL"); +module_param(sda, int, 0); +MODULE_PARM_DESC(sda, "GPIO line for SDA"); + static void scx200_i2c_setscl(void *data, int state) { scx200_gpio_set(scl, state); diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index af8d273d0..d624f4a16 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -149,7 +149,7 @@ config SENSORS_LM80 config SENSORS_LM83 tristate "National Semiconductor LM83" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for National Semiconductor @@ -191,6 +191,19 @@ config SENSORS_MAX1619 This driver can also be built as a module. If so, the module will be called max1619. +config SENSORS_SMSC47M1 + tristate "SMSC LPC47M10x and compatibles" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated fan + monitoring and control capabilities of the SMSC LPC47B27x, + LPC47M10x, LPC47M13x and LPC47M14x chips. + + This driver can also be built as a module. If so, the module + will be called smsc47m1. + config SENSORS_VIA686A tristate "VIA686A" depends on I2C && PCI && EXPERIMENTAL @@ -286,4 +299,16 @@ config SENSORS_RTC8564 This driver can also be built as a module. If so, the module will be called i2c-rtc8564. +config ISP1301_OMAP + tristate "Philips ISP1301 with OMAP OTG" + depends on I2C && ARCH_OMAP_OTG + help + If you say yes here you get support for the Philips ISP1301 + USB-On-The-Go transceiver working with the OMAP OTG controller. + The ISP1301 is used in products including H2 and H3 development + boards for Texas Instruments OMAP processors. + + This driver can also be built as a module. If so, the module + will be called isp1301_omap. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index f024e71a5..0f051183b 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -26,9 +26,12 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o +obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG endif + diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 73ca01db6..49a431bc7 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -418,7 +418,7 @@ MODULE_AUTHOR ("Frodo Looijaard and " MODULE_DESCRIPTION("adm1021 driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(read_only, "i"); +module_param(read_only, bool, 0); MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); module_init(sensors_adm1021_init) diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c index d38336fbc..711eaa21f 100644 --- a/drivers/i2c/chips/adm1025.c +++ b/drivers/i2c/chips/adm1025.c @@ -455,7 +455,7 @@ static void adm1025_init_client(struct i2c_client *client) struct adm1025_data *data = i2c_get_clientdata(client); int i; - data->vrm = 82; + data->vrm = i2c_which_vrm(); /* * Set high limits diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index a416e4ee5..e170b2a78 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -63,9 +63,6 @@ static unsigned short normal_i2c_range[] = { 0x28, 0x2f, I2C_CLIENT_END }; static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; -/* default VRM to 9.0 instead of 8.2 */ -#define ASB100_DEFAULT_VRM 90 - /* Insmod parameters */ SENSORS_INSMOD_1(asb100); I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " @@ -523,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) @@ -959,7 +956,7 @@ static void asb100_init_client(struct i2c_client *client) vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; - data->vrm = ASB100_DEFAULT_VRM; + data->vrm = i2c_which_vrm(); vid = vid_from_reg(vid, data->vrm); /* Start monitoring */ diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index bf3e21495..3aa72985e 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c @@ -37,7 +37,7 @@ static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ SENSORS_INSMOD_1(ds1621); static int polarity = -1; -MODULE_PARM(polarity, "i"); +module_param(polarity, int, 0); MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); /* Many DS1621 constants specified below */ diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 6617ff76c..44a17f61e 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -45,7 +45,7 @@ static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; SENSORS_INSMOD_1(eeprom); static int checksum = 0; -MODULE_PARM(checksum, "i"); +module_param(checksum, bool, 0); MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct"); diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c new file mode 100644 index 000000000..11d0df3b0 --- /dev/null +++ b/drivers/i2c/chips/isp1301_omap.c @@ -0,0 +1,1660 @@ +/* + * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller + * + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004 David Brownell + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#undef DEBUG +#undef VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#ifndef DEBUG +#undef VERBOSE +#endif + + +#define DRIVER_VERSION "24 August 2004" +#define DRIVER_NAME (isp1301_driver.name) + +MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver"); +MODULE_LICENSE("GPL"); + +struct isp1301 { + struct otg_transceiver otg; + struct i2c_client client; + void (*i2c_release)(struct device *dev); + + int irq; + + u32 last_otg_ctrl; + unsigned working:1; + + struct timer_list timer; + + /* use keventd context to change the state for us */ + struct work_struct work; + + unsigned long todo; +# define WORK_UPDATE_ISP 0 /* update ISP from OTG */ +# define WORK_UPDATE_OTG 1 /* update OTG from ISP */ +# define WORK_HOST_RESUME 4 /* resume host */ +# define WORK_TIMER 6 /* timer fired */ +# define WORK_STOP 7 /* don't resubmit */ +}; + + +/* bits in OTG_CTRL_REG */ + +#define OTG_XCEIV_OUTPUTS \ + (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) +#define OTG_XCEIV_INPUTS \ + (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) +#define OTG_CTRL_BITS \ + (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) + /* and OTG_PULLUP is sometimes written */ + +#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ + OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ + OTG_CTRL_BITS) + + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_MACH_OMAP_H2 + +/* board-specific PM hooks */ + +#include +#include +#include + + +#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) + +#include + +#else + +static inline int tps65010_set_vbus_draw(unsigned mA) +{ + pr_debug("tps65010: draw %d mA (STUB)\n", mA); + return 0; +} + +#endif + +static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) +{ + int status = tps65010_set_vbus_draw(mA); + if (status < 0) + pr_debug(" VBUS %d mA error %d\n", mA, status); +} + +static void enable_vbus_source(struct isp1301 *isp) +{ + /* this board won't supply more than 8mA vbus power. + * some boards can switch a 100ma "unit load" (or more). + */ +} + + +/* products will deliver OTG messages with LEDs, GUI, etc */ +static inline void notresponding(struct isp1301 *isp) +{ + printk(KERN_NOTICE "OTG device not responding.\n"); +} + + +#endif + +/*-------------------------------------------------------------------------*/ + +/* only two addresses possible */ +#define ISP_BASE 0x2c +static unsigned short normal_i2c[] = { + ISP_BASE, ISP_BASE + 1, + I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static struct i2c_driver isp1301_driver; + +/* smbus apis are used for portability */ + +static inline u8 +isp1301_get_u8(struct isp1301 *isp, u8 reg) +{ + return i2c_smbus_read_byte_data(&isp->client, reg + 0); +} + +static inline int +isp1301_get_u16(struct isp1301 *isp, u8 reg) +{ + return i2c_smbus_read_word_data(&isp->client, reg); +} + +static inline int +isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits) +{ + return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits); +} + +static inline int +isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) +{ + return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits); +} + +/*-------------------------------------------------------------------------*/ + +/* identification */ +#define ISP1301_VENDOR_ID 0x00 /* u16 read */ +#define ISP1301_PRODUCT_ID 0x02 /* u16 read */ +#define ISP1301_BCD_DEVICE 0x14 /* u16 read */ + +#define I2C_VENDOR_ID_PHILIPS 0x04cc +#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301 + +/* operational registers */ +#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ +# define MC1_SPEED_REG (1 << 0) +# define MC1_SUSPEND_REG (1 << 1) +# define MC1_DAT_SE0 (1 << 2) +# define MC1_TRANSPARENT (1 << 3) +# define MC1_BDIS_ACON_EN (1 << 4) +# define MC1_OE_INT_EN (1 << 5) +# define MC1_UART_EN (1 << 6) +# define MC1_MASK 0x7f +#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ +# define MC2_GLOBAL_PWR_DN (1 << 0) +# define MC2_SPD_SUSP_CTRL (1 << 1) +# define MC2_BI_DI (1 << 2) +# define MC2_TRANSP_BDIR0 (1 << 3) +# define MC2_TRANSP_BDIR1 (1 << 4) +# define MC2_AUDIO_EN (1 << 5) +# define MC2_PSW_EN (1 << 6) +# define MC2_EN2V7 (1 << 7) +#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ +# define OTG1_DP_PULLUP (1 << 0) +# define OTG1_DM_PULLUP (1 << 1) +# define OTG1_DP_PULLDOWN (1 << 2) +# define OTG1_DM_PULLDOWN (1 << 3) +# define OTG1_ID_PULLDOWN (1 << 4) +# define OTG1_VBUS_DRV (1 << 5) +# define OTG1_VBUS_DISCHRG (1 << 6) +# define OTG1_VBUS_CHRG (1 << 7) +#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ +# define OTG_B_SESS_END (1 << 6) +# define OTG_B_SESS_VLD (1 << 7) + +#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */ +#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */ + +#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */ +#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */ + +/* same bitfields in all interrupt registers */ +# define INTR_VBUS_VLD (1 << 0) +# define INTR_SESS_VLD (1 << 1) +# define INTR_DP_HI (1 << 2) +# define INTR_ID_GND (1 << 3) +# define INTR_DM_HI (1 << 4) +# define INTR_ID_FLOAT (1 << 5) +# define INTR_BDIS_ACON (1 << 6) +# define INTR_CR_INT (1 << 7) + +/*-------------------------------------------------------------------------*/ + +static const char *state_string(enum usb_otg_state state) +{ + switch (state) { + case OTG_STATE_A_IDLE: return "a_idle"; + case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; + case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; + case OTG_STATE_A_HOST: return "a_host"; + case OTG_STATE_A_SUSPEND: return "a_suspend"; + case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; + case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; + case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; + case OTG_STATE_B_IDLE: return "b_idle"; + case OTG_STATE_B_SRP_INIT: return "b_srp_init"; + case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; + case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; + case OTG_STATE_B_HOST: return "b_host"; + default: return "UNDEFINED"; + } +} + +static inline const char *state_name(struct isp1301 *isp) +{ + return state_string(isp->otg.state); +} + +#ifdef VERBOSE +#define dev_vdbg dev_dbg +#else +#define dev_vdbg(dev, fmt, arg...) do{}while(0) +#endif + +/*-------------------------------------------------------------------------*/ + +/* NOTE: some of this ISP1301 setup is specific to H2 boards; + * not everything is guarded by board-specific checks, or even using + * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI. + * + * ALSO: this currently doesn't use ISP1301 low-power modes + * while OTG is running. + */ + +static void power_down(struct isp1301 *isp) +{ + isp->otg.state = OTG_STATE_UNDEFINED; + + // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG); + + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); +} + +static void power_up(struct isp1301 *isp) +{ + // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG); + + /* do this only when cpu is driving transceiver, + * so host won't see a low speed device... + */ + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); +} + +#define NO_HOST_SUSPEND + +static int host_suspend(struct isp1301 *isp) +{ +#ifdef NO_HOST_SUSPEND + return 0; +#else + struct device *dev; + + if (!isp->otg.host) + return -ENODEV; + + /* Currently ASSUMES only the OTG port matters; + * other ports could be active... + */ + dev = isp->otg.host->controller; + return dev->driver->suspend(dev, 3, 0); +#endif +} + +static int host_resume(struct isp1301 *isp) +{ +#ifdef NO_HOST_SUSPEND + return 0; +#else + struct device *dev; + + if (!isp->otg.host) + return -ENODEV; + + dev = isp->otg.host->controller; + return dev->driver->resume(dev, 0); +#endif +} + +static int gadget_suspend(struct isp1301 *isp) +{ + isp->otg.gadget->b_hnp_enable = 0; + isp->otg.gadget->a_hnp_support = 0; + isp->otg.gadget->a_alt_hnp_support = 0; + return usb_gadget_vbus_disconnect(isp->otg.gadget); +} + +/*-------------------------------------------------------------------------*/ + +#define TIMER_MINUTES 10 +#define TIMER_JIFFIES (TIMER_MINUTES * 60 * HZ) + +/* Almost all our I2C messaging comes from a work queue's task context. + * NOTE: guaranteeing certain response times might mean we shouldn't + * share keventd's work queue; a realtime task might be safest. + */ +void +isp1301_defer_work(struct isp1301 *isp, int work) +{ + int status; + + if (isp && !test_and_set_bit(work, &isp->todo)) { + (void) get_device(&isp->client.dev); + status = schedule_work(&isp->work); + if (!status && !isp->working) + dev_vdbg(&isp->client.dev, + "work item %d may be lost\n", work); + } +} + +/* called from irq handlers */ +static void a_idle(struct isp1301 *isp, const char *tag) +{ + if (isp->otg.state == OTG_STATE_A_IDLE) + return; + + isp->otg.default_a = 1; + if (isp->otg.host) { + isp->otg.host->is_b_host = 0; + host_suspend(isp); + } + if (isp->otg.gadget) { + isp->otg.gadget->is_a_peripheral = 1; + gadget_suspend(isp); + } + isp->otg.state = OTG_STATE_A_IDLE; + isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + pr_debug(" --> %s/%s\n", state_name(isp), tag); +} + +/* called from irq handlers */ +static void b_idle(struct isp1301 *isp, const char *tag) +{ + if (isp->otg.state == OTG_STATE_B_IDLE) + return; + + isp->otg.default_a = 0; + if (isp->otg.host) { + isp->otg.host->is_b_host = 1; + host_suspend(isp); + } + if (isp->otg.gadget) { + isp->otg.gadget->is_a_peripheral = 0; + gadget_suspend(isp); + } + isp->otg.state = OTG_STATE_B_IDLE; + isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + pr_debug(" --> %s/%s\n", state_name(isp), tag); +} + +static void +dump_regs(struct isp1301 *isp, const char *label) +{ +#ifdef DEBUG + u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); + u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); + u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); + + pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n", + OTG_CTRL_REG, label, state_name(isp), + ctrl, status, src); + /* mode control and irq enables don't change much */ +#endif +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_OTG + +/* + * The OMAP OTG controller handles most of the OTG state transitions. + * + * We translate isp1301 outputs (mostly voltage comparator status) into + * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state + * flags into isp1301 inputs ... and infer state transitions. + */ + +#ifdef VERBOSE + +static void check_state(struct isp1301 *isp, const char *tag) +{ + enum usb_otg_state state = OTG_STATE_UNDEFINED; + u8 fsm = OTG_TEST_REG & 0x0ff; + unsigned extra = 0; + + switch (fsm) { + + /* default-b */ + case 0x0: + state = OTG_STATE_B_IDLE; + break; + case 0x3: + case 0x7: + extra = 1; + case 0x1: + state = OTG_STATE_B_PERIPHERAL; + break; + case 0x11: + state = OTG_STATE_B_SRP_INIT; + break; + + /* extra dual-role default-b states */ + case 0x12: + case 0x13: + case 0x16: + extra = 1; + case 0x17: + state = OTG_STATE_B_WAIT_ACON; + break; + case 0x34: + state = OTG_STATE_B_HOST; + break; + + /* default-a */ + case 0x36: + state = OTG_STATE_A_IDLE; + break; + case 0x3c: + state = OTG_STATE_A_WAIT_VFALL; + break; + case 0x7d: + state = OTG_STATE_A_VBUS_ERR; + break; + case 0x9e: + case 0x9f: + extra = 1; + case 0x89: + state = OTG_STATE_A_PERIPHERAL; + break; + case 0xb7: + state = OTG_STATE_A_WAIT_VRISE; + break; + case 0xb8: + state = OTG_STATE_A_WAIT_BCON; + break; + case 0xb9: + state = OTG_STATE_A_HOST; + break; + case 0xba: + state = OTG_STATE_A_SUSPEND; + break; + default: + break; + } + if (isp->otg.state == state && !extra) + return; + pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, + state_string(state), fsm, state_name(isp), OTG_CTRL_REG); +} + +#else + +static inline void check_state(struct isp1301 *isp, const char *tag) { } + +#endif + +/* outputs from ISP1301_INTERRUPT_SOURCE */ +static void update_otg1(struct isp1301 *isp, u8 int_src) +{ + u32 otg_ctrl; + + otg_ctrl = OTG_CTRL_REG + & OTG_CTRL_MASK + & ~OTG_XCEIV_INPUTS + & ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD); + if (int_src & INTR_SESS_VLD) + otg_ctrl |= OTG_ASESSVLD; + else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) { + a_idle(isp, "vfall"); + otg_ctrl &= ~OTG_CTRL_BITS; + } + if (int_src & INTR_VBUS_VLD) + otg_ctrl |= OTG_VBUSVLD; + if (int_src & INTR_ID_GND) { /* default-A */ + if (isp->otg.state == OTG_STATE_B_IDLE + || isp->otg.state == OTG_STATE_UNDEFINED) { + a_idle(isp, "init"); + return; + } + } else { /* default-B */ + otg_ctrl |= OTG_ID; + if (isp->otg.state == OTG_STATE_A_IDLE + || isp->otg.state == OTG_STATE_UNDEFINED) { + b_idle(isp, "init"); + return; + } + } + OTG_CTRL_REG = otg_ctrl; +} + +/* outputs from ISP1301_OTG_STATUS */ +static void update_otg2(struct isp1301 *isp, u8 otg_status) +{ + u32 otg_ctrl; + + otg_ctrl = OTG_CTRL_REG + & OTG_CTRL_MASK + & ~OTG_XCEIV_INPUTS + & ~(OTG_BSESSVLD|OTG_BSESSEND); + if (otg_status & OTG_B_SESS_VLD) + otg_ctrl |= OTG_BSESSVLD; + else if (otg_status & OTG_B_SESS_END) + otg_ctrl |= OTG_BSESSEND; + OTG_CTRL_REG = otg_ctrl; +} + +/* inputs going to ISP1301 */ +static void otg_update_isp(struct isp1301 *isp) +{ + u32 otg_ctrl, otg_change; + u8 set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP; + + otg_ctrl = OTG_CTRL_REG; + otg_change = otg_ctrl ^ isp->last_otg_ctrl; + isp->last_otg_ctrl = otg_ctrl; + otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; + + switch (isp->otg.state) { + case OTG_STATE_B_IDLE: + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_SRP_INIT: + if (!(otg_ctrl & OTG_PULLUP)) { + // if (otg_ctrl & OTG_B_HNPEN) { + if (isp->otg.gadget->b_hnp_enable) { + isp->otg.state = OTG_STATE_B_WAIT_ACON; + pr_debug(" --> b_wait_acon\n"); + } + goto pulldown; + } +pullup: + set |= OTG1_DP_PULLUP; + clr |= OTG1_DP_PULLDOWN; + break; + case OTG_STATE_A_SUSPEND: + case OTG_STATE_A_PERIPHERAL: + if (otg_ctrl & OTG_PULLUP) + goto pullup; + /* FALLTHROUGH */ + // case OTG_STATE_B_WAIT_ACON: + default: +pulldown: + set |= OTG1_DP_PULLDOWN; + clr |= OTG1_DP_PULLUP; + break; + } + +# define toggle(OTG,ISP) do { \ + if (otg_ctrl & OTG) set |= ISP; \ + else clr |= ISP; \ + } while (0) + + if (!(isp->otg.host)) + otg_ctrl &= ~OTG_DRV_VBUS; + + switch (isp->otg.state) { + case OTG_STATE_A_SUSPEND: + if (otg_ctrl & OTG_DRV_VBUS) { + set |= OTG1_VBUS_DRV; + break; + } + /* HNP failed for some reason (A_AIDL_BDIS timeout) */ + notresponding(isp); + + /* FALLTHROUGH */ + case OTG_STATE_A_VBUS_ERR: + isp->otg.state = OTG_STATE_A_WAIT_VFALL; + pr_debug(" --> a_wait_vfall\n"); + /* FALLTHROUGH */ + case OTG_STATE_A_WAIT_VFALL: + /* FIXME usbcore thinks port power is still on ... */ + clr |= OTG1_VBUS_DRV; + break; + case OTG_STATE_A_IDLE: + if (otg_ctrl & OTG_DRV_VBUS) { + isp->otg.state = OTG_STATE_A_WAIT_VRISE; + pr_debug(" --> a_wait_vrise\n"); + } + /* FALLTHROUGH */ + default: + toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); + } + + toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG); + toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG); + +# undef toggle + + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr); + + /* HNP switch to host or peripheral; and SRP */ + if (otg_change & OTG_PULLUP) { + switch (isp->otg.state) { + case OTG_STATE_B_IDLE: + if (clr & OTG1_DP_PULLUP) + break; + isp->otg.state = OTG_STATE_B_PERIPHERAL; + pr_debug(" --> b_peripheral\n"); + break; + case OTG_STATE_A_SUSPEND: + if (clr & OTG1_DP_PULLUP) + break; + isp->otg.state = OTG_STATE_A_PERIPHERAL; + pr_debug(" --> a_peripheral\n"); + break; + default: + break; + } + OTG_CTRL_REG |= OTG_PULLUP; + } + + check_state(isp, __FUNCTION__); + dump_regs(isp, "otg->isp1301"); +} + +static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs) +{ + u16 otg_irq = OTG_IRQ_SRC_REG; + u32 otg_ctrl; + int ret = IRQ_NONE; + struct isp1301 *isp = _isp; + + /* update ISP1301 transciever from OTG controller */ + if (otg_irq & OPRT_CHG) { + OTG_IRQ_SRC_REG = OPRT_CHG; + isp1301_defer_work(isp, WORK_UPDATE_ISP); + ret = IRQ_HANDLED; + + /* SRP to become b_peripheral failed */ + } else if (otg_irq & B_SRP_TMROUT) { + pr_debug("otg: B_SRP_TIMEOUT, %06x\n", OTG_CTRL_REG); + notresponding(isp); + + /* gadget drivers that care should monitor all kinds of + * remote wakeup (SRP, normal) using their own timer + * to give "check cable and A-device" messages. + */ + if (isp->otg.state == OTG_STATE_B_SRP_INIT) + b_idle(isp, "srp_timeout"); + + OTG_IRQ_SRC_REG = B_SRP_TMROUT; + ret = IRQ_HANDLED; + + /* HNP to become b_host failed */ + } else if (otg_irq & B_HNP_FAIL) { + pr_debug("otg: %s B_HNP_FAIL, %06x\n", + state_name(isp), OTG_CTRL_REG); + notresponding(isp); + + otg_ctrl = OTG_CTRL_REG; + otg_ctrl |= OTG_BUSDROP; + otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl; + + /* subset of b_peripheral()... */ + isp->otg.state = OTG_STATE_B_PERIPHERAL; + pr_debug(" --> b_peripheral\n"); + + OTG_IRQ_SRC_REG = B_HNP_FAIL; + ret = IRQ_HANDLED; + + /* detect SRP from B-device ... */ + } else if (otg_irq & A_SRP_DETECT) { + pr_debug("otg: %s SRP_DETECT, %06x\n", + state_name(isp), OTG_CTRL_REG); + + isp1301_defer_work(isp, WORK_UPDATE_OTG); + switch (isp->otg.state) { + case OTG_STATE_A_IDLE: + if (!isp->otg.host) + break; + isp1301_defer_work(isp, WORK_HOST_RESUME); + otg_ctrl = OTG_CTRL_REG; + otg_ctrl |= OTG_A_BUSREQ; + otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) + & ~OTG_XCEIV_INPUTS + & OTG_CTRL_MASK; + OTG_CTRL_REG = otg_ctrl; + break; + default: + break; + } + + OTG_IRQ_SRC_REG = A_SRP_DETECT; + ret = IRQ_HANDLED; + + /* timer expired: T(a_wait_bcon) and maybe T(a_wait_vrise) + * we don't track them separately + */ + } else if (otg_irq & A_REQ_TMROUT) { + otg_ctrl = OTG_CTRL_REG; + pr_info("otg: BCON_TMOUT from %s, %06x\n", + state_name(isp), otg_ctrl); + notresponding(isp); + + otg_ctrl |= OTG_BUSDROP; + otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl; + isp->otg.state = OTG_STATE_A_WAIT_VFALL; + + OTG_IRQ_SRC_REG = A_REQ_TMROUT; + ret = IRQ_HANDLED; + + /* A-supplied voltage fell too low; overcurrent */ + } else if (otg_irq & A_VBUS_ERR) { + otg_ctrl = OTG_CTRL_REG; + printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n", + state_name(isp), otg_irq, otg_ctrl); + + otg_ctrl |= OTG_BUSDROP; + otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl; + isp->otg.state = OTG_STATE_A_VBUS_ERR; + + OTG_IRQ_SRC_REG = A_VBUS_ERR; + ret = IRQ_HANDLED; + + /* switch driver; the transciever code activates it, + * ungating the udc clock or resuming OHCI. + */ + } else if (otg_irq & DRIVER_SWITCH) { + int kick = 0; + + otg_ctrl = OTG_CTRL_REG; + printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n", + state_name(isp), + (otg_ctrl & OTG_DRIVER_SEL) + ? "gadget" : "host", + otg_ctrl); + isp1301_defer_work(isp, WORK_UPDATE_ISP); + + /* role is peripheral */ + if (otg_ctrl & OTG_DRIVER_SEL) { + switch (isp->otg.state) { + case OTG_STATE_A_IDLE: + b_idle(isp, __FUNCTION__); + break; + default: + break; + } + isp1301_defer_work(isp, WORK_UPDATE_ISP); + + /* role is host */ + } else { + if (!(otg_ctrl & OTG_ID)) { + otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; + OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ; + } + + if (isp->otg.host) { + switch (isp->otg.state) { + case OTG_STATE_B_WAIT_ACON: + isp->otg.state = OTG_STATE_B_HOST; + pr_debug(" --> b_host\n"); + kick = 1; + break; + case OTG_STATE_A_WAIT_BCON: + isp->otg.state = OTG_STATE_A_HOST; + pr_debug(" --> a_host\n"); + break; + case OTG_STATE_A_PERIPHERAL: + isp->otg.state = OTG_STATE_A_WAIT_BCON; + pr_debug(" --> a_wait_bcon\n"); + break; + default: + break; + } + isp1301_defer_work(isp, WORK_HOST_RESUME); + } + } + + OTG_IRQ_SRC_REG = DRIVER_SWITCH; + ret = IRQ_HANDLED; + + if (kick) + usb_bus_start_enum(isp->otg.host, + isp->otg.host->otg_port); + } + + check_state(isp, __FUNCTION__); + return ret; +} + +static struct platform_device *otg_dev; + +static int otg_init(struct isp1301 *isp) +{ + if (!otg_dev) + return -ENODEV; + + dump_regs(isp, __FUNCTION__); + /* some of these values are board-specific... */ + OTG_SYSCON_2_REG |= OTG_EN + /* for B-device: */ + | SRP_GPDATA /* 9msec Bdev D+ pulse */ + | SRP_GPDVBUS /* discharge after VBUS pulse */ + // | (3 << 24) /* 2msec VBUS pulse */ + /* for A-device: */ + | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */ + | SRP_DPW /* detect 167+ns SRP pulses */ + | SRP_DATA | SRP_VBUS /* accept both kinds of SRP pulse */ + ; + + update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); + update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); + + check_state(isp, __FUNCTION__); + pr_debug("otg: %s, %s %06x\n", + state_name(isp), __FUNCTION__, OTG_CTRL_REG); + + OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG + | B_SRP_TMROUT | B_HNP_FAIL + | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT; + OTG_SYSCON_2_REG |= OTG_EN; + + return 0; +} + +static int otg_probe(struct device *dev) +{ + // struct omap_usb_config *config = dev->platform_data; + + otg_dev = to_platform_device(dev); + return 0; +} + +static int otg_remove(struct device *dev) +{ + otg_dev = 0; + return 0; +} + +struct device_driver omap_otg_driver = { + .name = "omap_otg", + .bus = &platform_bus_type, + .probe = otg_probe, + .remove = otg_remove, +}; + +static int otg_bind(struct isp1301 *isp) +{ + int status; + + if (otg_dev) + return -EBUSY; + + status = driver_register(&omap_otg_driver); + if (status < 0) + return status; + + if (otg_dev) + status = request_irq(otg_dev->resource[1].start, omap_otg_irq, + SA_INTERRUPT, DRIVER_NAME, isp); + else + status = -ENODEV; + + if (status < 0) + driver_unregister(&omap_otg_driver); + return status; +} + +static void otg_unbind(struct isp1301 *isp) +{ + if (!otg_dev) + return; + free_irq(otg_dev->resource[1].start, isp); +} + +#else + +/* OTG controller isn't clocked */ + +#endif /* CONFIG_USB_OTG */ + +/*-------------------------------------------------------------------------*/ + +static void b_peripheral(struct isp1301 *isp) +{ + enable_vbus_draw(isp, 8); + OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + usb_gadget_vbus_connect(isp->otg.gadget); + +#ifdef CONFIG_USB_OTG + otg_update_isp(isp); +#else + /* UDC driver just set OTG_BSESSVLD */ + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); + isp->otg.state = OTG_STATE_B_PERIPHERAL; + pr_debug(" --> b_peripheral\n"); + dump_regs(isp, "2periph"); +#endif +} + +static int isp_update_otg(struct isp1301 *isp, u8 stat) +{ + u8 isp_stat, isp_bstat; + enum usb_otg_state state = isp->otg.state; + + if (stat & INTR_BDIS_ACON) + pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); + + /* start certain state transitions right away */ + isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); + if (isp_stat & INTR_ID_GND) { + if (isp->otg.default_a) { + switch (state) { + case OTG_STATE_B_IDLE: + a_idle(isp, "idle"); + /* FALLTHROUGH */ + case OTG_STATE_A_IDLE: + enable_vbus_source(isp); + /* FALLTHROUGH */ + case OTG_STATE_A_WAIT_VRISE: + /* we skip over OTG_STATE_A_WAIT_BCON, since + * the HC will transition to A_HOST (or + * A_SUSPEND!) without our noticing except + * when HNP is used. + */ + if (isp_stat & INTR_VBUS_VLD) + isp->otg.state = OTG_STATE_A_HOST; + break; + case OTG_STATE_A_WAIT_VFALL: + if (!(isp_stat & INTR_SESS_VLD)) + a_idle(isp, "vfell"); + break; + default: + if (!(isp_stat & INTR_VBUS_VLD)) + isp->otg.state = OTG_STATE_A_VBUS_ERR; + break; + } + isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); + } else { + switch (state) { + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_HOST: + case OTG_STATE_B_WAIT_ACON: + usb_gadget_vbus_disconnect(isp->otg.gadget); + break; + default: + break; + } + if (state != OTG_STATE_A_IDLE) + a_idle(isp, "id"); + if (isp->otg.host && state == OTG_STATE_A_IDLE) + isp1301_defer_work(isp, WORK_HOST_RESUME); + isp_bstat = 0; + } + } else { + /* if user unplugged mini-A end of cable, + * don't bypass A_WAIT_VFALL. + */ + if (isp->otg.default_a) { + switch (state) { + default: + isp->otg.state = OTG_STATE_A_WAIT_VFALL; + break; + case OTG_STATE_A_WAIT_VFALL: + state = OTG_STATE_A_IDLE; + /* khubd may take a while to notice and + * handle this disconnect, so don't go + * to B_IDLE quite yet. + */ + break; + case OTG_STATE_A_IDLE: + host_suspend(isp); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, + MC1_BDIS_ACON_EN); + isp->otg.state = OTG_STATE_B_IDLE; + OTG_CTRL_REG &= OTG_CTRL_REG & OTG_CTRL_MASK + & ~OTG_CTRL_BITS; + break; + case OTG_STATE_B_IDLE: + break; + } + } + isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); + + switch (isp->otg.state) { + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_WAIT_ACON: + case OTG_STATE_B_HOST: + if (likely(isp_bstat & OTG_B_SESS_VLD)) + break; + enable_vbus_draw(isp, 0); +#ifndef CONFIG_USB_OTG + /* UDC driver will clear OTG_BSESSVLD */ + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, + OTG1_DP_PULLDOWN); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, + OTG1_DP_PULLUP); + dump_regs(isp, __FUNCTION__); +#endif + /* FALLTHROUGH */ + case OTG_STATE_B_SRP_INIT: + b_idle(isp, __FUNCTION__); + OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; + /* FALLTHROUGH */ + case OTG_STATE_B_IDLE: + if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) { +#ifdef CONFIG_USB_OTG + update_otg1(isp, isp_stat); + update_otg2(isp, isp_bstat); +#endif + b_peripheral(isp); + } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD))) + isp_bstat |= OTG_B_SESS_END; + break; + case OTG_STATE_A_WAIT_VFALL: + break; + default: + pr_debug("otg: unsupported b-device %s\n", + state_name(isp)); + break; + } + } + + if (state != isp->otg.state) + pr_debug(" isp, %s -> %s\n", + state_string(state), state_name(isp)); + +#ifdef CONFIG_USB_OTG + /* update the OTG controller state to match the isp1301; may + * trigger OPRT_CHG irqs for changes going to the isp1301. + */ + update_otg1(isp, isp_stat); + update_otg2(isp, isp_bstat); + check_state(isp, __FUNCTION__); +#endif + + dump_regs(isp, "isp1301->otg"); +} + +/*-------------------------------------------------------------------------*/ + +static u8 isp1301_clear_latch(struct isp1301 *isp) +{ + u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch); + return latch; +} + +static void +isp1301_work(void *data) +{ + struct isp1301 *isp = data; + int stop; + + /* implicit lock: we're the only task using this device */ + isp->working = 1; + do { + stop = test_bit(WORK_STOP, &isp->todo); + +#ifdef CONFIG_USB_OTG + /* transfer state from otg engine to isp1301 */ + if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) { + otg_update_isp(isp); + put_device(&isp->client.dev); + } +#endif + /* transfer state from isp1301 to otg engine */ + if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) { + u8 stat = isp1301_clear_latch(isp); + + isp_update_otg(isp, stat); + put_device(&isp->client.dev); + } + + if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) { + u32 otg_ctrl; + + /* + * skip A_WAIT_VRISE; hc transitions invisibly + * skip A_WAIT_BCON; same. + */ + switch (isp->otg.state) { + case OTG_STATE_A_WAIT_BCON: + case OTG_STATE_A_WAIT_VRISE: + isp->otg.state = OTG_STATE_A_HOST; + pr_debug(" --> a_host\n"); + otg_ctrl = OTG_CTRL_REG; + otg_ctrl |= OTG_A_BUSREQ; + otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) + & OTG_CTRL_MASK; + OTG_CTRL_REG = otg_ctrl; + break; + case OTG_STATE_B_WAIT_ACON: + isp->otg.state = OTG_STATE_B_HOST; + pr_debug(" --> b_host (acon)\n"); + break; + case OTG_STATE_B_HOST: + case OTG_STATE_B_IDLE: + case OTG_STATE_A_IDLE: + break; + default: + pr_debug(" host resume in %s\n", + state_name(isp)); + } + host_resume(isp); + // mdelay(10); + put_device(&isp->client.dev); + } + + if (test_and_clear_bit(WORK_TIMER, &isp->todo)) { +#ifdef VERBOSE + dump_regs(isp, "timer"); + if (!stop) + mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); +#endif + put_device(&isp->client.dev); + } + + if (isp->todo) + dev_vdbg(&isp->client.dev, + "work done, todo = 0x%lx\n", + isp->todo); + if (stop) { + dev_dbg(&isp->client.dev, "stop\n"); + break; + } + } while (isp->todo); + isp->working = 0; +} + +static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs) +{ + isp1301_defer_work(isp, WORK_UPDATE_OTG); + return IRQ_HANDLED; +} + +static void isp1301_timer(unsigned long _isp) +{ + isp1301_defer_work((void *)_isp, WORK_TIMER); +} + +/*-------------------------------------------------------------------------*/ + +static void isp1301_release(struct device *dev) +{ + struct isp1301 *isp; + + isp = container_of(dev, struct isp1301, client.dev); + + /* ugly -- i2c hijacks our memory hook to wait_for_completion() */ + if (isp->i2c_release) + isp->i2c_release(dev); + kfree (isp); +} + +static struct isp1301 *the_transceiver; + +static int isp1301_detach_client(struct i2c_client *i2c) +{ + struct isp1301 *isp; + + isp = container_of(i2c, struct isp1301, client); + + isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); + free_irq(isp->irq, isp); +#ifdef CONFIG_USB_OTG + otg_unbind(isp); +#endif + if (machine_is_omap_h2()) + omap_free_gpio(2); + + isp->timer.data = 0; + set_bit(WORK_STOP, &isp->todo); + del_timer_sync(&isp->timer); + flush_scheduled_work(); + + put_device(&i2c->dev); + the_transceiver = 0; + + return i2c_detach_client(i2c); +} + +/*-------------------------------------------------------------------------*/ + +/* NOTE: three modes are possible here, only one of which + * will be standards-conformant on any given system: + * + * - OTG mode (dual-role), required if there's a Mini-AB connector + * - HOST mode, for when there's one or more A (host) connectors + * - DEVICE mode, for when there's a B/Mini-B (device) connector + * + * As a rule, you won't have an isp1301 chip unless it's there to + * support the OTG mode. Other modes help testing USB controllers + * in isolation from (full) OTG support, or maybe so later board + * revisions can help to support those feature. + */ + +#ifdef CONFIG_USB_OTG + +static int isp1301_otg_enable(struct isp1301 *isp) +{ + power_up(isp); + otg_init(isp); + + /* NOTE: since we don't change this, this provides + * a few more interrupts than are strictly needed. + */ + isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, + INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); + isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, + INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); + + dev_info(&isp->client.dev, "ready for dual-role USB ...\n"); + + return 0; +} + +#endif + +/* add or disable the host device+driver */ +static int +isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + struct isp1301 *isp = container_of(otg, struct isp1301, otg); + + if (!otg || isp != the_transceiver) + return -ENODEV; + + if (!host) { + OTG_IRQ_EN_REG = 0; + power_down(isp); + isp->otg.host = 0; + return 0; + } + +#ifdef CONFIG_USB_OTG + isp->otg.host = host; + dev_dbg(&isp->client.dev, "registered host\n"); + host_suspend(isp); + if (isp->otg.gadget) + return isp1301_otg_enable(isp); + return 0; + +#elif !defined(CONFIG_USB_GADGET_OMAP) + // FIXME update its refcount + isp->otg.host = host; + + power_up(isp); + + if (machine_is_omap_h2()) + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); + + dev_info(&isp->client.dev, "A-Host sessions ok\n"); + isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, + INTR_ID_GND); + isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, + INTR_ID_GND); + + /* If this has a Mini-AB connector, this mode is highly + * nonstandard ... but can be handy for testing, especially with + * the Mini-A end of an OTG cable. (Or something nonstandard + * like MiniB-to-StandardB, maybe built with a gender mender.) + */ + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); + + dump_regs(isp, __FUNCTION__); + + return 0; + +#else + dev_dbg(&isp->client.dev, "host sessions not allowed\n"); + return -EINVAL; +#endif + +} + +static int +isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) +{ + struct isp1301 *isp = container_of(otg, struct isp1301, otg); + + if (!otg || isp != the_transceiver) + return -ENODEV; + + if (!gadget) { + OTG_IRQ_EN_REG = 0; + if (!isp->otg.default_a) + enable_vbus_draw(isp, 0); + usb_gadget_vbus_disconnect(isp->otg.gadget); + isp->otg.gadget = 0; + power_down(isp); + return 0; + } + +#ifdef CONFIG_USB_OTG + isp->otg.gadget = gadget; + dev_dbg(&isp->client.dev, "registered gadget\n"); + /* gadget driver may be suspended until vbus_connect () */ + if (isp->otg.host) + return isp1301_otg_enable(isp); + return 0; + +#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE) + isp->otg.gadget = gadget; + // FIXME update its refcount + + OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK + & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS)) + | OTG_ID; + power_up(isp); + isp->otg.state = OTG_STATE_B_IDLE; + + if (machine_is_omap_h2()) + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); + + isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, + INTR_SESS_VLD); + isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, + INTR_VBUS_VLD); + dev_info(&isp->client.dev, "B-Peripheral sessions ok\n"); + dump_regs(isp, __FUNCTION__); + + /* If this has a Mini-AB connector, this mode is highly + * nonstandard ... but can be handy for testing, so long + * as you don't plug a Mini-A cable into the jack. + */ + if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD) + b_peripheral(isp); + + return 0; + +#else + dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n"); + return -EINVAL; +#endif +} + + +/*-------------------------------------------------------------------------*/ + +static int +isp1301_set_power(struct otg_transceiver *dev, unsigned mA) +{ + if (!the_transceiver) + return -ENODEV; + if (dev->state == OTG_STATE_B_PERIPHERAL) + enable_vbus_draw(the_transceiver, mA); + return 0; +} + +static int +isp1301_start_srp(struct otg_transceiver *dev) +{ + struct isp1301 *isp = container_of(dev, struct isp1301, otg); + u32 otg_ctrl; + + if (!dev || isp != the_transceiver + || isp->otg.state != OTG_STATE_B_IDLE) + return -ENODEV; + + otg_ctrl = OTG_CTRL_REG; + if (!(otg_ctrl & OTG_BSESSEND)) + return -EINVAL; + + otg_ctrl |= OTG_B_BUSREQ; + otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; + OTG_CTRL_REG = otg_ctrl; + isp->otg.state = OTG_STATE_B_SRP_INIT; + + pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG); +#ifdef CONFIG_USB_OTG + check_state(isp, __FUNCTION__); +#endif + return 0; +} + +static int +isp1301_start_hnp(struct otg_transceiver *dev) +{ +#ifdef CONFIG_USB_OTG + struct isp1301 *isp = container_of(dev, struct isp1301, otg); + + if (!dev || isp != the_transceiver) + return -ENODEV; + if (isp->otg.default_a && (isp->otg.host == NULL + || !isp->otg.host->b_hnp_enable)) + return -ENOTCONN; + if (!isp->otg.default_a && (isp->otg.gadget == NULL + || !isp->otg.gadget->b_hnp_enable)) + return -ENOTCONN; + + /* We want hardware to manage most HNP protocol timings. + * So do this part as early as possible... + */ + switch (isp->otg.state) { + case OTG_STATE_B_HOST: + isp->otg.state = OTG_STATE_B_PERIPHERAL; + /* caller will suspend next */ + break; + case OTG_STATE_A_HOST: +#if 0 + /* autoconnect mode avoids irq latency bugs */ + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, + MC1_BDIS_ACON_EN); +#endif + /* caller must suspend then clear A_BUSREQ */ + usb_gadget_vbus_connect(isp->otg.gadget); + OTG_CTRL_REG |= OTG_A_SETB_HNPEN; + + break; + case OTG_STATE_A_PERIPHERAL: + /* initiated by B-Host suspend */ + break; + default: + return -EILSEQ; + } + pr_debug("otg: HNP %s, %06x ...\n", + state_name(isp), OTG_CTRL_REG); + check_state(isp, __FUNCTION__); + return 0; +#else + /* srp-only */ + return -EINVAL; +#endif +} + +/*-------------------------------------------------------------------------*/ + +/* no error returns, they'd just make bus scanning stop */ +static int isp1301_probe(struct i2c_adapter *bus, int address, int kind) +{ + int status; + struct isp1301 *isp; + struct i2c_client *i2c; + + if (the_transceiver) + return 0; + + isp = kmalloc(sizeof *isp, GFP_KERNEL); + if (!isp) + return 0; + + memset(isp, 0, sizeof *isp); + + INIT_WORK(&isp->work, isp1301_work, isp); + init_timer(&isp->timer); + isp->timer.function = isp1301_timer; + isp->timer.data = (unsigned long) isp; + + isp->irq = -1; + isp->client.addr = address; + i2c_set_clientdata(&isp->client, isp); + isp->client.adapter = bus; + isp->client.id = 1301; + isp->client.driver = &isp1301_driver; + strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE); + i2c = &isp->client; + + /* if this is a true probe, verify the chip ... */ + if (kind < 0) { + status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); + if (status != I2C_VENDOR_ID_PHILIPS) { + dev_dbg(&bus->dev, "addr %d not philips id: %d\n", + address, status); + goto fail1; + } + status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID); + if (status != I2C_PRODUCT_ID_PHILIPS_1301) { + dev_dbg(&bus->dev, "%d not isp1301, %d\n", + address, status); + goto fail1; + } + } + + status = i2c_attach_client(i2c); + if (status < 0) { + dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", + DRIVER_NAME, address, status); +fail1: + kfree(isp); + return 0; + } + isp->i2c_release = i2c->dev.release; + i2c->dev.release = isp1301_release; + + /* initial development used chiprev 2.00 */ + status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE); + dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n", + status >> 8, status & 0xff); + + /* make like power-on reset */ + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK); + + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI); + isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI); + + isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, + OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); + isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, + ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); + + isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); + isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); + +#ifdef CONFIG_USB_OTG + status = otg_bind(isp); + if (status < 0) { + dev_dbg(&i2c->dev, "can't bind OTG\n"); + goto fail2; + } +#endif + + if (machine_is_omap_h2()) { + /* full speed signaling by default */ + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, + MC1_SPEED_REG); + isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, + MC2_SPD_SUSP_CTRL); + + /* IRQ wired at M14 */ + omap_cfg_reg(M14_1510_GPIO2); + isp->irq = OMAP_GPIO_IRQ(2); + omap_request_gpio(2); + omap_set_gpio_direction(2, 1); + omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE); + } + + status = request_irq(isp->irq, isp1301_irq, + SA_SAMPLE_RANDOM, DRIVER_NAME, isp); + if (status < 0) { + dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n", + isp->irq, status); +#ifdef CONFIG_USB_OTG +fail2: +#endif + i2c_detach_client(i2c); + goto fail1; + } + + isp->otg.dev = &isp->client.dev; + isp->otg.label = DRIVER_NAME; + + isp->otg.set_host = isp1301_set_host, + isp->otg.set_peripheral = isp1301_set_peripheral, + isp->otg.set_power = isp1301_set_power, + isp->otg.start_srp = isp1301_start_srp, + isp->otg.start_hnp = isp1301_start_hnp, + + enable_vbus_draw(isp, 0); + power_down(isp); + the_transceiver = isp; + +#ifdef CONFIG_USB_OTG + update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); + update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); +#endif + + dump_regs(isp, __FUNCTION__); + +#ifdef VERBOSE + mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); + dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); +#endif + + status = otg_set_transceiver(&isp->otg); + if (status < 0) + dev_err(&i2c->dev, "can't register transceiver, %d\n", + status); + + return 0; +} + +static int isp1301_scan_bus(struct i2c_adapter *bus) +{ + if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -EINVAL; + return i2c_probe(bus, &addr_data, isp1301_probe); +} + +static struct i2c_driver isp1301_driver = { + .owner = THIS_MODULE, + .name = "isp1301_omap", + .id = 1301, /* FIXME "official", i2c-ids.h */ + .class = I2C_CLASS_HWMON, + .flags = I2C_DF_NOTIFY, + .attach_adapter = isp1301_scan_bus, + .detach_client = isp1301_detach_client, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init isp_init(void) +{ + return i2c_add_driver(&isp1301_driver); +} +module_init(isp_init); + +static void __exit isp_exit(void) +{ + if (the_transceiver) + otg_set_transceiver(0); + i2c_del_driver(&isp1301_driver); +} +module_exit(isp_exit); + diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index ef6562987..c7c068b82 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -47,7 +48,7 @@ static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_1(it87); +SENSORS_INSMOD_2(it87, it8712); #define REG 0x2e /* The register to read/write */ #define DEV 0x07 /* Register: Logical device select */ @@ -163,8 +164,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) ((val)+500)/1000),-128,127)) #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) #define ALARMS_FROM_REG(val) (val) static int DIV_TO_REG(int val) @@ -201,6 +200,7 @@ struct it87_data { u8 sensor; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ + int vrm; u32 alarms; /* Register encoding, combined */ }; @@ -543,6 +543,38 @@ static ssize_t show_alarms(struct device *dev, char *buf) } static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL); +static ssize_t +show_vrm_reg(struct device *dev, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} +static ssize_t +store_vrm_reg(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm) + +static ssize_t +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(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +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 available adapter @@ -659,7 +691,11 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) if (kind <= 0) { i = it87_read_value(new_client, IT87_REG_CHIPID); if (i == 0x90) { + u16 val; kind = it87; + val = (superio_inb(DEVID) << 8) | + superio_inb(DEVID + 1); + if (val == IT8712F_DEVID) kind = it8712; } else { if (kind == 0) @@ -674,6 +710,8 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) if (kind == it87) { name = "it87"; + } else if (kind == it8712) { + name = "it8712"; } /* Fill in the remaining client fields and put it into the global list */ @@ -741,6 +779,12 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_fan3_div); device_create_file(&new_client->dev, &dev_attr_alarms); + if (data->type == it8712) { + device_create_file_vrm(new_client); + device_create_file_vid(new_client); + data->vrm = i2c_which_vrm(); + } + return 0; ERROR2: @@ -910,7 +954,11 @@ static struct it87_data *it87_update_device(struct device *dev) (it87_read_value(client, IT87_REG_ALARM3) << 16); data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); - + /* The 8705 does not have VID capability */ + if (data->type == it8712) { + data->vid = it87_read_value(client, IT87_REG_VID); + data->vid &= 0x1f; + } data->last_updated = jiffies; data->valid = 1; } @@ -938,9 +986,9 @@ static void __exit sm_it87_exit(void) MODULE_AUTHOR("Chris Gauthron "); MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); -MODULE_PARM(update_vbat, "i"); +module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); -MODULE_PARM(reset, "i"); +module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Reset the chip's registers, default no"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 40385ffd8..b3cab5fa9 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/lm83.c b/drivers/i2c/chips/lm83.c index f6023e989..7e4cb6bd7 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -83,8 +83,10 @@ SENSORS_INSMOD_1(lm83); * The LM83 uses signed 8-bit values. */ -#define TEMP_FROM_REG(val) ((val > 127 ? val-256 : val) * 1000) -#define TEMP_TO_REG(val) ((val < 0 ? val+256 : val) / 1000) +#define TEMP_FROM_REG(val) (((val) > 127 ? (val) - 0x100 : (val)) * 1000) +#define TEMP_TO_REG(val) ((val) <= -50000 ? -50 + 0x100 : (val) >= 127000 ? 127 : \ + (val) > -500 ? ((val)+500) / 1000 : \ + ((val)-500) / 1000 + 0x100) static const u8 LM83_REG_R_TEMP[] = { LM83_REG_R_LOCAL_TEMP, @@ -178,7 +180,7 @@ static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm83_data *data = i2c_get_clientdata(client); \ - data->value = TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ + data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \ i2c_smbus_write_byte_data(client, reg, data->value); \ return count; \ } @@ -206,8 +208,11 @@ static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3, set_temp_high3); static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4, set_temp_high4); -static DEVICE_ATTR(temp_crit, S_IWUSR | S_IRUGO, show_temp_crit, +static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL); +static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL); +static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit, set_temp_crit); +static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -259,6 +264,11 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) * means that the driver was loaded with the force parameter and a * given kind of chip is requested, so both the detection and the * identification steps are skipped. */ + + /* Default to an LM83 if forced */ + if (kind == 0) + kind = lm83; + if (kind < 0) { /* detection */ if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) & 0xA8) != 0x00) || @@ -322,7 +332,10 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) 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_temp4_max); - device_create_file(&new_client->dev, &dev_attr_temp_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + device_create_file(&new_client->dev, &dev_attr_temp4_crit); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index 11f850431..757520f75 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -308,9 +308,6 @@ static int ZONE_TO_REG( int zone ) * version of the driver. */ -/* Typically used with Pentium 4 systems v9.1 VRM spec */ -#define LM85_INIT_VRM 91 - /* Chip sampling rates * * Some sensors are not updated more frequently than once per second @@ -468,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) { @@ -832,7 +829,7 @@ int lm85_detect(struct i2c_adapter *adapter, int address, goto ERROR1; /* Set the VRM version */ - data->vrm = LM85_INIT_VRM ; + data->vrm = i2c_which_vrm(); /* Initialize the LM85 chip */ lm85_init_client(new_client); @@ -877,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/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 87ad9b973..d63e06d37 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -36,7 +36,7 @@ static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; SENSORS_INSMOD_1(pcf8591); static int input_mode; -MODULE_PARM(input_mode, "i"); +module_param(input_mode, int, 0); MODULE_PARM_DESC(input_mode, "Analog input mode:\n" " 0 = four single ended inputs\n" diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 0fa55d45e..acfd3f804 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -56,8 +56,8 @@ static inline u8 _rtc8564_ctrl2(struct i2c_client *client) #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) #define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) -static int debug = 0; -MODULE_PARM(debug, "i"); +static int debug;; +module_param(debug, int, S_IRUGO | S_IWUSR); static struct i2c_driver rtc8564_driver; diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c new file mode 100644 index 000000000..078c65fe3 --- /dev/null +++ b/drivers/i2c/chips/smsc47m1.c @@ -0,0 +1,579 @@ +/* + smsc47m1.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x + Super-I/O chips. + + Copyright (C) 2002 Mark D. Studebaker + Copyright (C) 2004 Jean Delvare + Ported to Linux 2.6 by Gabriele Gorla + and Jean Delvare + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +/* Address is autodetected, there is no default value */ +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{NULL}}; + +enum chips { any_chip, smsc47m1 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_i2c_range = normal_i2c_range, + .normal_isa = normal_isa, + .normal_isa_range = normal_isa_range, + .probe = normal_i2c, /* cheat */ + .probe_range = normal_i2c_range, /* cheat */ + .ignore = normal_i2c, /* cheat */ + .ignore_range = normal_i2c_range, /* cheat */ + .forces = forces, +}; + +/* Super-I/0 registers and commands */ + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +/* logical device for fans is 0x0A */ +#define superio_select() superio_outb(0x07, 0x0A) + +static inline void +superio_enter(void) +{ + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xAA, REG); +} + +#define SUPERIO_REG_ACT 0x30 +#define SUPERIO_REG_BASE 0x60 +#define SUPERIO_REG_DEVID 0x20 + +/* Logical device registers */ + +#define SMSC_EXTENT 0x80 + +/* nr is 0 or 1 in the macros below */ +#define SMSC47M1_REG_ALARM 0x04 +#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) +#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) +#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) +#define SMSC47M1_REG_FANDIV 0x58 +#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) +#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) + +#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ + 983040/((192-(reg))*(div))) +#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ + 983040/(((reg)-(preload))*(div))) +#define DIV_FROM_REG(reg) (1 << (reg)) +#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) +#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) +#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) + +struct smsc47m1_data { + struct i2c_client client; + struct semaphore lock; + int sysctl_id; + + struct semaphore update_lock; + unsigned long last_updated; /* In jiffies */ + + u8 fan[2]; /* Register value */ + u8 fan_preload[2]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u8 alarms; /* Register encoding */ + u8 pwm[2]; /* Register value (bit 7 is enable) */ +}; + + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); +static int smsc47m1_find(int *address); +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind); +static int smsc47m1_detach_client(struct i2c_client *client); + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg); +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init); + + +static int smsc47m1_id; + +static struct i2c_driver smsc47m1_driver = { + .owner = THIS_MODULE, + .name = "smsc47m1", + .id = I2C_DRIVERID_SMSC47M1, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47m1_attach_adapter, + .detach_client = smsc47m1_detach_client, +}; + +/* nr is 0 or 1 in the callback functions below */ + +static ssize_t get_fan(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + /* This chip (stupidly) stops monitoring fan speed if PWM is + enabled and duty cycle is 0%. This is fine if the monitoring + and control concern the same fan, but troublesome if they are + not (which could as well happen). */ + int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : + FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]), + data->fan_preload[nr]); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_min(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + int rpm = MIN_FROM_REG(data->fan_preload[nr], + DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_div(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t get_fan_pwm(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_fan_pwm_en(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_alarms(struct device *dev, char *buf) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long rpmdiv = simple_strtol(buf, NULL, 10) + * DIV_FROM_REG(data->fan_div[nr]); + + if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) + return -EINVAL; + + data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + + return count; +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan clock divider. This follows the principle + of least suprise; the user doesn't expect the fan minimum to change just + because the divider changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long new_div = simple_strtol(buf, NULL, 10), tmp; + u8 old_div = DIV_FROM_REG(data->fan_div[nr]); + + if (new_div == old_div) /* No change */ + return count; + switch (new_div) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: return -EINVAL; + } + + tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; + tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); + smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); + + /* Preserve fan min */ + tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + + new_div / 2) / new_div; + data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + + return count; +} + +static ssize_t set_fan_pwm(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val < 0 || val > 255) + return -EINVAL; + + data->pwm[nr] &= 0x81; /* Preserve additional bits */ + data->pwm[nr] |= PWM_TO_REG(val); + + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + return count; +} + +static ssize_t set_fan_pwm_en(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val != 0 && val != 1) + return -EINVAL; + + data->pwm[nr] &= 0xFE; /* preserve the other bits */ + data->pwm[nr] |= !val; + + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + + return count; +} + +#define fan_present(offset) \ +static ssize_t get_fan##offset (struct device *dev, char *buf) \ +{ \ + return get_fan(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_min (struct device *dev, char *buf) \ +{ \ + return get_fan_min(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_div (struct device *dev, char *buf) \ +{ \ + return get_fan_div(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_div (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_pwm (struct device *dev, char *buf) \ +{ \ + return get_fan_pwm(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_pwm (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_pwm(dev, buf, count, 0x##offset - 1); \ +} \ +static ssize_t get_fan##offset##_pwm_en (struct device *dev, char *buf) \ +{ \ + return get_fan_pwm_en(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan##offset##_pwm_en (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_pwm_en(dev, buf, count, 0x##offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + get_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + get_fan##offset##_div, set_fan##offset##_div); \ +static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \ + get_fan##offset##_pwm, set_fan##offset##_pwm); \ +static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, \ + get_fan##offset##_pwm_en, set_fan##offset##_pwm_en); + +fan_present(1); +fan_present(2); + +static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, smsc47m1_detect); +} + +static int smsc47m1_find(int *address) +{ + u8 val; + + superio_enter(); + val = superio_inb(SUPERIO_REG_DEVID); + + /* + * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id + * 0x5F) and LPC47B27x (device id 0x51) have fan control. + * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" + * can do much more besides (device id 0x60, unsupported). + */ + if (val == 0x51) + printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n"); + else if (val == 0x59) + printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n"); + else if (val == 0x5F) + printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n"); + else { + superio_exit(); + return -ENODEV; + } + + superio_select(); + *address = (superio_inb(SUPERIO_REG_BASE) << 8) + | superio_inb(SUPERIO_REG_BASE + 1); + val = superio_inb(SUPERIO_REG_ACT); + if (*address == 0 || (val & 0x01) == 0) { + printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); + superio_exit(); + return -ENODEV; + } + + superio_exit(); + return 0; +} + +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct smsc47m1_data *data; + int err = 0; + + if (!i2c_is_isa_adapter(adapter)) { + return 0; + } + + if (!request_region(address, SMSC_EXTENT, "smsc47m1")) { + dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); + return -EBUSY; + } + + if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error_release; + } + memset(data, 0x00, sizeof(struct smsc47m1_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &smsc47m1_driver; + new_client->flags = 0; + + strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); + + new_client->id = smsc47m1_id++; + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto error_free; + + /* Some values (fan min, clock dividers, pwm registers) may be + needed before any update is triggered, so we better read them + at least once here. We don't usually do it that way, but in + this particular case, manually reading 5 registers out of 8 + doesn't make much sense and we're better using the existing + function. */ + smsc47m1_update_device(&new_client->dev, 1); + + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) + == 0x05) { + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + } else + dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " + "skipping\n"); + + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) + == 0x05) { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + } else + dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " + "skipping\n"); + + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) + == 0x04) { + device_create_file(&new_client->dev, &dev_attr_fan1_pwm); + device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable); + } else + dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " + "skipping\n"); + if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) + == 0x04) { + device_create_file(&new_client->dev, &dev_attr_fan2_pwm); + device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable); + } else + dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " + "skipping\n"); + + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error_free: + kfree(new_client); +error_release: + release_region(address, SMSC_EXTENT); + return err; +} + +static int smsc47m1_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + release_region(client->addr, SMSC_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + res = inb_p(client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + return res; +} + +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + outb_p(value, client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); +} + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || init) { + int i; + + for (i = 0; i < 2; i++) { + data->fan[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN(i)); + data->fan_preload[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN_PRELOAD(i)); + data->pwm[i] = smsc47m1_read_value(client, + SMSC47M1_REG_PWM(i)); + } + + i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + + data->alarms = smsc47m1_read_value(client, + SMSC47M1_REG_ALARM) >> 6; + /* Clear alarms if needed */ + if (data->alarms) + smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); + + data->last_updated = jiffies; + } + + up(&data->update_lock); + return data; +} + +static int __init sm_smsc47m1_init(void) +{ + if (smsc47m1_find(normal_isa)) { + return -ENODEV; + } + + return i2c_add_driver(&smsc47m1_driver); +} + +static void __exit sm_smsc47m1_exit(void) +{ + i2c_del_driver(&smsc47m1_driver); +} + +MODULE_AUTHOR("Mark D. Studebaker "); +MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_smsc47m1_init); +module_exit(sm_smsc47m1_exit); diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 3aa334583..851c5b260 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -43,8 +43,8 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); +static unsigned short force_addr = 0; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors"); diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 5d1a31bcb..5c3ade5b6 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -46,12 +46,12 @@ #include #include "lm75.h" -static int force_addr; -MODULE_PARM(force_addr, "i"); +static u16 force_addr; +module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors"); -static int force_i2c = 0x1f; -MODULE_PARM(force_i2c, "i"); +static u8 force_i2c = 0x1f; +module_param(force_i2c, byte, 0); MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors"); @@ -65,7 +65,7 @@ static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf); static int init = 1; -MODULE_PARM(init, "i"); +module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); /* modified from kernel/include/traps.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) @@ -1281,7 +1281,7 @@ static void w83627hf_init_client(struct i2c_client *client) data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; } else { /* Convert VID to voltage based on default VRM */ - data->vrm = DEFAULT_VRM; + data->vrm = i2c_which_vrm(); } tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 785203d39..063d34a0d 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -60,7 +60,7 @@ I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); static int init = 1; -MODULE_PARM(init, "i"); +module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); /* Constants specified below */ @@ -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) { @@ -815,8 +815,7 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) data->sens[nr - 1] = val; break; default: - dev_err(&client->dev, - "Invalid sensor type %ld; must be 1, 2, or %d\n", + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", (long) val, W83781D_DEFAULT_BETA); break; } @@ -1513,7 +1512,7 @@ w83781d_init_client(struct i2c_client *client) w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); } - data->vrm = 82; + data->vrm = i2c_which_vrm(); if ((type != w83781d) && (type != as99127f)) { tmp = w83781d_read_value(client, W83781D_REG_SCFG1); @@ -1593,7 +1592,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) if (time_after (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2)) || time_before(jiffies, data->last_updated) || !data->valid) { - pr_debug("Starting device update\n"); + dev_dbg(dev, "Starting device update\n"); for (i = 0; i <= 8; i++) { if ((data->type == w83783s || data->type == w83697hf) diff --git a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c new file mode 100644 index 000000000..70e82f23e --- /dev/null +++ b/drivers/i2c/i2c-sensor-detect.c @@ -0,0 +1,169 @@ +/* + i2c-sensor-detect.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2001 Frodo Looijaard and + Mark D. Studebaker + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ +int i2c_detect(struct i2c_adapter *adapter, + struct i2c_address_data *address_data, + int (*found_proc) (struct i2c_adapter *, int, int)) +{ + int addr, i, found, j, err; + struct i2c_force_data *this_force; + int is_isa = i2c_is_isa_adapter(adapter); + int adapter_id = + is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter); + + /* Forget it if we can't probe using SMBUS_QUICK */ + if ((!is_isa) && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) + return -1; + + for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { + if (!is_isa && i2c_check_addr(adapter, addr)) + continue; + + /* If it is in one of the force entries, we don't do any + detection at all */ + found = 0; + for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) { + for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) { + if ( ((adapter_id == this_force->force[j]) || + ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) && + (addr == this_force->force[j + 1]) ) { + dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr); + if ((err = found_proc(adapter, addr, this_force->kind))) + return err; + found = 1; + } + } + } + if (found) + continue; + + /* If this address is in one of the ignores, we can forget about it + right now */ + for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) { + if ( ((adapter_id == address_data->ignore[i]) || + ((address_data->ignore[i] == ANY_I2C_BUS) && + !is_isa)) && + (addr == address_data->ignore[i + 1])) { + dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) { + if ( ((adapter_id == address_data->ignore_range[i]) || + ((address_data-> ignore_range[i] == ANY_I2C_BUS) & + !is_isa)) && + (addr >= address_data->ignore_range[i + 1]) && + (addr <= address_data->ignore_range[i + 2])) { + dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + if (found) + continue; + + /* Now, we will do a detection, but only if it is in the normal or + probe entries */ + if (is_isa) { + for (i = 0; !found && (address_data->normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) { + if (addr == address_data->normal_isa[i]) { + dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->normal_isa_range[i] != I2C_CLIENT_ISA_END); i += 3) { + if ((addr >= address_data->normal_isa_range[i]) && + (addr <= address_data->normal_isa_range[i + 1]) && + ((addr - address_data->normal_isa_range[i]) % address_data->normal_isa_range[i + 2] == 0)) { + dev_dbg(&adapter->dev, "found normal isa_range entry for adapter %d, addr %04x", adapter_id, addr); + found = 1; + } + } + } else { + for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) { + if (addr == address_data->normal_i2c[i]) { + found = 1; + dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x", adapter_id, addr); + } + } + for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) { + if ((addr >= address_data->normal_i2c_range[i]) && + (addr <= address_data->normal_i2c_range[i + 1])) { + dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + } + + for (i = 0; + !found && (address_data->probe[i] != I2C_CLIENT_END); + i += 2) { + if (((adapter_id == address_data->probe[i]) || + ((address_data-> + probe[i] == ANY_I2C_BUS) && !is_isa)) + && (addr == address_data->probe[i + 1])) { + dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) { + if ( ((adapter_id == address_data->probe_range[i]) || + ((address_data->probe_range[i] == ANY_I2C_BUS) && !is_isa)) && + (addr >= address_data->probe_range[i + 1]) && + (addr <= address_data->probe_range[i + 2])) { + found = 1; + dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, addr %04x\n", adapter_id, addr); + } + } + if (!found) + continue; + + /* OK, so we really should examine this address. First check + whether there is some client here at all! */ + if (is_isa || + (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) + if ((err = found_proc(adapter, addr, -1))) + return err; + } + return 0; +} + +EXPORT_SYMBOL(i2c_detect); + +MODULE_AUTHOR("Frodo Looijaard , " + "Rudolf Marek "); + +MODULE_DESCRIPTION("i2c-sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/i2c-sensor-vid.c b/drivers/i2c/i2c-sensor-vid.c new file mode 100644 index 000000000..017dcc5c6 --- /dev/null +++ b/drivers/i2c/i2c-sensor-vid.c @@ -0,0 +1,99 @@ +/* + i2c-sensor-vid.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 2004 Rudolf Marek + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +struct vrm_model { + u8 vendor; + u8 eff_family; + u8 eff_model; + int vrm_type; +}; + +#define ANY 0xFF + +#ifdef CONFIG_X86 + +static struct vrm_model vrm_models[] = { + {X86_VENDOR_AMD, 0x6, ANY, 90}, /* Athlon Duron etc */ + {X86_VENDOR_AMD, 0xF, 0x4, 90}, /* Athlon 64 */ + {X86_VENDOR_AMD, 0xF, 0x5, 24}, /* Opteron */ + {X86_VENDOR_INTEL, 0x6, 0x9, 85}, /* 0.13um too */ + {X86_VENDOR_INTEL, 0x6, 0xB, 85}, /* 0xB Tualatin */ + {X86_VENDOR_INTEL, 0x6, ANY, 82}, /* any P6 */ + {X86_VENDOR_INTEL, 0x7, ANY, 0}, /* Itanium */ + {X86_VENDOR_INTEL, 0xF, 0x3, 100}, /* P4 Prescott */ + {X86_VENDOR_INTEL, 0xF, ANY, 90}, /* P4 before Prescott */ + {X86_VENDOR_INTEL, 0x10,ANY, 0}, /* Itanium 2 */ + {X86_VENDOR_UNKNOWN, ANY, ANY, 0} /* stop here */ + }; + +static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor) +{ + int i = 0; + + while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) { + if (vrm_models[i].vendor==vendor) + if ((vrm_models[i].eff_family==eff_family)&& \ + ((vrm_models[i].eff_model==eff_model)|| \ + (vrm_models[i].eff_model==ANY))) + return vrm_models[i].vrm_type; + i++; + } + + return 0; +} + +int i2c_which_vrm(void) +{ + struct cpuinfo_x86 *c = cpu_data; + u32 eax; + u8 eff_family, eff_model; + int vrm_ret; + + if (c->x86 < 6) return 0; /* any CPU with familly lower than 6 + dont have VID and/or CPUID */ + eax = cpuid_eax(1); + eff_family = ((eax & 0x00000F00)>>8); + eff_model = ((eax & 0x000000F0)>>4); + if (eff_family == 0xF) { /* use extended model & family */ + eff_family += ((eax & 0x00F00000)>>20); + eff_model += ((eax & 0x000F0000)>>16)<<4; + } + vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor); + if (vrm_ret == 0) + printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your" + " x86 CPU\n"); + return vrm_ret; +} + +/* and now something completely different for Non-x86 world*/ +#else +int i2c_which_vrm(void) +{ + printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your CPU\n"); + return 0; +} +#endif + +EXPORT_SYMBOL(i2c_which_vrm); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index f28496bd2..4305f7cc2 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -457,11 +457,6 @@ config IDEDMA_ONLYDISK Generally say N here. -config BLK_DEV_ADMA - bool - depends on PCI && BLK_DEV_IDEPCI - default BLK_DEV_IDEDMA_PCI - config BLK_DEV_AEC62XX tristate "AEC62XX chipset support" help @@ -835,6 +830,13 @@ config BLK_DEV_IDE_RAPIDE Say Y here if you want to support the Yellowstone RapIDE controller manufactured for use with Acorn computers. +config BLK_DEV_IDE_BAST + tristate "Simtec BAST / Thorcom VR1000 IDE support" + depends on ARM && (ARCH_BAST || MACH_VR100) + help + Say Y here if you want to support the onboard IDE channels on the + Simtec BAST or the Thorcom VR1000 + config BLK_DEV_GAYLE bool "Amiga Gayle IDE interface support" depends on AMIGA diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile index ba897493d..6a78f0755 100644 --- a/drivers/ide/arm/Makefile +++ b/drivers/ide/arm/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o +obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c new file mode 100644 index 000000000..9d474e5fd --- /dev/null +++ b/drivers/ide/arm/bast-ide.c @@ -0,0 +1,71 @@ +/* linux/drivers/ide/arm/bast-ide.c + * + * Copyright (c) 2003-2004 Simtec Electronics + * Ben Dooks + * + * 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* list of registered interfaces */ +static ide_hwif_t *ifs[2]; + +static int __init +bastide_register(unsigned int base, unsigned int aux, int irq, + ide_hwif_t **hwif) +{ + hw_regs_t hw; + int i; + + memset(&hw, 0, sizeof(hw)); + + base += BAST_IDE_CS; + aux += BAST_IDE_CS; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw.io_ports[i] = (unsigned long)base; + base += 0x20; + } + + hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20); + hw.irq = irq; + + ide_register_hw(&hw, hwif); + + return 0; +} + +static int __init bastide_init(void) +{ + /* we can treat the VR1000 and the BAST the same */ + + if (!(machine_is_bast() || machine_is_vr1000())) + return 0; + + printk("BAST: IDE driver, (c) 2003-2004 Simtec Electronics\n"); + + bastide_register(BAST_VA_IDEPRI, BAST_VA_IDEPRIAUX, IRQ_IDE0, &ifs[0]); + bastide_register(BAST_VA_IDESEC, BAST_VA_IDESECAUX, IRQ_IDE1, &ifs[1]); + return 0; +} + +module_init(bastide_init); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simtec BAST / Thorcom VR1000 IDE driver"); diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index f40a61320..edc9de780 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -215,8 +215,6 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) struct scatterlist *sg = hwif->sg_table; int nents; - BUG_ON(hwif->sg_dma_active); - if (rq->flags & REQ_DRIVE_TASKFILE) { ide_task_t *args = rq->special; @@ -401,8 +399,6 @@ static int icside_dma_end(ide_drive_t *drive) dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); - hwif->sg_dma_active = 0; - return get_dma_residue(hwif->hw.dma) != 0; } @@ -454,7 +450,6 @@ icside_dma_common(ide_drive_t *drive, struct request *rq, /* * We can not enable DMA on both channels. */ - BUG_ON(hwif->sg_dma_active); BUG_ON(dma_channel_active(hwif->hw.dma)); icside_build_sglist(drive, rq); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index c3d6286eb..cc6b66e34 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -2719,8 +2719,10 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) if (!cdrom_get_media_event(cdi, &med)) { if (med.media_present) return CDS_DISC_OK; - if (med.door_open) + else if (med.door_open) return CDS_TRAY_OPEN; + else + return CDS_NO_DISC; } if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04) @@ -2732,10 +2734,12 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) * any other way to detect this... */ if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a && sense.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; + if (sense.asc == 0x3a) { + if (sense.ascq == 0 || sense.ascq == 1) + return CDS_NO_DISC; + else if (sense.ascq == 2) + return CDS_TRAY_OPEN; + } } return CDS_DRIVE_NOT_READY; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 7b3bf05cb..020bb4c11 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -340,12 +340,18 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive) ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = HWIF(drive); + unsigned int dma = drive->using_dma; u8 lba48 = (drive->addressing == 1) ? 1 : 0; task_ioreg_t command = WIN_NOP; ata_nsector_t nsectors; nsectors.all = (u16) rq->nr_sectors; + if (hwif->no_lba48_dma && lba48 && dma) { + if (rq->sector + rq->nr_sectors > 1ULL << 28) + dma = 0; + } + if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -414,7 +420,7 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector } if (rq_data_dir(rq) == READ) { - if (drive->using_dma && !hwif->ide_dma_read(drive)) + if (dma && !hwif->ide_dma_read(drive)) return ide_started; command = ((drive->mult_count) ? @@ -425,7 +431,7 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector } else { ide_startstop_t startstop; - if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive))) + if (dma && !hwif->ide_dma_write(drive)) return ide_started; command = ((drive->mult_count) ? @@ -488,31 +494,38 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector } EXPORT_SYMBOL_GPL(__ide_do_rw_disk); -static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) +static u8 get_command(ide_drive_t *drive, struct request *rq, ide_task_t *task) { unsigned int lba48 = (drive->addressing == 1) ? 1 : 0; + unsigned int dma = drive->using_dma; + + if (drive->hwif->no_lba48_dma && lba48 && dma) { + if (rq->sector + rq->nr_sectors > 1ULL << 28) + dma = 0; + } - if (cmd == READ) { + if (rq_data_dir(rq) == READ) { task->command_type = IDE_DRIVE_TASK_IN; - if (drive->using_dma) + if (dma) return lba48 ? WIN_READDMA_EXT : WIN_READDMA; + task->handler = &task_in_intr; if (drive->mult_count) { - task->handler = &task_mulin_intr; + task->data_phase = TASKFILE_MULTI_IN; return lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD; } - task->handler = &task_in_intr; + task->data_phase = TASKFILE_IN; return lba48 ? WIN_READ_EXT : WIN_READ; } else { task->command_type = IDE_DRIVE_TASK_RAW_WRITE; - if (drive->using_dma) + if (dma) return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + task->prehandler = &pre_task_out_intr; + task->handler = &task_out_intr; if (drive->mult_count) { - task->prehandler = &pre_task_mulout_intr; - task->handler = &task_mulout_intr; + task->data_phase = TASKFILE_MULTI_OUT; return lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; } - task->prehandler = &pre_task_out_intr; - task->handler = &task_out_intr; + task->data_phase = TASKFILE_OUT; return lba48 ? WIN_WRITE_EXT : WIN_WRITE; } } @@ -541,9 +554,10 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8); args.tfRegister[IDE_SELECT_OFFSET] = head; args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; + drive->hwif->data_phase = args.data_phase; return do_rw_taskfile(drive, &args); } @@ -565,9 +579,10 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f); args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; + drive->hwif->data_phase = args.data_phase; return do_rw_taskfile(drive, &args); } @@ -595,7 +610,7 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ args.tfRegister[IDE_SELECT_OFFSET] = drive->select.all; - args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args); + args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args); args.hobRegister[IDE_SECTOR_OFFSET] = (block>>=8); /* low lba */ args.hobRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.hobRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ @@ -603,6 +618,7 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; + drive->hwif->data_phase = args.data_phase; return do_rw_taskfile(drive, &args); } @@ -638,7 +654,6 @@ static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat) local_irq_set(flags); printk("%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS printk(" { "); if (stat & BUSY_STAT) printk("Busy "); @@ -652,12 +667,10 @@ static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat) if (stat & ERR_STAT) printk("Error "); } printk("}"); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { err = hwif->INB(IDE_ERROR_REG); printk("%s: %s: error=0x%02x", drive->name, msg, err); -#if FANCY_STATUS_DUMPS printk(" { "); if (err & ABRT_ERR) printk("DriveStatusError "); if (err & ICRC_ERR) @@ -700,8 +713,38 @@ static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat) (unsigned long long)HWGROUP(drive)->rq->sector); } } -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); + { + struct request *rq; + unsigned char opcode = 0; + int found = 0; + + spin_lock(&ide_lock); + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + goto out; + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + char *args = rq->buffer; + if (args) { + opcode = args[0]; + found = 1; + } + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + found = 1; + } + } + printk("ide: failed opcode was: "); + if (!found) + printk("unknown\n"); + else + printk("0x%02x\n", opcode); + } +out: local_irq_restore(flags); return err; } @@ -1117,6 +1160,7 @@ static int get_smart_values(ide_drive_t *drive, u8 *buf) args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; args.command_type = IDE_DRIVE_TASK_IN; + args.data_phase = TASKFILE_IN; args.handler = &task_in_intr; (void) smart_enable(drive); return ide_raw_taskfile(drive, &args, buf); @@ -1203,6 +1247,42 @@ static ide_proc_entry_t idedisk_proc[] = { #endif /* CONFIG_PROC_FS */ +static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + ide_drive_t *drive = q->queuedata; + struct request *rq; + int ret; + + if (!drive->wcache) + return 0; + + rq = blk_get_request(q, WRITE, __GFP_WAIT); + + memset(rq->cmd, 0, sizeof(rq->cmd)); + + if (ide_id_has_flush_cache_ext(drive->id) && + (drive->capacity64 >= (1UL << 28))) + rq->cmd[0] = WIN_FLUSH_CACHE_EXT; + else + rq->cmd[0] = WIN_FLUSH_CACHE; + + + rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER; + rq->buffer = rq->cmd; + + ret = blk_execute_rq(q, disk, rq); + + /* + * if we failed and caller wants error offset, get it + */ + if (ret && error_sector) + *error_sector = ide_get_error_location(drive, rq->cmd); + + blk_put_request(rq); + return ret; +} + /* * This is tightly woven into the driver->do_special can not touch. * DON'T do it again until a total personality rewrite is committed. @@ -1231,16 +1311,10 @@ static int set_nowerr(ide_drive_t *drive, int arg) return 0; } -/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ -#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) - -/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */ -#define ide_id_has_flush_cache_ext(id) \ - (((id)->cfs_enable_2 & 0x2400) == 0x2400) - -static int write_cache (ide_drive_t *drive, int arg) +static int write_cache(ide_drive_t *drive, int arg) { ide_task_t args; + int err; if (!ide_id_has_flush_cache(drive->id)) return 1; @@ -1251,7 +1325,10 @@ static int write_cache (ide_drive_t *drive, int arg) args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; args.command_type = IDE_DRIVE_TASK_NO_DATA; args.handler = &task_no_data_intr; - (void) ide_raw_taskfile(drive, &args, NULL); + + err = ide_raw_taskfile(drive, &args, NULL); + if (err) + return err; drive->wcache = arg; return 0; @@ -1412,6 +1489,7 @@ static void idedisk_setup (ide_drive_t *drive) { struct hd_driveid *id = drive->id; unsigned long long capacity; + int barrier; idedisk_add_settings(drive); @@ -1443,7 +1521,7 @@ static void idedisk_setup (ide_drive_t *drive) blk_queue_max_sectors(drive->queue, max_s); } - printk("%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2); + printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2); /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { @@ -1472,13 +1550,22 @@ static void idedisk_setup (ide_drive_t *drive) /* limit drive capacity to 137GB if LBA48 cannot be used */ if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) { - printk("%s: cannot use LBA48 - full capacity " + printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " "%llu sectors (%llu MB)\n", drive->name, (unsigned long long)drive->capacity64, sectors_to_MB(drive->capacity64)); drive->capacity64 = 1ULL << 28; } + if (drive->hwif->no_lba48_dma && drive->addressing) { + if (drive->capacity64 > 1ULL << 28) { + printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will" + " be used for accessing sectors > %u\n", + drive->name, 1 << 28); + } else + drive->addressing = 0; + } + /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: @@ -1543,6 +1630,29 @@ static void idedisk_setup (ide_drive_t *drive) drive->wcache = 1; write_cache(drive, 1); + + /* + * We must avoid issuing commands a drive does not understand + * or we may crash it. We check flush cache is supported. We also + * check we have the LBA48 flush cache if the drive capacity is + * too large. By this time we have trimmed the drive capacity if + * LBA48 is not available so we don't need to recheck that. + */ + barrier = 0; + if (ide_id_has_flush_cache(id)) + barrier = 1; + if (drive->addressing == 1) { + /* Can't issue the correct flush ? */ + if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id)) + barrier = 0; + } + + printk(KERN_DEBUG "%s: cache flushes %ssupported\n", + drive->name, barrier ? "" : "not "); + if (barrier) { + blk_queue_ordered(drive->queue, 1); + blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush); + } } static void ide_cacheflush_p(ide_drive_t *drive) @@ -1723,11 +1833,9 @@ static int idedisk_attach(ide_drive_t *drive) if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); - ide_cacheflush_p(drive); - ide_unregister_subdriver(drive); - DRIVER(drive)->busy--; - goto failed; - } + drive->attach = 0; + } else + drive->attach = 1; DRIVER(drive)->busy--; g->minors = 1 << PARTN_BITS; strcpy(g->devfs_name, drive->devfs_name); @@ -1735,7 +1843,6 @@ static int idedisk_attach(ide_drive_t *drive) g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; set_capacity(g, current_capacity(drive)); g->fops = &idedisk_ops; - drive->attach = 1; add_disk(g); return 0; failed: diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 6ed4de8a5..cd32057b5 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -208,9 +208,6 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq) struct scatterlist *sg = hwif->sg_table; int nents; - if (hwif->sg_dma_active) - BUG(); - nents = blk_rq_map_sg(drive->queue, rq, hwif->sg_table); if (rq_data_dir(rq) == READ) @@ -366,7 +363,6 @@ use_pio_instead: hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); - hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */ } @@ -390,7 +386,6 @@ void ide_destroy_dmatable (ide_drive_t *drive) int nents = HWIF(drive)->sg_nents; pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction); - HWIF(drive)->sg_dma_active = 0; } EXPORT_SYMBOL_GPL(ide_destroy_dmatable); @@ -412,10 +407,6 @@ static int config_drive_for_dma (ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); if ((id->capability & 1) && hwif->autodma) { - /* Consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - return __ide_dma_off(drive); - /* * Enable DMA on any drive that has * UltraDMA (mode 0/1/2/3/4/5/6) enabled @@ -569,6 +560,10 @@ EXPORT_SYMBOL(__ide_dma_host_on); int __ide_dma_on (ide_drive_t *drive) { + /* consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + return 1; + drive->using_dma = 1; ide_toggle_bounce(drive, 1); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ff5b16a87..d20cd1eb5 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -54,38 +54,77 @@ #include #include -/** - * ide_end_request - complete an IDE I/O - * @drive: IDE device for the I/O - * @uptodate: - * @nr_sectors: number of sectors completed - * - * This is our end_request wrapper function. We complete the I/O - * update random number input and dequeue the request, which if - * it was tagged may be out of order. +static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq) +{ + char *buf = rq->cmd; + + /* + * reuse cdb space for ata command + */ + memset(buf, 0, sizeof(rq->cmd)); + + rq->flags |= REQ_DRIVE_TASK | REQ_STARTED; + rq->buffer = buf; + rq->buffer[0] = WIN_FLUSH_CACHE; + + if (ide_id_has_flush_cache_ext(drive->id) && + (drive->capacity64 >= (1UL << 28))) + rq->buffer[0] = WIN_FLUSH_CACHE_EXT; +} + +/* + * preempt pending requests, and store this cache flush for immediate + * execution */ - -int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +static struct request *ide_queue_flush_cmd(ide_drive_t *drive, + struct request *rq, int post) { - struct request *rq; - unsigned long flags; - int ret = 1; + struct request *flush_rq = &HWGROUP(drive)->wrq; - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; + /* + * write cache disabled, clear the barrier bit and treat it like + * an ordinary write + */ + if (!drive->wcache) { + rq->flags |= REQ_BAR_PREFLUSH; + return rq; + } - BUG_ON(!(rq->flags & REQ_STARTED)); + ide_init_drive_cmd(flush_rq); + ide_fill_flush_cmd(drive, flush_rq); - if (!nr_sectors) - nr_sectors = rq->hard_cur_sectors; + flush_rq->special = rq; + flush_rq->nr_sectors = rq->nr_sectors; + + if (!post) { + drive->doing_barrier = 1; + flush_rq->flags |= REQ_BAR_PREFLUSH; + blkdev_dequeue_request(rq); + } else + flush_rq->flags |= REQ_BAR_POSTFLUSH; + + __elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0); + HWGROUP(drive)->rq = NULL; + return flush_rq; +} + +static int __ide_end_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + int ret = 1; + + BUG_ON(!(rq->flags & REQ_STARTED)); /* * if failfast is set on a request, override number of sectors and * complete the whole request right now */ - if (blk_noretry_request(rq) && !uptodate) + if (blk_noretry_request(rq) && end_io_error(uptodate)) nr_sectors = rq->hard_nr_sectors; + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO @@ -97,15 +136,56 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) if (!end_that_request_first(rq, uptodate, nr_sectors)) { add_disk_randomness(rq->rq_disk); + + if (blk_rq_tagged(rq)) + blk_queue_end_tag(drive->queue, rq); + blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; } - spin_unlock_irqrestore(&ide_lock, flags); return ret; } +/** + * ide_end_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * This is our end_request wrapper function. We complete the I/O + * update random number input and dequeue the request, which if + * it was tagged may be out of order. + */ + +int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + rq = HWGROUP(drive)->rq; + + if (!nr_sectors) + nr_sectors = rq->hard_cur_sectors; + + if (!blk_barrier_rq(rq) || !drive->wcache) + ret = __ide_end_request(drive, rq, uptodate, nr_sectors); + else { + struct request *flush_rq = &HWGROUP(drive)->wrq; + + flush_rq->nr_sectors -= nr_sectors; + if (!flush_rq->nr_sectors) { + ide_queue_flush_cmd(drive, rq, 1); + ret = 0; + } + } + + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} EXPORT_SYMBOL(ide_end_request); /** @@ -137,6 +217,113 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) spin_unlock_irqrestore(&ide_lock, flags); } +/* + * FIXME: probably move this somewhere else, name is bad too :) + */ +u64 ide_get_error_location(ide_drive_t *drive, char *args) +{ + u32 high, low; + u8 hcyl, lcyl, sect; + u64 sector; + + high = 0; + hcyl = args[5]; + lcyl = args[4]; + sect = args[3]; + + if (ide_id_has_flush_cache_ext(drive->id)) { + low = (hcyl << 16) | (lcyl << 8) | sect; + HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + } else { + u8 cur = HWIF(drive)->INB(IDE_SELECT_REG); + if (cur & 0x40) + low = (hcyl << 16) | (lcyl << 8) | sect; + else { + low = hcyl * drive->head * drive->sect; + low += lcyl * drive->sect; + low += sect - 1; + } + } + + sector = ((u64) high << 24) | low; + return sector; +} +EXPORT_SYMBOL(ide_get_error_location); + +static void ide_complete_barrier(ide_drive_t *drive, struct request *rq, + int error) +{ + struct request *real_rq = rq->special; + int good_sectors, bad_sectors; + sector_t sector; + + if (!error) { + if (blk_barrier_postflush(rq)) { + /* + * this completes the barrier write + */ + __ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors); + drive->doing_barrier = 0; + } else { + /* + * just indicate that we did the pre flush + */ + real_rq->flags |= REQ_BAR_PREFLUSH; + elv_requeue_request(drive->queue, real_rq); + } + /* + * all is fine, return + */ + return; + } + + /* + * we need to end real_rq, but it's not on the queue currently. + * put it back on the queue, so we don't have to special case + * anything else for completing it + */ + if (!blk_barrier_postflush(rq)) + elv_requeue_request(drive->queue, real_rq); + + /* + * drive aborted flush command, assume FLUSH_CACHE_* doesn't + * work and disable barrier support + */ + if (error & ABRT_ERR) { + printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name); + __ide_end_request(drive, real_rq, -EOPNOTSUPP, real_rq->hard_nr_sectors); + blk_queue_ordered(drive->queue, 0); + blk_queue_issue_flush_fn(drive->queue, NULL); + } else { + /* + * find out what part of the request failed + */ + good_sectors = 0; + if (blk_barrier_postflush(rq)) { + sector = ide_get_error_location(drive, rq->buffer); + + if ((sector >= real_rq->hard_sector) && + (sector < real_rq->hard_sector + real_rq->hard_nr_sectors)) + good_sectors = sector - real_rq->hard_sector; + } else + sector = real_rq->hard_sector; + + bad_sectors = real_rq->hard_nr_sectors - good_sectors; + if (good_sectors) + __ide_end_request(drive, real_rq, 1, good_sectors); + if (bad_sectors) + __ide_end_request(drive, real_rq, 0, bad_sectors); + + printk(KERN_ERR "%s: failed barrier write: " + "sector=%Lx(good=%d/bad=%d)\n", + drive->name, (unsigned long long)sector, + good_sectors, bad_sectors); + } + + drive->doing_barrier = 0; +} + /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -197,6 +384,8 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args->hobRegister[IDE_DATA_OFFSET] = (data >> 8) & 0xFF; } args->tfRegister[IDE_ERROR_OFFSET] = err; + /* be sure we're looking at the low order bits */ + hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); @@ -226,6 +415,10 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); + + if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq)) + ide_complete_barrier(drive, rq, err); + HWGROUP(drive)->rq = NULL; end_that_request_last(rq); spin_unlock_irqrestore(&ide_lock, flags); @@ -501,7 +694,9 @@ ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) if (!args) goto done; - + + hwif->data_phase = args->data_phase; + if (args->tf_out_flags.all != 0) return flagged_taskfile(drive, args); return do_rw_taskfile(drive, args); @@ -712,6 +907,22 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) repeat: best = NULL; drive = hwgroup->drive; + + /* + * drive is doing pre-flush, ordered write, post-flush sequence. even + * though that is 3 requests, it must be seen as a single transaction. + * we must not preempt this drive until that is complete + */ + if (drive->doing_barrier) { + /* + * small race where queue could get replugged during + * the 3-request flush cycle, just yank the plug since + * we want it to finish asap + */ + blk_remove_plug(drive->queue); + return drive; + } + do { if ((!drive->sleep || time_after_eq(jiffies, drive->sleep)) && !elv_queue_empty(drive->queue)) { @@ -867,6 +1078,13 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) break; } + /* + * if rq is a barrier write, issue pre cache flush if not + * already done + */ + if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq)) + rq = ide_queue_flush_cmd(drive, rq, 0); + /* * Sanity: don't accept a request that isn't a PM request * if we are currently power managed. This is very important as @@ -917,7 +1135,9 @@ EXPORT_SYMBOL(ide_do_request); */ void do_ide_request(request_queue_t *q) { - ide_do_request(q->queuedata, IDE_NO_IRQ); + ide_drive_t *drive = q->queuedata; + + ide_do_request(HWGROUP(drive), IDE_NO_IRQ); } /* @@ -1286,6 +1506,7 @@ void ide_init_drive_cmd (struct request *rq) { memset(rq, 0, sizeof(*rq)); rq->flags = REQ_DRIVE_CMD; + rq->ref_count = 1; } EXPORT_SYMBOL(ide_init_drive_cmd); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index b7c47d235..c104120ae 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -112,57 +112,57 @@ EXPORT_SYMBOL(default_hwif_iops); static u8 ide_mm_inb (unsigned long port) { - return (u8) readb(port); + return (u8) readb((void __iomem *) port); } static u16 ide_mm_inw (unsigned long port) { - return (u16) readw(port); + return (u16) readw((void __iomem *) port); } static void ide_mm_insw (unsigned long port, void *addr, u32 count) { - __ide_mm_insw(port, addr, count); + __ide_mm_insw((void __iomem *) port, addr, count); } static u32 ide_mm_inl (unsigned long port) { - return (u32) readl(port); + return (u32) readl((void __iomem *) port); } static void ide_mm_insl (unsigned long port, void *addr, u32 count) { - __ide_mm_insl(port, addr, count); + __ide_mm_insl((void __iomem *) port, addr, count); } static void ide_mm_outb (u8 value, unsigned long port) { - writeb(value, port); + writeb(value, (void __iomem *) port); } static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port) { - writeb(value, port); + writeb(value, (void __iomem *) port); } static void ide_mm_outw (u16 value, unsigned long port) { - writew(value, port); + writew(value, (void __iomem *) port); } static void ide_mm_outsw (unsigned long port, void *addr, u32 count) { - __ide_mm_outsw(port, addr, count); + __ide_mm_outsw((void __iomem *) port, addr, count); } static void ide_mm_outl (u32 value, unsigned long port) { - writel(value, port); + writel(value, (void __iomem *) port); } static void ide_mm_outsl (unsigned long port, void *addr, u32 count) { - __ide_mm_outsl(port, addr, count); + __ide_mm_outsl((void __iomem *) port, addr, count); } void default_hwif_mmiops (ide_hwif_t *hwif) @@ -1096,7 +1096,6 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) drive->failures = 0; } else { drive->failures++; -#if FANCY_STATUS_DUMPS printk("master: "); switch (tmp & 0x7f) { case 1: printk("passed"); @@ -1114,9 +1113,6 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) if (tmp & 0x80) printk("; slave: failed"); printk("\n"); -#else - printk("failed\n"); -#endif /* FANCY_STATUS_DUMPS */ } } hwgroup->poll_timeout = 0; /* done polling */ diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 073c3fb82..b2fa5eccd 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -465,7 +465,6 @@ byte ide_dump_atapi_status (ide_drive_t *drive, const char *msg, byte stat) status.all = stat; local_irq_set(flags); printk("%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS printk(" { "); if (status.b.bsy) printk("Busy "); @@ -479,19 +478,16 @@ byte ide_dump_atapi_status (ide_drive_t *drive, const char *msg, byte stat) if (status.b.check) printk("Error "); } printk("}"); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) { error.all = HWIF(drive)->INB(IDE_ERROR_REG); printk("%s: %s: error=0x%02x", drive->name, msg, error.all); -#if FANCY_STATUS_DUMPS if (error.b.ili) printk("IllegalLengthIndication "); if (error.b.eom) printk("EndOfMedia "); if (error.b.abrt) printk("Aborted Command "); if (error.b.mcr) printk("MediaChangeRequested "); if (error.b.sense_key) printk("LastFailedSense 0x%02x ", error.b.sense_key); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); } local_irq_restore(flags); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 4ffaf9016..61c72a700 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -389,15 +389,6 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) */ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie); -#ifdef CONFIG_BLK_DEV_CMD640 -#ifdef CMD640_DUMP_REGS - if (hwif->chipset == ide_cmd640) { - printk("%s: Hmmm.. probably a driver " - "problem.\n", drive->name); - CMD640_DUMP_REGS; - } -#endif /* CMD640_DUMP_REGS */ -#endif /* CONFIG_BLK_DEV_CMD640 */ } } } @@ -635,12 +626,11 @@ static void hwif_register (ide_hwif_t *hwif) device_register(&hwif->gendev); } -#ifdef CONFIG_PPC static int wait_hwif_ready(ide_hwif_t *hwif) { int rc; - printk(KERN_INFO "Probing IDE interface %s...\n", hwif->name); + printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name); /* Let HW settle down a bit from whatever init state we * come from */ @@ -671,7 +661,6 @@ static int wait_hwif_ready(ide_hwif_t *hwif) return rc; } -#endif /* * This routine only knows how to look for drive units 0 and 1 @@ -717,7 +706,6 @@ static void probe_hwif(ide_hwif_t *hwif) local_irq_set(flags); -#ifdef CONFIG_PPC /* This is needed on some PPCs and a bunch of BIOS-less embedded * platforms. Typical cases are: * @@ -738,8 +726,7 @@ static void probe_hwif(ide_hwif_t *hwif) * BenH. */ if (wait_hwif_ready(hwif)) - printk(KERN_WARNING "%s: Wait for ready failed before probe !\n", hwif->name); -#endif /* CONFIG_PPC */ + printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* * Second drive should only exist if first drive was found, @@ -749,6 +736,18 @@ static void probe_hwif(ide_hwif_t *hwif) ide_drive_t *drive = &hwif->drives[unit]; drive->dn = (hwif->channel ? 2 : 0) + unit; (void) probe_for_drive(drive); + if (drive->present && hwif->present && unit == 1) { + if (strcmp(hwif->drives[0].id->model, drive->id->model) == 0 && + /* Don't do this for noprobe or non ATA */ + strcmp(drive->id->model, "UNKNOWN") && + /* And beware of confused Maxtor drives that go "M0000000000" + "The SN# is garbage in the ID block..." [Eric] */ + strncmp(drive->id->serial_no, "M0000000000000000000", 20) && + strncmp(hwif->drives[0].id->serial_no, drive->id->serial_no, 20) == 0) { + printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n"); + drive->present = 0; + } + } if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || @@ -893,11 +892,15 @@ static int ide_init_queue(ide_drive_t *drive) if (!q) return 1; - q->queuedata = HWGROUP(drive); + q->queuedata = drive; blk_queue_segment_boundary(q, 0xffff); - if (!hwif->rqsize) - hwif->rqsize = hwif->no_lba48 ? 256 : 65536; + if (!hwif->rqsize) { + if (hwif->no_lba48 || hwif->no_lba48_dma) + hwif->rqsize = 256; + else + hwif->rqsize = 65536; + } if (hwif->rqsize < max_sectors) max_sectors = hwif->rqsize; blk_queue_max_sectors(q, max_sectors); @@ -906,11 +909,11 @@ static int ide_init_queue(ide_drive_t *drive) /* When we have an IOMMU, we may have a problem where pci_map_sg() * creates segments that don't completely match our boundary * requirements and thus need to be broken up again. Because it - * doesn't align properly neither, we may actually have to break up + * doesn't align properly either, we may actually have to break up * to more segments than what was we got in the first place, a max * worst case is twice as many. * This will be fixed once we teach pci_map_sg() about our boundary - * requirements, hopefully soon + * requirements, hopefully soon. *FIXME* */ if (!PCI_DMA_BUS_IS_PHYS) max_sg_entries >>= 1; diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index a3ebd9e12..07c989bb1 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -360,27 +360,14 @@ static int proc_ide_read_identify int err = 0; len = sprintf(page, "\n"); - - if (drive) - { + + if (drive) { unsigned short *val = (unsigned short *) page; - - /* - * The current code can't handle a driverless - * identify query taskfile. Now the right fix is - * to add a 'default' driver but that is a bit - * more work. - * - * FIXME: this has to be fixed for hotswap devices - */ - - if(DRIVER(drive)) - err = taskfile_lib_get_identify(drive, page); - else /* This relies on the ID changes */ - val = (unsigned short *)drive->id; - - if(!err) - { + + BUG_ON(!drive->driver); + + err = taskfile_lib_get_identify(drive, page); + if (!err) { char *out = ((char *)page) + (SECTOR_WORDS * 4); page = out; do { diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index d19ee543e..9d19fab9c 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -530,7 +530,6 @@ typedef struct os_dat_s { */ #define IDETAPE_DEBUG_INFO 0 #define IDETAPE_DEBUG_LOG 0 -#define IDETAPE_DEBUG_LOG_VERBOSE 0 #define IDETAPE_DEBUG_BUGS 1 /* @@ -1260,70 +1259,6 @@ typedef struct { */ static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES]; -#if IDETAPE_DEBUG_LOG_VERBOSE - -/* - * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI - */ - -char *idetape_sense_key_verbose(u8 idetape_sense_key) -{ - switch (idetape_sense_key) { - default: { - char buf[22]; - sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key); - return(buf); - } - - } -} - -char *idetape_command_key_verbose(u8 idetape_command_key) -{ - switch (idetape_command_key) { - case IDETAPE_TEST_UNIT_READY_CMD: - return("TEST_UNIT_READY_CMD"); - case IDETAPE_REWIND_CMD: - return("REWIND_CMD"); - case IDETAPE_REQUEST_SENSE_CMD: - return("REQUEST_SENSE_CMD"); - case IDETAPE_READ_CMD: - return("READ_CMD"); - case IDETAPE_WRITE_CMD: - return("WRITE_CMD"); - case IDETAPE_WRITE_FILEMARK_CMD: - return("WRITE_FILEMARK_CMD"); - case IDETAPE_SPACE_CMD: - return("SPACE_CMD"); - case IDETAPE_INQUIRY_CMD: - return("INQUIRY_CMD"); - case IDETAPE_ERASE_CMD: - return("ERASE_CMD"); - case IDETAPE_MODE_SENSE_CMD: - return("MODE_SENSE_CMD"); - case IDETAPE_MODE_SELECT_CMD: - return("MODE_SELECT_CMD"); - case IDETAPE_LOAD_UNLOAD_CMD: - return("LOAD_UNLOAD_CMD"); - case IDETAPE_PREVENT_CMD: - return("PREVENT_CMD"); - case IDETAPE_LOCATE_CMD: - return("LOCATE_CMD"); - case IDETAPE_READ_POSITION_CMD: - return("READ_POSITION_CMD"); - case IDETAPE_READ_BUFFER_CMD: - return("READ_BUFFER_CMD"); - case IDETAPE_SET_SPEED_CMD: - return("SET_SPEED_CMD"); - default: { - char buf[20]; - sprintf(buf, "CMD (0x%02x)", idetape_command_key); - return(buf); - } - } -} -#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ - /* * Function declarations * @@ -1507,15 +1442,6 @@ static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_res "asc = %x, ascq = %x\n", pc->c[0], result->sense_key, result->asc, result->ascq); -#if IDETAPE_DEBUG_LOG_VERBOSE - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: pc = %s, sense key = %x, " - "asc = %x, ascq = %x\n", - idetape_command_key_verbose((byte) pc->c[0]), - result->sense_key, - result->asc, - result->ascq); -#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ #endif /* IDETAPE_DEBUG_LOG */ /* diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index e83c9a9eb..8de2a111b 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -96,36 +96,13 @@ int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) else args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY; args.command_type = IDE_DRIVE_TASK_IN; + args.data_phase = TASKFILE_IN; args.handler = &task_in_intr; return ide_raw_taskfile(drive, &args, buf); } EXPORT_SYMBOL(taskfile_lib_get_identify); -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG -void debug_taskfile (ide_drive_t *drive, ide_task_t *args) -{ - printk(KERN_INFO "%s: ", drive->name); -// printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]); - printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]); - printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]); - printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]); - printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]); - printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]); - printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]); - printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]); - printk(KERN_INFO "%s: ", drive->name); -// printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET]); - printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET]); - printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET]); - printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET]); - printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET]); - printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET]); - printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET]); - printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]); -} -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) { ide_hwif_t *hwif = HWIF(drive); @@ -133,10 +110,6 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; u8 HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF; -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG - void debug_taskfile(drive, task); -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ if (IDE_CONTROL_REG) { /* clear nIEN */ @@ -367,12 +340,44 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) return stat; } +static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq, + unsigned int write) +{ + switch (drive->hwif->data_phase) { + case TASKFILE_MULTI_IN: + case TASKFILE_MULTI_OUT: + task_multi_sectors(drive, rq, write); + break; + default: + task_sectors(drive, rq, 1, write); + break; + } +} + #ifdef CONFIG_IDE_TASKFILE_IO static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, - const char *s, u8 stat, unsigned cur_bad) + const char *s, u8 stat) { if (rq->bio) { - int sectors = rq->hard_nr_sectors - rq->nr_sectors - cur_bad; + int sectors = rq->hard_nr_sectors - rq->nr_sectors; + + switch (drive->hwif->data_phase) { + case TASKFILE_IN: + if (rq->nr_sectors) + break; + /* fall through */ + case TASKFILE_OUT: + sectors--; + break; + case TASKFILE_MULTI_IN: + if (rq->nr_sectors) + break; + /* fall through */ + case TASKFILE_MULTI_OUT: + sectors -= drive->mult_count; + default: + break; + } if (sectors > 0) drive->driver->end_request(drive, 1, sectors); @@ -380,7 +385,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, return drive->driver->error(drive, s, stat); } #else -# define task_error(d, rq, s, stat, cur_bad) drive->driver->error(d, s, stat) +# define task_error(d, rq, s, stat) drive->driver->error(d, s, stat) #endif static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) @@ -398,7 +403,7 @@ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) } /* - * Handler for command with PIO data-in phase (Read). + * Handler for command with PIO data-in phase (Read/Read Multiple). */ ide_startstop_t task_in_intr (ide_drive_t *drive) { @@ -407,19 +412,19 @@ ide_startstop_t task_in_intr (ide_drive_t *drive) if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { if (stat & (ERR_STAT | DRQ_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, 0); + return task_error(drive, rq, __FUNCTION__, stat); /* No data yet, so wait for another IRQ. */ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started; } - task_sectors(drive, rq, 1, IDE_PIO_IN); + ide_pio_datablock(drive, rq, 0); /* If it was the last datablock check status and finish transfer. */ if (!rq->nr_sectors) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_R_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, 1); + return task_error(drive, rq, __FUNCTION__, stat); task_end_request(drive, rq, stat); return ide_stopped; } @@ -432,41 +437,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive) EXPORT_SYMBOL(task_in_intr); /* - * Handler for command with PIO data-in phase (Read Multiple). - */ -ide_startstop_t task_mulin_intr (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - u8 stat = HWIF(drive)->INB(IDE_STATUS_REG); - - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { - if (stat & (ERR_STAT | DRQ_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, 0); - /* No data yet, so wait for another IRQ. */ - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - - task_multi_sectors(drive, rq, IDE_PIO_IN); - - /* If it was the last datablock check status and finish transfer. */ - if (!rq->nr_sectors) { - stat = wait_drive_not_busy(drive); - if (!OK_STAT(stat, 0, BAD_R_STAT)) - return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); - task_end_request(drive, rq, stat); - return ide_stopped; - } - - /* Still data left to transfer. */ - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} -EXPORT_SYMBOL(task_mulin_intr); - -/* - * Handler for command with PIO data-out phase (Write). + * Handler for command with PIO data-out phase (Write/Write Multiple). */ ide_startstop_t task_out_intr (ide_drive_t *drive) { @@ -475,11 +446,11 @@ ide_startstop_t task_out_intr (ide_drive_t *drive) stat = HWIF(drive)->INB(IDE_STATUS_REG); if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) - return task_error(drive, rq, __FUNCTION__, stat, 1); + return task_error(drive, rq, __FUNCTION__, stat); /* Deal with unexpected ATA data phase. */ if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) - return task_error(drive, rq, __FUNCTION__, stat, 1); + return task_error(drive, rq, __FUNCTION__, stat); if (!rq->nr_sectors) { task_end_request(drive, rq, stat); @@ -487,7 +458,7 @@ ide_startstop_t task_out_intr (ide_drive_t *drive) } /* Still data left to transfer. */ - task_sectors(drive, rq, 1, IDE_PIO_OUT); + ide_pio_datablock(drive, rq, 1); ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); return ide_started; @@ -501,8 +472,10 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n", - drive->name, drive->addressing ? "_EXT" : ""); + printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", + drive->name, + drive->hwif->data_phase ? "MULT" : "", + drive->addressing ? "_EXT" : ""); return startstop; } @@ -510,62 +483,12 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) local_irq_disable(); ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); - task_sectors(drive, rq, 1, IDE_PIO_OUT); + ide_pio_datablock(drive, rq, 1); return ide_started; } EXPORT_SYMBOL(pre_task_out_intr); -/* - * Handler for command with PIO data-out phase (Write Multiple). - */ -ide_startstop_t task_mulout_intr (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - u8 stat; - - stat = HWIF(drive)->INB(IDE_STATUS_REG); - if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) - return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); - - /* Deal with unexpected ATA data phase. */ - if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) - return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); - - if (!rq->nr_sectors) { - task_end_request(drive, rq, stat); - return ide_stopped; - } - - /* Still data left to transfer. */ - task_multi_sectors(drive, rq, IDE_PIO_OUT); - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} -EXPORT_SYMBOL(task_mulout_intr); - -ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing MULTWRITE%s\n", - drive->name, drive->addressing ? "_EXT" : ""); - return startstop; - } - - if (!drive->unmask) - local_irq_disable(); - - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - task_multi_sectors(drive, rq, IDE_PIO_OUT); - - return ide_started; -} -EXPORT_SYMBOL(pre_task_mulout_intr); - int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) { struct request rq; @@ -688,19 +611,6 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) case TASKFILE_IN_DMA: err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; - case TASKFILE_IN_OUT: -#if 0 - args.prehandler = &pre_task_out_intr; - args.handler = &task_out_intr; - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - args.prehandler = NULL; - args.handler = &task_in_intr; - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; -#else - err = -EFAULT; - goto abort; -#endif case TASKFILE_MULTI_OUT: if (!drive->mult_count) { /* (hs): give up if multcount is not set */ @@ -710,10 +620,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) err = -EPERM; goto abort; } - args.prehandler = &pre_task_mulout_intr; - args.handler = &task_mulout_intr; - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - break; + /* fall through */ case TASKFILE_OUT: args.prehandler = &pre_task_out_intr; args.handler = &task_out_intr; @@ -728,9 +635,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) err = -EPERM; goto abort; } - args.handler = &task_mulin_intr; - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; + /* fall through */ case TASKFILE_IN: args.handler = &task_in_intr; err = ide_diag_taskfile(drive, &args, taskin, inbuf); @@ -907,11 +812,6 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) u8 status; #endif - -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG - void debug_taskfile(drive, task); -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - if (task->data_phase == TASKFILE_MULTI_IN || task->data_phase == TASKFILE_MULTI_OUT) { if (!drive->mult_count) { diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index e99d9ec19..c57bd4cc9 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -320,13 +320,19 @@ static void __init init_ide_data (void) #endif } -/* - * ide_system_bus_speed() returns what we think is the system VESA/PCI - * bus speed (in MHz). This is used for calculating interface PIO timings. - * The default is 40 for known PCI systems, 50 otherwise. - * The "idebus=xx" parameter can be used to override this value. - * The actual value to be used is computed/displayed the first time through. +/** + * ide_system_bus_speed - guess bus speed + * + * ide_system_bus_speed() returns what we think is the system VESA/PCI + * bus speed (in MHz). This is used for calculating interface PIO timings. + * The default is 40 for known PCI systems, 50 otherwise. + * The "idebus=xx" parameter can be used to override this value. + * The actual value to be used is computed/displayed the first time + * through. Drivers should only use this as a last resort. + * + * Returns a guessed speed in MHz. */ + int ide_system_bus_speed (void) { if (!system_bus_speed) { @@ -347,10 +353,15 @@ int ide_system_bus_speed (void) return system_bus_speed; } -/* - * current_capacity() returns the capacity (in sectors) of a drive - * according to its current geometry/LBA settings. +/** + * current_capacity - drive capacity + * @drive: drive to query + * + * Return the current capacity (in sectors) of a drive according to + * its current geometry/LBA settings. Empty removables are reported + * as size zero. */ + sector_t current_capacity (ide_drive_t *drive) { if (!drive->present) @@ -360,9 +371,17 @@ sector_t current_capacity (ide_drive_t *drive) EXPORT_SYMBOL(current_capacity); -/* - * Error reporting, in human readable form (luxurious, but a memory hog). +/** + * ide_dump_status - translate ATA error + * @drive: drive the error occured on + * @msg: information string + * @stat: status byte + * + * Error reporting, in human readable form (luxurious, but a memory hog). + * Combines the drive name, message and status byte to provide a + * user understandable explanation of the device error. */ + u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat) { ide_hwif_t *hwif = HWIF(drive); @@ -371,7 +390,6 @@ u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat) local_irq_set(flags); printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS printk(" { "); if (stat & BUSY_STAT) { printk("Busy "); @@ -385,12 +403,10 @@ u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat) if (stat & ERR_STAT) printk("Error "); } printk("}"); -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { err = hwif->INB(IDE_ERROR_REG); printk("%s: %s: error=0x%02x", drive->name, msg, err); -#if FANCY_STATUS_DUMPS if (drive->media == ide_disk) { printk(" { "); if (err & ABRT_ERR) printk("DriveStatusError "); @@ -434,9 +450,34 @@ u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat) printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector); } } -#endif /* FANCY_STATUS_DUMPS */ printk("\n"); } + { + struct request *rq; + int opcode = 0x100; + + spin_lock(&ide_lock); + rq = NULL; + if (HWGROUP(drive)) + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + goto out; + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + char *args = rq->buffer; + if (args) + opcode = args[0]; + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + } + } + + printk("ide: failed opcode was %x\n", opcode); + } +out: local_irq_restore(flags); return err; } @@ -448,11 +489,17 @@ static int ide_open (struct inode * inode, struct file * filp) return -ENXIO; } +/* + * drives_lock protects the list of drives, drivers_lock the + * list of drivers. Currently nobody takes both at once. + */ + static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED; static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(drivers); -/* Iterator */ +/* Iterator for the driver list. */ + static void *m_start(struct seq_file *m, loff_t *pos) { struct list_head *p; @@ -463,22 +510,26 @@ static void *m_start(struct seq_file *m, loff_t *pos) return list_entry(p, ide_driver_t, drivers); return NULL; } + static void *m_next(struct seq_file *m, void *v, loff_t *pos) { struct list_head *p = ((ide_driver_t *)v)->drivers.next; (*pos)++; return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers); } + static void m_stop(struct seq_file *m, void *v) { spin_unlock(&drivers_lock); } + static int show_driver(struct seq_file *m, void *v) { ide_driver_t *driver = v; seq_printf(m, "%s version %s\n", driver->name, driver->version); return 0; } + struct seq_operations ide_drivers_op = { .start = m_start, .next = m_next, @@ -515,6 +566,7 @@ static struct resource* hwif_request_region(ide_hwif_t *hwif, * MMIO leaves it to the controller driver, * PIO will migrate this way over time. */ + int ide_hwif_request_regions(ide_hwif_t *hwif) { unsigned long addr; @@ -564,6 +616,7 @@ control_region_busy: * importantly our caller should be doing this so we need to * restructure this as a helper function for drivers. */ + void ide_hwif_release_regions(ide_hwif_t *hwif) { u32 i = 0; @@ -581,7 +634,15 @@ void ide_hwif_release_regions(ide_hwif_t *hwif) release_region(hwif->io_ports[i], 1); } -/* restore hwif to a sane state */ +/** + * ide_hwif_restore - restore hwif to template + * @hwif: hwif to update + * @tmp_hwif: template + * + * Restore hwif to a previous state by copying most settngs + * from the template. + */ + static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) { hwif->hwgroup = tmp_hwif->hwgroup; @@ -702,18 +763,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) void ide_unregister(unsigned int index) { ide_drive_t *drive; - ide_hwif_t *hwif, *g, *tmp_hwif; + ide_hwif_t *hwif, *g; + static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */ ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; BUG_ON(index >= MAX_HWIFS); - tmp_hwif = kmalloc(sizeof(*tmp_hwif), GFP_KERNEL|__GFP_NOFAIL); - if (!tmp_hwif) { - printk(KERN_ERR "%s: unable to allocate memory\n", __FUNCTION__); - return; - } - BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); down(&ide_cfg_sem); @@ -860,19 +916,17 @@ void ide_unregister(unsigned int index) } /* copy original settings */ - *tmp_hwif = *hwif; + tmp_hwif = *hwif; /* restore hwif data to pristine status */ init_hwif_data(hwif, index); init_hwif_default(hwif, index); - ide_hwif_restore(hwif, tmp_hwif); + ide_hwif_restore(hwif, &tmp_hwif); abort: spin_unlock_irq(&ide_lock); up(&ide_cfg_sem); - - kfree(tmp_hwif); } EXPORT_SYMBOL(ide_unregister); @@ -931,10 +985,17 @@ void ide_setup_ports ( hw_regs_t *hw, */ } -/* - * Register an IDE interface, specifying exactly the registers etc - * Set init=1 iff calling before probes have taken place. +/** + * ide_register_hw - register IDE interface + * @hw: hardware registers + * @hwifp: pointer to returned hwif + * + * Register an IDE interface, specifying exactly the registers etc. + * Set init=1 iff calling before probes have taken place. + * + * Returns -1 on error. */ + int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) { int index, retry = 1; @@ -1188,6 +1249,15 @@ int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting) return val; } +/** + * ide_spin_wait_hwgroup - wait for group + * @drive: drive in the group + * + * Wait for an IDE device group to go non busy and then return + * holding the ide_lock which guards the hwgroup->busy status + * and right to use it. + */ + int ide_spin_wait_hwgroup (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -1229,6 +1299,7 @@ EXPORT_SYMBOL(ide_spin_wait_hwgroup); * to the driver to change settings, and then wait on a sema for completion. * The current scheme of polling is kludgy, though safe enough. */ + int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) { int i; @@ -1322,22 +1393,14 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) return err; } -int ide_atapi_to_scsi (ide_drive_t *drive, int arg) -{ - if (drive->media == ide_disk) { - drive->scsi = 0; - return 0; - } - - if (DRIVER(drive)->cleanup(drive)) { - drive->scsi = 0; - return 0; - } - - drive->scsi = (u8) arg; - ata_attach(drive); - return 0; -} +/** + * ide_add_generic_settings - generic ide settings + * @drive: drive being configured + * + * Add the generic parts of the system settings to the /proc files and + * ioctls for this IDE device. The caller must not be holding the + * ide_setting_sem. + */ void ide_add_generic_settings (ide_drive_t *drive) { @@ -1353,10 +1416,15 @@ void ide_add_generic_settings (ide_drive_t *drive) ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL); ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); - if (drive->media != ide_disk) - ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi); } +/** + * system_bus_clock - clock guess + * + * External version of the bus clock guess used by very old IDE drivers + * for things like VLB timings. Should not be used. + */ + int system_bus_clock (void) { return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); @@ -1391,6 +1459,22 @@ abort: return 1; } +/** + * ata_attach - attach an ATA/ATAPI device + * @drive: drive to attach + * + * Takes a drive that is as yet not assigned to any midlayer IDE + * driver (or is assigned to the default driver) and figures out + * which driver would like to own it. If nobody claims the drive + * then it is automatically attached to the default driver used for + * unclaimed objects. + * + * A return of zero indicates attachment to a driver, of one + * attachment to the default driver. + * + * Takes drivers_lock. + */ + int ata_attach(ide_drive_t *drive) { struct list_head *p; @@ -2199,6 +2283,20 @@ int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver) EXPORT_SYMBOL(ide_register_subdriver); +/** + * ide_unregister_subdriver - disconnect drive from driver + * @drive: drive to unplug + * + * Disconnect a drive from the driver it was attached to and then + * clean up the various proc files and other objects attached to it. + * + * Takes ide_setting_sem, ide_lock and drives_lock. + * Caller must hold none of the locks. + * + * No locking versus subdriver unload because we are moving to the + * default driver anyway. Wants double checking. + */ + int ide_unregister_subdriver (ide_drive_t *drive) { unsigned long flags; @@ -2234,6 +2332,17 @@ static int ide_drive_remove(struct device * dev) return 0; } +/** + * ide_register_driver - register IDE device driver + * @driver: the IDE device driver + * + * Register a new device driver and then scan the devices + * on the IDE bus in case any should be attached to the + * driver we have just registered. If so attach them. + * + * Takes drivers_lock and drives_lock. + */ + int ide_register_driver(ide_driver_t *driver) { struct list_head list; @@ -2265,6 +2374,17 @@ int ide_register_driver(ide_driver_t *driver) EXPORT_SYMBOL(ide_register_driver); +/** + * ide_unregister_driver - unregister IDE device driver + * @driver: the IDE device driver + * + * Called when a driver module is being unloaded. We reattach any + * devices to whatever driver claims them next (typically the default + * driver). + * + * Takes drivers_lock and called functions will take ide_setting_sem. + */ + void ide_unregister_driver(ide_driver_t *driver) { ide_drive_t *drive; diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile index ad8ae32b8..c0f353e57 100644 --- a/drivers/ide/legacy/Makefile +++ b/drivers/ide/legacy/Makefile @@ -10,6 +10,5 @@ obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o # Last of all obj-$(CONFIG_BLK_DEV_HD) += hd.o -obj-$(CONFIG_BLK_DEV_HD98) += hd98.o EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 3147d9099..dda2a17e0 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -412,12 +412,6 @@ void ide_release(dev_link_t *link) /* FIXME: if this fails we need to queue the cleanup somehow -- need to investigate the required PCMCIA magic */ ide_unregister(info->hd); - /* deal with brain dead IDE resource management */ - request_region(link->io.BasePort1, link->io.NumPorts1, - info->node.dev_name); - if (link->io.NumPorts2) - request_region(link->io.BasePort2, link->io.NumPorts2, - info->node.dev_name); } info->ndev = 0; link->dev = NULL; diff --git a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c index c07d341d1..86219e18f 100644 --- a/drivers/ide/legacy/pdc4030.c +++ b/drivers/ide/legacy/pdc4030.c @@ -354,15 +354,6 @@ read_next: (unsigned long)rq->nr_sectors - nsect); #endif /* DEBUG_READ */ -#ifdef CONFIG_IDE_TASKFILE_IO - task_bio_sectors(drive, rq, nsect, IDE_PIO_IN); - - /* FIXME: can we check status after transfer on pdc4030? */ - /* Complete previously submitted bios. */ - while (rq->bio != rq->cbio) - if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) - return ide_stopped; -#else /* CONFIG_IDE_TASKFILE_IO */ HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); rq->buffer += nsect<<9; rq->sector += nsect; @@ -370,7 +361,6 @@ read_next: rq->nr_sectors -= nsect; if (!rq->current_nr_sectors) DRIVER(drive)->end_request(drive, 1, 0); -#endif /* CONFIG_IDE_TASKFILE_IO */ /* * Now the data has been read in, do the following: @@ -421,12 +411,8 @@ read_next: static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef CONFIG_IDE_TASKFILE_IO - struct request *rq = hwgroup->rq; -#else struct request *rq = &hwgroup->wrq; struct bio *bio = rq->bio; -#endif if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -450,15 +436,10 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive) printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); #endif /* DEBUG_WRITE */ -#ifdef CONFIG_IDE_TASKFILE_IO - /* Complete previously submitted bios. */ - while (rq->bio != rq->cbio) - (void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio)); -#else bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments; rq = hwgroup->rq; DRIVER(drive)->end_request(drive, 1, rq->hard_nr_sectors); -#endif + return ide_stopped; } @@ -466,27 +447,6 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive) * promise_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. */ -#ifdef CONFIG_IDE_TASKFILE_IO -static void promise_multwrite (ide_drive_t *drive, unsigned int msect) -{ - struct request* rq = HWGROUP(drive)->rq; - unsigned int nsect; - - rq->errors = 0; - do { - nsect = rq->current_nr_sectors; - if (nsect > msect) - nsect = msect; - - task_bio_sectors(drive, rq, nsect, IDE_PIO_OUT); - - if (!rq->nr_sectors) - msect = 0; - else - msect -= nsect; - } while (msect); -} -#else /* CONFIG_IDE_TASKFILE_IO */ static void promise_multwrite (ide_drive_t *drive, unsigned int mcount) { ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -537,7 +497,6 @@ static void promise_multwrite (ide_drive_t *drive, unsigned int mcount) taskfile_output_data(drive, buffer, nsect<<7); } while (mcount); } -#endif /* * promise_write_pollfunc() is the handler for disk write completion polling. @@ -545,12 +504,8 @@ static void promise_multwrite (ide_drive_t *drive, unsigned int mcount) static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef CONFIG_IDE_TASKFILE_IO - struct request *rq = hwgroup->rq; -#else struct request *rq = &hwgroup->wrq; struct bio *bio = rq->bio; -#endif if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -564,19 +519,11 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: write timed-out!\n",drive->name); -#ifndef CONFIG_IDE_TASKFILE_IO bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments; -#endif return DRIVER(drive)->error(drive, "write timeout", HWIF(drive)->INB(IDE_STATUS_REG)); } -#ifdef CONFIG_IDE_TASKFILE_IO - /* Complete previously submitted bios. */ - while (rq->bio != rq->cbio) - (void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio)); -#endif - /* * Now write out last 4 sectors and poll for not BUSY */ @@ -602,11 +549,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) static ide_startstop_t promise_write (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef CONFIG_IDE_TASKFILE_IO - struct request *rq = hwgroup->rq; -#else struct request *rq = &hwgroup->wrq; -#endif #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: %s: sectors(%lu-%lu)\n", @@ -654,39 +597,14 @@ static ide_startstop_t promise_write (ide_drive_t *drive) * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */ -#ifndef CONFIG_IDE_TASKFILE_IO ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; unsigned long timeout; u8 stat = 0; -#else -static ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) -{ - struct request *rq = HWGROUP(drive)->rq; - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - ide_startstop_t startstop; - unsigned long timeout; - u8 stat = 0; - - if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(drive, 0); - HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG); - HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); - /* refers to number of sectors to transfer */ - HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG); - /* refers to sector offset or start sector */ - HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); - HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); - HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG); - HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG); -#endif if (rq_data_dir(rq) == READ) { -#ifndef CONFIG_IDE_TASKFILE_IO HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG); -#endif /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -722,9 +640,7 @@ static ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) "waiting - Odd!\n", drive->name); return ide_stopped; } else { -#ifndef CONFIG_IDE_TASKFILE_IO HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG); -#endif if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing " @@ -733,9 +649,7 @@ static ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) } if (!drive->unmask) local_irq_disable(); -#ifndef CONFIG_IDE_TASKFILE_IO HWGROUP(drive)->wrq = *rq; /* scratchpad */ -#endif return promise_write(drive); } } @@ -749,14 +663,9 @@ static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, */ ide_hwif_t *hwif = HWIF(drive); int drive_number = (hwif->channel << 1) + drive->select.b.unit; -#ifdef CONFIG_IDE_TASKFILE_IO - struct hd_drive_task_hdr taskfile; - ide_task_t args; -#endif BUG_ON(rq->nr_sectors > 127); -#ifndef CONFIG_IDE_TASKFILE_IO if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); hwif->OUTB(drive_number, IDE_FEATURE_REG); @@ -767,27 +676,4 @@ static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); return do_pdc4030_io(drive, rq); -#else /* !CONFIG_IDE_TASKFILE_IO */ - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - - taskfile.feature = drive_number; - taskfile.sector_count = rq->nr_sectors; - taskfile.sector_number = block; - taskfile.low_cylinder = (block>>=8); - taskfile.high_cylinder = (block>>=8); - taskfile.device_head = ((block>>8)&0x0f)|drive->select.all; - taskfile.command = (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE; - - memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); - memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr)); - /* - * Setup the bits of args that we do need. - * Note that we don't use the generic interrupt handlers. - */ - args.handler = NULL; - args.rq = (struct request *) rq; - rq->special = (ide_task_t *)&args; - - return do_pdc4030_io(drive, &args); -#endif /* !CONFIG_IDE_TASKFILE_IO */ } diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h index 1557a47ff..603018e44 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/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index b032d2459..d80959488 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -29,8 +29,6 @@ static u8 aec62xx_proc = 0; static struct pci_dev *aec_devs[AEC_MAX_DEVS]; static int n_aec_devs; -#undef DEBUG_AEC_REGS - static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; @@ -44,9 +42,6 @@ static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) struct pci_dev *dev = aec_devs[i]; unsigned long iobase = pci_resource_start(dev, 4); u8 c0 = 0, c1 = 0, art = 0; -#ifdef DEBUG_AEC_REGS - u8 uart = 0; -#endif /* DEBUG_AEC_REGS */ c0 = inb(iobase + 0x02); c1 = inb(iobase + 0x0a); @@ -83,24 +78,6 @@ static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) p += sprintf(p, " %s(%s)\n", (c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO", (art&0x80)?"2":(art&0x40)?"1":"0"); -#ifdef DEBUG_AEC_REGS - (void) pci_read_config_byte(dev, 0x40, &art); - p += sprintf(p, "Active: 0x%02x", art); - (void) pci_read_config_byte(dev, 0x42, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x44, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x46, &art); - p += sprintf(p, " 0x%02x\n", art); - (void) pci_read_config_byte(dev, 0x41, &art); - p += sprintf(p, "Recovery: 0x%02x", art); - (void) pci_read_config_byte(dev, 0x43, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x45, &art); - p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(dev, 0x47, &art); - p += sprintf(p, " 0x%02x\n", art); -#endif /* DEBUG_AEC_REGS */ } else { /* * case PCI_DEVICE_ID_ARTOP_ATP860: @@ -146,28 +123,6 @@ static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) ((art&0x30)==0x30)?"2": ((art&0x20)==0x20)?"1": ((art&0x10)==0x10)?"0":"?"); -#ifdef DEBUG_AEC_REGS - (void) pci_read_config_byte(dev, 0x40, &art); - p += sprintf(p, "Active: 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x41, &art); - p += sprintf(p, " 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x42, &art); - p += sprintf(p, " 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x43, &art); - p += sprintf(p, " 0x%02x\n", HIGH_4(art)); - (void) pci_read_config_byte(dev, 0x40, &art); - p += sprintf(p, "Recovery: 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x41, &art); - p += sprintf(p, " 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x42, &art); - p += sprintf(p, " 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x43, &art); - p += sprintf(p, " 0x%02x\n", LOW_4(art)); - (void) pci_read_config_byte(dev, 0x49, &uart); - p += sprintf(p, "reg49h = 0x%02x ", uart); - (void) pci_read_config_byte(dev, 0x4a, &uart); - p += sprintf(p, "reg4ah = 0x%02x\n", uart); -#endif /* DEBUG_AEC_REGS */ } } /* p - buffer must be less than 4k! */ @@ -240,6 +195,7 @@ static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed) unsigned long flags; local_irq_save(flags); + /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */ pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev)); SPLIT_BYTE(tmp0,tmp1,tmp2); @@ -268,6 +224,7 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed) unsigned long flags; local_irq_save(flags); + /* high 4-bits: Active, low 4-bits: Recovery */ pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev)); pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); @@ -540,7 +497,7 @@ static struct pci_device_id aec62xx_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); static struct pci_driver driver = { - .name = "AEC62xx IDE", + .name = "AEC62xx_IDE", .id_table = aec62xx_pci_tbl, .probe = aec62xx_init_one, }; diff --git a/drivers/ide/pci/aec62xx.h b/drivers/ide/pci/aec62xx.h index 3f272752c..460d7e365 100644 --- a/drivers/ide/pci/aec62xx.h +++ b/drivers/ide/pci/aec62xx.h @@ -53,13 +53,6 @@ struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { { 0, 0x00, 0x00 } }; - -#ifndef HIGH_4 -#define HIGH_4(H) ((H)=(H>>4)) -#endif -#ifndef LOW_4 -#define LOW_4(L) ((L)=(L-((L>>4)<<4))) -#endif #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 2a343679a..82a449dc8 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -752,8 +752,8 @@ static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif) hwif->tuneproc = &ali15x3_tune_drive; hwif->speedproc = &ali15x3_tune_chipset; - /* Don't use LBA48 on ALi devices before rev 0xC5 */ - hwif->no_lba48 = (m5229_revision <= 0xC4) ? 1 : 0; + /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ + hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0; if (!hwif->dma_base) { hwif->drives[0].autotune = 1; @@ -893,7 +893,7 @@ static struct pci_device_id alim15x3_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); static struct pci_driver driver = { - .name = "ALI15x3 IDE", + .name = "ALI15x3_IDE", .id_table = alim15x3_pci_tbl, .probe = alim15x3_init_one, }; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 30bdcb3ec..3967254ce 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -416,6 +416,9 @@ static void __init init_hwif_amd74xx(ide_hwif_t *hwif) { int i; + if (!hwif->irq) + hwif->irq = hwif->channel ? 15 : 14; + hwif->autodma = 0; hwif->tuneproc = &amd74xx_tune_drive; @@ -520,7 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); static struct pci_driver driver = { - .name = "AMD IDE", + .name = "AMD_IDE", .id_table = amd74xx_pci_tbl, .probe = amd74xx_probe, }; diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index bd3708568..5a65d5dc1 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -490,7 +490,7 @@ static struct pci_device_id atiixp_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); static struct pci_driver driver = { - .name = "ATIIXP IDE", + .name = "ATIIXP_IDE", .id_table = atiixp_pci_tbl, .probe = atiixp_init_one, }; diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 0eac8ee64..92a2b7cae 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -101,6 +101,8 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ #define CMD640_PREFETCH_MASKS 1 +//#define CMD640_DUMP_REGS + #include #include #include @@ -748,7 +750,7 @@ int __init ide_probe_for_cmd640x (void) put_cmd640_reg(0x5b, 0); #ifdef CMD640_DUMP_REGS - CMD640_DUMP_REGS; + cmd640_dump_regs(); #endif /* @@ -870,7 +872,7 @@ int __init ide_probe_for_cmd640x (void) } #ifdef CMD640_DUMP_REGS - CMD640_DUMP_REGS; + cmd640_dump_regs(); #endif return 1; } diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 06b00a3c3..abea997dc 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -38,8 +38,6 @@ static u8 cmd64x_proc = 0; static struct pci_dev *cmd_devs[CMD_MAX_DEVS]; static int n_cmd_devs; -#undef DEBUG_CMD_REGS - static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) { char *p = buf; @@ -49,9 +47,6 @@ static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) u8 reg72 = 0, reg73 = 0; /* primary */ u8 reg7a = 0, reg7b = 0; /* secondary */ u8 reg50 = 0, reg71 = 0; /* extra */ -#ifdef DEBUG_CMD_REGS - u8 hi_byte = 0, lo_byte = 0; -#endif /* DEBUG_CMD_REGS */ p += sprintf(p, "\nController: %d\n", index); p += sprintf(p, "CMD%x Chipset.\n", dev->device); @@ -127,18 +122,6 @@ static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled", (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled"); -#ifdef DEBUG_CMD_REGS - SPLIT_BYTE(reg50, hi_byte, lo_byte); - p += sprintf(p, "CFR = 0x%02x, HI = 0x%02x, " - "LOW = 0x%02x\n", reg50, hi_byte, lo_byte); - SPLIT_BYTE(reg57, hi_byte, lo_byte); - p += sprintf(p, "ARTTIM23 = 0x%02x, HI = 0x%02x, " - "LOW = 0x%02x\n", reg57, hi_byte, lo_byte); - SPLIT_BYTE(reg71, hi_byte, lo_byte); - p += sprintf(p, "MRDMODE = 0x%02x, HI = 0x%02x, " - "LOW = 0x%02x\n", reg71, hi_byte, lo_byte); -#endif /* DEBUG_CMD_REGS */ - return (char *)p; } @@ -760,7 +743,7 @@ static struct pci_device_id cmd64x_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl); static struct pci_driver driver = { - .name = "CMD64x IDE", + .name = "CMD64x_IDE", .id_table = cmd64x_pci_tbl, .probe = cmd64x_init_one, }; diff --git a/drivers/ide/pci/cmd64x.h b/drivers/ide/pci/cmd64x.h index f5dde235a..78490275d 100644 --- a/drivers/ide/pci/cmd64x.h +++ b/drivers/ide/pci/cmd64x.h @@ -15,10 +15,6 @@ #define cmdprintk(x...) #endif -#ifndef SPLIT_BYTE -#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) -#endif - /* * CMD64x specific registers definition. */ diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 5882693d0..e65dec73c 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -290,7 +290,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic return 1; } pci_set_master(dev); - pci_set_dma_mask(dev, 0xFFFFFFFF); + if (pci_set_dma_mask(dev, 0xFFFFFFFF)) { + printk(KERN_WARNING "cs5520: No suitable DMA available.\n"); + return -ENODEV; + } init_chipset_cs5520(dev, d->name); index.all = 0xf0f0; @@ -319,7 +322,7 @@ static struct pci_device_id cs5520_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl); static struct pci_driver driver = { - .name = "CyrixIDE", + .name = "Cyrix_IDE", .id_table = cs5520_pci_tbl, .probe = cs5520_init_one, }; diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index fe840cbe0..83bfe92d2 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -444,7 +444,7 @@ static struct pci_device_id cy82c693_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); static struct pci_driver driver = { - .name = "Cypress IDE", + .name = "Cypress_IDE", .id_table = cy82c693_pci_tbl, .probe = cy82c693_init_one, }; diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 2150a18a8..a4154e702 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -138,7 +138,7 @@ static struct pci_device_id generic_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, generic_pci_tbl); static struct pci_driver driver = { - .name = "PCI IDE", + .name = "PCI_IDE", .id_table = generic_pci_tbl, .probe = generic_init_one, }; diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index f9c9ab664..8eb72f446 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -44,65 +44,6 @@ #include "hpt34x.h" -#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) -#include -#include - -static u8 hpt34x_proc = 0; - -#define HPT34X_MAX_DEVS 8 -static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS]; -static int n_hpt34x_devs; - -static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - int i, len; - - p += sprintf(p, "\n " - "HPT34X Chipset.\n"); - for (i = 0; i < n_hpt34x_devs; i++) { - struct pci_dev *dev = hpt34x_devs[i]; - unsigned long bibma = pci_resource_start(dev, 4); - u8 c0 = 0, c1 = 0; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((u16)bibma + 0x02); - c1 = inb_p((u16)bibma + 0x0a); - p += sprintf(p, "\nController: %d\n", i); - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, " %sabled " - " %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 " - "-------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s" - " %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - } - p += sprintf(p, "\n"); - - /* p - buffer must be less than 4k! */ - len = (p - buffer) - offset; - *addr = buffer + offset; - - return len > count ? count : len; -} -#endif /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */ - static u8 hpt34x_ratemask (ide_drive_t *drive) { return 1; @@ -277,15 +218,6 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha local_irq_restore(flags); -#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) - hpt34x_devs[n_hpt34x_devs++] = dev; - - if (!hpt34x_proc) { - hpt34x_proc = 1; - ide_pci_create_host_proc("hpt34x", hpt34x_get_info); - } -#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ - return dev->irq; } @@ -339,7 +271,7 @@ static struct pci_device_id hpt34x_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl); static struct pci_driver driver = { - .name = "HPT34x IDE", + .name = "HPT34x_IDE", .id_table = hpt34x_pci_tbl, .probe = hpt34x_init_one, }; diff --git a/drivers/ide/pci/hpt34x.h b/drivers/ide/pci/hpt34x.h index 465f56715..d1a840034 100644 --- a/drivers/ide/pci/hpt34x.h +++ b/drivers/ide/pci/hpt34x.h @@ -11,8 +11,6 @@ #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif -#undef DISPLAY_HPT34X_TIMINGS - static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *); static void init_hwif_hpt34x(ide_hwif_t *); diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 5f5bc3b6e..d1e8adbe7 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -777,9 +777,6 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state) u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40; u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53; - if (!hwif) - return -EINVAL; - // hwif->bus_state = state; pci_read_config_byte(dev, 0x59, ®59h); @@ -813,9 +810,6 @@ static int hpt370_busproc(ide_drive_t * drive, int state) u8 tristate = 0, resetmask = 0, bus_reg = 0; u16 tri_reg; - if (!hwif) - return -EINVAL; - hwif->bus_state = state; if (hwif->channel) { @@ -958,7 +952,7 @@ static int __devinit init_hpt37x(struct pci_dev *dev) /* Unsupported */ } else if (pll == F_LOW_PCI_50) { if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, NULL); + pci_set_drvdata(dev, (void *) fifty_base_hpt370a); else if (hpt_minimum_revision(dev,5)) pci_set_drvdata(dev, (void *) fifty_base_hpt372); else if (hpt_minimum_revision(dev,4)) @@ -991,11 +985,6 @@ static int __devinit init_hpt37x(struct pci_dev *dev) if (pci_get_drvdata(dev)) goto init_hpt37X_done; - if (hpt_minimum_revision(dev,8)) - { - printk(KERN_ERR "HPT374: Only 33MHz PCI timings are supported.\n"); - return -EOPNOTSUPP; - } /* * adjust PLL based upon PCI clock, enable it, and wait for * stabilization. @@ -1403,7 +1392,7 @@ static struct pci_device_id hpt366_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); static struct pci_driver driver = { - .name = "HPT366 IDE", + .name = "HPT366_IDE", .id_table = hpt366_pci_tbl, .probe = hpt366_init_one, }; diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c index b65ce0877..3a163fa85 100644 --- a/drivers/ide/pci/it8172.c +++ b/drivers/ide/pci/it8172.c @@ -302,7 +302,7 @@ static struct pci_device_id it8172_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); static struct pci_driver driver = { - .name = "IT8172IDE", + .name = "IT8172_IDE", .id_table = it8172_pci_tbl, .probe = it8172_init_one, }; diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index a5b6e7e5c..44f782492 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -236,7 +236,7 @@ static struct pci_device_id ns87415_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); static struct pci_driver driver = { - .name = "NS87415IDE", + .name = "NS87415_IDE", .id_table = ns87415_pci_tbl, .probe = ns87415_init_one, }; diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 3ca7db7d5..ab76641ae 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -367,7 +367,7 @@ static struct pci_device_id opti621_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); static struct pci_driver driver = { - .name = "Opti621 IDE", + .name = "Opti621_IDE", .id_table = opti621_pci_tbl, .probe = opti621_init_one, }; diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index f493b29ce..8f635922a 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -531,7 +531,7 @@ static struct pci_device_id pdc202new_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); static struct pci_driver driver = { - .name = "Promise IDE", + .name = "Promise_IDE", .id_table = pdc202new_pci_tbl, .probe = pdc202new_init_one, }; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 3b4379c63..651879a49 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -314,17 +314,6 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); } -#if PDC202XX_DECODE_REGISTER_INFO - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - pci_read_config_byte(dev, (drive_pci)|0x03, &DP); - - decode_registers(REG_A, AP); - decode_registers(REG_B, BP); - decode_registers(REG_C, CP); - decode_registers(REG_D, DP); -#endif /* PDC202XX_DECODE_REGISTER_INFO */ #if PDC202XX_DEBUG_DRIVE_INFO printk(KERN_DEBUG "%s: %s drive%d 0x%08x ", drive->name, ide_xfer_verbose(speed), @@ -905,7 +894,7 @@ static struct pci_device_id pdc202xx_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl); static struct pci_driver driver = { - .name = "Promise Old IDE", + .name = "Promise_Old_IDE", .id_table = pdc202xx_pci_tbl, .probe = pdc202xx_init_one, }; diff --git a/drivers/ide/pci/pdc202xx_old.h b/drivers/ide/pci/pdc202xx_old.h index 95ea2c8aa..6afebd1d2 100644 --- a/drivers/ide/pci/pdc202xx_old.h +++ b/drivers/ide/pci/pdc202xx_old.h @@ -10,7 +10,6 @@ #endif #define PDC202XX_DEBUG_DRIVE_INFO 0 -#define PDC202XX_DECODE_REGISTER_INFO 0 static const char *pdc_quirk_drives[] = { "QUANTUM FIREBALLlct08 08", @@ -99,76 +98,6 @@ static inline u8 *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable) #define MC1 0x02 /* DMA"C" timing */ #define MC0 0x01 /* DMA"C" timing */ -#if PDC202XX_DECODE_REGISTER_INFO - -#define REG_A 0x01 -#define REG_B 0x02 -#define REG_C 0x04 -#define REG_D 0x08 - -static void decode_registers (u8 registers, u8 value) -{ - u8 bit = 0, bit1 = 0, bit2 = 0; - - switch(registers) { - case REG_A: - bit2 = 0; - printk("A Register "); - if (value & 0x80) printk("SYNC_IN "); - if (value & 0x40) printk("ERRDY_EN "); - if (value & 0x20) printk("IORDY_EN "); - if (value & 0x10) printk("PREFETCH_EN "); - if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; } - if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; } - if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; } - if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; } - printk("PIO(A) = %d ", bit2); - break; - case REG_B: - bit1 = 0;bit2 = 0; - printk("B Register "); - if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; } - if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; } - if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; } - printk("DMA(B) = %d ", bit1 >> 5); - if (value & 0x10) printk("PIO_FORCED/PB4 "); - if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; } - if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; } - if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; } - if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; } - printk("PIO(B) = %d ", bit2); - break; - case REG_C: - bit2 = 0; - printk("C Register "); - if (value & 0x80) printk("DMARQp "); - if (value & 0x40) printk("IORDYp "); - if (value & 0x20) printk("DMAR_EN "); - if (value & 0x10) printk("DMAW_EN "); - - if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; } - if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; } - if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; } - if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; } - printk("DMA(C) = %d ", bit2); - break; - case REG_D: - printk("D Register "); - break; - default: - return; - } - printk("\n %s ", (registers & REG_D) ? "DP" : - (registers & REG_C) ? "CP" : - (registers & REG_B) ? "BP" : - (registers & REG_A) ? "AP" : "ERROR"); - for (bit=128;bit>0;bit/=2) - printk("%s", (value & bit) ? "1" : "0"); - printk("\n"); -} - -#endif /* PDC202XX_DECODE_REGISTER_INFO */ - #define DISPLAY_PDC202XX_TIMINGS static void init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d); diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 26719f2c7..c4161a5f5 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -561,36 +561,31 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive) drive->init_speed = 0; if ((id->capability & 1) && drive->autodma) { + /* Consult the list of known "bad" drives */ if (__ide_dma_bad_drive(drive)) goto fast_ata_pio; - if (id->field_valid & 4) { - if (id->dma_ultra & hwif->ultra_mask) { - /* Force if Capable UltraDMA */ - if ((id->field_valid & 2) && - (!piix_config_drive_for_dma(drive))) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & hwif->mwdma_mask) || - (id->dma_1word & hwif->swdma_mask)) { - /* Force if Capable regular DMA modes */ - if (!piix_config_drive_for_dma(drive)) - goto no_dma_set; - } - } else if (__ide_dma_good_drive(drive) && - (id->eide_dma_time < 150)) { - /* Consult the list of known "good" drives */ - if (!piix_config_drive_for_dma(drive)) - goto no_dma_set; - } else { - goto fast_ata_pio; + + /** + * Try to turn DMA on if: + * - UDMA or EIDE modes are supported or + * - drive is a known "good" drive + * + * Checks for best mode supported are down later by + * piix_config_drive_for_dma() -> ide_dma_speed() + */ + if ((id->field_valid & (4 | 2)) || + (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)) { + if (piix_config_drive_for_dma(drive)) + return hwif->ide_dma_on(drive); } - return hwif->ide_dma_on(drive); + + /* For some reason DMA wasn't turned on, so try PIO. */ + goto fast_ata_pio; + } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: -no_dma_set: + /* Find best PIO mode. */ hwif->tuneproc(drive, 255); return hwif->ide_dma_off_quietly(drive); } @@ -803,7 +798,7 @@ static struct pci_device_id piix_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, piix_pci_tbl); static struct pci_driver driver = { - .name = "PIIX IDE", + .name = "PIIX_IDE", .id_table = piix_pci_tbl, .probe = piix_init_one, }; diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c index 3405e6a1b..8281e4fa6 100644 --- a/drivers/ide/pci/rz1000.c +++ b/drivers/ide/pci/rz1000.c @@ -74,7 +74,7 @@ static struct pci_device_id rz1000_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); static struct pci_driver driver = { - .name = "RZ1000 IDE", + .name = "RZ1000_IDE", .id_table = rz1000_pci_tbl, .probe = rz1000_init_one, }; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 902408d18..4cd5d013f 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -565,7 +565,7 @@ static struct pci_device_id sc1200_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl); static struct pci_driver driver = { - .name = "SC1200 IDE", + .name = "SC1200_IDE", .id_table = sc1200_pci_tbl, .probe = sc1200_init_one, .suspend = sc1200_suspend, diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index 27d907c9b..510ca140c 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -812,7 +812,7 @@ static struct pci_device_id svwks_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); static struct pci_driver driver = { - .name = "Serverworks IDE", + .name = "Serverworks_IDE", .id_table = svwks_pci_tbl, .probe = svwks_init_one, #if 0 /* FIXME: implement */ diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 0187aafac..6a3d79b29 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -570,7 +570,6 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) use_pio_instead: pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); - hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */ } @@ -702,6 +701,10 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) hwif->name, d->name); probe_hwif_init(hwif); + + /* Create /proc/ide entries */ + create_proc_ide_interfaces(); + return 0; } @@ -782,7 +785,7 @@ static struct pci_device_id sgiioc4_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, sgiioc4_pci_tbl); static struct pci_driver driver = { - .name = "SGI-IOC4 IDE", + .name = "SGI-IOC4_IDE", .id_table = sgiioc4_pci_tbl, .probe = sgiioc4_init_one, }; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 91b039826..6c874989b 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -727,8 +727,7 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) unsigned long bar5 = pci_resource_start(dev, 5); unsigned long barsize = pci_resource_len(dev, 5); u8 tmpbyte = 0; - unsigned long addr; - void *ioaddr; + void __iomem *ioaddr; /* * Drop back to PIO if we can't map the mmio. Some @@ -751,22 +750,21 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) } pci_set_master(dev); - pci_set_drvdata(dev, ioaddr); - addr = (unsigned long) ioaddr; + pci_set_drvdata(dev, (void *) ioaddr); if (pdev_is_sata(dev)) { - writel(0, addr + 0x148); - writel(0, addr + 0x1C8); + writel(0, ioaddr + 0x148); + writel(0, ioaddr + 0x1C8); } - writeb(0, addr + 0xB4); - writeb(0, addr + 0xF4); - tmpbyte = readb(addr + 0x4A); + writeb(0, ioaddr + 0xB4); + writeb(0, ioaddr + 0xF4); + tmpbyte = readb(ioaddr + 0x4A); switch(tmpbyte & 0x30) { case 0x00: /* In 100 MHz clocking, try and switch to 133 */ - writeb(tmpbyte|0x10, addr + 0x4A); + writeb(tmpbyte|0x10, ioaddr + 0x4A); break; case 0x10: /* On 133Mhz clocking */ @@ -777,29 +775,29 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) case 0x30: /* Clocking is disabled */ /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, addr + 0x4A); + writeb(tmpbyte & ~0x20, ioaddr + 0x4A); break; } - writeb( 0x72, addr + 0xA1); - writew( 0x328A, addr + 0xA2); - writel(0x62DD62DD, addr + 0xA4); - writel(0x43924392, addr + 0xA8); - writel(0x40094009, addr + 0xAC); - writeb( 0x72, addr + 0xE1); - writew( 0x328A, addr + 0xE2); - writel(0x62DD62DD, addr + 0xE4); - writel(0x43924392, addr + 0xE8); - writel(0x40094009, addr + 0xEC); + writeb( 0x72, ioaddr + 0xA1); + writew( 0x328A, ioaddr + 0xA2); + writel(0x62DD62DD, ioaddr + 0xA4); + writel(0x43924392, ioaddr + 0xA8); + writel(0x40094009, ioaddr + 0xAC); + writeb( 0x72, ioaddr + 0xE1); + writew( 0x328A, ioaddr + 0xE2); + writel(0x62DD62DD, ioaddr + 0xE4); + writel(0x43924392, ioaddr + 0xE8); + writel(0x40094009, ioaddr + 0xEC); if (pdev_is_sata(dev)) { - writel(0xFFFF0000, addr + 0x108); - writel(0xFFFF0000, addr + 0x188); - writel(0x00680000, addr + 0x148); - writel(0x00680000, addr + 0x1C8); + writel(0xFFFF0000, ioaddr + 0x108); + writel(0xFFFF0000, ioaddr + 0x188); + writel(0x00680000, ioaddr + 0x148); + writel(0x00680000, ioaddr + 0x1C8); } - tmpbyte = readb(addr + 0x4A); + tmpbyte = readb(ioaddr + 0x4A); proc_reports_siimage(dev, (tmpbyte>>4), name); return 1; @@ -1137,7 +1135,7 @@ static struct pci_device_id siimage_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); static struct pci_driver driver = { - .name = "SiI IDE", + .name = "SiI_IDE", .id_table = siimage_pci_tbl, .probe = siimage_init_one, }; diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index d06b1fd8c..964f80604 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -788,6 +788,15 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char if (trueid == 0x5518) { printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); chipset_family = ATA_133; + + /* Check for 5513 compability mapping + * We must use this, else the port enabled code will fail, + * as it expects the enablebits at 0x4a. + */ + if ((idemisc & 0x40000000) == 0) { + pci_write_config_dword(dev, 0x54, idemisc | 0x40000000); + printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n"); + } } } @@ -963,12 +972,13 @@ static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_devi static struct pci_device_id sis5513_pci_tbl[] = { { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5518, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl); static struct pci_driver driver = { - .name = "SIS IDE", + .name = "SIS_IDE", .id_table = sis5513_pci_tbl, .probe = sis5513_init_one, }; diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 38bd8077b..563c44c7d 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -503,7 +503,7 @@ static struct pci_device_id sl82c105_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl); static struct pci_driver driver = { - .name = "W82C105 IDE", + .name = "W82C105_IDE", .id_table = sl82c105_pci_tbl, .probe = sl82c105_init_one, }; diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 1a0183d1b..5a82a5fba 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -387,7 +387,7 @@ static struct pci_device_id slc90e66_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl); static struct pci_driver driver = { - .name = "SLC90e66 IDE", + .name = "SLC90e66_IDE", .id_table = slc90e66_pci_tbl, .probe = slc90e66_init_one, }; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 52e088e25..eca0772f2 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -41,57 +41,6 @@ #include #include -static struct pci_dev *triflex_dev; - -#ifdef CONFIG_PROC_FS -static int triflex_get_info(char *buf, char **addr, off_t offset, int count) -{ - char *p = buf; - int len; - - struct pci_dev *dev = triflex_dev; - unsigned long bibma = pci_resource_start(dev, 4); - u8 c0 = 0, c1 = 0; - u32 pri_timing, sec_timing; - - p += sprintf(p, "\n Compaq Triflex Chipset\n"); - - pci_read_config_dword(dev, 0x70, &pri_timing); - pci_read_config_dword(dev, 0x74, &sec_timing); - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb((unsigned short)bibma + 0x02); - c1 = inb((unsigned short)bibma + 0x0a); - - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, " %sabled " - " %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 " - "-------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s " - " %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - - len = (p - buf) - offset; - *addr = buf + offset; - - return len > count ? count : len; -} -#endif - static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); @@ -206,18 +155,8 @@ static void __init init_hwif_triflex(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static unsigned int __init init_chipset_triflex(struct pci_dev *dev, - const char *name) -{ -#ifdef CONFIG_PROC_FS - ide_pci_create_host_proc("triflex", triflex_get_info); -#endif - return 0; -} - static ide_pci_device_t triflex_device __devinitdata = { .name = "TRIFLEX", - .init_chipset = init_chipset_triflex, .init_hwif = init_hwif_triflex, .channels = 2, .autodma = AUTODMA, @@ -229,7 +168,6 @@ static int __devinit triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) { ide_setup_pci_device(dev, &triflex_device); - triflex_dev = dev; return 0; } @@ -242,7 +180,7 @@ static struct pci_device_id triflex_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); static struct pci_driver driver = { - .name = "TRIFLEX IDE", + .name = "TRIFLEX_IDE", .id_table = triflex_pci_tbl, .probe = triflex_init_one, }; diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index d4c753930..bb7de7a96 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -408,7 +408,7 @@ static struct pci_device_id trm290_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, trm290_pci_tbl); static struct pci_driver driver = { - .name = "TRM290 IDE", + .name = "TRM290_IDE", .id_table = trm290_pci_tbl, .probe = trm290_init_one, }; diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 9aa563300..c83d5e5e8 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -632,7 +632,7 @@ static struct pci_device_id via_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, via_pci_tbl); static struct pci_driver driver = { - .name = "VIA IDE", + .name = "VIA_IDE", .id_table = via_pci_tbl, .probe = via_init_one, }; diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 7030168e6..3625e38a7 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -62,10 +62,10 @@ typedef struct pmac_ide_hwif { int irq; int kind; int aapl_bus_id; - int cable_80 : 1; - int mediabay : 1; - int broken_dma : 1; - int broken_dma_warn : 1; + unsigned cable_80 : 1; + unsigned mediabay : 1; + unsigned broken_dma : 1; + unsigned broken_dma_warn : 1; struct device_node* node; struct macio_dev *mdev; u32 timings[4]; @@ -75,7 +75,7 @@ typedef struct pmac_ide_hwif { * beeing done by the generic code about the kind of dma controller * and format of the dma table. This will have to be fixed though. */ - volatile struct dbdma_regs* dma_regs; + volatile struct dbdma_regs __iomem * dma_regs; struct dbdma_cmd* dma_table_cpu; dma_addr_t dma_table_dma; struct scatterlist* sg_table; @@ -497,6 +497,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw, *irq = pmac_ide[ix].irq; } +#define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(x))) + /* * Apply the timings of the proper unit (master/slave) to the shared * timing register when selecting that unit. This version is for @@ -511,12 +513,10 @@ pmac_ide_selectproc(ide_drive_t *drive) return; if (drive->select.b.unit & 0x01) - writel(pmif->timings[1], - (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); + writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG)); else - writel(pmif->timings[0], - (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); - (void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); + writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG)); + (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } /* @@ -533,17 +533,13 @@ pmac_ide_kauai_selectproc(ide_drive_t *drive) return; if (drive->select.b.unit & 0x01) { - writel(pmif->timings[1], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)); - writel(pmif->timings[3], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG)); + writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); + writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); } else { - writel(pmif->timings[0], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)); - writel(pmif->timings[2], - (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG)); + writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); + writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); } - (void)readl((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)); + (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); } /* @@ -568,8 +564,8 @@ pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port) { u32 tmp; - writeb(value, port); - tmp = readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)); + writeb(value, (void __iomem *) port); + tmp = readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } /* @@ -792,7 +788,7 @@ static int __pmac set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, u8 speed, int drive_cycle_time) { - int cycleTime, accessTime, recTime; + int cycleTime, accessTime = 0, recTime = 0; unsigned accessTicks, recTicks; struct mdma_timings_t* tm = NULL; int i; @@ -1281,7 +1277,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) static int __devinit pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) { - unsigned long base, regbase; + void __iomem *base; + unsigned long regbase; int irq; ide_hwif_t *hwif; pmac_ide_hwif_t *pmif; @@ -1324,8 +1321,8 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) } else irq = macio_irq(mdev, 0); - base = (unsigned long)ioremap(macio_resource_start(mdev, 0), 0x400); - regbase = base; + base = ioremap(macio_resource_start(mdev, 0), 0x400); + regbase = (unsigned long) base; hwif->pci_dev = mdev->bus->pdev; hwif->gendev.parent = &mdev->ofdev.dev; @@ -1339,8 +1336,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) if (macio_request_resource(mdev, 1, "ide-pmac (dma)")) printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i); else - pmif->dma_regs = (volatile struct dbdma_regs*) - ioremap(macio_resource_start(mdev, 1), 0x1000); + pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000); } else pmif->dma_regs = NULL; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -1350,9 +1346,9 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) if (rc != 0) { /* The inteface is released to the common IDE layer */ dev_set_drvdata(&mdev->ofdev.dev, NULL); - iounmap((void *)base); + iounmap(base); if (pmif->dma_regs) - iounmap((void *)pmif->dma_regs); + iounmap(pmif->dma_regs); memset(pmif, 0, sizeof(*pmif)); macio_release_resource(mdev, 0); if (pmif->dma_regs) @@ -1401,7 +1397,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) ide_hwif_t *hwif; struct device_node *np; pmac_ide_hwif_t *pmif; - unsigned long base; + void __iomem *base; unsigned long rbase, rlen; int i, rc; @@ -1444,10 +1440,10 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) rbase = pci_resource_start(pdev, 0); rlen = pci_resource_len(pdev, 0); - base = (unsigned long) ioremap(rbase, rlen); - pmif->regbase = base + 0x2000; + base = ioremap(rbase, rlen); + pmif->regbase = (unsigned long) base + 0x2000; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - pmif->dma_regs = (volatile struct dbdma_regs*)(base + 0x1000); + pmif->dma_regs = base + 0x1000; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ /* We use the OF node irq mapping */ @@ -1462,7 +1458,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) if (rc != 0) { /* The inteface is released to the common IDE layer */ pci_set_drvdata(pdev, NULL); - iounmap((void *)base); + iounmap(base); memset(pmif, 0, sizeof(*pmif)); pci_release_regions(pdev); } @@ -1578,9 +1574,6 @@ pmac_ide_build_sglist(ide_drive_t *drive, struct request *rq) struct scatterlist *sg = pmif->sg_table; int nents; - if (hwif->sg_dma_active) - BUG(); - nents = blk_rq_map_sg(drive->queue, rq, sg); if (rq_data_dir(rq) == READ) @@ -1639,7 +1632,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) int i, count = 0; ide_hwif_t *hwif = HWIF(drive); pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - volatile struct dbdma_regs *dma = pmif->dma_regs; + volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; struct scatterlist *sg; int wr = (rq_data_dir(rq) == WRITE); @@ -1715,7 +1708,6 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) pmif->sg_table, pmif->sg_nents, pmif->sg_dma_direction); - hwif->sg_dma_active = 0; return 0; /* revert to PIO for this request */ } @@ -1731,7 +1723,6 @@ pmac_ide_destroy_dmatable (ide_drive_t *drive) if (nents) { pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction); pmif->sg_nents = 0; - HWIF(drive)->sg_dma_active = 0; } } @@ -1912,8 +1903,8 @@ pmac_ide_dma_start(ide_drive_t *drive, int reading) /* Apple adds 60ns to wrDataSetup on reads */ if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { writel(pmif->timings[unit] + (reading ? 0x00800000UL : 0), - (unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)); - (void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)); + PMAC_IDE_REG(IDE_TIMING_CONFIG)); + (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } drive->waiting_for_dma = 1; @@ -1992,7 +1983,7 @@ static int __pmac pmac_ide_dma_begin (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; if (pmif == NULL) return 1; @@ -2011,7 +2002,7 @@ static int __pmac pmac_ide_dma_end (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; u32 dstat; if (pmif == NULL) @@ -2039,7 +2030,7 @@ static int __pmac pmac_ide_dma_test_irq (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; unsigned long status, timeout; if (pmif == NULL) @@ -2107,7 +2098,7 @@ static int __pmac pmac_ide_dma_lostirq (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs *dma; + volatile struct dbdma_regs __iomem *dma; unsigned long status; if (pmif == NULL) diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index a9709b846..798537f68 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -132,7 +132,7 @@ struct eth1394_node_info { }; /* Our ieee1394 highlevel driver */ -#define ETH1394_DRIVER_NAME "ip1394" +#define ETH1394_DRIVER_NAME "eth1394" static const char driver_name[] = ETH1394_DRIVER_NAME; static kmem_cache_t *packet_task_cache; @@ -850,7 +850,7 @@ static inline u16 ether1394_type_trans(struct sk_buff *skb, skb->mac.raw = skb->data; skb_pull (skb, ETH1394_HLEN); - eth = (struct eth1394hdr*)skb->mac.raw; + eth = eth1394_hdr(skb); if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h index 015f8178c..ed8f1c4b7 100644 --- a/drivers/ieee1394/eth1394.h +++ b/drivers/ieee1394/eth1394.h @@ -81,7 +81,14 @@ struct eth1394hdr { unsigned short h_proto; /* packet type ID field */ } __attribute__((packed)); +#ifdef __KERNEL__ +#include +static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb) +{ + return (struct eth1394hdr *)skb->mac.raw; +} +#endif typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index e2e6194c9..d1758d409 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -163,7 +163,7 @@ struct ti_ohci { } init_state; /* remapped memory spaces */ - void *registers; + void __iomem *registers; /* dma buffer for self-id packets */ quadlet_t *selfid_buf_cpu; diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c index 71fcad10c..8459e05c6 100644 --- a/drivers/input/gameport/cs461x.c +++ b/drivers/input/gameport/cs461x.c @@ -312,7 +312,7 @@ static void __devexit cs461x_pci_remove(struct pci_dev *pdev) } static struct pci_driver cs461x_pci_driver = { - .name = "CS461x Gameport", + .name = "CS461x_gameport", .id_table = cs461x_pci_tbl, .probe = cs461x_pci_probe, .remove = __devexit_p(cs461x_pci_remove), diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index 89d469378..8f1461ad2 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -50,8 +50,11 @@ struct emu { }; static struct pci_device_id emu_tbl[] = { + { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ + { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ + { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ { 0, } }; @@ -109,7 +112,7 @@ static void __devexit emu_remove(struct pci_dev *pdev) } static struct pci_driver emu_driver = { - .name = "Emu10k1 Gameport", + .name = "Emu10k1_gameport", .id_table = emu_tbl, .probe = emu_probe, .remove = __devexit_p(emu_remove), diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index ff3b620b8..93849a6cc 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -137,7 +137,7 @@ static struct pci_device_id fm801_gp_id_table[] = { }; static struct pci_driver fm801_gp_driver = { - .name = "FM801 GP", + .name = "FM801_gameport", .id_table = fm801_gp_id_table, .probe = fm801_gp_probe, .remove = __devexit_p(fm801_gp_remove), diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c index 02c31b779..e0a1c3eb5 100644 --- a/drivers/input/gameport/vortex.c +++ b/drivers/input/gameport/vortex.c @@ -55,8 +55,8 @@ MODULE_LICENSE("GPL"); struct vortex { struct gameport gameport; struct pci_dev *dev; - unsigned char *base; - unsigned char *io; + unsigned char __iomem *base; + unsigned char __iomem *io; char phys[32]; }; @@ -166,7 +166,7 @@ static struct pci_device_id vortex_id_table[] = { 0 }}; static struct pci_driver vortex_driver = { - .name = "vortex", + .name = "vortex_gameport", .id_table = vortex_id_table, .probe = vortex_probe, .remove = __devexit_p(vortex_remove), diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 5eb884656..3e47218e0 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -232,8 +232,10 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo && list->head == list->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->joydev->wait, list->joydev->exist - && (list->startup < joydev->nabs + joydev->nkey || list->head != list->tail)); + retval = wait_event_interruptible(list->joydev->wait, + !list->joydev->exist || + list->startup < joydev->nabs + joydev->nkey || + list->head != list->tail); if (retval) return retval; diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 7d506f1f7..8f62f70d0 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -247,9 +247,9 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. -config INPUT_JOYDUMP +config JOYSTICK_JOYDUMP tristate "Gameport data dumper" - depends on INPUT && INPUT_JOYSTICK + depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you want to dump data from your joystick into the system log for debugging purposes. Say N if you are making a production diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 555fb362b..46326b701 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -1,17 +1,14 @@ /* - * $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $ + * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux * - * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Peter Nelson * * Based on the work of: * Andree Borrmann John Dahlstrom * David Kuder Nathan Hand */ -/* - * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux - */ - /* * 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 @@ -72,8 +69,9 @@ __obsolete_setup("gc_3="); #define GC_MULTI2 5 #define GC_N64 6 #define GC_PSX 7 +#define GC_DDR 8 -#define GC_MAX 7 +#define GC_MAX 8 #define GC_REFRESH_TIME HZ/100 @@ -91,7 +89,8 @@ static struct gc *gc_base[3]; static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", - "Multisystem 2-button joystick", "N64 controller", "PSX controller" }; + "Multisystem 2-button joystick", "N64 controller", "PSX controller" + "PSX DDR controller" }; /* * N64 support. */ @@ -237,7 +236,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ #define GC_PSX_CLOCK 0x04 /* Pin 4 */ -#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_COMMAND 0x01 /* Pin 2 */ #define GC_PSX_POWER 0xf8 /* Pins 5-9 */ #define GC_PSX_SELECT 0x02 /* Pin 3 */ @@ -253,25 +252,29 @@ __obsolete_setup("gc_psx_delay="); static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; +static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 }; /* * gc_psx_command() writes 8bit command and reads 8bit data from * the psx pad. */ -static int gc_psx_command(struct gc *gc, int b) +static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH]) { - int i, cmd, data = 0; + int i, j, cmd, read; + for (i = 0; i < 5; i++) + data[i] = 0; for (i = 0; i < 8; i++, b >>= 1) { cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); udelay(gc_psx_delay); - data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; + read = parport_read_status(gc->pd->port) ^ 0x80; + for (j = 0; j < 5; j++) + data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(gc_psx_delay); } - return data; } /* @@ -279,30 +282,39 @@ static int gc_psx_command(struct gc *gc, int b) * device identifier code. */ -static int gc_psx_read_packet(struct gc *gc, unsigned char *data) +static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5]) { - int i, id; + int i, j, max_len = 0; unsigned long flags; + unsigned char data2[5]; parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); local_irq_save(flags); - gc_psx_command(gc, 0x01); /* Access pad */ - id = gc_psx_command(gc, 0x42); /* Get device id */ - if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ - for (i = 0; i < GC_PSX_LEN(id) * 2; i++) - data[i] = gc_psx_command(gc, 0); - } else id = 0; + gc_psx_command(gc, 0x01, data2); /* Access pad */ + gc_psx_command(gc, 0x42, id); /* Get device ids */ + gc_psx_command(gc, 0, data2); /* Dump status */ + + for (i =0; i < 5; i++) /* Find the longest pad */ + if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len)) + max_len = GC_PSX_LEN(id[i]); + + for (i = 0; i < max_len * 2; i++) { /* Read in all the data */ + gc_psx_command(gc, 0, data2); + for (j = 0; j < 5; j++) + data[j][i] = data2[j]; + } local_irq_restore(flags); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); - return GC_PSX_ID(id); + for(i = 0; i < 5; i++) /* Set id's to the real value */ + id[i] = GC_PSX_ID(id[i]); } /* @@ -316,6 +328,7 @@ static void gc_timer(unsigned long private) struct gc *gc = (void *) private; struct input_dev *dev = gc->dev; unsigned char data[GC_MAX_LENGTH]; + unsigned char data_psx[5][GC_PSX_LENGTH]; int i, j, s; /* @@ -412,53 +425,72 @@ static void gc_timer(unsigned long private) * PSX controllers */ - if (gc->pads[GC_PSX]) { + if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) { - for (i = 0; i < 5; i++) - if (gc->pads[GC_PSX] & gc_status_bit[i]) - break; + gc_psx_read_packet(gc, data_psx, data); - switch (gc_psx_read_packet(gc, data)) { + for (i = 0; i < 5; i++) { + switch (data[i]) { - case GC_PSX_RUMBLE: + case GC_PSX_RUMBLE: - input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04); - input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02); - input_sync(dev + i); + input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); + input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); - case GC_PSX_NEGCON: - case GC_PSX_ANALOG: + case GC_PSX_NEGCON: + case GC_PSX_ANALOG: - for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); - input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); - input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; - case GC_PSX_NORMAL: + case GC_PSX_NORMAL: + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); - input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); + /* for some reason if the extra axes are left unset they drift */ + /* for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], 128); + * This needs to be debugged properly, + * maybe fuzz processing needs to be done in input_sync() + * --vojtech + */ + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; + + case 0: /* not a pad, ignore */ + break; + } } } @@ -490,8 +522,7 @@ static struct gc __init *gc_probe(int *config, int nargs) { struct gc *gc; struct parport *pp; - int i, j, psx; - unsigned char data[32]; + int i, j; if (config[0] < 0) return NULL; @@ -588,43 +619,22 @@ static struct gc __init *gc_probe(int *config, int nargs) break; case GC_PSX: - - psx = gc_psx_read_packet(gc, data); - - switch(psx) { - case GC_PSX_NEGCON: - case GC_PSX_NORMAL: - case GC_PSX_ANALOG: - case GC_PSX_RUMBLE: - - for (j = 0; j < 6; j++) { - psx = gc_psx_abs[j]; - set_bit(psx, gc->dev[i].absbit); - if (j < 4) { - gc->dev[i].absmin[psx] = 4; - gc->dev[i].absmax[psx] = 252; - gc->dev[i].absflat[psx] = 2; - } else { - gc->dev[i].absmin[psx] = -1; - gc->dev[i].absmax[psx] = 1; - } - } - - for (j = 0; j < 12; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - - break; - - case 0: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); - break; - - default: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," - " please report to .\n", psx); + case GC_DDR: + if(config[i + 1] == GC_DDR) { + for (j = 0; j < 4; j++) + set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); + } else { + for (j = 0; j < 6; j++) { + set_bit(gc_psx_abs[j], gc->dev[i].absbit); + gc->dev[i].absmin[gc_psx_abs[j]] = 4; + gc->dev[i].absmax[gc_psx_abs[j]] = 252; + gc->dev[i].absflat[gc_psx_abs[j]] = 2; + } } + + for (j = 0; j < 12; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); + break; } diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index 8e1949683..849d0de04 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -107,6 +107,8 @@ static const int init_seq[] = { static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; +static void register_slot(int i, struct grip_mp *grip); + /* * Returns whether an odd or even number of bits are on in pkt. */ @@ -355,7 +357,6 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) u32 packet; int joytype = 0; int slot = 0; - static void register_slot(int i, struct grip_mp *grip); /* Get a packet and check for validity */ diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 71cb7db75..cf815c7ee 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -524,7 +524,7 @@ static int __init iforce_init(void) usb_register(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_register_device(&iforce_serio_dev); + serio_register_driver(&iforce_serio_drv); #endif return 0; } @@ -535,7 +535,7 @@ static void __exit iforce_exit(void) usb_deregister(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_device(&iforce_serio_dev); + serio_unregister_driver(&iforce_serio_drv); #endif } diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 0665b5460..9422407c2 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -124,7 +124,7 @@ out: return IRQ_HANDLED; } -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { struct iforce *iforce; if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) @@ -137,7 +137,7 @@ static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) iforce->serio = serio; serio->private = iforce; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(iforce); return; } @@ -158,9 +158,13 @@ static void iforce_serio_disconnect(struct serio *serio) kfree(iforce); } -struct serio_dev iforce_serio_dev = { - .write_wakeup = iforce_serio_write_wakeup, - .interrupt = iforce_serio_irq, - .connect = iforce_serio_connect, - .disconnect = iforce_serio_disconnect, +struct serio_driver iforce_serio_drv = { + .driver = { + .name = "iforce", + }, + .description = "RS232 I-Force joysticks and wheels driver", + .write_wakeup = iforce_serio_write_wakeup, + .interrupt = iforce_serio_irq, + .connect = iforce_serio_connect, + .disconnect = iforce_serio_disconnect, }; diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index a8586abf5..bce247bc3 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -187,5 +187,5 @@ int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); /* Public variables */ -extern struct serio_dev iforce_serio_dev; +extern struct serio_driver iforce_serio_drv; extern struct usb_driver iforce_usb_driver; diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index f326299b4..2b303bac5 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -146,7 +148,7 @@ static void magellan_disconnect(struct serio *serio) * it as an input device. */ -static void magellan_connect(struct serio *serio, struct serio_dev *dev) +static void magellan_connect(struct serio *serio, struct serio_driver *drv) { struct magellan *magellan; int i, t; @@ -184,7 +186,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) serio->private = magellan; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(magellan); return; } @@ -199,10 +201,14 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev magellan_dev = { - .interrupt = magellan_interrupt, - .connect = magellan_connect, - .disconnect = magellan_disconnect, +static struct serio_driver magellan_drv = { + .driver = { + .name = "magellan", + }, + .description = DRIVER_DESC, + .interrupt = magellan_interrupt, + .connect = magellan_connect, + .disconnect = magellan_disconnect, }; /* @@ -211,13 +217,13 @@ static struct serio_dev magellan_dev = { int __init magellan_init(void) { - serio_register_device(&magellan_dev); + serio_register_driver(&magellan_drv); return 0; } void __exit magellan_exit(void) { - serio_unregister_device(&magellan_dev); + serio_unregister_driver(&magellan_drv); } module_init(magellan_init); diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index eb5b6f76c..40412528e 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -39,8 +39,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -201,7 +203,7 @@ static void spaceball_disconnect(struct serio *serio) * it as an input device. */ -static void spaceball_connect(struct serio *serio, struct serio_dev *dev) +static void spaceball_connect(struct serio *serio, struct serio_driver *drv) { struct spaceball *spaceball; int i, t, id; @@ -254,7 +256,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) serio->private = spaceball; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceball); return; } @@ -269,10 +271,14 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev spaceball_dev = { - .interrupt = spaceball_interrupt, - .connect = spaceball_connect, - .disconnect = spaceball_disconnect, +static struct serio_driver spaceball_drv = { + .driver = { + .name = "spaceball", + }, + .description = DRIVER_DESC, + .interrupt = spaceball_interrupt, + .connect = spaceball_connect, + .disconnect = spaceball_disconnect, }; /* @@ -281,13 +287,13 @@ static struct serio_dev spaceball_dev = { int __init spaceball_init(void) { - serio_register_device(&spaceball_dev); + serio_register_driver(&spaceball_drv); return 0; } void __exit spaceball_exit(void) { - serio_unregister_device(&spaceball_dev); + serio_unregister_driver(&spaceball_drv); } module_init(spaceball_init); diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 00da66c4b..c20091a6e 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -38,8 +38,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -162,7 +164,7 @@ static void spaceorb_disconnect(struct serio *serio) * it as an input device. */ -static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) +static void spaceorb_connect(struct serio *serio, struct serio_driver *drv) { struct spaceorb *spaceorb; int i, t; @@ -201,7 +203,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) serio->private = spaceorb; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceorb); return; } @@ -213,10 +215,14 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev spaceorb_dev = { - .interrupt = spaceorb_interrupt, - .connect = spaceorb_connect, - .disconnect = spaceorb_disconnect, +static struct serio_driver spaceorb_drv = { + .driver = { + .name = "spaceorb", + }, + .description = DRIVER_DESC, + .interrupt = spaceorb_interrupt, + .connect = spaceorb_connect, + .disconnect = spaceorb_disconnect, }; /* @@ -225,13 +231,13 @@ static struct serio_dev spaceorb_dev = { int __init spaceorb_init(void) { - serio_register_device(&spaceorb_dev); + serio_register_driver(&spaceorb_drv); return 0; } void __exit spaceorb_exit(void) { - serio_unregister_device(&spaceorb_dev); + serio_unregister_driver(&spaceorb_drv); } module_init(spaceorb_init); diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index ce9be4563..580e32375 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gravis Stinger gamepad driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gravis Stinger gamepad driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -134,7 +136,7 @@ static void stinger_disconnect(struct serio *serio) * it as an input device. */ -static void stinger_connect(struct serio *serio, struct serio_dev *dev) +static void stinger_connect(struct serio *serio, struct serio_driver *drv) { struct stinger *stinger; int i; @@ -172,7 +174,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) stinger->dev.private = stinger; serio->private = stinger; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(stinger); return; } @@ -187,10 +189,14 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev stinger_dev = { - .interrupt = stinger_interrupt, - .connect = stinger_connect, - .disconnect = stinger_disconnect, +static struct serio_driver stinger_drv = { + .driver = { + .name = "stinger", + }, + .description = DRIVER_DESC, + .interrupt = stinger_interrupt, + .connect = stinger_connect, + .disconnect = stinger_disconnect, }; /* @@ -199,13 +205,13 @@ static struct serio_dev stinger_dev = { int __init stinger_init(void) { - serio_register_device(&stinger_dev); + serio_register_driver(&stinger_drv); return 0; } void __exit stinger_exit(void) { - serio_unregister_device(&stinger_dev); + serio_unregister_driver(&stinger_drv); } module_init(stinger_init); diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 6ed46ec46..e11d29148 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -322,7 +322,7 @@ static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev) tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { - if (tmdc->abs[i] < 0) continue; + if (tmdc->abs[j][i] < 0) continue; set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index eb5c935a6..909b6b54a 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -187,7 +187,7 @@ static void twidjoy_disconnect(struct serio *serio) * it as an input device. */ -static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) +static void twidjoy_connect(struct serio *serio, struct serio_driver *drv) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; @@ -232,7 +232,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) twidjoy->dev.private = twidjoy; serio->private = twidjoy; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(twidjoy); return; } @@ -246,10 +246,14 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev twidjoy_dev = { - .interrupt = twidjoy_interrupt, - .connect = twidjoy_connect, - .disconnect = twidjoy_disconnect, +static struct serio_driver twidjoy_drv = { + .driver = { + .name = "twidjoy", + }, + .description = DRIVER_DESC, + .interrupt = twidjoy_interrupt, + .connect = twidjoy_connect, + .disconnect = twidjoy_disconnect, }; /* @@ -258,13 +262,13 @@ static struct serio_dev twidjoy_dev = { int __init twidjoy_init(void) { - serio_register_device(&twidjoy_dev); + serio_register_driver(&twidjoy_drv); return 0; } void __exit twidjoy_exit(void) { - serio_unregister_device(&twidjoy_dev); + serio_unregister_driver(&twidjoy_drv); } module_init(twidjoy_init); diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 32ec90e81..5f19b2a51 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Logitech WingMan Warrior joystick driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -139,7 +141,7 @@ static void warrior_disconnect(struct serio *serio) * it as an input device. */ -static void warrior_connect(struct serio *serio, struct serio_dev *dev) +static void warrior_connect(struct serio *serio, struct serio_driver *drv) { struct warrior *warrior; int i; @@ -185,7 +187,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) serio->private = warrior; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(warrior); return; } @@ -199,10 +201,14 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev warrior_dev = { - .interrupt = warrior_interrupt, - .connect = warrior_connect, - .disconnect = warrior_disconnect, +static struct serio_driver warrior_drv = { + .driver = { + .name = "warrior", + }, + .description = DRIVER_DESC, + .interrupt = warrior_interrupt, + .connect = warrior_connect, + .disconnect = warrior_disconnect, }; /* @@ -211,13 +217,13 @@ static struct serio_dev warrior_dev = { int __init warrior_init(void) { - serio_register_device(&warrior_dev); + serio_register_driver(&warrior_drv); return 0; } void __exit warrior_exit(void) { - serio_unregister_device(&warrior_dev); + serio_unregister_driver(&warrior_drv); } module_init(warrior_init); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 00ec1f86a..ec97ae7d5 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -27,8 +27,10 @@ #include #include +#define DRIVER_DESC "AT and PS/2 keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static int atkbd_set = 2; @@ -47,6 +49,10 @@ static int atkbd_softrepeat; module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); +static int atkbd_softraw = 1; +module_param_named(softraw, atkbd_softraw, bool, 0); +MODULE_PARM_DESC(softraw, "Use software generated rawmode"); + static int atkbd_scroll; module_param_named(scroll, atkbd_scroll, bool, 0); MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); @@ -164,36 +170,64 @@ static unsigned char atkbd_scroll_keys[5][2] = { { ATKBD_SCR_CLICK, 0x60 }, }; +#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */ +#define ATKBD_FLAG_CMD1 2 /* First byte of command response */ +#define ATKBD_FLAG_ENABLED 3 /* Waining for init to finish */ + /* * The atkbd control structure */ struct atkbd { - unsigned char keycode[512]; - struct input_dev dev; - struct serio *serio; + /* Written only during init */ char name[64]; char phys[32]; - unsigned short id; + struct serio *serio; + struct input_dev dev; + unsigned char set; - unsigned int translated:1; - unsigned int extra:1; - unsigned int write:1; + unsigned short id; + unsigned char keycode[512]; + unsigned char translated; + unsigned char extra; + unsigned char write; + + /* Protected by FLAG_ACK */ + unsigned char nak; + /* Protected by FLAG_CMD */ unsigned char cmdbuf[4]; unsigned char cmdcnt; - volatile signed char ack; - unsigned char emul; - unsigned int resend:1; - unsigned int release:1; - unsigned int bat_xl:1; - unsigned int enabled:1; + /* Accessed only from interrupt */ + unsigned char emul; + unsigned char resend; + unsigned char release; + unsigned char bat_xl; unsigned int last; unsigned long time; + + /* Ensures that only one command is executing at a time */ + struct semaphore cmd_sem; + + /* Used to signal completion from interrupt handler */ + wait_queue_head_t wait; + + /* Flags */ + unsigned long flags; +}; + +/* Work structure to schedule execution of a command */ +struct atkbd_work { + struct work_struct work; + struct atkbd *atkbd; + int command; + unsigned char param[0]; }; + static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) { input_regs(dev, regs); @@ -224,7 +258,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, #if !defined(__i386__) && !defined (__x86_64__) if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { - printk("atkbd.c: frame/parity error: %02x\n", flags); + printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); atkbd->resend = 1; goto out; @@ -234,24 +268,46 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, atkbd->resend = 0; #endif - if (!atkbd->ack) + if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) { switch (code) { case ATKBD_RET_ACK: - atkbd->ack = 1; - goto out; + atkbd->nak = 0; + if (atkbd->cmdcnt) { + set_bit(ATKBD_FLAG_CMD, &atkbd->flags); + set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + } + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + break; case ATKBD_RET_NAK: - atkbd->ack = -1; - goto out; + atkbd->nak = 1; + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + break; } + goto out; + } + + if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) { + + if (atkbd->cmdcnt) + atkbd->cmdbuf[--atkbd->cmdcnt] = code; - if (atkbd->cmdcnt) { - atkbd->cmdbuf[--atkbd->cmdcnt] = code; + if (test_and_clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags) && atkbd->cmdcnt) + wake_up_interruptible(&atkbd->wait); + + if (!atkbd->cmdcnt) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + } goto out; } - if (!atkbd->enabled) + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) goto out; + input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); + if (atkbd->translated) { if (atkbd->emul || @@ -270,6 +326,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, switch (code) { case ATKBD_RET_BAT: + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); serio_rescan(atkbd->serio); goto out; case ATKBD_RET_EMUL0: @@ -300,6 +357,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, code |= (atkbd->set != 3) ? 0x80 : 0x100; } + if (atkbd->keycode[code] != ATKBD_KEY_NULL) + input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); + switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: break; @@ -372,83 +432,147 @@ out: * acknowledge. It doesn't handle resends according to the keyboard * protocol specs, because if these are needed, the keyboard needs * replacement anyway, and they only make a mess in the protocol. + * + * atkbd_sendbyte() can only be called from a process context */ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) { - int timeout = 20000; /* 200 msec */ - atkbd->ack = 0; - #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif - if (serio_write(atkbd->serio, byte)) - return -1; + atkbd->nak = 1; + set_bit(ATKBD_FLAG_ACK, &atkbd->flags); - while (!atkbd->ack && timeout--) udelay(10); + if (serio_write(atkbd->serio, byte) == 0) + wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_ACK, &atkbd->flags), + msecs_to_jiffies(200)); - return -(atkbd->ack <= 0); + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + return -atkbd->nak; } /* * atkbd_command() sends a command, and its parameters to the keyboard, * then waits for the response and puts it in the param array. + * + * atkbd_command() can only be called from a process context */ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) { - int timeout = 500000; /* 500 msec */ + int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; + int rc = -1; int i; - atkbd->cmdcnt = receive; + timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500); - if (command == ATKBD_CMD_RESET_BAT) - timeout = 2000000; /* 2 sec */ + down(&atkbd->cmd_sem); + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); if (receive && param) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; + atkbd->cmdcnt = receive; + if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) - return (atkbd->cmdcnt = 0) - 1; + goto out; for (i = 0; i < send; i++) if (atkbd_sendbyte(atkbd, param[i])) - return (atkbd->cmdcnt = 0) - 1; - - while (atkbd->cmdcnt && timeout--) { - - if (atkbd->cmdcnt == 1 && - command == ATKBD_CMD_RESET_BAT && timeout > 100000) - timeout = 100000; + goto out; - if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID && - atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) { + timeout = wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_CMD1, &atkbd->flags), timeout); + + if (atkbd->cmdcnt && timeout > 0) { + if (command == ATKBD_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100) + timeout = msecs_to_jiffies(100); + + if (command == ATKBD_CMD_GETID && + atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); atkbd->cmdcnt = 0; - break; } - udelay(1); + wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_CMD, &atkbd->flags), timeout); } if (param) for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; - if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) - atkbd->cmdcnt = 0; + if (atkbd->cmdcnt && (command != ATKBD_CMD_RESET_BAT || atkbd->cmdcnt != 1)) + goto out; + + rc = 0; + +out: + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + up(&atkbd->cmd_sem); + + return rc; +} + +/* + * atkbd_execute_scheduled_command() sends a command, previously scheduled by + * atkbd_schedule_command(), to the keyboard. + */ + +static void atkbd_execute_scheduled_command(void *data) +{ + struct atkbd_work *atkbd_work = data; + + atkbd_command(atkbd_work->atkbd, atkbd_work->param, atkbd_work->command); + + kfree(atkbd_work); +} + +/* + * atkbd_schedule_command() allows to schedule delayed execution of a keyboard + * command and can be used to issue a command from an interrupt or softirq + * context. + */ + +static int atkbd_schedule_command(struct atkbd *atkbd, unsigned char *param, int command) +{ + struct atkbd_work *atkbd_work; + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) + return -1; + + if (!(atkbd_work = kmalloc(sizeof(struct atkbd_work) + max(send, receive), GFP_ATOMIC))) + return -1; + + memset(atkbd_work, 0, sizeof(struct atkbd_work)); + atkbd_work->atkbd = atkbd; + atkbd_work->command = command; + memcpy(atkbd_work->param, param, send); + INIT_WORK(&atkbd_work->work, atkbd_execute_scheduled_command, atkbd_work); - if (atkbd->cmdcnt) { - atkbd->cmdcnt = 0; + if (!schedule_work(&atkbd_work->work)) { + kfree(atkbd_work); return -1; } return 0; } + /* * Event callback from the input module. Events that change the state of * the hardware are processed here. @@ -475,7 +599,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | (test_bit(LED_NUML, dev->led) ? 2 : 0) | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); - atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETLEDS); if (atkbd->extra) { param[0] = 0; @@ -484,7 +608,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); - atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); } return 0; @@ -500,7 +624,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co dev->rep[REP_PERIOD] = period[i]; dev->rep[REP_DELAY] = delay[j]; param[0] = i | (j << 5); - atkbd_command(atkbd, param, ATKBD_CMD_SETREP); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP); return 0; } @@ -672,6 +796,11 @@ static void atkbd_cleanup(struct serio *serio) static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; + + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + synchronize_kernel(); + flush_scheduled_work(); + input_unregister_device(&atkbd->dev); serio_close(serio); kfree(atkbd); @@ -684,7 +813,7 @@ static void atkbd_disconnect(struct serio *serio) * to the input module. */ -static void atkbd_connect(struct serio *serio, struct serio_dev *dev) +static void atkbd_connect(struct serio *serio, struct serio_driver *drv) { struct atkbd *atkbd; int i; @@ -693,6 +822,9 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) return; memset(atkbd, 0, sizeof(struct atkbd)); + init_MUTEX(&atkbd->cmd_sem); + init_waitqueue_head(&atkbd->wait); + switch (serio->type & SERIO_TYPE) { case SERIO_8042_XL: @@ -709,17 +841,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) return; } + if (!atkbd->write) + atkbd_softrepeat = 1; + if (atkbd_softrepeat) + atkbd_softraw = 1; + if (atkbd->write) { - atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); + atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); if (!atkbd_softrepeat) { atkbd->dev.rep[REP_DELAY] = 250; atkbd->dev.rep[REP_PERIOD] = 33; - } + } else atkbd_softraw = 1; - atkbd->ack = 1; atkbd->serio = serio; init_input_dev(&atkbd->dev); @@ -732,7 +869,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) serio->private = atkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(atkbd); return; } @@ -754,8 +891,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) atkbd->id = 0xab00; } - atkbd->enabled = 1; - if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); sprintf(atkbd->name, "AT Set 2 Extra keyboard"); @@ -797,6 +932,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) input_register_device(&atkbd->dev); + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); } @@ -808,10 +945,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; - struct serio_dev *dev = serio->dev; + struct serio_driver *drv = serio->drv; unsigned char param[1]; - if (!dev) { + if (!drv) { printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -832,26 +969,32 @@ static int atkbd_reconnect(struct serio *serio) return -1; } + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + return 0; } -static struct serio_dev atkbd_dev = { - .interrupt = atkbd_interrupt, - .connect = atkbd_connect, - .reconnect = atkbd_reconnect, - .disconnect = atkbd_disconnect, - .cleanup = atkbd_cleanup, +static struct serio_driver atkbd_drv = { + .driver = { + .name = "atkbd", + }, + .description = DRIVER_DESC, + .interrupt = atkbd_interrupt, + .connect = atkbd_connect, + .reconnect = atkbd_reconnect, + .disconnect = atkbd_disconnect, + .cleanup = atkbd_cleanup, }; int __init atkbd_init(void) { - serio_register_device(&atkbd_dev); + serio_register_driver(&atkbd_drv); return 0; } void __exit atkbd_exit(void) { - serio_unregister_device(&atkbd_dev); + serio_unregister_driver(&atkbd_drv); } module_init(atkbd_init); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 8dc51e296..a04cf3efd 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -76,8 +76,10 @@ #include #include +#define DRIVER_DESC "LK keyboard driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("LK keyboard driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); /* @@ -622,7 +624,7 @@ lkkbd_reinit (void *data) * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */ static void -lkkbd_connect (struct serio *serio, struct serio_dev *dev) +lkkbd_connect (struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; int i; @@ -665,7 +667,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) serio->private = lk; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (lk); return; } @@ -703,10 +705,14 @@ lkkbd_disconnect (struct serio *serio) kfree (lk); } -static struct serio_dev lkkbd_dev = { - .connect = lkkbd_connect, - .disconnect = lkkbd_disconnect, - .interrupt = lkkbd_interrupt, +static struct serio_driver lkkbd_drv = { + .driver = { + .name = "lkkbd", + }, + .description = DRIVER_DESC, + .connect = lkkbd_connect, + .disconnect = lkkbd_disconnect, + .interrupt = lkkbd_interrupt, }; /* @@ -715,14 +721,14 @@ static struct serio_dev lkkbd_dev = { int __init lkkbd_init (void) { - serio_register_device (&lkkbd_dev); + serio_register_driver(&lkkbd_drv); return 0; } void __exit lkkbd_exit (void) { - serio_unregister_device (&lkkbd_dev); + serio_unregister_driver(&lkkbd_drv); } module_init (lkkbd_init); diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index dc47acb0a..caa92dd8b 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -32,8 +32,10 @@ #include #include +#define DRIVER_DESC "Newton keyboard driver" + MODULE_AUTHOR("Justin Cormack "); -MODULE_DESCRIPTION("Newton keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define NKBD_KEY 0x7f @@ -82,7 +84,7 @@ irqreturn_t nkbd_interrupt(struct serio *serio, } -void nkbd_connect(struct serio *serio, struct serio_dev *dev) +void nkbd_connect(struct serio *serio, struct serio_driver *drv) { struct nkbd *nkbd; int i; @@ -106,7 +108,7 @@ void nkbd_connect(struct serio *serio, struct serio_dev *dev) nkbd->dev.private = nkbd; serio->private = nkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(nkbd); return; } @@ -138,21 +140,25 @@ void nkbd_disconnect(struct serio *serio) kfree(nkbd); } -struct serio_dev nkbd_dev = { - .interrupt = nkbd_interrupt, - .connect = nkbd_connect, - .disconnect = nkbd_disconnect +struct serio_driver nkbd_drv = { + .driver = { + .name = "newtonkbd", + }, + .description = DRIVER_DESC, + .interrupt = nkbd_interrupt, + .connect = nkbd_connect, + .disconnect = nkbd_disconnect, }; int __init nkbd_init(void) { - serio_register_device(&nkbd_dev); + serio_register_driver(&nkbd_drv); return 0; } void __exit nkbd_exit(void) { - serio_unregister_device(&nkbd_dev); + serio_unregister_driver(&nkbd_drv); } module_init(nkbd_init); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index c281e726b..7f0342c56 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Sun keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Sun keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { @@ -221,7 +223,7 @@ static void sunkbd_reinit(void *data) * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. */ -static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) +static void sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; int i; @@ -257,7 +259,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) serio->private = sunkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sunkbd); return; } @@ -301,10 +303,14 @@ static void sunkbd_disconnect(struct serio *serio) kfree(sunkbd); } -static struct serio_dev sunkbd_dev = { - .interrupt = sunkbd_interrupt, - .connect = sunkbd_connect, - .disconnect = sunkbd_disconnect +static struct serio_driver sunkbd_drv = { + .driver = { + .name = "sunkbd", + }, + .description = DRIVER_DESC, + .interrupt = sunkbd_interrupt, + .connect = sunkbd_connect, + .disconnect = sunkbd_disconnect, }; /* @@ -313,13 +319,13 @@ static struct serio_dev sunkbd_dev = { int __init sunkbd_init(void) { - serio_register_device(&sunkbd_dev); + serio_register_driver(&sunkbd_drv); return 0; } void __exit sunkbd_exit(void) { - serio_unregister_device(&sunkbd_dev); + serio_unregister_driver(&sunkbd_drv); } module_init(sunkbd_init); diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 56adfa1cc..eb8a9b72b 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -34,8 +34,10 @@ #include #include +#define DRIVER_DESC "XT keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("XT keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define XTKBD_EMUL0 0xe0 @@ -86,7 +88,7 @@ irqreturn_t xtkbd_interrupt(struct serio *serio, return IRQ_HANDLED; } -void xtkbd_connect(struct serio *serio, struct serio_dev *dev) +void xtkbd_connect(struct serio *serio, struct serio_driver *drv) { struct xtkbd *xtkbd; int i; @@ -111,7 +113,7 @@ void xtkbd_connect(struct serio *serio, struct serio_dev *dev) serio->private = xtkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(xtkbd); return; } @@ -143,21 +145,25 @@ void xtkbd_disconnect(struct serio *serio) kfree(xtkbd); } -struct serio_dev xtkbd_dev = { - .interrupt = xtkbd_interrupt, - .connect = xtkbd_connect, - .disconnect = xtkbd_disconnect +struct serio_driver xtkbd_drv = { + .driver = { + .name = "xtkbd", + }, + .description = DRIVER_DESC, + .interrupt = xtkbd_interrupt, + .connect = xtkbd_connect, + .disconnect = xtkbd_disconnect, }; int __init xtkbd_init(void) { - serio_register_device(&xtkbd_dev); + serio_register_driver(&xtkbd_drv); return 0; } void __exit xtkbd_exit(void) { - serio_unregister_device(&xtkbd_dev); + serio_unregister_driver(&xtkbd_drv); } module_init(xtkbd_init); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d3e5d841e..a89050e12 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -14,7 +14,7 @@ config INPUT_MISC config INPUT_PCSPKR tristate "PC Speaker support" - depends on (ALPHA || X86 || X86_64 || MIPS) && INPUT && INPUT_MISC + depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC help Say Y here if you want the standard PC Speaker to be used for bells and whistles. diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index b86acf04d..477579b9e 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) { struct uinput_device *udev = file->private_data; + if (!test_bit(UIST_CREATED, &(udev->state))) + return 0; + poll_wait(file, &udev->waitq, wait); if (udev->head != udev->tail) diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 1274cb68b..bd2744fa2 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -30,8 +30,6 @@ config MOUSE_PS2 and a new verion of GPM at: http://www.geocities.com/dt_or/gpm/gpm.html to take advantage of the advanced features of the touchpad. - If you do not want install specialized drivers but want tapping - working please use option psmouse.proto=imps. If unsure, say Y. diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 0063af037..6af1455fd 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) protocol = PSMOUSE_PS2TPP; } - } else if (get_model_info(model) != NULL) { + } else if (model_info != NULL) { param[0] = param[1] = param[2] = 0; ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index 526a11e70..fa8cff3df 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -109,9 +109,9 @@ static int pc110pad_open(struct input_dev *dev) static int __init pc110pad_init(void) { - if (request_region(pc110pad_io, 4, "pc110pad")) - { - printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", pc110pad_io, pc110pad_io + 4); + if (!request_region(pc110pad_io, 4, "pc110pad")) { + printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", + pc110pad_io, pc110pad_io + 4); return -EBUSY; } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 0b3826724..7fbd926dd 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -22,8 +22,10 @@ #include "synaptics.h" #include "logips2pp.h" +#define DRIVER_DESC "PS/2 mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("PS/2 mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *psmouse_proto; @@ -142,37 +144,67 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_PARITY ? " bad parity" : ""); - if (psmouse->acking) { - psmouse->ack = -1; - psmouse->acking = 0; - } - psmouse->pktcnt = 0; + psmouse->nak = 1; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); goto out; } - if (psmouse->acking) { + if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) { switch (data) { case PSMOUSE_RET_ACK: - psmouse->ack = 1; + psmouse->nak = 0; break; + case PSMOUSE_RET_NAK: - psmouse->ack = -1; + psmouse->nak = 1; break; + + /* + * Workaround for mice which don't ACK the Get ID command. + * These are valid mouse IDs that we recognize. + */ + case 0x00: + case 0x03: + case 0x04: + if (test_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags)) { + psmouse->nak = 0; + break; + } + /* Fall through */ default: - psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ - if (psmouse->cmdcnt) - psmouse->cmdbuf[--psmouse->cmdcnt] = data; - break; + goto out; } - psmouse->acking = 0; - goto out; + + if (!psmouse->nak && psmouse->cmdcnt) { + set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + } + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); + + if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK) + goto out; } - if (psmouse->cmdcnt) { - psmouse->cmdbuf[--psmouse->cmdcnt] = data; + if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { + if (psmouse->cmdcnt) + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + + if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags) && psmouse->cmdcnt) + wake_up_interruptible(&psmouse->wait); + + if (!psmouse->cmdcnt) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); + } goto out; } + if (psmouse->state == PSMOUSE_INITIALIZING) + goto out; + if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", @@ -238,78 +270,96 @@ out: * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge. * It doesn't handle retransmission, though it could - because when there would * be need for retransmissions, the mouse has to be replaced anyway. + * + * psmouse_sendbyte() can only be called from a process context */ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) { - int timeout = 10000; /* 100 msec */ - psmouse->ack = 0; - psmouse->acking = 1; - - if (serio_write(psmouse->serio, byte)) { - psmouse->acking = 0; - return -1; - } + psmouse->nak = 1; + set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - while (!psmouse->ack && timeout--) udelay(10); + if (serio_write(psmouse->serio, byte) == 0) + wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags), + msecs_to_jiffies(200)); - return -(psmouse->ack <= 0); + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + return -psmouse->nak; } /* * psmouse_command() sends a command and its parameters to the mouse, * then waits for the response and puts it in the param array. + * + * psmouse_command() can only be called from a process context */ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) { - int timeout = 500000; /* 500 msec */ + int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; + int rc = -1; int i; - psmouse->cmdcnt = receive; + timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500); - if (command == PSMOUSE_CMD_RESET_BAT) - timeout = 4000000; /* 4 sec */ + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + if (command == PSMOUSE_CMD_GETID) + set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); - /* initialize cmdbuf with preset values from param */ - if (receive) - for (i = 0; i < receive; i++) - psmouse->cmdbuf[(receive - 1) - i] = param[i]; + if (receive && param) + for (i = 0; i < receive; i++) + psmouse->cmdbuf[(receive - 1) - i] = param[i]; + + psmouse->cmdcnt = receive; if (command & 0xff) if (psmouse_sendbyte(psmouse, command & 0xff)) - return (psmouse->cmdcnt = 0) - 1; + goto out; for (i = 0; i < send; i++) if (psmouse_sendbyte(psmouse, param[i])) - return (psmouse->cmdcnt = 0) - 1; - - while (psmouse->cmdcnt && timeout--) { - - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && - timeout > 100000) /* do not run in a endless loop */ - timeout = 100000; /* 1 sec */ + goto out; - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && - psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) { + timeout = wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags), timeout); + + if (psmouse->cmdcnt && timeout > 0) { + if (command == PSMOUSE_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100) + timeout = msecs_to_jiffies(100); + + if (command == PSMOUSE_CMD_GETID && + psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); psmouse->cmdcnt = 0; - break; } - udelay(1); + wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags), timeout); } - for (i = 0; i < receive; i++) - param[i] = psmouse->cmdbuf[(receive - 1) - i]; + if (param) + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; - if (psmouse->cmdcnt) - return (psmouse->cmdcnt = 0) - 1; + if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1)) + goto out; - return 0; -} + rc = 0; +out: + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); + return rc; +} /* * psmouse_sliced_command() sends an extended PS/2 command to the mouse @@ -394,6 +444,8 @@ static int im_explorer_detect(struct psmouse *psmouse) { unsigned char param[2]; + intellimouse_detect(psmouse); + param[0] = 200; psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); param[0] = 200; @@ -597,6 +649,21 @@ static void psmouse_initialize(struct psmouse *psmouse) psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM); } +/* + * psmouse_set_state() sets new psmouse state and resets all flags and + * counters while holding serio lock so fighting with interrupt handler + * is not a concern. + */ + +static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) +{ + serio_pause_rx(psmouse->serio); + psmouse->state = new_state; + psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0; + psmouse->flags = 0; + serio_continue_rx(psmouse->serio); +} + /* * psmouse_activate() enables the mouse so that we get motion reports from it. */ @@ -606,9 +673,24 @@ static void psmouse_activate(struct psmouse *psmouse) if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys); - psmouse->state = PSMOUSE_ACTIVATED; + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); +} + + +/* + * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion + * reports from it unless we explicitely request it. + */ + +static void psmouse_deactivate(struct psmouse *psmouse) +{ + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE)) + printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse->serio->phys); + + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); } + /* * psmouse_cleanup() resets the mouse into power-on state. */ @@ -626,22 +708,21 @@ static void psmouse_cleanup(struct serio *serio) static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse = serio->private; + struct psmouse *psmouse, *parent; - psmouse->state = PSMOUSE_CMD_MODE; + psmouse = serio->private; + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - if (psmouse->ptport) { - if (psmouse->ptport->deactivate) - psmouse->ptport->deactivate(psmouse); - __serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */ - kfree(psmouse->ptport); - psmouse->ptport = NULL; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + if (parent->pt_deactivate) + parent->pt_deactivate(parent); } if (psmouse->disconnect) psmouse->disconnect(psmouse); - psmouse->state = PSMOUSE_IGNORE; + psmouse_set_state(psmouse, PSMOUSE_IGNORE); input_unregister_device(&psmouse->dev); serio_close(serio); @@ -652,39 +733,49 @@ static void psmouse_disconnect(struct serio *serio) * psmouse_connect() is a callback from the serio module when * an unhandled serio port is found. */ -static void psmouse_connect(struct serio *serio, struct serio_dev *dev) +static void psmouse_connect(struct serio *serio, struct serio_driver *drv) { - struct psmouse *psmouse; + struct psmouse *psmouse, *parent = NULL; if ((serio->type & SERIO_TYPE) != SERIO_8042 && (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; + /* + * If this is a pass-through port deactivate parent so the device + * connected to this port can be successfully identified + */ + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + psmouse_deactivate(parent); + } + if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) - return; + goto out; memset(psmouse, 0, sizeof(struct psmouse)); + init_waitqueue_head(&psmouse->wait); init_input_dev(&psmouse->dev); psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - psmouse->state = PSMOUSE_CMD_MODE; psmouse->serio = serio; psmouse->dev.private = psmouse; + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); serio->private = psmouse; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(psmouse); serio->private = NULL; - return; + goto out; } if (psmouse_probe(psmouse) < 0) { serio_close(serio); kfree(psmouse); serio->private = NULL; - return; + goto out; } psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); @@ -711,63 +802,88 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - if (psmouse->ptport) { - printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys); - __serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */ - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); + if (parent && parent->pt_activate) + parent->pt_activate(parent); + + if (serio->child) { + /* + * Nothing to be done here, serio core will detect that + * the driver set serio->child and will register it for us. + */ + printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys); } psmouse_activate(psmouse); + +out: + /* If this is a pass-through port the parent awaits to be activated */ + if (parent) + psmouse_activate(parent); } static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio->private; - struct serio_dev *dev = serio->dev; + struct psmouse *parent = NULL; + struct serio_driver *drv = serio->drv; + int rc = -1; - if (!dev || !psmouse) { + if (!drv || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } - psmouse->state = PSMOUSE_CMD_MODE; - psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + psmouse_deactivate(parent); + } + + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) - return -1; + goto out; } else if (psmouse_probe(psmouse) < 0 || psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) - return -1; + goto out; /* ok, the device type (and capabilities) match the old one, * we can continue using it, complete intialization */ + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - if (psmouse->ptport) { - if (psmouse_reconnect(&psmouse->ptport->serio)) { - __serio_unregister_port(&psmouse->ptport->serio); - __serio_register_port(&psmouse->ptport->serio); - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); - } - } + if (parent && parent->pt_activate) + parent->pt_activate(parent); psmouse_activate(psmouse); - return 0; + rc = 0; + +out: + /* If this is a pass-through port the parent waits to be activated */ + if (parent) + psmouse_activate(parent); + + return rc; } -static struct serio_dev psmouse_dev = { - .interrupt = psmouse_interrupt, - .connect = psmouse_connect, - .reconnect = psmouse_reconnect, - .disconnect = psmouse_disconnect, - .cleanup = psmouse_cleanup, +static struct serio_driver psmouse_drv = { + .driver = { + .name = "psmouse", + }, + .description = DRIVER_DESC, + .interrupt = psmouse_interrupt, + .connect = psmouse_connect, + .reconnect = psmouse_reconnect, + .disconnect = psmouse_disconnect, + .cleanup = psmouse_cleanup, }; static inline void psmouse_parse_proto(void) @@ -787,13 +903,13 @@ static inline void psmouse_parse_proto(void) int __init psmouse_init(void) { psmouse_parse_proto(); - serio_register_device(&psmouse_dev); + serio_register_driver(&psmouse_drv); return 0; } void __exit psmouse_exit(void) { - serio_unregister_device(&psmouse_dev); + serio_unregister_driver(&psmouse_drv); } module_init(psmouse_init); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 47fbc48f6..20bbab42d 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -9,6 +9,7 @@ #define PSMOUSE_CMD_GETID 0x02f2 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_DISABLE 0x00f5 #define PSMOUSE_CMD_RESET_DIS 0x00f6 #define PSMOUSE_CMD_RESET_BAT 0x02ff @@ -17,10 +18,17 @@ #define PSMOUSE_RET_ACK 0xfa #define PSMOUSE_RET_NAK 0xfe -/* psmouse states */ -#define PSMOUSE_CMD_MODE 0 -#define PSMOUSE_ACTIVATED 1 -#define PSMOUSE_IGNORE 2 +#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ +#define PSMOUSE_FLAG_CMD1 2 /* Waiting for the first byte of command response */ +#define PSMOUSE_FLAG_WAITID 3 /* Command execiting is GET ID */ + +enum psmouse_state { + PSMOUSE_IGNORE, + PSMOUSE_INITIALIZING, + PSMOUSE_CMD_MODE, + PSMOUSE_ACTIVATED, +}; /* psmouse protocol handler return codes */ typedef enum { @@ -29,20 +37,10 @@ typedef enum { PSMOUSE_FULL_PACKET } psmouse_ret_t; -struct psmouse; - -struct psmouse_ptport { - struct serio serio; - - void (*activate)(struct psmouse *parent); - void (*deactivate)(struct psmouse *parent); -}; - struct psmouse { void *private; struct input_dev dev; struct serio *serio; - struct psmouse_ptport *ptport; char *vendor; char *name; unsigned char cmdbuf[8]; @@ -53,16 +51,22 @@ struct psmouse { unsigned char model; unsigned long last; unsigned long out_of_sync; - unsigned char state; - char acking; - volatile char ack; + enum psmouse_state state; + unsigned char nak; char error; char devname[64]; char phys[32]; + unsigned long flags; - psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); + /* Used to signal completion from interrupt handler */ + wait_queue_head_t wait; + + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); + + void (*pt_activate)(struct psmouse *psmouse); + void (*pt_deactivate)(struct psmouse *psmouse); }; #define PSMOUSE_PS2 1 diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 9c97a0a40..e1db6e078 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Serial mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Serial mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", @@ -237,7 +239,7 @@ static void sermouse_disconnect(struct serio *serio) * an unhandled serio port is found. */ -static void sermouse_connect(struct serio *serio, struct serio_dev *dev) +static void sermouse_connect(struct serio *serio, struct serio_driver *drv) { struct sermouse *sermouse; unsigned char c; @@ -279,7 +281,7 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev) sermouse->dev.id.product = c; sermouse->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sermouse); return; } @@ -289,21 +291,25 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev) printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); } -static struct serio_dev sermouse_dev = { - .interrupt = sermouse_interrupt, - .connect = sermouse_connect, - .disconnect = sermouse_disconnect +static struct serio_driver sermouse_drv = { + .driver = { + .name = "sermouse", + }, + .description = DRIVER_DESC, + .interrupt = sermouse_interrupt, + .connect = sermouse_connect, + .disconnect = sermouse_disconnect, }; int __init sermouse_init(void) { - serio_register_device(&sermouse_dev); + serio_register_driver(&sermouse_drv); return 0; } void __exit sermouse_exit(void) { - serio_unregister_device(&sermouse_dev); + serio_unregister_driver(&sermouse_drv); } module_init(sermouse_init); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2bd152fe0..101b80947 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -212,9 +212,9 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *port, unsigned char c) +static int synaptics_pt_write(struct serio *serio, unsigned char c) { - struct psmouse *parent = port->driver; + struct psmouse *parent = serio->parent->private; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ if (psmouse_sliced_command(parent, c)) @@ -233,22 +233,19 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet { struct psmouse *child = ptport->private; - if (child) { - if (child->state == PSMOUSE_ACTIVATED) { - serio_interrupt(ptport, packet[1], 0, NULL); - serio_interrupt(ptport, packet[4], 0, NULL); - serio_interrupt(ptport, packet[5], 0, NULL); - if (child->type >= PSMOUSE_GENPS) - serio_interrupt(ptport, packet[2], 0, NULL); - } else if (child->state != PSMOUSE_IGNORE) { - serio_interrupt(ptport, packet[1], 0, NULL); - } - } + if (child && child->state == PSMOUSE_ACTIVATED) { + serio_interrupt(ptport, packet[1], 0, NULL); + serio_interrupt(ptport, packet[4], 0, NULL); + serio_interrupt(ptport, packet[5], 0, NULL); + if (child->type >= PSMOUSE_GENPS) + serio_interrupt(ptport, packet[2], 0, NULL); + } else + serio_interrupt(ptport, packet[1], 0, NULL); } static void synaptics_pt_activate(struct psmouse *psmouse) { - struct psmouse *child = psmouse->ptport->serio.private; + struct psmouse *child = psmouse->serio->child->private; /* adjust the touchpad to child's choice of protocol */ if (child && child->type >= PSMOUSE_GENPS) { @@ -259,23 +256,25 @@ static void synaptics_pt_activate(struct psmouse *psmouse) static void synaptics_pt_create(struct psmouse *psmouse) { - struct psmouse_ptport *port; + struct serio *serio; - psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); - if (!port) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } - memset(port, 0, sizeof(struct psmouse_ptport)); + memset(serio, 0, sizeof(struct serio)); + + serio->type = SERIO_PS_PSTHRU; + strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); + strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); + serio->write = synaptics_pt_write; + serio->parent = psmouse->serio; - port->serio.type = SERIO_PS_PSTHRU; - port->serio.name = "Synaptics pass-through"; - port->serio.phys = "synaptics-pt/serio0"; - port->serio.write = synaptics_pt_write; - port->serio.driver = psmouse; + psmouse->pt_activate = synaptics_pt_activate; - port->activate = synaptics_pt_activate; + psmouse->serio->child = serio; } /***************************************************************************** @@ -470,9 +469,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) - synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); - else + if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { + if (psmouse->serio->child) + synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); + } else synaptics_process_packet(psmouse); return PSMOUSE_FULL_PACKET; diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index c26d907e8..3845ca458 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -82,8 +82,10 @@ #include #include +#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); #undef VSXXXAA_DEBUG @@ -482,7 +484,7 @@ vsxxxaa_disconnect (struct serio *serio) } static void -vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) +vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; @@ -524,7 +526,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) mouse->dev.id.bustype = BUS_RS232; mouse->serio = serio; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (mouse); return; } @@ -540,23 +542,27 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); } -static struct serio_dev vsxxxaa_dev = { - .connect = vsxxxaa_connect, - .interrupt = vsxxxaa_interrupt, - .disconnect = vsxxxaa_disconnect, +static struct serio_driver vsxxxaa_drv = { + .driver = { + .name = "vsxxxaa", + }, + .description = DRIVER_DESC, + .connect = vsxxxaa_connect, + .interrupt = vsxxxaa_interrupt, + .disconnect = vsxxxaa_disconnect, }; int __init vsxxxaa_init (void) { - serio_register_device (&vsxxxaa_dev); + serio_register_driver(&vsxxxaa_drv); return 0; } void __exit vsxxxaa_exit (void) { - serio_unregister_device (&vsxxxaa_dev); + serio_unregister_driver(&vsxxxaa_drv); } module_init (vsxxxaa_init); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index f266b7ef5..bd1a6d98b 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -48,8 +48,15 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; module_param(yres, uint, 0); MODULE_PARM_DESC(yres, "Vertical screen resolution"); -struct mousedev_motion { +static unsigned tap_time = 200; +module_param(tap_time, uint, 0); +MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); + +struct mousedev_hw_data { int dx, dy, dz; + int x, y; + int abs_event; + unsigned long buttons; }; struct mousedev { @@ -61,22 +68,38 @@ struct mousedev { struct list_head list; struct input_handle handle; - struct mousedev_motion packet; - unsigned long buttons; + struct mousedev_hw_data packet; unsigned int pkt_count; int old_x[4], old_y[4]; - unsigned int touch; + unsigned long touch; +}; + +enum mousedev_emul { + MOUSEDEV_EMUL_PS2, + MOUSEDEV_EMUL_IMPS, + MOUSEDEV_EMUL_EXPS }; +struct mousedev_motion { + int dx, dy, dz; + unsigned long buttons; +}; + +#define PACKET_QUEUE_LEN 16 struct mousedev_list { struct fasync_struct *fasync; struct mousedev *mousedev; struct list_head node; - int dx, dy, dz; - unsigned long buttons; + + struct mousedev_motion packets[PACKET_QUEUE_LEN]; + unsigned int head, tail; + spinlock_t packet_lock; + int pos_x, pos_y; + signed char ps2[6]; unsigned char ready, buffer, bufsiz; - unsigned char mode, imexseq, impsseq; + unsigned char imexseq, impsseq; + enum mousedev_emul mode; }; #define MOUSEDEV_SEQ_LEN 6 @@ -119,15 +142,19 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, case ABS_X: size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; if (size == 0) size = xres; - mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size; - mousedev->old_x[0] = mousedev->packet.dx * size; + if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; + if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; + mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; + mousedev->packet.abs_event = 1; break; case ABS_Y: size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; if (size == 0) size = yres; - mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size; - mousedev->old_y[0] = mousedev->packet.dy * size; + if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; + if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; + mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; + mousedev->packet.abs_event = 1; break; } } @@ -165,30 +192,82 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int } if (value) { - set_bit(index, &mousedev->buttons); - set_bit(index, &mousedev_mix.buttons); + set_bit(index, &mousedev->packet.buttons); + set_bit(index, &mousedev_mix.packet.buttons); } else { - clear_bit(index, &mousedev->buttons); - clear_bit(index, &mousedev_mix.buttons); + clear_bit(index, &mousedev->packet.buttons); + clear_bit(index, &mousedev_mix.packet.buttons); } } -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) +static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) { struct mousedev_list *list; + struct mousedev_motion *p; + unsigned long flags; list_for_each_entry(list, &mousedev->list, node) { - list->dx += packet->dx; - list->dy += packet->dy; - list->dz += packet->dz; - list->buttons = mousedev->buttons; + spin_lock_irqsave(&list->packet_lock, flags); + + p = &list->packets[list->head]; + if (list->ready && p->buttons != packet->buttons) { + unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; + if (new_head != list->tail) { + p = &list->packets[list->head = new_head]; + memset(p, 0, sizeof(struct mousedev_motion)); + } + } + + if (packet->abs_event) { + p->dx += packet->x - list->pos_x; + p->dy += packet->y - list->pos_y; + list->pos_x = packet->x; + list->pos_y = packet->y; + } + + list->pos_x += packet->dx; + list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x); + list->pos_y += packet->dy; + list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y); + + p->dx += packet->dx; + p->dy += packet->dy; + p->dz += packet->dz; + p->buttons = mousedev->packet.buttons; + list->ready = 1; + + spin_unlock_irqrestore(&list->packet_lock, flags); kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&mousedev->wait); } +static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) +{ + if (!value) { + if (mousedev->touch && + time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { + /* + * Toggle left button to emulate tap. + * We rely on the fact that mousedev_mix always has 0 + * motion packet so we won't mess current position. + */ + set_bit(0, &mousedev->packet.buttons); + set_bit(0, &mousedev_mix.packet.buttons); + mousedev_notify_readers(mousedev, &mousedev_mix.packet); + mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); + clear_bit(0, &mousedev->packet.buttons); + clear_bit(0, &mousedev_mix.packet.buttons); + } + mousedev->touch = mousedev->pkt_count = 0; + } + else + if (!mousedev->touch) + mousedev->touch = jiffies; +} + static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct mousedev *mousedev = handle->private; @@ -212,12 +291,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig case EV_KEY: if (value != 2) { - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { - /* Handle touchpad data */ - mousedev->touch = value; - if (!mousedev->touch) - mousedev->pkt_count = 0; - } + if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) + mousedev_touchpad_touch(mousedev, value); else mousedev_key_event(mousedev, code, value); } @@ -237,7 +312,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig mousedev_notify_readers(mousedev, &mousedev->packet); mousedev_notify_readers(&mousedev_mix, &mousedev->packet); - memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); + mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; + mousedev->packet.abs_event = 0; } break; } @@ -322,6 +398,9 @@ static int mousedev_open(struct inode * inode, struct file * file) return -ENOMEM; memset(list, 0, sizeof(struct mousedev_list)); + spin_lock_init(&list->packet_lock); + list->pos_x = xres / 2; + list->pos_y = yres / 2; list->mousedev = mousedev_table[i]; list_add_tail(&list->node, &mousedev_table[i]->list); file->private_data = list; @@ -341,32 +420,56 @@ static int mousedev_open(struct inode * inode, struct file * file) return 0; } -static void mousedev_packet(struct mousedev_list *list, unsigned char off) +static inline int mousedev_limit_delta(int delta, int limit) { - list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); - list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); - list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); - list->dx -= list->ps2[off + 1]; - list->dy -= list->ps2[off + 2]; - list->bufsiz = off + 3; - - if (list->mode == 2) { - list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); - list->bufsiz++; - } else { - list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); + return delta > limit ? limit : (delta < -limit ? -limit : delta); +} + +static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) +{ + struct mousedev_motion *p; + unsigned long flags; + + spin_lock_irqsave(&list->packet_lock, flags); + p = &list->packets[list->tail]; + + ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); + ps2_data[1] = mousedev_limit_delta(p->dx, 127); + ps2_data[2] = mousedev_limit_delta(p->dy, 127); + p->dx -= ps2_data[1]; + p->dy -= ps2_data[2]; + + switch (list->mode) { + case MOUSEDEV_EMUL_EXPS: + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_IMPS: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_PS2: + default: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + p->dz = 0; + list->bufsiz = 3; + break; } - if (list->mode == 1) { - list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->bufsiz++; + if (!p->dx && !p->dy && !p->dz) { + if (list->tail != list->head) + list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; + if (list->tail == list->head) + list->ready = 0; } - if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; - list->buffer = list->bufsiz; + spin_unlock_irqrestore(&list->packet_lock, flags); } @@ -384,31 +487,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si if (c == mousedev_imex_seq[list->imexseq]) { if (++list->imexseq == MOUSEDEV_SEQ_LEN) { list->imexseq = 0; - list->mode = 2; + list->mode = MOUSEDEV_EMUL_EXPS; } } else list->imexseq = 0; if (c == mousedev_imps_seq[list->impsseq]) { if (++list->impsseq == MOUSEDEV_SEQ_LEN) { list->impsseq = 0; - list->mode = 1; + list->mode = MOUSEDEV_EMUL_IMPS; } } else list->impsseq = 0; list->ps2[0] = 0xfa; - list->bufsiz = 1; switch (c) { case 0xeb: /* Poll */ - mousedev_packet(list, 1); + mousedev_packet(list, &list->ps2[1]); + list->bufsiz++; /* account for leading ACK */ break; case 0xf2: /* Get ID */ switch (list->mode) { - case 0: list->ps2[1] = 0; break; - case 1: list->ps2[1] = 3; break; - case 2: list->ps2[1] = 4; break; + case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; + case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; + case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; } list->bufsiz = 2; break; @@ -419,13 +522,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si break; case 0xff: /* Reset */ - list->impsseq = 0; - list->imexseq = 0; - list->mode = 0; - list->ps2[1] = 0xaa; - list->ps2[2] = 0x00; + list->impsseq = list->imexseq = 0; + list->mode = MOUSEDEV_EMUL_PS2; + list->ps2[1] = 0xaa; list->ps2[2] = 0x00; list->bufsiz = 3; break; + + default: + list->bufsiz = 1; + break; } list->buffer = list->bufsiz; @@ -446,13 +551,19 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->mousedev->wait, list->ready || list->buffer); + retval = wait_event_interruptible(list->mousedev->wait, + !list->mousedev->exist || list->ready || list->buffer); if (retval) return retval; - if (!list->buffer && list->ready) - mousedev_packet(list, 0); + if (!list->mousedev->exist) + return -ENODEV; + + if (!list->buffer && list->ready) { + mousedev_packet(list, list->ps2); + list->buffer = list->bufsiz; + } if (count > list->buffer) count = list->buffer; diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index cd74954bd..db1a8ce43 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -20,7 +20,7 @@ config SERIO_I8042 tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y select SERIO - depends on !PARISC + depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) ---help--- i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, @@ -130,3 +130,19 @@ config SERIO_MACEPS2 To compile this driver as a module, choose M here: the module will be called maceps2. + +config SERIO_RAW + tristate "Raw access to serio ports" + depends on SERIO + help + Say Y here if you want to have raw access to serio ports, such as + AUX ports on i8042 keyboard controller. Each serio port that is + bound to this driver will be accessible via a char device with + major 10 and dynamically allocated minor. The driver will try + allocating minor 1 (that historically corresponds to /dev/psaux) + first. To bind this driver to a serio port use sysfs interface: + + echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver + + To compile this driver as a module, choose M here: the + module will be called serio_raw. diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index a47dec255..cf52b6141 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o +obj-$(CONFIG_SERIO_RAW) += serio_raw.o diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 6a780c10f..4b3b5135f 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -29,7 +29,7 @@ #define KMI_BASE (kmi->base) struct amba_kmi_port { - struct serio io; + struct serio *io; struct clk *clk; unsigned char *base; unsigned int irq; @@ -44,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) int handled = IRQ_NONE; while (status & KMIIR_RXINTR) { - serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs); + serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); status = readb(KMIIR); handled = IRQ_HANDLED; } @@ -54,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) static int amba_kmi_write(struct serio *io, unsigned char val) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int timeleft = 10000; /* timeout in 100ms */ while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) @@ -68,7 +68,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val) static int amba_kmi_open(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int divisor; int ret; @@ -105,7 +105,7 @@ static int amba_kmi_open(struct serio *io) static void amba_kmi_close(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; writeb(0, KMICR); @@ -117,6 +117,7 @@ static void amba_kmi_close(struct serio *io) static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; + struct serio *io; int ret; ret = amba_request_regions(dev, NULL); @@ -124,21 +125,25 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) return ret; kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); - if (!kmi) { + io = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!kmi || !io) { ret = -ENOMEM; goto out; } memset(kmi, 0, sizeof(struct amba_kmi_port)); - - kmi->io.type = SERIO_8042; - kmi->io.write = amba_kmi_write; - kmi->io.open = amba_kmi_open; - kmi->io.close = amba_kmi_close; - kmi->io.name = dev->dev.bus_id; - kmi->io.phys = dev->dev.bus_id; - kmi->io.driver = kmi; - + memset(io, 0, sizeof(struct serio)); + + io->type = SERIO_8042; + io->write = amba_kmi_write; + io->open = amba_kmi_open; + io->close = amba_kmi_close; + strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); + strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); + io->port_data = kmi; + io->dev.parent = &dev->dev; + + kmi->io = io; kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { ret = -ENOMEM; @@ -154,13 +159,14 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) kmi->irq = dev->irq[0]; amba_set_drvdata(dev, kmi); - serio_register_port(&kmi->io); + serio_register_port(kmi->io); return 0; unmap: iounmap(kmi->base); out: kfree(kmi); + kfree(io); amba_release_regions(dev); return ret; } @@ -171,7 +177,7 @@ static int amba_kmi_remove(struct amba_device *dev) amba_set_drvdata(dev, NULL); - serio_unregister_port(&kmi->io); + serio_unregister_port(kmi->io); clk_put(kmi->clk); iounmap(kmi->base); kfree(kmi); @@ -184,7 +190,7 @@ static int amba_kmi_resume(struct amba_device *dev) struct amba_kmi_port *kmi = amba_get_drvdata(dev); /* kick the serio layer to rescan this port */ - serio_rescan(&kmi->io); + serio_reconnect(kmi->io); return 0; } @@ -214,7 +220,7 @@ static int __init amba_kmi_init(void) static void __exit amba_kmi_exit(void) { - return amba_driver_unregister(&ambakmi_driver); + amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init); diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 2234ff39d..ee785460b 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -43,9 +44,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); MODULE_LICENSE("GPL"); -static char ct82c710_name[] = "C&T 82c710 mouse port"; -static char ct82c710_phys[16]; - /* * ct82c710 interface */ @@ -61,10 +59,22 @@ static char ct82c710_phys[16]; #define CT82C710_IRQ 12 -static int ct82c710_data; -static int ct82c710_status; +#define CT82C710_DATA ct82c710_iores.start +#define CT82C710_STATUS (ct82c710_iores.start + 1) + +static struct serio *ct82c710_port; +static struct platform_device *ct82c710_device; +static struct resource ct82c710_iores; + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs); +static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +{ + return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs); +} /* * Wait for device to send output char and flush any input char. @@ -74,10 +84,10 @@ static int ct82c170_wait(void) { int timeout = 60000; - while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) + while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { - if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data); + if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA); udelay(1); timeout--; @@ -91,7 +101,7 @@ static void ct82c710_close(struct serio *serio) if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); - outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status); + outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS); if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); @@ -106,21 +116,21 @@ static int ct82c710_open(struct serio *serio) if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) return -1; - status = inb_p(ct82c710_status); + status = inb_p(CT82C710_STATUS); status |= (CT82C710_ENABLE | CT82C710_RESET); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); status &= ~(CT82C710_RESET); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); status |= CT82C710_INTS_ON; - outb_p(status, ct82c710_status); /* Enable interrupts */ + outb_p(status, CT82C710_STATUS); /* Enable interrupts */ while (ct82c170_wait()) { printk(KERN_ERR "ct82c710: Device busy in open()\n"); status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); free_irq(CT82C710_IRQ, NULL); return -1; } @@ -135,30 +145,10 @@ static int ct82c710_open(struct serio *serio) static int ct82c710_write(struct serio *port, unsigned char c) { if (ct82c170_wait()) return -1; - outb_p(c, ct82c710_data); + outb_p(c, CT82C710_DATA); return 0; } -static struct serio ct82c710_port = -{ - .type = SERIO_8042, - .name = ct82c710_name, - .phys = ct82c710_phys, - .write = ct82c710_write, - .open = ct82c710_open, - .close = ct82c710_close, -}; - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - return serio_interrupt(&ct82c710_port, inb(ct82c710_data), 0, regs); -} - /* * See if we can find a 82C710 device. Read mouse address. */ @@ -175,36 +165,60 @@ static int __init ct82c710_probe(void) return -1; /* No: no 82C710 here */ outb_p(0x0d, 0x390); /* Write index */ - ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */ - ct82c710_status = ct82c710_data + 1; + ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ + ct82c710_iores.end = ct82c710_iores.start + 1; + ct82c710_iores.flags = IORESOURCE_IO; outb_p(0x0f, 0x390); outb_p(0x0f, 0x391); /* Close config mode */ return 0; } +static struct serio * __init ct82c710_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->open = ct82c710_open; + serio->close = ct82c710_close; + serio->write = ct82c710_write; + serio->dev.parent = &ct82c710_device->dev; + strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA); + } + + return serio; +} + int __init ct82c710_init(void) { if (ct82c710_probe()) return -ENODEV; - if (request_region(ct82c710_data, 2, "ct82c710")) - return -EBUSY; + ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1); + if (IS_ERR(ct82c710_device)) + return PTR_ERR(ct82c710_device); - sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); + if (!(ct82c710_port = ct82c710_allocate_port())) { + platform_device_unregister(ct82c710_device); + return -ENOMEM; + } - serio_register_port(&ct82c710_port); + serio_register_port(ct82c710_port); - printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", - ct82c710_data, CT82C710_IRQ); + printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n", + CT82C710_DATA, CT82C710_IRQ); return 0; } void __exit ct82c710_exit(void) { - serio_unregister_port(&ct82c710_port); - release_region(ct82c710_data, 2); + serio_unregister_port(ct82c710_port); + platform_device_unregister(ct82c710_device); } module_init(ct82c710_init); diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 48a0ad587..cd9f987fb 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -6,7 +6,7 @@ * Copyright (c) 2002 Thibaut Varene * * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries + * Copyright (c) 1999 Alex deVries * Copyright (c) 1999-2000 Philipp Rumpf * Copyright (c) 2000 Xavier Debacker * Copyright (c) 2000-2001 Thomas Marteau @@ -91,7 +91,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); struct gscps2port { struct list_head node; struct parisc_device *padev; - struct serio port; + struct serio *port; spinlock_t lock; char *addr; u8 act, append; /* position in buffer[] */ @@ -100,7 +100,6 @@ struct gscps2port { u8 str; } buffer[BUFFER_SIZE+1]; int id; - char name[32]; }; /* @@ -272,7 +271,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); - serio_interrupt(&ps2port->port, data, rxflags, regs); + serio_interrupt(ps2port->port, data, rxflags, regs); } /* while() */ @@ -288,7 +287,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) static int gscps2_write(struct serio *port, unsigned char data) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; if (!gscps2_writeb_output(ps2port, data)) { printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); @@ -304,7 +303,7 @@ static int gscps2_write(struct serio *port, unsigned char data) static int gscps2_open(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_reset(ps2port); @@ -319,7 +318,7 @@ static int gscps2_open(struct serio *port) static void gscps2_close(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_enable(ps2port, DISABLE); } @@ -343,7 +342,8 @@ static struct serio gscps2_serio_port = static int __init gscps2_probe(struct parisc_device *dev) { - struct gscps2port *ps2port; + struct gscps2port *ps2port; + struct serio *serio; unsigned long hpa = dev->hpa; int ret; @@ -355,34 +355,45 @@ static int __init gscps2_probe(struct parisc_device *dev) hpa += GSC_DINO_OFFSET; ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); - if (!ps2port) - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2port || !serio) { + ret = -ENOMEM; + goto fail_nomem; + } dev_set_drvdata(&dev->dev, ps2port); memset(ps2port, 0, sizeof(struct gscps2port)); + memset(serio, 0, sizeof(struct serio)); + ps2port->port = serio; ps2port->padev = dev; ps2port->addr = ioremap(hpa, GSC_STATUS + 4); spin_lock_init(&ps2port->lock); gscps2_reset(ps2port); - ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; - snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", - gscps2_serio_port.name, - (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); - - memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); - ps2port->port.driver = ps2port; - ps2port->port.name = ps2port->name; - ps2port->port.phys = dev->dev.bus_id; + ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; + + snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", + (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->idbus = BUS_GSC; + serio->idvendor = PCI_VENDOR_ID_HP; + serio->idproduct = 0x0001; + serio->idversion = 0x0010; + serio->type = SERIO_8042; + serio->write = gscps2_write; + serio->open = gscps2_open; + serio->close = gscps2_close; + serio->port_data = ps2port; + serio->dev.parent = &dev->dev; list_add_tail(&ps2port->node, &ps2port_list); ret = -EBUSY; - if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) + if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) goto fail_miserably; - if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { + if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) { printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", hpa, ps2port->id); ret = -ENODEV; @@ -395,12 +406,12 @@ static int __init gscps2_probe(struct parisc_device *dev) #endif printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", - ps2port->name, + ps2port->port->name, ps2port->addr, ps2port->padev->irq, - ps2port->port.phys); + ps2port->port->phys); - serio_register_port(&ps2port->port); + serio_register_port(ps2port->port); return 0; @@ -411,7 +422,10 @@ fail_miserably: list_del(&ps2port->node); iounmap(ps2port->addr); release_mem_region(dev->hpa, GSC_STATUS + 4); + +fail_nomem: kfree(ps2port); + kfree(serio); return ret; } @@ -424,7 +438,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev) { struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); - serio_unregister_port(&ps2port->port); + serio_unregister_port(ps2port->port); free_irq(dev->irq, ps2port); gscps2_flush(ps2port); list_del(&ps2port->node); diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 2cba08840..b567c116a 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -65,6 +65,31 @@ static inline void i8042_write_command(int val) return; } +#if defined(__i386__) + +#include + +static struct dmi_system_id __initdata i8042_dmi_table[] = { + { + .ident = "Compaq Proliant 8500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), + }, + }, + { + .ident = "Compaq Proliant DL760", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), + }, + }, + { } +}; +#endif + static inline int i8042_platform_init(void) { /* @@ -79,6 +104,12 @@ static inline int i8042_platform_init(void) #if !defined(__i386__) && !defined(__x86_64__) i8042_reset = 1; #endif + +#if defined(__i386__) + if (dmi_check_system(i8042_dmi_table)) + i8042_noloop = 1; +#endif + return 0; } diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index e0b8f3219..da2a19812 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -18,7 +18,7 @@ static int i8042_aux_irq = -1; #define I8042_AUX_PHYS_DESC "sparcps2/serio1" #define I8042_MUX_PHYS_DESC "sparcps2/serio%d" -static unsigned long kbd_iobase; +static void __iomem *kbd_iobase; #define I8042_COMMAND_REG (kbd_iobase + 0x64UL) #define I8042_DATA_REG (kbd_iobase + 0x60UL) @@ -64,7 +64,7 @@ static int i8042_platform_init(void) if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { /* Hardcoded values for MrCoffee. */ i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; - kbd_iobase = (unsigned long) ioremap(0x71300060, 8); + kbd_iobase = ioremap(0x71300060, 8); if (!kbd_iobase) return -1; } else { @@ -85,7 +85,7 @@ static int i8042_platform_init(void) if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { i8042_kbd_irq = child->irqs[0]; - kbd_iobase = (unsigned long) + kbd_iobase = ioremap(child->resource[0].start, 8); } if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || @@ -109,7 +109,7 @@ static int i8042_platform_init(void) static inline void i8042_platform_exit(void) { #ifdef CONFIG_PCI - iounmap((void *)kbd_iobase); + iounmap(kbd_iobase); #endif } diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index e9d8dabd1..151c29ddb 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1,7 +1,7 @@ /* * i8042 keyboard and mouse controller driver for Linux * - * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik */ /* @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -52,6 +53,10 @@ static unsigned int i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +static unsigned int i8042_noloop; +module_param_named(noloop, i8042_noloop, bool, 0); +MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port"); + __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_unlock"); @@ -70,19 +75,35 @@ struct i8042_values { unsigned char irqen; unsigned char exists; signed char mux; - unsigned char *name; - unsigned char *phys; + char name[8]; +}; + +static struct i8042_values i8042_kbd_values = { + .disable = I8042_CTR_KBDDIS, + .irqen = I8042_CTR_KBDINT, + .mux = -1, + .name = "KBD", +}; + +static struct i8042_values i8042_aux_values = { + .disable = I8042_CTR_AUXDIS, + .irqen = I8042_CTR_AUXINT, + .mux = -1, + .name = "AUX", }; -static struct serio i8042_kbd_port; -static struct serio i8042_aux_port; +static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS]; + +static struct serio *i8042_kbd_port; +static struct serio *i8042_aux_port; +static struct serio *i8042_mux_port[I8042_NUM_MUX_PORTS]; static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; -static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; -struct timer_list i8042_timer; +static struct timer_list i8042_timer; +static struct platform_device *i8042_platform_device; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -95,6 +116,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * be ready for reading values from it / writing values to it. + * Called always with i8042_lock held. */ static int i8042_wait_read(void) @@ -131,6 +153,7 @@ static int i8042_flush(void) spin_lock_irqsave(&i8042_lock, flags); while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) { + udelay(50); data = i8042_read_data(); dbg("%02x <- i8042 (flush, %s)", data, i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd"); @@ -154,6 +177,9 @@ static int i8042_command(unsigned char *param, int command) unsigned long flags; int retval = 0, i = 0; + if (i8042_noloop && command == I8042_CMD_AUX_LOOP) + return -1; + spin_lock_irqsave(&i8042_lock, flags); retval = i8042_wait_write(); @@ -214,7 +240,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) static int i8042_aux_write(struct serio *port, unsigned char c) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; int retval; /* @@ -242,7 +268,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c) static int i8042_activate_port(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; i8042_flush(); @@ -270,7 +296,7 @@ static int i8042_activate_port(struct serio *port) static int i8042_open(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (i8042_mux_open++) @@ -309,7 +335,7 @@ irq_fail: static void i8042_close(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (--i8042_mux_open) @@ -327,52 +353,6 @@ static void i8042_close(struct serio *port) i8042_flush(); } -/* - * Structures for registering the devices in the serio.c module. - */ - -static struct i8042_values i8042_kbd_values = { - .irqen = I8042_CTR_KBDINT, - .disable = I8042_CTR_KBDDIS, - .name = "KBD", - .mux = -1, -}; - -static struct serio i8042_kbd_port = -{ - .type = SERIO_8042_XL, - .write = i8042_kbd_write, - .open = i8042_open, - .close = i8042_close, - .driver = &i8042_kbd_values, - .name = "i8042 Kbd Port", - .phys = I8042_KBD_PHYS_DESC, -}; - -static struct i8042_values i8042_aux_values = { - .irqen = I8042_CTR_AUXINT, - .disable = I8042_CTR_AUXDIS, - .name = "AUX", - .mux = -1, -}; - -static struct serio i8042_aux_port = -{ - .type = SERIO_8042, - .write = i8042_aux_write, - .open = i8042_open, - .close = i8042_close, - .driver = &i8042_aux_values, - .name = "i8042 Aux Port", - .phys = I8042_AUX_PHYS_DESC, -}; - -static struct i8042_values i8042_mux_values[4]; -static struct serio i8042_mux_port[4]; -static char i8042_mux_names[4][32]; -static char i8042_mux_short[4][16]; -static char i8042_mux_phys[4][32]; - /* * i8042_interrupt() is the most important function in this driver - * it handles the interrupts from the i8042, and sends incoming bytes @@ -384,6 +364,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned long flags; unsigned char str, data = 0; unsigned int dfl; + unsigned int aux_idx; int ret; mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); @@ -400,44 +381,67 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) goto out; } - dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - - if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { + if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { + static unsigned long last_transmit; + static unsigned char last_str; + dfl = 0; if (str & I8042_STR_MUXERR) { + dbg("MUX error, status is %02x, data is %02x", str, data); switch (data) { + default: +/* + * When MUXERR condition is signalled the data register can only contain + * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately + * it is not always the case. Some KBC just get confused which port the + * data came from and signal error leaving the data intact. They _do not_ + * revert to legacy mode (actually I've never seen KBC reverting to legacy + * mode yet, when we see one we'll add proper handling). + * Anyway, we will assume that the data came from the same serio last byte + * was transmitted (if transmission happened not too long ago). + */ + if (time_before(jiffies, last_transmit + HZ/10)) { + str = last_str; + break; + } + /* fall through - report timeout */ case 0xfd: - case 0xfe: dfl = SERIO_TIMEOUT; break; - case 0xff: dfl = SERIO_PARITY; break; + case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; + case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; } - data = 0xfe; - } else dfl = 0; + } + + aux_idx = (str >> 6) & 3; dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", - data, (str >> 6), irq, + data, aux_idx, irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); + if (likely(i8042_mux_values[aux_idx].exists)) + serio_interrupt(i8042_mux_port[aux_idx], data, dfl, regs); + last_str = str; + last_transmit = jiffies; goto irq_ret; } + dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); + dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { - serio_interrupt(&i8042_aux_port, data, dfl, regs); - goto irq_ret; - } - - if (!i8042_kbd_values.exists) - goto irq_ret; - serio_interrupt(&i8042_kbd_port, data, dfl, regs); + if (str & I8042_STR_AUXDATA) { + if (likely(i8042_aux_values.exists)) + serio_interrupt(i8042_aux_port, data, dfl, regs); + } else { + if (likely(i8042_kbd_values.exists)) + serio_interrupt(i8042_kbd_port, data, dfl, regs); + } irq_ret: ret = 1; @@ -474,17 +478,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa9) return -1; param = 0xa4; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) { - -/* - * Do another loop test with the 0x5a value. Doing anything else upsets - * Profusion/ServerWorks OSB4 chipsets. - */ - - param = 0x5a; - i8042_command(¶m, I8042_CMD_AUX_LOOP); + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) return -1; - } if (mux_version) *mux_version = ~param; @@ -639,8 +634,10 @@ static int __init i8042_check_aux(struct i8042_values *values) * registers it, and reports to the user. */ -static int __init i8042_port_register(struct i8042_values *values, struct serio *port) +static int __init i8042_port_register(struct serio *port) { + struct i8042_values *values = port->port_data; + values->exists = 1; i8042_ctr &= ~values->disable; @@ -677,6 +674,7 @@ static void i8042_timer_func(unsigned long data) static int i8042_controller_init(void) { + unsigned long flags; /* * Test the i8042. We need to know if it thinks it's working correctly @@ -723,12 +721,14 @@ static int i8042_controller_init(void) * Handle keylock. */ + spin_lock_irqsave(&i8042_lock, flags); if (~i8042_read_status() & I8042_STR_KEYLOCK) { if (i8042_unlock) i8042_ctr |= I8042_CTR_IGNKEYLOCK; else printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } + spin_unlock_irqrestore(&i8042_lock, flags); /* * If the chip is configured into nontranslated mode by the BIOS, don't @@ -745,10 +745,8 @@ static int i8042_controller_init(void) * BIOSes. */ - if (i8042_direct) { + if (i8042_direct) i8042_ctr &= ~I8042_CTR_XLATE; - i8042_kbd_port.type = SERIO_8042; - } /* * Write CTR back. @@ -802,14 +800,14 @@ void i8042_controller_cleanup(void) */ if (i8042_kbd_values.exists) - serio_cleanup(&i8042_kbd_port); + serio_cleanup(i8042_kbd_port); if (i8042_aux_values.exists) - serio_cleanup(&i8042_aux_port); + serio_cleanup(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_cleanup(i8042_mux_port + i); + serio_cleanup(i8042_mux_port[i]); i8042_controller_reset(); } @@ -851,15 +849,15 @@ static int i8042_controller_resume(void) * Reconnect anything that was connected to the ports. */ - if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0) - serio_reconnect(&i8042_kbd_port); + if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0) + serio_reconnect(i8042_kbd_port); - if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0) - serio_reconnect(&i8042_aux_port); + if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0) + serio_reconnect(i8042_aux_port); - for (i = 0; i < 4; i++) - if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0) - serio_reconnect(i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) + if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0) + serio_reconnect(i8042_mux_port[i]); /* * Restart timer (for polling "stuck" data) */ @@ -882,7 +880,7 @@ static int i8042_notify_sys(struct notifier_block *this, unsigned long code, return NOTIFY_DONE; } -static struct notifier_block i8042_notifier= +static struct notifier_block i8042_notifier = { i8042_notify_sys, NULL, @@ -892,25 +890,27 @@ static struct notifier_block i8042_notifier= /* * Suspend/resume handlers for the new PM scheme (driver model) */ -static int i8042_suspend(struct sys_device *dev, u32 state) +static int i8042_suspend(struct device *dev, u32 state, u32 level) { - return i8042_controller_suspend(); + return level == SUSPEND_DISABLE ? i8042_controller_suspend() : 0; } -static int i8042_resume(struct sys_device *dev) +static int i8042_resume(struct device *dev, u32 level) { - return i8042_controller_resume(); + return level == RESUME_ENABLE ? i8042_controller_resume() : 0; } -static struct sysdev_class kbc_sysclass = { - set_kset_name("i8042"), - .suspend = i8042_suspend, - .resume = i8042_resume, -}; +static void i8042_shutdown(struct device *dev) +{ + i8042_controller_cleanup(); +} -static struct sys_device device_i8042 = { - .id = 0, - .cls = &kbc_sysclass, +static struct device_driver i8042_driver = { + .name = "i8042", + .bus = &platform_bus_type, + .suspend = i8042_suspend, + .resume = i8042_resume, + .shutdown = i8042_shutdown, }; /* @@ -929,23 +929,75 @@ static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dum return 0; } -static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index) +static struct serio * __init i8042_allocate_kbd_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = i8042_direct ? SERIO_8042 : SERIO_8042_XL, + serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write, + serio->open = i8042_open, + serio->close = i8042_close, + serio->port_data = &i8042_kbd_values, + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_aux_port(void) { - memcpy(port, &i8042_aux_port, sizeof(struct serio)); - memcpy(values, &i8042_aux_values, sizeof(struct i8042_values)); - sprintf(i8042_mux_names[index], "i8042 Aux-%d Port", index); - sprintf(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1); - sprintf(i8042_mux_short[index], "AUX%d", index); - port->name = i8042_mux_names[index]; - port->phys = i8042_mux_phys[index]; - port->driver = values; - values->name = i8042_mux_short[index]; - values->mux = index; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = &i8042_aux_values, + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_mux_port(int index) +{ + struct serio *serio; + struct i8042_values *values = &i8042_mux_values[index]; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + *values = i8042_aux_values; + snprintf(values->name, sizeof(values->name), "AUX%d", index); + values->mux = index; + + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = values; + serio->dev.parent = &i8042_platform_device->dev; + snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); + } + + return serio; } int __init i8042_init(void) { int i; + int err; dbg_init(); @@ -961,30 +1013,36 @@ int __init i8042_init(void) if (i8042_controller_init()) return -ENODEV; - if (i8042_dumbkbd) - i8042_kbd_port.write = NULL; + err = driver_register(&i8042_driver); + if (err) + return err; + + i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); + if (IS_ERR(i8042_platform_device)) { + driver_unregister(&i8042_driver); + return PTR_ERR(i8042_platform_device); + } if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) - for (i = 0; i < 4; i++) { - i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i); - i8042_port_register(i8042_mux_values + i, i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { + i8042_mux_port[i] = i8042_allocate_mux_port(i); + if (i8042_mux_port[i]) + i8042_port_register(i8042_mux_port[i]); } - else - i8042_port_register(&i8042_aux_values, &i8042_aux_port); + else { + i8042_aux_port = i8042_allocate_aux_port(); + if (i8042_aux_port) + i8042_port_register(i8042_aux_port); + } } - i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + i8042_kbd_port = i8042_allocate_kbd_port(); + if (i8042_kbd_port) + i8042_port_register(i8042_kbd_port); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - if (sysdev_class_register(&kbc_sysclass) == 0) { - if (sysdev_register(&device_i8042) == 0) - i8042_sysdev_initialized = 1; - else - sysdev_class_unregister(&kbc_sysclass); - } - i8042_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, i8042_pm_callback); register_reboot_notifier(&i8042_notifier); @@ -1001,24 +1059,23 @@ void __exit i8042_exit(void) if (i8042_pm_dev) pm_unregister(i8042_pm_dev); - if (i8042_sysdev_initialized) { - sysdev_unregister(&device_i8042); - sysdev_class_unregister(&kbc_sysclass); - } - i8042_controller_cleanup(); if (i8042_kbd_values.exists) - serio_unregister_port(&i8042_kbd_port); + serio_unregister_port(i8042_kbd_port); if (i8042_aux_values.exists) - serio_unregister_port(&i8042_aux_port); + serio_unregister_port(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_unregister_port(i8042_mux_port + i); + serio_unregister_port(i8042_mux_port[i]); + del_timer_sync(&i8042_timer); + platform_device_unregister(i8042_platform_device); + driver_unregister(&i8042_driver); + i8042_platform_exit(); } diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index f0f637483..cea24034d 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -103,6 +103,13 @@ #define I8042_BUFFER_SIZE 32 +/* + * Number of AUX ports on controllers supporting active multiplexing + * specification + */ + +#define I8042_NUM_MUX_PORTS 4 + /* * Debug. */ diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index c7db1de49..78f4d9b5a 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -46,15 +47,18 @@ MODULE_LICENSE("GPL"); #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ #define PS2_CONTROL_RESET BIT(5) /* reset */ - struct maceps2_data { struct mace_ps2port *port; int irq; }; +static struct maceps2_data port_data[2]; +static struct serio *maceps2_port[2]; +static struct platform_device *maceps2_device; + static int maceps2_write(struct serio *dev, unsigned char val) { - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int timeout = MACE_PS2_TIMEOUT; do { @@ -68,11 +72,10 @@ static int maceps2_write(struct serio *dev, unsigned char val) return -1; } -static irqreturn_t maceps2_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct serio *dev = dev_id; - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int byte; if (mace_read(port->status) & PS2_STATUS_RX_FULL) { @@ -85,7 +88,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id, static int maceps2_open(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); @@ -106,7 +109,7 @@ static int maceps2_open(struct serio *dev) static void maceps2_close(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, data->port->control); @@ -114,46 +117,59 @@ static void maceps2_close(struct serio *dev) free_irq(data->irq, dev); } -static struct maceps2_data port0_data, port1_data; -static struct serio maceps2_port0 = +static struct serio * __init maceps2_allocate_port(int idx) { - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port0", - .phys = "mace/serio0", - .driver = &port0_data, -}; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = maceps2_write; + serio->open = maceps2_open; + serio->close = maceps2_close; + snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); + snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); + serio->port_data = &port_data[idx]; + serio->dev.parent = &maceps2_device->dev; + } + + return serio; +} -static struct serio maceps2_port1 = -{ - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port1", - .phys = "mace/serio1", - .driver = &port1_data, -}; static int __init maceps2_init(void) { - port0_data.port = &mace->perif.ps2.keyb; - port0_data.irq = MACEISA_KEYB_IRQ; - port1_data.port = &mace->perif.ps2.mouse; - port1_data.irq = MACEISA_MOUSE_IRQ; - serio_register_port(&maceps2_port0); - serio_register_port(&maceps2_port1); + maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0); + if (IS_ERR(maceps2_device)) + return PTR_ERR(maceps2_device); + + port_data[0].port = &mace->perif.ps2.keyb; + port_data[0].irq = MACEISA_KEYB_IRQ; + port_data[1].port = &mace->perif.ps2.mouse; + port_data[1].irq = MACEISA_MOUSE_IRQ; + + maceps2_port[0] = maceps2_allocate_port(0); + maceps2_port[1] = maceps2_allocate_port(1); + if (!maceps2_port[0] || !maceps2_port[1]) { + kfree(maceps2_port[0]); + kfree(maceps2_port[1]); + platform_device_unregister(maceps2_device); + return -ENOMEM; + } + + serio_register_port(maceps2_port[0]); + serio_register_port(maceps2_port[1]); return 0; } static void __exit maceps2_exit(void) { - serio_unregister_port(&maceps2_port0); - serio_unregister_port(&maceps2_port1); + serio_unregister_port(maceps2_port[0]); + serio_unregister_port(maceps2_port[1]); + platform_device_unregister(maceps2_device); } module_init(maceps2_init); diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 5f25b21be..a859df676 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -53,9 +53,7 @@ static int parkbd_writing; static unsigned long parkbd_start; static struct pardevice *parkbd_dev; - -static char parkbd_name[] = "PARKBD AT/XT keyboard adapter"; -static char parkbd_phys[32]; +static struct serio *parkbd_port; static int parkbd_readlines(void) { @@ -86,13 +84,6 @@ static int parkbd_write(struct serio *port, unsigned char c) return 0; } -static struct serio parkbd_port = -{ - .write = parkbd_write, - .name = parkbd_name, - .phys = parkbd_phys, -}; - static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -125,7 +116,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; if (parkbd_counter == parkbd_mode + 10) - serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); + serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); } parkbd_last = jiffies; @@ -163,16 +154,39 @@ static int parkbd_getport(void) return 0; } +static struct serio * __init parkbd_allocate_serio(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = parkbd_mode; + serio->write = parkbd_write, + strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); + } + + return serio; +} int __init parkbd_init(void) { - if (parkbd_getport()) return -1; - parkbd_writelines(3); - parkbd_port.type = parkbd_mode; + int err; + + err = parkbd_getport(); + if (err) + return err; - sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); + parkbd_port = parkbd_allocate_serio(); + if (!parkbd_port) { + parport_release(parkbd_dev); + return -ENOMEM; + } + + parkbd_writelines(3); - serio_register_port(&parkbd_port); + serio_register_port(parkbd_port); printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); @@ -183,7 +197,7 @@ int __init parkbd_init(void) void __exit parkbd_exit(void) { parport_release(parkbd_dev); - serio_unregister_port(&parkbd_port); + serio_unregister_port(parkbd_port); parport_unregister_device(parkbd_dev); } diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 2b4acac94..489749e7c 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -38,14 +38,14 @@ #define PS2_STAT_TXEMPTY (1<<7) struct pcips2_data { - struct serio io; + struct serio *io; unsigned int base; struct pci_dev *dev; }; static int pcips2_write(struct serio *io, unsigned char val) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; unsigned int stat; do { @@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); } while (1); return IRQ_RETVAL(handled); } @@ -101,7 +101,7 @@ static void pcips2_flush_input(struct pcips2_data *ps2if) static int pcips2_open(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; int ret, val = 0; outb(PS2_CTRL_ENABLE, ps2if->base); @@ -119,7 +119,7 @@ static int pcips2_open(struct serio *io) static void pcips2_close(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; outb(0, ps2if->base); @@ -129,46 +129,51 @@ static void pcips2_close(struct serio *io) static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct pcips2_data *ps2if; + struct serio *serio; int ret; ret = pci_enable_device(dev); if (ret) - return ret; + goto out; - if (!request_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0), "pcips2")) { - ret = -EBUSY; + ret = pci_request_regions(dev, "pcips2"); + if (ret) goto disable; - } ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); - if (!ps2if) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { ret = -ENOMEM; goto release; } memset(ps2if, 0, sizeof(struct pcips2_data)); - - ps2if->io.type = SERIO_8042; - ps2if->io.write = pcips2_write; - ps2if->io.open = pcips2_open; - ps2if->io.close = pcips2_close; - ps2if->io.name = pci_name(dev); - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + memset(serio, 0, sizeof(struct serio)); + + serio->type = SERIO_8042; + serio->write = pcips2_write; + serio->open = pcips2_open; + serio->close = pcips2_close; + strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; ps2if->dev = dev; ps2if->base = pci_resource_start(dev, 0); pci_set_drvdata(dev, ps2if); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; release: - release_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + kfree(ps2if); + kfree(serio); + pci_release_regions(dev); disable: pci_disable_device(dev); + out: return ret; } @@ -176,11 +181,10 @@ static void __devexit pcips2_remove(struct pci_dev *dev) { struct pcips2_data *ps2if = pci_get_drvdata(dev); - serio_unregister_port(&ps2if->io); - release_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + serio_unregister_port(ps2if->io); pci_set_drvdata(dev, NULL); kfree(ps2if); + pci_release_regions(dev); pci_disable_device(dev); } diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 7f4a26287..7d5ecce92 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -47,43 +48,106 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); -static struct serio q40kbd_port = -{ - .type = SERIO_8042, - .name = "Q40 kbd port", - .phys = "Q40", - .write = NULL, -}; - -static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +spinlock_t q40kbd_lock = SPIN_LOCK_UNLOCKED; +static struct serio *q40kbd_port; +static struct platform_device *q40kbd_device; + +static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; + + spin_lock_irqsave(&q40kbd_lock, flags); + if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) - serio_interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0, regs); + serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); master_outb(-1, KEYBOARD_UNLOCK_REG); + + spin_unlock_irqrestore(&q40kbd_lock, flags); + return IRQ_HANDLED; } -static int __init q40kbd_init(void) +/* + * q40kbd_flush() flushes all data that may be in the keyboard buffers + */ + +static void q40kbd_flush(void) +{ + int maxread = 100; + unsigned long flags; + + spin_lock_irqsave(&q40kbd_lock, flags); + + while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) + master_inb(KEYCODE_REG); + + spin_unlock_irqrestore(&q40kbd_lock, flags); +} + +/* + * q40kbd_open() is called when a port is open by the higher layer. + * It allocates the interrupt and enables in in the chip. + */ + +static int q40kbd_open(struct serio *port) { - int maxread = 100; + q40kbd_flush(); + if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { + printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); + return -1; + } + + /* off we go */ + master_outb(-1, KEYBOARD_UNLOCK_REG); + master_outb(1, KEY_IRQ_ENABLE_REG); + + return 0; +} + +static void q40kbd_close(struct serio *port) +{ + master_outb(0, KEY_IRQ_ENABLE_REG); + master_outb(-1, KEYBOARD_UNLOCK_REG); + free_irq(Q40_IRQ_KEYBOARD, NULL); + + q40kbd_flush(); +} + +static struct serio * __init q40kbd_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->open = q40kbd_open; + serio->close = q40kbd_close; + serio->dev.parent = &q40kbd_device->dev; + strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, "Q40", sizeof(serio->phys)); + } + + return serio; +} + +static int __init q40kbd_init(void) +{ if (!MACH_IS_Q40) return -EIO; - /* allocate the IRQ */ - request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL); - - /* flush any pending input */ - while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) - master_inb(KEYCODE_REG); + q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0); + if (IS_ERR(q40kbd_device)) + return PTR_ERR(q40kbd_device); - /* off we go */ - master_outb(-1,KEYBOARD_UNLOCK_REG); - master_outb(1,KEY_IRQ_ENABLE_REG); + if (!(q40kbd_port = q40kbd_allocate_port())) { + platform_device_unregister(q40kbd_device); + return -ENOMEM; + } - serio_register_port(&q40kbd_port); + serio_register_port(q40kbd_port); printk(KERN_INFO "serio: Q40 kbd registered\n"); return 0; @@ -91,11 +155,8 @@ static int __init q40kbd_init(void) static void __exit q40kbd_exit(void) { - master_outb(0,KEY_IRQ_ENABLE_REG); - master_outb(-1,KEYBOARD_UNLOCK_REG); - - serio_unregister_port(&q40kbd_port); - free_irq(Q40_IRQ_KEYBOARD, NULL); + serio_unregister_port(q40kbd_port); + platform_device_unregister(q40kbd_device); } module_init(q40kbd_init); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index a2e4be7ae..b25d2e3b0 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,9 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell King"); MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); +static struct serio *rpckbd_port; +static struct platform_device *rpckbd_device; + static int rpckbd_write(struct serio *port, unsigned char val) { while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) @@ -101,25 +105,49 @@ static void rpckbd_close(struct serio *port) free_irq(IRQ_KEYBOARDTX, port); } -static struct serio rpckbd_port = +/* + * Allocate and initialize serio structure for subsequent registration + * with serio core. + */ + +static struct serio * __init rpckbd_allocate_port(void) { - .type = SERIO_8042, - .open = rpckbd_open, - .close = rpckbd_close, - .write = rpckbd_write, - .name = "RiscPC PS/2 kbd port", - .phys = "rpckbd/serio0", -}; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = rpckbd_write; + serio->open = rpckbd_open; + serio->close = rpckbd_close; + serio->dev.parent = &rpckbd_device->dev; + strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); + strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); + } + + return serio; +} static int __init rpckbd_init(void) { - serio_register_port(&rpckbd_port); + rpckbd_device = platform_device_register_simple("rpckbd", -1, NULL, 0); + if (IS_ERR(rpckbd_device)) + return PTR_ERR(rpckbd_device); + + if (!(rpckbd_port = rpckbd_allocate_port())) { + platform_device_unregister(rpckbd_device); + return -ENOMEM; + } + + serio_register_port(rpckbd_port); return 0; } static void __exit rpckbd_exit(void) { - serio_unregister_port(&rpckbd_port); + serio_unregister_port(rpckbd_port); + platform_device_unregister(rpckbd_device); } module_init(rpckbd_init); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 9beb7575c..62937f5b3 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -26,7 +26,7 @@ #include struct ps2if { - struct serio io; + struct serio *io; struct sa1111_dev *dev; unsigned long base; unsigned int open; @@ -59,7 +59,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); status = sa1111_readl(ps2if->base + SA1111_PS2STAT); } @@ -95,7 +95,7 @@ static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs) */ static int ps2_write(struct serio *io, unsigned char val) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; unsigned long flags; unsigned int head; @@ -122,7 +122,7 @@ static int ps2_write(struct serio *io, unsigned char val) static int ps2_open(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; int ret; sa1111_enable_device(ps2if->dev); @@ -154,7 +154,7 @@ static int ps2_open(struct serio *io) static void ps2_close(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; sa1111_writel(0, ps2if->base + SA1111_PS2CR); @@ -232,22 +232,28 @@ static int __init ps2_test(struct ps2if *ps2if) static int ps2_probe(struct sa1111_dev *dev) { struct ps2if *ps2if; + struct serio *serio; int ret; ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); - if (!ps2if) { - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + ret = -ENOMEM; + goto free; } memset(ps2if, 0, sizeof(struct ps2if)); - - ps2if->io.type = SERIO_8042; - ps2if->io.write = ps2_write; - ps2if->io.open = ps2_open; - ps2if->io.close = ps2_close; - ps2if->io.name = dev->dev.bus_id; - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + memset(serio, 0, sizeof(struct serio)); + + serio->type = SERIO_8042; + serio->write = ps2_write; + serio->open = ps2_open; + serio->close = ps2_close; + strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; ps2if->dev = dev; sa1111_set_drvdata(dev, ps2if); @@ -292,7 +298,7 @@ static int ps2_probe(struct sa1111_dev *dev) ps2_clear_input(ps2if); sa1111_disable_device(ps2if->dev); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; out: @@ -302,6 +308,7 @@ static int ps2_probe(struct sa1111_dev *dev) free: sa1111_set_drvdata(dev, NULL); kfree(ps2if); + kfree(serio); return ret; } @@ -312,7 +319,7 @@ static int ps2_remove(struct sa1111_dev *dev) { struct ps2if *ps2if = sa1111_get_drvdata(dev); - serio_unregister_port(&ps2if->io); + serio_unregister_port(ps2if->io); release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); sa1111_set_drvdata(dev, NULL); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 6f003197b..268ca1d63 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -1,11 +1,9 @@ -/* - * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - */ - /* * The Serio abstraction module + * + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Dmitry Torokhov + * Copyright (c) 2003 Daniele Bellucci */ /* @@ -26,10 +24,6 @@ * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - * - * Changes: - * 20 Jul. 2003 Daniele Bellucci - * Minor cleanups. */ #include @@ -50,100 +44,178 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_register_port_delayed); -EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port_delayed); -EXPORT_SYMBOL(__serio_unregister_port); -EXPORT_SYMBOL(serio_register_device); -EXPORT_SYMBOL(serio_unregister_device); +EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_reconnect); +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list */ +static LIST_HEAD(serio_list); +static LIST_HEAD(serio_driver_list); +static unsigned int serio_no; + +struct bus_type serio_bus = { + .name = "serio", +}; + +static void serio_find_driver(struct serio *serio); +static void serio_create_port(struct serio *serio); +static void serio_destroy_port(struct serio *serio); +static void serio_connect_port(struct serio *serio, struct serio_driver *drv); +static void serio_reconnect_port(struct serio *serio); +static void serio_disconnect_port(struct serio *serio); + +static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) +{ + get_driver(&drv->driver); + + drv->connect(serio, drv); + if (serio->drv) { + down_write(&serio_bus.subsys.rwsem); + serio->dev.driver = &drv->driver; + device_bind_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + return 1; + } + + put_driver(&drv->driver); + return 0; +} + +/* serio_find_driver() must be called with serio_sem down. */ +static void serio_find_driver(struct serio *serio) +{ + struct serio_driver *drv; + + list_for_each_entry(drv, &serio_driver_list, node) + if (!drv->manual_bind) + if (serio_bind_driver(serio, drv)) + break; +} + +/* + * Serio event processing. + */ + struct serio_event { int type; struct serio *serio; struct list_head node; }; -static DECLARE_MUTEX(serio_sem); -static LIST_HEAD(serio_list); -static LIST_HEAD(serio_dev_list); +enum serio_event_type { + SERIO_RESCAN, + SERIO_RECONNECT, + SERIO_REGISTER_PORT, + SERIO_UNREGISTER_PORT, +}; + +static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ static LIST_HEAD(serio_event_list); +static DECLARE_WAIT_QUEUE_HEAD(serio_wait); +static DECLARE_COMPLETION(serio_exited); static int serio_pid; -static void serio_find_dev(struct serio *serio) +static void serio_queue_event(struct serio *serio, int event_type) { - struct serio_dev *dev; + unsigned long flags; + struct serio_event *event; - list_for_each_entry(dev, &serio_dev_list, node) { - if (serio->dev) - break; - if (dev->connect) - dev->connect(serio, dev); - } -} + spin_lock_irqsave(&serio_event_lock, flags); -#define SERIO_RESCAN 1 -#define SERIO_RECONNECT 2 -#define SERIO_REGISTER_PORT 3 -#define SERIO_UNREGISTER_PORT 4 + if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { + event->type = event_type; + event->serio = serio; -static DECLARE_WAIT_QUEUE_HEAD(serio_wait); -static DECLARE_COMPLETION(serio_exited); + list_add_tail(&event->node, &serio_event_list); + wake_up(&serio_wait); + } + + spin_unlock_irqrestore(&serio_event_lock, flags); +} -static void serio_invalidate_pending_events(struct serio *serio) +static struct serio_event *serio_get_event(void) { struct serio_event *event; + struct list_head *node; + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + if (list_empty(&serio_event_list)) { + spin_unlock_irqrestore(&serio_event_lock, flags); + return NULL; + } + + node = serio_event_list.next; + event = container_of(node, struct serio_event, node); + list_del_init(node); + + spin_unlock_irqrestore(&serio_event_lock, flags); - list_for_each_entry(event, &serio_event_list, node) - if (event->serio == serio) - event->serio = NULL; + return event; } -void serio_handle_events(void) +static void serio_handle_events(void) { - struct list_head *node, *next; struct serio_event *event; - list_for_each_safe(node, next, &serio_event_list) { - event = container_of(node, struct serio_event, node); + while ((event = serio_get_event())) { down(&serio_sem); - if (event->serio == NULL) - goto event_done; switch (event->type) { case SERIO_REGISTER_PORT : - __serio_register_port(event->serio); + serio_create_port(event->serio); + serio_connect_port(event->serio, NULL); break; case SERIO_UNREGISTER_PORT : - __serio_unregister_port(event->serio); + serio_disconnect_port(event->serio); + serio_destroy_port(event->serio); break; case SERIO_RECONNECT : - if (event->serio->dev && event->serio->dev->reconnect) - if (event->serio->dev->reconnect(event->serio) == 0) - break; - /* reconnect failed - fall through to rescan */ + serio_reconnect_port(event->serio); + break; case SERIO_RESCAN : - if (event->serio->dev && event->serio->dev->disconnect) - event->serio->dev->disconnect(event->serio); - serio_find_dev(event->serio); + serio_disconnect_port(event->serio); + serio_connect_port(event->serio, NULL); break; default: break; } -event_done: + up(&serio_sem); - list_del_init(node); kfree(event); } } +static void serio_remove_pending_events(struct serio *serio) +{ + struct list_head *node, *next; + struct serio_event *event; + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + list_for_each_safe(node, next, &serio_event_list) { + event = container_of(node, struct serio_event, node); + if (event->serio == serio) { + list_del_init(node); + kfree(event); + } + } + + spin_unlock_irqrestore(&serio_event_lock, flags); +} + + static int serio_thread(void *nothing) { lock_kernel(); @@ -163,52 +235,239 @@ static int serio_thread(void *nothing) complete_and_exit(&serio_exited, 0); } -static void serio_queue_event(struct serio *serio, int event_type) + +/* + * Serio port operations + */ + +static ssize_t serio_show_description(struct device *dev, char *buf) { - struct serio_event *event; + struct serio *serio = to_serio_port(dev); + return sprintf(buf, "%s\n", serio->name); +} - if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { - event->type = event_type; - event->serio = serio; +static ssize_t serio_show_driver(struct device *dev, char *buf) +{ + return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)"); +} - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); +static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) +{ + struct serio *serio = to_serio_port(dev); + struct device_driver *drv; + int retval; + + retval = down_interruptible(&serio_sem); + if (retval) + return retval; + + retval = count; + if (!strncmp(buf, "none", count)) { + serio_disconnect_port(serio); + } else if (!strncmp(buf, "reconnect", count)) { + serio_reconnect_port(serio); + } else if (!strncmp(buf, "rescan", count)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { + serio_disconnect_port(serio); + serio_connect_port(serio, to_serio_driver(drv)); + put_driver(drv); + } else { + retval = -EINVAL; } + + up(&serio_sem); + + return retval; } -void serio_rescan(struct serio *serio) +static ssize_t serio_show_bind_mode(struct device *dev, char *buf) { - serio_queue_event(serio, SERIO_RESCAN); + struct serio *serio = to_serio_port(dev); + return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); } -void serio_reconnect(struct serio *serio) +static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) { - serio_queue_event(serio, SERIO_RECONNECT); + struct serio *serio = to_serio_port(dev); + int retval; + + retval = count; + if (!strncmp(buf, "manual", count)) { + serio->manual_bind = 1; + } else if (!strncmp(buf, "auto", count)) { + serio->manual_bind = 0; + } else { + retval = -EINVAL; + } + + return retval; } -irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) +static struct device_attribute serio_device_attrs[] = { + __ATTR(description, S_IRUGO, serio_show_description, NULL), + __ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver), + __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), + __ATTR_NULL +}; + + +static void serio_release_port(struct device *dev) { - irqreturn_t ret = IRQ_NONE; + struct serio *serio = to_serio_port(dev); - if (serio->dev && serio->dev->interrupt) { - ret = serio->dev->interrupt(serio, data, flags, regs); - } else { - if (!flags) { - if ((serio->type == SERIO_8042 || - serio->type == SERIO_8042_XL) && (data != 0xaa)) - return ret; - serio_rescan(serio); - ret = IRQ_HANDLED; + kfree(serio); + module_put(THIS_MODULE); +} + +static void serio_create_port(struct serio *serio) +{ + try_module_get(THIS_MODULE); + + spin_lock_init(&serio->lock); + list_add_tail(&serio->node, &serio_list); + snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++); + serio->dev.bus = &serio_bus; + serio->dev.release = serio_release_port; + if (serio->parent) + serio->dev.parent = &serio->parent->dev; + device_register(&serio->dev); +} + +/* + * serio_destroy_port() completes deregistration process and removes + * port from the system + */ +static void serio_destroy_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + unsigned long flags; + + serio_remove_pending_events(serio); + list_del_init(&serio->node); + + if (drv) { + drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } + + if (serio->parent) { + spin_lock_irqsave(&serio->parent->lock, flags); + serio->parent->child = NULL; + spin_unlock_irqrestore(&serio->parent->lock, flags); + } + + device_unregister(&serio->dev); +} + +/* + * serio_connect_port() tries to bind the port and possible all its + * children to appropriate drivers. If driver passed in the function will not + * try otehr drivers when binding parent port. + */ +static void serio_connect_port(struct serio *serio, struct serio_driver *drv) +{ + WARN_ON(serio->drv); + WARN_ON(serio->child); + + if (drv) + serio_bind_driver(serio, drv); + else if (!serio->manual_bind) + serio_find_driver(serio); + + /* Ok, now bind children, if any */ + while (serio->child) { + serio = serio->child; + + WARN_ON(serio->drv); + WARN_ON(serio->child); + + serio_create_port(serio); + + if (!serio->manual_bind) { + /* + * With children we just _prefer_ passed in driver, + * but we will try other options in case preferred + * is not the one + */ + if (!drv || !serio_bind_driver(serio, drv)) + serio_find_driver(serio); } } - return ret; +} + +/* + * + */ +static void serio_reconnect_port(struct serio *serio) +{ + do { + if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* Ok, old children are now gone, we are done */ + break; + } + serio = serio->child; + } while (serio); +} + +/* + * serio_disconnect_port() unbinds a port from its driver. As a side effect + * all child ports are unbound and destroyed. + */ +static void serio_disconnect_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + struct serio *s; + + if (serio->child) { + /* + * Children ports should be disconnected and destroyed + * first, staring with the leaf one, since we don't want + * to do recursion + */ + do { + s = serio->child; + } while (s->child); + + while (s != serio) { + s = s->parent; + serio_destroy_port(s->child); + } + } + + /* + * Ok, no children left, now disconnect this port + */ + if (drv) { + drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } +} + +void serio_rescan(struct serio *serio) +{ + serio_queue_event(serio, SERIO_RESCAN); +} + +void serio_reconnect(struct serio *serio) +{ + serio_queue_event(serio, SERIO_RECONNECT); } void serio_register_port(struct serio *serio) { down(&serio_sem); - __serio_register_port(serio); + serio_create_port(serio); + serio_connect_port(serio, NULL); up(&serio_sem); } @@ -222,21 +481,11 @@ void serio_register_port_delayed(struct serio *serio) serio_queue_event(serio, SERIO_REGISTER_PORT); } -/* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * connect() function. - */ -void __serio_register_port(struct serio *serio) -{ - list_add_tail(&serio->node, &serio_list); - serio_find_dev(serio); -} - void serio_unregister_port(struct serio *serio) { down(&serio_sem); - __serio_unregister_port(serio); + serio_disconnect_port(serio); + serio_destroy_port(serio); up(&serio_sem); } @@ -250,82 +499,171 @@ void serio_unregister_port_delayed(struct serio *serio) serio_queue_event(serio, SERIO_UNREGISTER_PORT); } + /* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * disconnect() function. + * Serio driver operations */ -void __serio_unregister_port(struct serio *serio) + +static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) { - serio_invalidate_pending_events(serio); - list_del_init(&serio->node); - if (serio->dev && serio->dev->disconnect) - serio->dev->disconnect(serio); + struct serio_driver *driver = to_serio_driver(drv); + return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); +} + +static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) +{ + struct serio_driver *serio_drv = to_serio_driver(drv); + return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); } -void serio_register_device(struct serio_dev *dev) +static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) +{ + struct serio_driver *serio_drv = to_serio_driver(drv); + int retval; + + retval = count; + if (!strncmp(buf, "manual", count)) { + serio_drv->manual_bind = 1; + } else if (!strncmp(buf, "auto", count)) { + serio_drv->manual_bind = 0; + } else { + retval = -EINVAL; + } + + return retval; +} + + +static struct driver_attribute serio_driver_attrs[] = { + __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), + __ATTR(bind_mode, S_IWUSR | S_IRUGO, + serio_driver_show_bind_mode, serio_driver_set_bind_mode), + __ATTR_NULL +}; + +void serio_register_driver(struct serio_driver *drv) { struct serio *serio; + down(&serio_sem); - list_add_tail(&dev->node, &serio_dev_list); - list_for_each_entry(serio, &serio_list, node) - if (!serio->dev && dev->connect) - dev->connect(serio, dev); + + list_add_tail(&drv->node, &serio_driver_list); + + drv->driver.bus = &serio_bus; + driver_register(&drv->driver); + + if (drv->manual_bind) + goto out; + +start_over: + list_for_each_entry(serio, &serio_list, node) { + if (!serio->drv) { + serio_connect_port(serio, drv); + /* + * if new child appeared then the list is changed, + * we need to start over + */ + if (serio->child) + goto start_over; + } + } + +out: up(&serio_sem); } -void serio_unregister_device(struct serio_dev *dev) +void serio_unregister_driver(struct serio_driver *drv) { struct serio *serio; down(&serio_sem); - list_del_init(&dev->node); + list_del_init(&drv->node); + +start_over: list_for_each_entry(serio, &serio_list, node) { - if (serio->dev == dev && dev->disconnect) - dev->disconnect(serio); - serio_find_dev(serio); + if (serio->drv == drv) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* we could've deleted some ports, restart */ + goto start_over; + } } + + driver_unregister(&drv->driver); + up(&serio_sem); } -/* called from serio_dev->connect/disconnect methods under serio_sem */ -int serio_open(struct serio *serio, struct serio_dev *dev) +/* called from serio_driver->connect/disconnect methods under serio_sem */ +int serio_open(struct serio *serio, struct serio_driver *drv) { - serio->dev = dev; + serio_pause_rx(serio); + serio->drv = drv; + serio_continue_rx(serio); + if (serio->open && serio->open(serio)) { - serio->dev = NULL; + serio_pause_rx(serio); + serio->drv = NULL; + serio_continue_rx(serio); return -1; } return 0; } -/* called from serio_dev->connect/disconnect methods under serio_sem */ +/* called from serio_driver->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { if (serio->close) serio->close(serio); - serio->dev = NULL; + + serio_pause_rx(serio); + serio->drv = NULL; + serio_continue_rx(serio); } -static int __init serio_init(void) +irqreturn_t serio_interrupt(struct serio *serio, + unsigned char data, unsigned int dfl, struct pt_regs *regs) { - int pid; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&serio->lock, flags); + + if (likely(serio->drv)) { + ret = serio->drv->interrupt(serio, data, dfl, regs); + } else { + if (!dfl) { + if ((serio->type != SERIO_8042 && + serio->type != SERIO_8042_XL) || (data == 0xaa)) { + serio_rescan(serio); + ret = IRQ_HANDLED; + } + } + } + + spin_unlock_irqrestore(&serio->lock, flags); - pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL); + return ret; +} - if (!pid) { +static int __init serio_init(void) +{ + if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { printk(KERN_WARNING "serio: Failed to start kseriod\n"); return -1; } - serio_pid = pid; + serio_bus.dev_attrs = serio_device_attrs; + serio_bus.drv_attrs = serio_driver_attrs; + bus_register(&serio_bus); return 0; } static void __exit serio_exit(void) { + bus_unregister(&serio_bus); kill_proc(serio_pid, SIGTERM, 1); wait_for_completion(&serio_exited); } diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c new file mode 100644 index 000000000..f424fdf19 --- /dev/null +++ b/drivers/input/serio/serio_raw.c @@ -0,0 +1,390 @@ +/* + * Raw serio device providing access to a raw byte stream from underlying + * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device + * + * Copyright (c) 2004 Dmitry Torokhov + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Raw serio driver" + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +#define SERIO_RAW_QUEUE_LEN 64 +struct serio_raw { + unsigned char queue[SERIO_RAW_QUEUE_LEN]; + unsigned int tail, head; + + char name[16]; + unsigned int refcnt; + struct serio *serio; + struct miscdevice dev; + wait_queue_head_t wait; + struct list_head list; + struct list_head node; +}; + +struct serio_raw_list { + struct fasync_struct *fasync; + struct serio_raw *serio_raw; + struct list_head node; +}; + +static DECLARE_MUTEX(serio_raw_sem); +static LIST_HEAD(serio_raw_list); +static unsigned int serio_raw_no; + +/********************************************************************* + * Interface with userspace (file operations) * + *********************************************************************/ + +static int serio_raw_fasync(int fd, struct file *file, int on) +{ + struct serio_raw_list *list = file->private_data; + int retval; + + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static struct serio_raw *serio_raw_locate(int minor) +{ + struct serio_raw *serio_raw; + + list_for_each_entry(serio_raw, &serio_raw_list, node) { + if (serio_raw->dev.minor == minor) + return serio_raw; + } + + return NULL; +} + +static int serio_raw_open(struct inode *inode, struct file *file) +{ + struct serio_raw *serio_raw; + struct serio_raw_list *list; + int retval = 0; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!(serio_raw = serio_raw_locate(iminor(inode)))) { + retval = -ENODEV; + goto out; + } + + if (!serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } + + memset(list, 0, sizeof(struct serio_raw_list)); + list->serio_raw = serio_raw; + file->private_data = list; + + serio_raw->refcnt++; + list_add_tail(&list->node, &serio_raw->list); + +out: + up(&serio_raw_sem); + return retval; +} + +static int serio_raw_cleanup(struct serio_raw *serio_raw) +{ + if (--serio_raw->refcnt == 0) { + misc_deregister(&serio_raw->dev); + list_del_init(&serio_raw->node); + kfree(serio_raw); + + return 1; + } + + return 0; +} + +static int serio_raw_release(struct inode *inode, struct file *file) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + + down(&serio_raw_sem); + + serio_raw_fasync(-1, file, 0); + serio_raw_cleanup(serio_raw); + + up(&serio_raw_sem); + return 0; +} + +static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) +{ + unsigned long flags; + int empty; + + spin_lock_irqsave(&serio_raw->serio->lock, flags); + + empty = serio_raw->head == serio_raw->tail; + if (!empty) { + *c = serio_raw->queue[serio_raw->tail]; + serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; + } + + spin_unlock_irqrestore(&serio_raw->serio->lock, flags); + + return !empty; +} + +static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + char c; + ssize_t retval = 0; + + if (!serio_raw->serio) + return -ENODEV; + + if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + + retval = wait_event_interruptible(list->serio_raw->wait, + serio_raw->head != serio_raw->tail || !serio_raw->serio); + if (retval) + return retval; + + if (!serio_raw->serio) + return -ENODEV; + + while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { + if (put_user(c, buffer++)) + return -EFAULT; + retval++; + } + + return retval; +} + +static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + ssize_t written = 0; + int retval; + unsigned char c; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!list->serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (count > 32) + count = 32; + + while (count--) { + if (get_user(c, buffer++)) { + retval = -EFAULT; + goto out; + } + if (serio_write(list->serio_raw->serio, c)) { + retval = -EIO; + goto out; + } + written++; + }; + +out: + up(&serio_raw_sem); + return written; +} + +static unsigned int serio_raw_poll(struct file *file, poll_table *wait) +{ + struct serio_raw_list *list = file->private_data; + + poll_wait(file, &list->serio_raw->wait, wait); + + if (list->serio_raw->head != list->serio_raw->tail) + return POLLIN | POLLRDNORM; + + return 0; +} + +struct file_operations serio_raw_fops = { + .owner = THIS_MODULE, + .open = serio_raw_open, + .release = serio_raw_release, + .read = serio_raw_read, + .write = serio_raw_write, + .poll = serio_raw_poll, + .fasync = serio_raw_fasync, +}; + + +/********************************************************************* + * Interface with serio port * + *********************************************************************/ + +static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, + unsigned int dfl, struct pt_regs *regs) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_raw_list *list; + unsigned int head = serio_raw->head; + + /* we are holding serio->lock here so we are prootected */ + serio_raw->queue[head] = data; + head = (head + 1) % SERIO_RAW_QUEUE_LEN; + if (likely(head != serio_raw->tail)) { + serio_raw->head = head; + list_for_each_entry(list, &serio_raw->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&serio_raw->wait); + } + + return IRQ_HANDLED; +} + +static void serio_raw_connect(struct serio *serio, struct serio_driver *drv) +{ + struct serio_raw *serio_raw; + int err; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { + printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); + return; + } + + down(&serio_raw_sem); + + memset(serio_raw, 0, sizeof(struct serio_raw)); + snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); + serio_raw->refcnt = 1; + serio_raw->serio = serio; + INIT_LIST_HEAD(&serio_raw->list); + init_waitqueue_head(&serio_raw->wait); + + serio->private = serio_raw; + if (serio_open(serio, drv)) + goto out_free; + + list_add_tail(&serio_raw->node, &serio_raw_list); + + serio_raw->dev.minor = PSMOUSE_MINOR; + serio_raw->dev.name = serio_raw->name; + serio_raw->dev.fops = &serio_raw_fops; + + err = misc_register(&serio_raw->dev); + if (err) { + serio_raw->dev.minor = MISC_DYNAMIC_MINOR; + err = misc_register(&serio_raw->dev); + } + + if (err) { + printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", + serio->phys); + goto out_close; + } + + printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", + serio->phys, serio_raw->name, serio_raw->dev.minor); + goto out; + +out_close: + serio_close(serio); + list_del_init(&serio_raw->node); +out_free: + serio->private = NULL; + kfree(serio_raw); +out: + up(&serio_raw_sem); +} + +static int serio_raw_reconnect(struct serio *serio) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_driver *drv = serio->drv; + + if (!drv || !serio_raw) { + printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); + return -1; + } + + /* + * Nothing needs to be done here, we just need this method to + * keep the same device. + */ + return 0; +} + +static void serio_raw_disconnect(struct serio *serio) +{ + struct serio_raw *serio_raw; + + down(&serio_raw_sem); + + serio_raw = serio->private; + + serio_close(serio); + serio->private = NULL; + + serio_raw->serio = NULL; + if (!serio_raw_cleanup(serio_raw)) + wake_up_interruptible(&serio_raw->wait); + + up(&serio_raw_sem); +} + +static struct serio_driver serio_raw_drv = { + .driver = { + .name = "serio_raw", + }, + .description = DRIVER_DESC, + .interrupt = serio_raw_interrupt, + .connect = serio_raw_connect, + .reconnect = serio_raw_reconnect, + .disconnect = serio_raw_disconnect, + .manual_bind = 1, +}; + +int __init serio_raw_init(void) +{ + serio_register_driver(&serio_raw_drv); + return 0; +} + +void __exit serio_raw_exit(void) +{ + serio_unregister_driver(&serio_raw_drv); +} + +module_init(serio_raw_init); +module_exit(serio_raw_exit); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 19e269249..5582ee822 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -31,28 +31,25 @@ MODULE_ALIAS_LDISC(N_MOUSE); struct serport { struct tty_struct *tty; wait_queue_head_t wait; - struct serio serio; + struct serio *serio; unsigned long flags; - char phys[32]; }; -char serport_name[] = "Serial port"; - /* * Callback functions from the serio code. */ static int serport_serio_write(struct serio *serio, unsigned char data) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); } static void serport_serio_close(struct serio *serio) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; - serport->serio.type = 0; + serport->serio->type = 0; wake_up_interruptible(&serport->wait); } @@ -64,26 +61,30 @@ static void serport_serio_close(struct serio *serio) static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; + struct serio *serio; char name[64]; serport = kmalloc(sizeof(struct serport), GFP_KERNEL); - if (unlikely(!serport)) + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (unlikely(!serport || !serio)) { + kfree(serport); + kfree(serio); return -ENOMEM; - memset(serport, 0, sizeof(struct serport)); + } + memset(serport, 0, sizeof(struct serport)); + serport->serio = serio; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; tty->disc_data = serport; - snprintf(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name)); - - serport->serio.name = serport_name; - serport->serio.phys = serport->phys; - - serport->serio.type = SERIO_RS232; - serport->serio.write = serport_serio_write; - serport->serio.close = serport_serio_close; - serport->serio.driver = serport; + memset(serio, 0, sizeof(struct serio)); + strlcpy(serio->name, "Serial port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); + serio->type = SERIO_RS232; + serio->write = serport_serio_write; + serio->close = serport_serio_close; + serio->port_data = serport; init_waitqueue_head(&serport->wait); @@ -114,7 +115,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c struct serport *serport = (struct serport*) tty->disc_data; int i; for (i = 0; i < count; i++) - serio_interrupt(&serport->serio, cp[i], 0, NULL); + serio_interrupt(serport->serio, cp[i], 0, NULL); } /* @@ -142,10 +143,10 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; - serio_register_port(&serport->serio); + serio_register_port(serport->serio); printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); - wait_event_interruptible(serport->wait, !serport->serio.type); - serio_unregister_port(&serport->serio); + wait_event_interruptible(serport->wait, !serport->serio->type); + serio_unregister_port(serport->serio); clear_bit(SERPORT_BUSY, &serport->flags); @@ -161,7 +162,7 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi struct serport *serport = (struct serport*) tty->disc_data; if (cmd == SPIOCSTYPE) - return get_user(serport->serio.type, (unsigned long __user *) arg); + return get_user(serport->serio->type, (unsigned long __user *) arg); return -EINVAL; } @@ -170,7 +171,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty) { struct serport *sp = (struct serport *) tty->disc_data; - serio_dev_write_wakeup(&sp->serio); + serio_drv_write_wakeup(sp->serio); } /* diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 775914980..e5e38dd4a 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gunze AHL-51S touchscreen driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -111,7 +113,7 @@ static void gunze_disconnect(struct serio *serio) * and if yes, registers it as an input device. */ -static void gunze_connect(struct serio *serio, struct serio_dev *dev) +static void gunze_connect(struct serio *serio, struct serio_driver *drv) { struct gunze *gunze; @@ -142,7 +144,7 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) gunze->dev.id.product = 0x0051; gunze->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(gunze); return; } @@ -156,10 +158,14 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev gunze_dev = { - .interrupt = gunze_interrupt, - .connect = gunze_connect, - .disconnect = gunze_disconnect, +static struct serio_driver gunze_drv = { + .driver = { + .name = "gunze", + }, + .description = DRIVER_DESC, + .interrupt = gunze_interrupt, + .connect = gunze_connect, + .disconnect = gunze_disconnect, }; /* @@ -168,13 +174,13 @@ static struct serio_dev gunze_dev = { int __init gunze_init(void) { - serio_register_device(&gunze_dev); + serio_register_driver(&gunze_drv); return 0; } void __exit gunze_exit(void) { - serio_unregister_device(&gunze_dev); + serio_unregister_driver(&gunze_drv); } module_init(gunze_init); diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 7b4c16d6f..5d719671c 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -45,8 +45,10 @@ #include #include +#define DRIVER_DESC "H3600 touchscreen driver" + MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("H3600 touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -373,7 +375,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, * new serio device. It looks whether it was registered as a H3600 touchscreen * and if yes, registers it as an input device. */ -static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) +static void h3600ts_connect(struct serio *serio, struct serio_driver *drv) { struct h3600_dev *ts; @@ -441,7 +443,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ ts->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); kfree(ts); @@ -478,10 +480,14 @@ static void h3600ts_disconnect(struct serio *serio) * The serio device structure. */ -static struct serio_dev h3600ts_dev = { - .interrupt = h3600ts_interrupt, - .connect = h3600ts_connect, - .disconnect = h3600ts_disconnect, +static struct serio_driver h3600ts_drv = { + .driver = { + .name = "h3600ts", + }, + .description = DRIVER_DESC, + .interrupt = h3600ts_interrupt, + .connect = h3600ts_connect, + .disconnect = h3600ts_disconnect, }; /* @@ -490,13 +496,13 @@ static struct serio_dev h3600ts_dev = { static int __init h3600ts_init(void) { - serio_register_device(&h3600ts_dev); + serio_register_driver(&h3600ts_drv); return 0; } static void __exit h3600ts_exit(void) { - serio_unregister_device(&h3600ts_dev); + serio_unregister_driver(&h3600ts_drv); } module_init(h3600ts_init); diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index ac072d37c..18c37d8ac 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -3,32 +3,42 @@ * * Copyright (c) 2001 "Crazy" james Simmons * - * Input driver to Touchscreen device driver module. + * Compaq touchscreen protocol driver. The protocol emulated by this driver + * is obsolete; for new programs use the tslib library which can read directly + * from evdev and perform dejittering, variance filtering and calibration - + * all in user space, not at kernel level. The meaning of this driver is + * to allow usage of newer input drivers with old applications that use the + * old /dev/h3600_ts and /dev/h3600_tsraw devices. * - * Sponsored by Transvirtual Technology + * 09-Apr-2004: Andrew Zabolotny + * Fixed to actually work, not just output random numbers. + * Added support for both h3600_ts and h3600_tsraw protocol + * emulation. */ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to . + * e-mail - mail your message to . */ #define TSDEV_MINOR_BASE 128 #define TSDEV_MINORS 32 +/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ +#define TSDEV_MINOR_MASK 15 #define TSDEV_BUFFER_SIZE 64 #include @@ -52,48 +62,84 @@ #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 #endif +/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw + * devices. The first one must output X/Y data in 'cooked' format, e.g. + * filtered, dejittered and calibrated. Second device just outputs raw + * data received from the hardware. + * + * This driver doesn't support filtering and dejittering; it supports only + * calibration. Filtering and dejittering must be done in the low-level + * driver, if needed, because it may gain additional benefits from knowing + * the low-level details, the nature of noise and so on. + * + * The driver precomputes a calibration matrix given the initial xres and + * yres values (quite innacurate for most touchscreens) that will result + * in a more or less expected range of output values. The driver supports + * the TS_SET_CAL ioctl, which will replace the calibration matrix with a + * new one, supposedly generated from the values taken from the raw device. + */ + MODULE_AUTHOR("James Simmons "); MODULE_DESCRIPTION("Input driver to touchscreen converter"); MODULE_LICENSE("GPL"); static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; module_param(xres, uint, 0); -MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; module_param(yres, uint, 0); -MODULE_PARM_DESC(yres, "Vertical screen resolution"); +MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); + +/* From Compaq's Touch Screen Specification version 0.2 (draft) */ +struct ts_event { + short pressure; + short x; + short y; + short millisecs; +}; + +struct ts_calibration { + int xscale; + int xtrans; + int yscale; + int ytrans; + int xyswap; +}; struct tsdev { int exist; int open; int minor; - char name[16]; + char name[8]; wait_queue_head_t wait; struct list_head list; struct input_handle handle; + int x, y, pressure; + struct ts_calibration cal; }; -/* From Compaq's Touch Screen Specification version 0.2 (draft) */ -typedef struct { - short pressure; - short x; - short y; - short millisecs; -} TS_EVENT; - struct tsdev_list { struct fasync_struct *fasync; struct list_head node; struct tsdev *tsdev; int head, tail; - int oldx, oldy, pendown; - TS_EVENT event[TSDEV_BUFFER_SIZE]; + struct ts_event event[TSDEV_BUFFER_SIZE]; + int raw; }; +/* The following ioctl codes are defined ONLY for backward compatibility. + * Don't use tsdev for new developement; use the tslib library instead. + * Touchscreen calibration is a fully userspace task. + */ +/* Use 'f' as magic number */ +#define IOC_H3600_TS_MAGIC 'f' +#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) +#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) + static struct input_handler tsdev_handler; -static struct tsdev *tsdev_table[TSDEV_MINORS]; +static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) { @@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inode, struct file *file) int i = iminor(inode) - TSDEV_MINOR_BASE; struct tsdev_list *list; - if (i >= TSDEV_MINORS || !tsdev_table[i]) + if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) return -ENOMEM; memset(list, 0, sizeof(struct tsdev_list)); + list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; + + i &= TSDEV_MINOR_MASK; list->tsdev = tsdev_table[i]; list_add_tail(&list->node, &tsdev_table[i]->list); file->private_data = list; @@ -161,7 +210,7 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, return -EAGAIN; retval = wait_event_interruptible(list->tsdev->wait, - (list->head != list->tail) && list->tsdev->exist); + list->head != list->tail || !list->tsdev->exist); if (retval) return retval; @@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, if (!list->tsdev->exist) return -ENODEV; - while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) { - if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT))) + while (list->head != list->tail && + retval + sizeof (struct ts_event) <= count) { + if (copy_to_user (buffer + retval, list->event + list->tail, + sizeof (struct ts_event))) return -EFAULT; list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); - retval += sizeof(TS_EVENT); + retval += sizeof (struct ts_event); } return retval; @@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct file *file, poll_table * wait) static int tsdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { -/* struct tsdev_list *list = file->private_data; - struct tsdev *evdev = list->tsdev; - struct input_dev *dev = tsdev->handle.dev; - int retval; - + struct tsdev *tsdev = list->tsdev; + int retval = 0; + switch (cmd) { - case HHEHE: - return 0; - case hjff: - return 0; - default: - return 0; + case TS_GET_CAL: + if (copy_to_user ((void __user *)arg, &tsdev->cal, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + case TS_SET_CAL: + if (copy_from_user (&tsdev->cal, (void __user *)arg, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + default: + retval = -EINVAL; + break; } -*/ - return -EINVAL; + + return retval; } struct file_operations tsdev_fops = { @@ -227,82 +283,85 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, struct tsdev *tsdev = handle->private; struct tsdev_list *list; struct timeval time; - int size; - list_for_each_entry(list, &tsdev->list, node) { - switch (type) { - case EV_ABS: - switch (code) { - case ABS_X: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - if (size > 0) - list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size); - else - list->oldx = ((value - handle->dev->absmin[ABS_X])); - break; - case ABS_Y: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - if (size > 0) - list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size); - else - list->oldy = ((value - handle->dev->absmin[ABS_Y])); - break; - case ABS_PRESSURE: - list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ? - value - handle->dev->absmin[ABS_PRESSURE] : 0; - break; - } + switch (type) { + case EV_ABS: + switch (code) { + case ABS_X: + tsdev->x = value; + break; + case ABS_Y: + tsdev->y = value; break; + case ABS_PRESSURE: + if (value > handle->dev->absmax[ABS_PRESSURE]) + value = handle->dev->absmax[ABS_PRESSURE]; + value -= handle->dev->absmin[ABS_PRESSURE]; + if (value < 0) + value = 0; + tsdev->pressure = value; + break; + } + break; + + case EV_REL: + switch (code) { + case REL_X: + tsdev->x += value; + if (tsdev->x < 0) + tsdev->x = 0; + else if (tsdev->x > xres) + tsdev->x = xres; + break; + case REL_Y: + tsdev->y += value; + if (tsdev->y < 0) + tsdev->y = 0; + else if (tsdev->y > yres) + tsdev->y = yres; + break; + } + break; - case EV_REL: - switch (code) { - case REL_X: - if (!list->pendown) - return; - list->oldx += value; - if (list->oldx < 0) - list->oldx = 0; - else if (list->oldx > xres) - list->oldx = xres; + case EV_KEY: + if (code == BTN_TOUCH || code == BTN_MOUSE) { + switch (value) { + case 0: + tsdev->pressure = 0; break; - case REL_Y: - if (!list->pendown) - return; - list->oldy += value; - if (list->oldy < 0) - list->oldy = 0; - else if (list->oldy > xres) - list->oldy = xres; + case 1: + if (!tsdev->pressure) + tsdev->pressure = 1; break; } - break; - - case EV_KEY: - if (code == BTN_TOUCH || code == BTN_MOUSE) { - switch (value) { - case 0: - list->pendown = 0; - break; - case 1: - if (!list->pendown) - list->pendown = 1; - break; - case 2: - return; - } - } else - return; - break; } + break; + } + + if (type != EV_SYN || code != SYN_REPORT) + return; + + list_for_each_entry(list, &tsdev->list, node) { + int x, y, tmp; + do_gettimeofday(&time); list->event[list->head].millisecs = time.tv_usec / 100; - list->event[list->head].pressure = list->pendown; - list->event[list->head].x = list->oldx; - list->event[list->head].y = list->oldy; + list->event[list->head].pressure = tsdev->pressure; + + x = tsdev->x; + y = tsdev->y; + + /* Calibration */ + if (!list->raw) { + x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; + y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; + if (tsdev->cal.xyswap) { + tmp = x; x = y; y = tmp; + } + } + + list->event[list->head].x = x; + list->event[list->head].y = y; list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } @@ -314,11 +373,11 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_device_id *id) { struct tsdev *tsdev; - int minor; + int minor, delta; - for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; + for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; minor++); - if (minor == TSDEV_MINORS) { + if (minor >= TSDEV_MINORS/2) { printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); return NULL; @@ -340,10 +399,25 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev->handle.handler = handler; tsdev->handle.private = tsdev; + /* Precompute the rough calibration matrix */ + delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.xscale = (xres << 8) / delta; + tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); + + delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.yscale = (yres << 8) / delta; + tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); + tsdev_table[minor] = tsdev; - + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), + S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->dev, "ts%d", minor); @@ -362,6 +436,7 @@ static void tsdev_disconnect(struct input_handle *handle) wake_up_interruptible(&tsdev->wait); } else tsdev_free(tsdev); + devfs_remove("input/tsraw%d", tsdev->minor); } static struct input_device_id tsdev_ids[] = { @@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[] = { .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, },/* A tablet like device, at least touch detection, two absolute axes */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, + },/* A tablet like device with several gradations of pressure */ + {},/* Terminating entry */ }; diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c index e84aa5fb3..b363d0976 100644 --- a/drivers/isdn/act2000/act2000_isa.c +++ b/drivers/isdn/act2000/act2000_isa.c @@ -434,7 +434,10 @@ act2000_isa_download(act2000_card * card, act2000_ddef __user * cb) l = (length > 1024) ? 1024 : length; c = 0; b = buf; - copy_from_user(buf, p, l); + if (copy_from_user(buf, p, l)) { + kfree(buf); + return -EFAULT; + } while (c < l) { if (act2000_isa_writeb(card, *b++)) { printk(KERN_WARNING diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 3429d57e2..9370808bb 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -436,51 +436,62 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) struct sk_buff *nskb; int datalen; u16 errcode, datahandle; - + struct tty_ldisc *ld; + datalen = skb->len - CAPIMSG_LEN(skb->data); - if (mp->tty) { - if (mp->tty->ldisc.receive_buf == 0) { - printk(KERN_ERR "capi: ldisc has no receive_buf function\n"); - return -1; - } - if (mp->ttyinstop) { + if (mp->tty == NULL) + { +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: currently no receiver\n"); +#endif + return -1; + } + + ld = tty_ldisc_ref(mp->tty); + if (ld == NULL) + return -1; + if (ld->receive_buf == NULL) { #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: recv tty throttled\n"); + printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); #endif - return -1; - } - if (mp->tty->ldisc.receive_room && - mp->tty->ldisc.receive_room(mp->tty) < datalen) { + goto bad; + } + if (mp->ttyinstop) { #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: no room in tty\n"); + printk(KERN_DEBUG "capi: recv tty throttled\n"); #endif - return -1; - } - if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { - printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); - return -1; - } - datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); - errcode = capi20_put_message(mp->ap, nskb); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", - errcode); - kfree_skb(nskb); - return -1; - } - (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", - datahandle, skb->len); + goto bad; + } + if (ld->receive_room && + ld->receive_room(mp->tty) < datalen) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: no room in tty\n"); #endif - mp->tty->ldisc.receive_buf(mp->tty, skb->data, NULL, skb->len); - kfree_skb(skb); - return 0; - + goto bad; } + if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); + goto bad; + } + datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + errcode = capi20_put_message(mp->ap, nskb); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", + errcode); + kfree_skb(nskb); + goto bad; + } + (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); #ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: currently no receiver\n"); + printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); #endif + ld->receive_buf(mp->tty, skb->data, NULL, skb->len); + kfree_skb(skb); + tty_ldisc_deref(ld); + return 0; +bad: + tty_ldisc_deref(ld); return -1; } @@ -614,6 +625,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); #ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", @@ -633,10 +645,8 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) #endif kfree_skb(skb); (void)capiminor_del_ack(mp, datahandle); - if (mp->tty) { - if (mp->tty->ldisc.write_wakeup) - mp->tty->ldisc.write_wakeup(mp->tty); - } + if (mp->tty) + tty_wakeup(mp->tty); (void)handle_minor_send(mp); } else { diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 150e31d32..44efe1906 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -512,7 +512,8 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg) len = CAPIMSG_LEN(cmsg->buf); skb = alloc_skb(len, GFP_ATOMIC); memcpy(skb_put(skb, len), cmsg->buf, len); - capi20_put_message(&global.ap, skb); + if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) + kfree_skb(skb); } /* -------- state machine -------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index c87516ab2..0c7061d55 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -389,7 +389,7 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) CAPIMSG_NCCI(skb->data), CAPIMSG_MSGID(skb->data)); if (retval != CAPI_NOERROR) - goto out; + return retval; dlen = CAPIMSG_DATALEN(skb->data); @@ -399,16 +399,14 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) b1_put_slice(port, skb->data + len, dlen); spin_unlock_irqrestore(&card->lock, flags); } else { - retval = CAPI_NOERROR; - spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_MESSAGE); b1_put_slice(port, skb->data, len); spin_unlock_irqrestore(&card->lock, flags); } - out: + dev_kfree_skb_any(skb); - return retval; + return CAPI_NOERROR; } /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index d2c69b727..55bed00ca 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -839,8 +839,6 @@ u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) } if (retval == CAPI_NOERROR) b1dma_queue_tx(card, skb); - else - dev_kfree_skb_any(skb); return retval; } diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 9e1285ca5..72b57d4fb 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -1029,8 +1029,6 @@ static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) spin_lock_irqsave(&card->lock, flags); c4_dispatch_tx(card); spin_unlock_irqrestore(&card->lock, flags); - } else { - dev_kfree_skb_any(skb); } return retval; } diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 9d777ebc8..cb9d9cee2 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -472,7 +472,7 @@ static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) CAPIMSG_NCCI(skb->data), CAPIMSG_MSGID(skb->data)); if (retval != CAPI_NOERROR) - goto out; + return retval; dlen = CAPIMSG_DATALEN(skb->data); @@ -482,16 +482,15 @@ static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) t1_put_slice(port, skb->data + len, dlen); spin_unlock_irqrestore(&card->lock, flags); } else { - retval = CAPI_NOERROR; spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_MESSAGE); t1_put_slice(port, skb->data, len); spin_unlock_irqrestore(&card->lock, flags); } - out: + dev_kfree_skb_any(skb); - return retval; + return CAPI_NOERROR; } /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c index 15d081a09..5c138a345 100644 --- a/drivers/isdn/hardware/eicon/capifunc.c +++ b/drivers/isdn/hardware/eicon/capifunc.c @@ -1,4 +1,4 @@ -/* $Id: capifunc.c,v 1.61.4.2 2004/05/05 16:09:25 armin Exp $ +/* $Id: capifunc.c,v 1.61.4.5 2004/08/27 20:10:12 armin Exp $ * * ISDN interface module for Eicon active cards DIVA. * CAPI Interface common functions @@ -998,7 +998,8 @@ static u16 diva_send_message(struct capi_ctr *ctrl, write_end: diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); - diva_os_free_message_buffer(dmb); + if (retval == CAPI_NOERROR) + diva_os_free_message_buffer(dmb); return retval; } diff --git a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h index 13f6ad242..bd256f297 100644 --- a/drivers/isdn/hardware/eicon/capifunc.h +++ b/drivers/isdn/hardware/eicon/capifunc.h @@ -1,4 +1,4 @@ -/* $Id: capifunc.h,v 1.11 2004/03/20 17:19:58 armin Exp $ +/* $Id: capifunc.h,v 1.11.4.1 2004/08/28 20:03:53 armin Exp $ * * ISDN interface module for Eicon active cards DIVA. * CAPI Interface common functions @@ -13,8 +13,6 @@ #ifndef __CAPIFUNC_H__ #define __CAPIFUNC_H__ -#define MAX_DESCRIPTORS 32 - #define DRRELMAJOR 2 #define DRRELMINOR 0 #define DRRELEXTRA "" diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c index e8e99ad35..6851c6270 100644 --- a/drivers/isdn/hardware/eicon/debug.c +++ b/drivers/isdn/hardware/eicon/debug.c @@ -5,6 +5,7 @@ #include "divasync.h" #include "kst_ifc.h" #include "maintidi.h" +#include "man_defs.h" /* LOCALS @@ -13,17 +14,23 @@ static void DI_register (void *arg); static void DI_deregister (pDbgHandle hDbg); -static void DI_format (int do_lock, word id, int type, char *format, va_list ap); +static void DI_format (int do_lock, word id, int type, char *format, va_list argument_list); static void DI_format_locked (word id, int type, char *format, va_list argument_list); static void DI_format_old (word id, char *format, va_list ap) { } -static void DiProcessEventLog (word id, dword msgID, va_list ap) { } +static void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap) { } static void single_p (byte * P, word * PLength, byte Id); static void diva_maint_xdi_cb (ENTITY* e); static word SuperTraceCreateReadReq (byte* P, const char* path); +static int diva_mnt_cmp_nmbr (const char* nmbr); +static void diva_free_dma_descriptor (IDI_CALL request, int nr); +static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic); void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...); static dword MaxDumpSize = 256 ; static dword MaxXlogSize = 2 + 128 ; +static char TraceFilter[DIVA_MAX_SELECTIVE_FILTER_LENGTH+1]; +static int TraceFilterIdent = -1; +static int TraceFilterChannel = -1; typedef struct _diva_maint_client { dword sec; @@ -40,9 +47,10 @@ typedef struct _diva_maint_client { BUFFERS XData; char xbuffer[2048+512]; byte* pmem; - int request_pending; + int request_pending; + int dma_handle; } diva_maint_client_t; -static diva_maint_client_t clients[64]; +static diva_maint_client_t clients[MAX_DESCRIPTORS]; static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask); @@ -201,6 +209,10 @@ int diva_maint_init (byte* base, unsigned long length, int do_init) { return (-1); } + TraceFilter[0] = 0; + TraceFilterIdent = -1; + TraceFilterChannel = -1; + dbg_base = base; diva_os_get_time (&start_sec, &start_usec); @@ -249,7 +261,6 @@ int diva_maint_init (byte* base, unsigned long length, int do_init) { return (-1); } - return (0); } @@ -302,16 +313,16 @@ diva_dbg_entry_head_t* diva_maint_get_message (word* size, diva_os_spin_lock_magic_t* old_irql) { diva_dbg_entry_head_t* pmsg = NULL; - diva_os_enter_spin_lock_hard (&dbg_q_lock, old_irql, "read"); + diva_os_enter_spin_lock (&dbg_q_lock, old_irql, "read"); if (dbg_q_busy) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_busy"); + diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_busy"); return NULL; } dbg_q_busy = 1; if (!(pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, size))) { dbg_q_busy = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_empty"); + diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_empty"); } return (pmsg); @@ -330,7 +341,7 @@ void diva_maint_ack_message (int do_release, queueFreeMsg (dbg_queue); } dbg_q_busy = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_ack"); + diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_ack"); } @@ -378,14 +389,14 @@ static void DI_register (void *arg) { return ; } - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register"); for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) { if (clients[id].hDbg == hDbg) { /* driver already registered */ - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); return; } if (clients[id].hDbg) { /* slot is busy */ @@ -468,7 +479,7 @@ static void DI_register (void *arg) { } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); } static void DI_deregister (pDbgHandle hDbg) { @@ -480,8 +491,8 @@ static void DI_deregister (pDbgHandle hDbg) { diva_os_get_time (&sec, &usec); - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "read"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read"); for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { if (clients[i].hDbg == hDbg) { @@ -543,8 +554,8 @@ static void DI_deregister (pDbgHandle hDbg) { } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "read_ack"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read_ack"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack"); if (pmem) { diva_os_free (0, pmem); @@ -572,13 +583,22 @@ static void DI_format (int do_lock, char *data; unsigned short code; - if (!format) + if (diva_os_in_irq()) { + dbg_sequence++; return; + } + + if ((!format) || + ((TraceFilter[0] != 0) && ((TraceFilterIdent < 0) || (TraceFilterChannel < 0)))) { + return; + } + + diva_os_get_time (&sec, &usec); if (do_lock) { - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "format"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "format"); } switch (type) { @@ -703,7 +723,7 @@ static void DI_format (int do_lock, } if (do_lock) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "format"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "format"); } } @@ -720,7 +740,7 @@ int diva_get_driver_info (dword id, byte* data, int data_length) { return (-1); } - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info"); if (clients[id].hDbg) { *p++ = 1; @@ -757,7 +777,7 @@ int diva_get_driver_info (dword id, byte* data, int data_length) { } *p++ = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info"); return (p - data); } @@ -769,7 +789,7 @@ int diva_get_driver_dbg_mask (dword id, byte* data) { if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) { return (-1); } - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info"); if (clients[id].hDbg) { ret = 4; @@ -779,7 +799,7 @@ int diva_get_driver_dbg_mask (dword id, byte* data) { *data++= (byte)(clients[id].hDbg->dbgMask >> 24); } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info"); return (ret); } @@ -793,8 +813,8 @@ int diva_set_driver_dbg_mask (dword id, dword mask) { return (-1); } - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "dbg mask"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "dbg mask"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "dbg mask"); if (clients[id].hDbg) { dword old_mask = clients[id].hDbg->dbgMask; @@ -806,14 +826,14 @@ int diva_set_driver_dbg_mask (dword id, dword mask) { } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "dbg mask"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "dbg mask"); if (clients[id].request_pending) { clients[id].request_pending = 0; (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib)); } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "dbg mask"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); return (ret); } @@ -851,12 +871,12 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { diva_os_get_time (&sec, &usec); diva_get_idi_adapter_info (d->request, &serial, &logical); if (serial & 0xff000000) { - sprintf (tmp, "ADAPTER:%d SN:%d-%d", + sprintf (tmp, "ADAPTER:%d SN:%u-%d", (int)logical, serial & 0x00ffffff, (byte)(((serial & 0xff000000) >> 24) + 1)); } else { - sprintf (tmp, "ADAPTER:%d SN:%d", (int)logical, serial); + sprintf (tmp, "ADAPTER:%d SN:%u", (int)logical, serial); } if (!(pmem = diva_os_malloc (0, DivaSTraceGetMemotyRequirement (d->channels)))) { @@ -864,13 +884,14 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { } memset (pmem, 0x00, DivaSTraceGetMemotyRequirement (d->channels)); - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register"); for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) { if (clients[id].hDbg && (clients[id].request == d->request)) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_free(0, pmem); return; } if (clients[id].hDbg) { /* slot is busy */ @@ -891,8 +912,8 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { } if (free_id < 0) { - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_os_free (0, pmem); return; } @@ -908,6 +929,7 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { clients[id].Dbg.drvTag[0] = 0; clients[id].logical = (int)logical; clients[id].channels = (int)d->channels; + clients[id].dma_handle = -1; clients[id].Dbg.dbgMask = 0; clients[id].dbgMask = clients[id].Dbg.dbgMask; @@ -949,8 +971,8 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { clients[id].request = NULL; clients[id].request_pending = 0; clients[id].hDbg = NULL; - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_os_free (0, pmem); return; } @@ -988,14 +1010,14 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { org_mask = clients[id].Dbg.dbgMask; clients[id].Dbg.dbgMask = 0; - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); if (clients[id].request_pending) { clients[id].request_pending = 0; (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib)); } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_set_driver_dbg_mask (id, org_mask); } @@ -1012,8 +1034,8 @@ void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) { diva_os_get_time (&sec, &usec); - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "read"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read"); for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { if (clients[i].hDbg && (clients[i].request == d->request)) { @@ -1030,8 +1052,15 @@ void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) { } clients[i].hDbg = NULL; - clients[i].request = NULL; clients[i].request_pending = 0; + if (clients[i].dma_handle >= 0) { + /* + Free DMA handle + */ + diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle); + clients[i].dma_handle = -1; + } + clients[i].request = NULL; /* Log driver register, MAINT driver ID is '0' @@ -1069,8 +1098,8 @@ void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) { } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "read_ack"); - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read_ack"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack"); if (pmem) { diva_os_free (0, pmem); @@ -1142,6 +1171,42 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) { if (pC && pC->pIdiLib && pC->request) { ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib); + IDI_SYNC_REQ* preq; + char buffer[((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)]; + char features[4]; + word assign_data_length = 1; + + features[0] = 0; + pC->xbuffer[0] = 0; + preq = (IDI_SYNC_REQ*)&buffer[0]; + preq->xdi_extended_features.Req = 0; + preq->xdi_extended_features.Rc = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES; + preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features); + preq->xdi_extended_features.info.features = &features[0]; + + (*(pC->request))((ENTITY*)preq); + + if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) && + (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) { + dword rx_dma_magic; + if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) { + pC->xbuffer[0] = LLI; + pC->xbuffer[1] = 8; + pC->xbuffer[2] = 0x40; + pC->xbuffer[3] = (byte)pC->dma_handle; + pC->xbuffer[4] = (byte)rx_dma_magic; + pC->xbuffer[5] = (byte)(rx_dma_magic >> 8); + pC->xbuffer[6] = (byte)(rx_dma_magic >> 16); + pC->xbuffer[7] = (byte)(rx_dma_magic >> 24); + pC->xbuffer[8] = (byte)DIVA_MAX_MANAGEMENT_TRANSFER_SIZE; + pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8); + pC->xbuffer[10] = 0; + + assign_data_length = 11; + } + } else { + pC->dma_handle = -1; + } e->Id = MAN_ID; e->callback = diva_maint_xdi_cb; @@ -1149,9 +1214,8 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) { e->X = &pC->XData; e->Req = ASSIGN; e->ReqCh = 0; - e->X->PLength = 1; + e->X->PLength = assign_data_length; e->X->P = (byte*)&pC->xbuffer[0]; - pC->xbuffer[0] = 0; pC->request_pending = 1; @@ -1300,16 +1364,25 @@ static void diva_maint_xdi_cb (ENTITY* e) { diva_os_spin_lock_magic_t old_irql, old_irql1; - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "xdi_cb"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "xdi_cb"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb"); pC = (diva_maint_client_t*)pLib->hAdapter; - if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) { - diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error"); + if ((e->complete == 255) || (pC->dma_handle < 0)) { + if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) { + diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error"); + } + } else { + /* + Process combined management interface indication + */ + if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) { + diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error (DMA mode)"); + } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "xdi_cb"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb"); if (pC->request_pending) { @@ -1317,7 +1390,7 @@ static void diva_maint_xdi_cb (ENTITY* e) { (*(pC->request))(e); } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "xdi_cb"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb"); } @@ -1365,8 +1438,42 @@ static void diva_maint_state_change_notify (void* user_context, } switch (notify_subject) { - case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: - if (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS) { + case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: { + int view = (TraceFilter[0] == 0); + /* + Process selective Trace + */ + if (channel->Line[0] == 'I' && channel->Line[1] == 'd' && + channel->Line[2] == 'l' && channel->Line[3] == 'e') { + if ((TraceFilterIdent == pC->hDbg->id) && (TraceFilterChannel == (int)channel->ChannelNumber)) { + (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 0); + (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 0); + diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace OFF for Ch=%d", + (int)channel->ChannelNumber); + TraceFilterIdent = -1; + TraceFilterChannel = -1; + view = 1; + } + } else if (TraceFilter[0] && (TraceFilterIdent < 0) && !(diva_mnt_cmp_nmbr (&channel->RemoteAddress[0]) && + diva_mnt_cmp_nmbr (&channel->LocalAddress[0]))) { + + if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0) { /* Activate B-channel trace */ + (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 1); + } + if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0) { /* Activate AudioTap Trace */ + (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 1); + } + + TraceFilterIdent = pC->hDbg->id; + TraceFilterChannel = (int)channel->ChannelNumber; + + if (TraceFilterIdent >= 0) { + diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace ON for Ch=%d", + (int)channel->ChannelNumber); + view = 1; + } + } + if (view && (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS)) { diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Ch = %d", (int)channel->ChannelNumber); diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]); @@ -1392,10 +1499,26 @@ static void diva_maint_state_change_notify (void* user_context, channel->LastDisconnecCause); diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Owner = <%s>", &channel->UserID[0]); } - break; + + } break; case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE: if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) { + { + int ch = TraceFilterChannel; + int id = TraceFilterIdent; + + if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { + if (ch != (int)modem->ChannelNumber) { + break; + } + } else if (TraceFilter[0] != 0) { + break; + } + } + + diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch = %lu", (int)modem->ChannelNumber); diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu", modem->Event); @@ -1428,6 +1551,20 @@ static void diva_maint_state_change_notify (void* user_context, case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE: if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) { + { + int ch = TraceFilterChannel; + int id = TraceFilterIdent; + + if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { + if (ch != (int)fax->ChannelNumber) { + break; + } + } else if (TraceFilter[0] != 0) { + break; + } + } + diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch = %lu",(int)fax->ChannelNumber); diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu", fax->Event); diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu", fax->Page_Counter); @@ -1660,6 +1797,52 @@ static void diva_maint_trace_notify (void* user_context, diva_dbg_entry_head_t* pmsg; word size; dword sec, usec; + int ch = TraceFilterChannel; + int id = TraceFilterIdent; + + /* + Selective trace + */ + if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { + const char* p = NULL; + int ch_value = -1; + MI_XLOG_HDR *TrcData = (MI_XLOG_HDR *)xlog_buffer; + + if (Adapter != clients[id].logical) { + return; /* Ignore all trace messages from other adapters */ + } + + if (TrcData->code == 24) { + p = (char*)&TrcData->code; + p += 2; + } + + /* + All L1 messages start as [dsp,ch], so we can filter this information + and filter out all messages that use different channel + */ + if (p && p[0] == '[') { + if (p[2] == ',') { + p += 3; + ch_value = *p - '0'; + } else if (p[3] == ',') { + p += 4; + ch_value = *p - '0'; + } + if (ch_value >= 0) { + if (p[2] == ']') { + ch_value = ch_value * 10 + p[1] - '0'; + } + if (ch_value != ch) { + return; /* Ignore other channels */ + } + } + } + + } else if (TraceFilter[0] != 0) { + return; /* Ignore trace if trace filter is activated, but idle */ + } diva_os_get_time (&sec, &usec); @@ -1705,18 +1888,20 @@ static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword ol (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib, (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0); } - if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) { - int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); + if (!TraceFilter[0]) { + if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) { + int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); - for (i = 0; i < pC->channels; i++) { - (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state); + for (i = 0; i < pC->channels; i++) { + (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state); + } } - } - if (changed & DIVA_MGT_DBG_IFC_AUDIO) { - int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); + if (changed & DIVA_MGT_DBG_IFC_AUDIO) { + int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); - for (i = 0; i < pC->channels; i++) { - (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state); + for (i = 0; i < pC->channels; i++) { + (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state); + } } } } @@ -1743,8 +1928,8 @@ int diva_mnt_shutdown_xdi_adapters (void) { for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { pmem = NULL; - diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload"); - diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "unload"); + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "unload"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "unload"); if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) { if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) { @@ -1759,19 +1944,31 @@ int diva_mnt_shutdown_xdi_adapters (void) { clients[i].pmem = NULL; } clients[i].hDbg = NULL; - clients[i].request = NULL; clients[i].request_pending = 0; + + if (clients[i].dma_handle >= 0) { + /* + Free DMA handle + */ + diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle); + clients[i].dma_handle = -1; + } + clients[i].request = NULL; } else { fret = -1; } } - diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "unload"); + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "unload"); if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) { clients[i].request_pending = 0; (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib)); + if (clients[i].dma_handle >= 0) { + diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle); + clients[i].dma_handle = -1; + } } - diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "unload"); if (pmem) { diva_os_free (0, pmem); @@ -1781,3 +1978,156 @@ int diva_mnt_shutdown_xdi_adapters (void) { return (fret); } +/* + Set/Read the trace filter used for selective tracing. + Affects B- and Audio Tap trace mask at run time + */ +int diva_set_trace_filter (int filter_length, const char* filter) { + diva_os_spin_lock_magic_t old_irql, old_irql1; + int i, ch, on, client_b_on, client_atap_on; + + diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + + if (filter_length <= DIVA_MAX_SELECTIVE_FILTER_LENGTH) { + memcpy (&TraceFilter[0], filter, filter_length); + if (TraceFilter[filter_length]) { + TraceFilter[filter_length] = 0; + } + if (TraceFilter[0] == '*') { + TraceFilter[0] = 0; + } + } else { + filter_length = -1; + } + + TraceFilterIdent = -1; + TraceFilterChannel = -1; + + on = (TraceFilter[0] == 0); + + for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) { + client_b_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); + client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); + for (ch = 0; ch < clients[i].channels; ch++) { + (*(clients[i].pIdiLib->DivaSTraceSetBChannel))(clients[i].pIdiLib->hLib, ch+1, client_b_on); + (*(clients[i].pIdiLib->DivaSTraceSetAudioTap))(clients[i].pIdiLib->hLib, ch+1, client_atap_on); + } + } + } + + for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) { + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + clients[i].request_pending = 0; + (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib)); + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + } + } + + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); + diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask"); + + return (filter_length); +} + +int diva_get_trace_filter (int max_length, char* filter) { + diva_os_spin_lock_magic_t old_irql; + int len; + + diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read_filter"); + len = strlen (&TraceFilter[0]) + 1; + if (max_length >= len) { + memcpy (filter, &TraceFilter[0], len); + } + diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_filter"); + + return (len); +} + +static int diva_dbg_cmp_key (const char* ref, const char* key) { + while (*key && (*ref++ == *key++)); + return (!*key && !*ref); +} + +/* + In case trace filter starts with "C" character then + all following characters are interpreted as command. + Followings commands are available: + - single, trace single call at time, independent from CPN/CiPN + */ +static int diva_mnt_cmp_nmbr (const char* nmbr) { + const char* ref = &TraceFilter[0]; + int ref_len = strlen(&TraceFilter[0]), nmbr_len = strlen(nmbr); + + if (ref[0] == 'C') { + if (diva_dbg_cmp_key (&ref[1], "single")) { + return (0); + } + return (-1); + } + + if (!ref_len || (ref_len > nmbr_len)) { + return (-1); + } + + nmbr = nmbr + nmbr_len - 1; + ref = ref + ref_len - 1; + + while (ref_len--) { + if (*nmbr-- != *ref--) { + return (-1); + } + } + + return (0); +} + +static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic) { + ENTITY e; + IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e; + + if (!request) { + return (-1); + } + + pReq->xdi_dma_descriptor_operation.Req = 0; + pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION; + + pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC; + pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1; + pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; + pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; + + (*request)((ENTITY*)pReq); + + if (!pReq->xdi_dma_descriptor_operation.info.operation && + (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) && + pReq->xdi_dma_descriptor_operation.info.descriptor_magic) { + *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic; + return (pReq->xdi_dma_descriptor_operation.info.descriptor_number); + } else { + return (-1); + } +} + +static void diva_free_dma_descriptor (IDI_CALL request, int nr) { + ENTITY e; + IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e; + + if (!request || (nr < 0)) { + return; + } + + pReq->xdi_dma_descriptor_operation.Req = 0; + pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION; + + pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE; + pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr; + pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; + pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; + + (*request)((ENTITY*)pReq); +} + diff --git a/drivers/isdn/hardware/eicon/debug_if.h b/drivers/isdn/hardware/eicon/debug_if.h index 0136eea12..4db739d58 100644 --- a/drivers/isdn/hardware/eicon/debug_if.h +++ b/drivers/isdn/hardware/eicon/debug_if.h @@ -57,12 +57,18 @@ void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d); void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d); int diva_mnt_shutdown_xdi_adapters (void); +#define DIVA_MAX_SELECTIVE_FILTER_LENGTH 127 +int diva_set_trace_filter (int filter_length, const char* filter); +int diva_get_trace_filter (int max_length, char* filter); + #define DITRACE_CMD_GET_DRIVER_INFO 1 #define DITRACE_READ_DRIVER_DBG_MASK 2 #define DITRACE_WRITE_DRIVER_DBG_MASK 3 #define DITRACE_READ_TRACE_ENTRY 4 #define DITRACE_READ_TRACE_ENTRYS 5 +#define DITRACE_WRITE_SELECTIVE_TRACE_FILTER 6 +#define DITRACE_READ_SELECTIVE_TRACE_FILTER 7 /* Trace lavels for debug via management interface diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h index 516d2bd8b..11b3b9edd 100644 --- a/drivers/isdn/hardware/eicon/debuglib.h +++ b/drivers/isdn/hardware/eicon/debuglib.h @@ -232,7 +232,7 @@ typedef struct _DbgHandle_ *pDbgHandle ; typedef void ( * DbgEnd) (pDbgHandle) ; typedef void ( * DbgLog) (unsigned short, int, char *, va_list) ; typedef void ( * DbgOld) (unsigned short, char *, va_list) ; -typedef void ( * DbgEv) (unsigned short, unsigned int, va_list) ; +typedef void ( * DbgEv) (unsigned short, unsigned long, va_list) ; typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ; typedef struct _DbgHandle_ { char Registered ; /* driver successfull registered */ @@ -259,7 +259,7 @@ typedef struct _DbgHandle_ void *pReserved3 ; } _DbgHandle_ ; extern _DbgHandle_ myDriverDebugHandle ; -typedef struct +typedef struct _OldDbgHandle_ { struct _OldDbgHandle_ *next ; void *pIrp ; long regTime[2] ; @@ -310,7 +310,7 @@ typedef struct unsigned long B_ChannelMask; unsigned long LogBufferSize; } CardTrace; - } u1; + }Data; } _DbgExtendedInfo_; #ifndef DIVA_NO_DEBUGLIB /* ------------------------------------------------------------- diff --git a/drivers/isdn/hardware/eicon/diddfunc.c b/drivers/isdn/hardware/eicon/diddfunc.c index 33172c1d6..302923417 100644 --- a/drivers/isdn/hardware/eicon/diddfunc.c +++ b/drivers/isdn/hardware/eicon/diddfunc.c @@ -1,4 +1,4 @@ -/* $Id: diddfunc.c,v 1.14 2003/08/25 10:06:37 schindler Exp $ +/* $Id: diddfunc.c,v 1.14.6.2 2004/08/28 20:03:53 armin Exp $ * * DIDD Interface module for Eicon active cards. * @@ -16,8 +16,6 @@ #include "dadapter.h" #include "divasync.h" -#define MAX_DESCRIPTORS 32 - #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c index 0afd015e0..48b3f15bc 100644 --- a/drivers/isdn/hardware/eicon/diva_didd.c +++ b/drivers/isdn/hardware/eicon/diva_didd.c @@ -1,4 +1,4 @@ -/* $Id: diva_didd.c,v 1.13 2003/08/27 10:11:21 schindler Exp $ +/* $Id: diva_didd.c,v 1.13.6.1 2004/08/28 20:03:53 armin Exp $ * * DIDD Interface module for Eicon active cards. * @@ -23,7 +23,7 @@ #include "divasync.h" #include "did_vers.h" -static char *main_revision = "$Revision: 1.13 $"; +static char *main_revision = "$Revision: 1.13.6.1 $"; static char *DRIVERNAME = "Eicon DIVA - DIDD table (http://www.melware.net)"; @@ -37,8 +37,6 @@ MODULE_AUTHOR("Cytronics & Melware, Eicon Networks"); MODULE_SUPPORTED_DEVICE("Eicon diva drivers"); MODULE_LICENSE("GPL"); -#define MAX_DESCRIPTORS 32 - #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) @@ -50,8 +48,8 @@ extern void DIVA_DIDD_Read(void *, int); static struct proc_dir_entry *proc_didd; struct proc_dir_entry *proc_net_eicon = NULL; -EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); -EXPORT_SYMBOL_NOVERS(proc_net_eicon); +EXPORT_SYMBOL(DIVA_DIDD_Read); +EXPORT_SYMBOL(proc_net_eicon); static char *getrev(const char *revision) { diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c index 6b22a8a5f..989cdef60 100644 --- a/drivers/isdn/hardware/eicon/divamnt.c +++ b/drivers/isdn/hardware/eicon/divamnt.c @@ -1,4 +1,4 @@ -/* $Id: divamnt.c,v 1.32 2004/01/15 09:48:13 armin Exp $ +/* $Id: divamnt.c,v 1.32.6.5 2004/08/28 20:03:53 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * Maint module @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include "platform.h" @@ -26,7 +24,7 @@ #include "divasync.h" #include "debug_if.h" -static char *main_revision = "$Revision: 1.32 $"; +static char *main_revision = "$Revision: 1.32.6.5 $"; static int major; @@ -47,8 +45,7 @@ static char *DEVNAME = "DivasMAINT"; char *DRIVERRELEASE_MNT = "2.0"; static wait_queue_head_t msgwaitq; -static DECLARE_MUTEX(opened_sem); -static int opened; +static unsigned long opened; static struct timeval start_time; extern int mntfunc_init(int *, void **, unsigned long); @@ -73,20 +70,6 @@ static char *getrev(const char *revision) return rev; } -/* - * buffer alloc - */ -void *diva_os_malloc_tbuffer(unsigned long flags, unsigned long size) -{ - return (kmalloc(size, GFP_KERNEL)); -} -void diva_os_free_tbuffer(unsigned long flags, void *ptr) -{ - if (ptr) { - kfree(ptr); - } -} - /* * kernel/user space copy functions */ @@ -131,154 +114,8 @@ void diva_os_get_time(dword * sec, dword * usec) } /* - * /proc entries + * device node operations */ - -extern struct proc_dir_entry *proc_net_eicon; -static struct proc_dir_entry *maint_proc_entry = NULL; - -/* - Read function is provided for compatibility reason - this allows - to read unstructured traces, formated as ascii string only - */ -static ssize_t -maint_read(struct file *file, char __user *buf, size_t count, loff_t * off) -{ - diva_dbg_entry_head_t *pmsg = NULL; - diva_os_spin_lock_magic_t old_irql; - word size; - char *pstr, *dli_label = "UNK"; - int str_length; - int *str_msg; - - if (!file->private_data) { - for (;;) { - while ( - (pmsg = - diva_maint_get_message(&size, - &old_irql))) { - if (!(pmsg->facility == MSG_TYPE_STRING)) { - diva_maint_ack_message(1, - &old_irql); - } else { - break; - } - } - - if (!pmsg) { - if (file->f_flags & O_NONBLOCK) { - return (-EAGAIN); - } - interruptible_sleep_on(&msgwaitq); - if (signal_pending(current)) { - return (-ERESTARTSYS); - } - } else { - break; - } - } - /* - The length of message that shoule be read is: - pmsg->data_length + label(25) + DrvID(2) + byte CR + trailing zero - */ - if (! - (str_msg = - (int *) diva_os_malloc_tbuffer(0, - pmsg->data_length + - 29 + 2 * sizeof(int)))) { - diva_maint_ack_message(0, &old_irql); - return (-ENOMEM); - } - pstr = (char *) &str_msg[2]; - - switch (pmsg->dli) { - case DLI_LOG: - dli_label = "LOG"; - break; - case DLI_FTL: - dli_label = "FTL"; - break; - case DLI_ERR: - dli_label = "ERR"; - break; - case DLI_TRC: - dli_label = "TRC"; - break; - case DLI_REG: - dli_label = "REG"; - break; - case DLI_MEM: - dli_label = "MEM"; - break; - case DLI_SPL: - dli_label = "SPL"; - break; - case DLI_IRP: - dli_label = "IRP"; - break; - case DLI_TIM: - dli_label = "TIM"; - break; - case DLI_TAPI: - dli_label = "TAPI"; - break; - case DLI_NDIS: - dli_label = "NDIS"; - break; - case DLI_CONN: - dli_label = "CONN"; - break; - case DLI_STAT: - dli_label = "STAT"; - break; - case DLI_PRV0: - dli_label = "PRV0"; - break; - case DLI_PRV1: - dli_label = "PRV1"; - break; - case DLI_PRV2: - dli_label = "PRV2"; - break; - case DLI_PRV3: - dli_label = "PRV3"; - break; - } - str_length = sprintf(pstr, "%s %02x %s\n", - dli_label, (byte) pmsg->drv_id, - (char *) &pmsg[1]); - str_msg[0] = str_length; - str_msg[1] = 0; - file->private_data = str_msg; - diva_maint_ack_message(1, &old_irql); - } else { - str_msg = (int *) file->private_data; - pstr = (char *) &str_msg[2]; - pstr += str_msg[1]; /* head + offset */ - str_length = str_msg[0] - str_msg[1]; /* length - offset */ - } - str_length = MIN(str_length, count); - - if (diva_os_copy_to_user(NULL, buf, pstr, str_length)) { - diva_os_free_tbuffer(0, str_msg); - file->private_data = NULL; - return (-EFAULT); - } - str_msg[1] += str_length; - if ((str_msg[0] - str_msg[1]) <= 0) { - diva_os_free_tbuffer(0, str_msg); - file->private_data = NULL; - } - - return (str_length); -} - -static ssize_t -maint_write(struct file *file, const char __user *buf, size_t count, loff_t * off) -{ - return (-ENODEV); -} - static unsigned int maint_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; @@ -293,13 +130,10 @@ static unsigned int maint_poll(struct file *file, poll_table * wait) static int maint_open(struct inode *ino, struct file *filep) { - down(&opened_sem); - if (opened) { - up(&opened_sem); + /* only one open is allowed, so we test + it atomically */ + if (test_and_set_bit(0, &opened)) return (-EBUSY); - } - opened++; - up(&opened_sem); filep->private_data = NULL; @@ -309,54 +143,16 @@ static int maint_open(struct inode *ino, struct file *filep) static int maint_close(struct inode *ino, struct file *filep) { if (filep->private_data) { - diva_os_free_tbuffer(0, filep->private_data); + diva_os_free(0, filep->private_data); filep->private_data = NULL; } - down(&opened_sem); - opened--; - up(&opened_sem); + /* clear 'used' flag */ + clear_bit(0, &opened); + return (0); } -/* - * fops - */ -static struct file_operations maint_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = maint_read, - .write = maint_write, - .poll = maint_poll, - .open = maint_open, - .release = maint_close -}; - -static int DIVA_INIT_FUNCTION create_maint_proc(void) -{ - maint_proc_entry = - create_proc_entry("maint", S_IFREG | S_IRUGO | S_IWUSR, - proc_net_eicon); - if (!maint_proc_entry) - return (0); - - maint_proc_entry->proc_fops = &maint_fops; - maint_proc_entry->owner = THIS_MODULE; - - return (1); -} - -static void remove_maint_proc(void) -{ - if (maint_proc_entry) { - remove_proc_entry("maint", proc_net_eicon); - maint_proc_entry = NULL; - } -} - -/* - * device node operations - */ static ssize_t divas_maint_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { @@ -427,18 +223,10 @@ static int DIVA_INIT_FUNCTION maint_init(void) ret = -EIO; goto out; } - if (!create_maint_proc()) { - printk(KERN_ERR "%s: failed to create proc entry.\n", - DRIVERLNAME); - divas_maint_unregister_chrdev(); - ret = -EIO; - goto out; - } if (!(mntfunc_init(&buffer_length, &buffer, diva_dbg_mem))) { printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME); - remove_maint_proc(); divas_maint_unregister_chrdev(); ret = -EIO; goto out; @@ -457,7 +245,6 @@ static int DIVA_INIT_FUNCTION maint_init(void) */ static void DIVA_EXIT_FUNCTION maint_exit(void) { - remove_maint_proc(); divas_maint_unregister_chrdev(); mntfunc_finit(); @@ -466,3 +253,4 @@ static void DIVA_EXIT_FUNCTION maint_exit(void) module_init(maint_init); module_exit(maint_exit); + diff --git a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c index 4ee56d4bb..df61e510a 100644 --- a/drivers/isdn/hardware/eicon/divasfunc.c +++ b/drivers/isdn/hardware/eicon/divasfunc.c @@ -1,4 +1,4 @@ -/* $Id: divasfunc.c,v 1.23 2004/04/08 01:17:57 armin Exp $ +/* $Id: divasfunc.c,v 1.23.4.2 2004/08/28 20:03:53 armin Exp $ * * Low level driver for Eicon DIVA Server ISDN cards. * @@ -27,8 +27,6 @@ extern void DIVA_DIDD_Read(void *, int); extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; -#define MAX_DESCRIPTORS 32 - extern char *DRIVERRELEASE_DIVAS; static dword notify_handle; @@ -76,10 +74,10 @@ void diva_xdi_didd_register_adapter(int card) d.features = IoAdapters[card - 1]->Properties.Features; DBG_TRC(("DIDD register A(%d) channels=%d", card, d.channels)) - /* workaround for different Name in structure */ - strlcpy(IoAdapters[card - 1]->Name, - IoAdapters[card - 1]->Properties.Name, - sizeof(IoAdapters[card - 1]->Name)); + /* workaround for different Name in structure */ + strlcpy(IoAdapters[card - 1]->Name, + IoAdapters[card - 1]->Properties.Name, + sizeof(IoAdapters[card - 1]->Name)); req.didd_remove_adapter.e.Req = 0; req.didd_add_adapter.e.Rc = IDI_SYNC_REQ_DIDD_ADD_ADAPTER; req.didd_add_adapter.info.descriptor = (void *) &d; diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h index 81c444828..0a5be7f96 100644 --- a/drivers/isdn/hardware/eicon/divasync.h +++ b/drivers/isdn/hardware/eicon/divasync.h @@ -31,33 +31,31 @@ #define IDI_SYNC_REQ_SET_POSTCALL 0x03 #define IDI_SYNC_REQ_GET_XLOG 0x04 #define IDI_SYNC_REQ_GET_FEATURES 0x05 -/* Added for DIVA USB support */ #define IDI_SYNC_REQ_USB_REGISTER 0x06 #define IDI_SYNC_REQ_USB_RELEASE 0x07 #define IDI_SYNC_REQ_USB_ADD_DEVICE 0x08 #define IDI_SYNC_REQ_USB_START_DEVICE 0x09 #define IDI_SYNC_REQ_USB_STOP_DEVICE 0x0A #define IDI_SYNC_REQ_USB_REMOVE_DEVICE 0x0B -/* Added for Diva Server Monitor */ #define IDI_SYNC_REQ_GET_CARDTYPE 0x0C #define IDI_SYNC_REQ_GET_DBG_XLOG 0x0D -#define IDI_SYNC_REQ_GET_LINE_IDX 0x0E #define DIVA_USB #define DIVA_USB_REQ 0xAC #define DIVA_USB_TEST 0xAB #define DIVA_USB_ADD_ADAPTER 0xAC #define DIVA_USB_REMOVE_ADAPTER 0xAD -/******************************************************************************/ #define IDI_SYNC_REQ_SERIAL_HOOK 0x80 #define IDI_SYNC_REQ_XCHANGE_STATUS 0x81 #define IDI_SYNC_REQ_USB_HOOK 0x82 #define IDI_SYNC_REQ_PORTDRV_HOOK 0x83 -#define IDI_SYNC_REQ_SLI (0x84) /* SLI request from 3signal modem drivers */ +#define IDI_SYNC_REQ_SLI 0x84 /* SLI request from 3signal modem drivers */ #define IDI_SYNC_REQ_RECONFIGURE 0x85 #define IDI_SYNC_REQ_RESET 0x86 +#define IDI_SYNC_REQ_GET_85X_DEVICE_DATA 0x87 #define IDI_SYNC_REQ_LOCK_85X 0x88 +#define IDI_SYNC_REQ_DIVA_85X_USB_DATA_EXCHANGE 0x99 +#define IDI_SYNC_REQ_DIPORT_EXCHANGE_REQ 0x98 #define IDI_SYNC_REQ_GET_85X_EXT_PORT_TYPE 0xA0 -#define IDI_SYNC_REQ_DIPORT_GET_85X_TX_CTRL_FN 0x98 /******************************************************************************/ #define IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES 0x92 /* @@ -87,6 +85,8 @@ typedef struct _diva_xdi_get_extended_xdi_features { #define DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS 0x08 #define DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC 0x10 #define DIVA_XDI_EXTENDED_FEATURE_RX_DMA 0x20 +#define DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA 0x40 +#define DIVA_XDI_EXTENDED_FEATURE_WIDE_ID 0x80 #define DIVA_XDI_EXTENDED_FEATURES_MAX_SZ 1 /******************************************************************************/ #define IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR 0x93 @@ -115,6 +115,7 @@ typedef struct _diva_xdi_get_capi_parameters { typedef struct _diva_xdi_get_logical_adapter_number { dword logical_adapter_number; dword controller; + dword total_controllers; } diva_xdi_get_logical_adapter_number_s_t; /******************************************************************************/ #define IDI_SYNC_REQ_UP1DM_OPERATION 0x96 @@ -134,6 +135,7 @@ typedef struct _diva_xdi_dma_descriptor_operation { #define IDI_SYNC_REQ_DIDD_ADD_ADAPTER 0x03 #define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER 0x04 #define IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY 0x05 +#define IDI_SYNC_REQ_DIDD_GET_CFG_LIB_IFC 0x10 typedef struct _diva_didd_adapter_notify { dword handle; /* Notification handle */ void * callback; @@ -149,6 +151,9 @@ typedef struct _diva_didd_read_adapter_array { void * buffer; dword length; } diva_didd_read_adapter_array_t; +typedef struct _diva_didd_get_cfg_lib_ifc { + void* ifc; +} diva_didd_get_cfg_lib_ifc_t; /******************************************************************************/ #define IDI_SYNC_REQ_XDI_GET_STREAM 0x91 #define DIVA_XDI_SYNCHRONOUS_SERVICE 0x01 @@ -466,6 +471,10 @@ typedef union ENTITY e; diva_didd_read_adapter_array_t info; } didd_read_adapter_array; + struct { + ENTITY e; + diva_didd_get_cfg_lib_ifc_t info; + } didd_get_cfg_lib_ifc; struct { unsigned char Req; unsigned char Rc; diff --git a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c index 63746f401..4cbc68cf4 100644 --- a/drivers/isdn/hardware/eicon/idifunc.c +++ b/drivers/isdn/hardware/eicon/idifunc.c @@ -1,4 +1,4 @@ -/* $Id: idifunc.c,v 1.14.4.2 2004/05/09 16:42:20 armin Exp $ +/* $Id: idifunc.c,v 1.14.4.4 2004/08/28 20:03:53 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * User Mode IDI Interface @@ -25,8 +25,6 @@ extern void DIVA_DIDD_Read(void *, int); extern int diva_user_mode_idi_create_adapter(const DESCRIPTOR *, int); extern void diva_user_mode_idi_remove_adapter(int); -#define MAX_DESCRIPTORS 32 - static dword notify_handle; static DESCRIPTOR DAdapter; static DESCRIPTOR MAdapter; diff --git a/drivers/isdn/hardware/eicon/io.c b/drivers/isdn/hardware/eicon/io.c index 6f94ee932..15bb9c636 100644 --- a/drivers/isdn/hardware/eicon/io.c +++ b/drivers/isdn/hardware/eicon/io.c @@ -77,6 +77,7 @@ static byte extended_xdi_features[DIVA_XDI_EXTENDED_FEATURES_MAX_SZ+1] = { #if defined(DIVA_IDI_RX_DMA) DIVA_XDI_EXTENDED_FEATURE_CMA | DIVA_XDI_EXTENDED_FEATURE_RX_DMA | + DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA | #endif DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC), 0 @@ -226,8 +227,10 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e) if (pI->descriptor_number >= 0) { dword dma_magic; void* local_addr; +#if 0 DBG_TRC(("A(%d) dma_alloc(%d)", IoAdapter->ANum, pI->descriptor_number)) +#endif diva_get_dma_map_entry (\ (struct _diva_dma_map_entry*)IoAdapter->dma_map, pI->descriptor_number, @@ -240,7 +243,9 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e) } } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) && (pI->descriptor_number >= 0)) { +#if 0 DBG_TRC(("A(%d) dma_free(%d)", IoAdapter->ANum, pI->descriptor_number)) +#endif diva_free_dma_map_entry((struct _diva_dma_map_entry*)IoAdapter->dma_map, pI->descriptor_number); pI->descriptor_number = -1; @@ -257,6 +262,7 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e) &syncReq->xdi_logical_adapter_number.info; pI->logical_adapter_number = IoAdapter->ANum; pI->controller = IoAdapter->ControllerNumber; + pI->total_controllers = IoAdapter->Properties.Adapters; } return; case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: { diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info; @@ -318,6 +324,16 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e) } syncReq->GetSerial.serial = 0 ; break ; + case IDI_SYNC_REQ_GET_CARDTYPE: + if ( IoAdapter ) + { + syncReq->GetCardType.cardtype = IoAdapter->cardType ; + DBG_TRC(("xdi: Adapter %d / CardType %ld", + IoAdapter->ANum, IoAdapter->cardType)) + return ; + } + syncReq->GetCardType.cardtype = 0 ; + break ; case IDI_SYNC_REQ_GET_XLOG: if ( IoAdapter ) { @@ -326,6 +342,14 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e) } e->Ind = 0 ; break ; + case IDI_SYNC_REQ_GET_DBG_XLOG: + if ( IoAdapter ) + { + pcm_req (IoAdapter, e) ; + return ; + } + e->Ind = 0 ; + break ; case IDI_SYNC_REQ_GET_FEATURES: if ( IoAdapter ) { @@ -345,7 +369,9 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e) } if ( IoAdapter ) { +#if 0 DBG_FTL(("xdi: unknown Req 0 / Rc %d !", e->Rc)) +#endif return ; } } @@ -496,7 +522,7 @@ pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e) diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &OldIrql, "data_pcm_1"); - IoAdapter->pcm_data = (unsigned long)pcm; + IoAdapter->pcm_data = (void *)pcm; IoAdapter->pcm_pending = 1; diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr); diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, @@ -510,7 +536,7 @@ pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e) &OldIrql, "data_pcm_3"); IoAdapter->pcm_pending = 0; - IoAdapter->pcm_data = 0; + IoAdapter->pcm_data = NULL ; diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &OldIrql, "data_pcm_3"); @@ -528,7 +554,7 @@ pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e) &OldIrql, "data_pcm_4"); IoAdapter->pcm_pending = 0; - IoAdapter->pcm_data = 0; + IoAdapter->pcm_data = NULL ; diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &OldIrql, "data_pcm_4"); @@ -668,7 +694,7 @@ word io_inw(ADAPTER * a, void * adr) void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len) { byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); - byte* P = (byte*)buffer; + byte* P = (byte*)buffer; if ((long)adr & 1) { outppw(Port+4, (word)(unsigned long)adr); *P = inpp(Port); @@ -678,7 +704,7 @@ void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len) if (!len) { DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); return; - } + } } outppw(Port+4, (word)(unsigned long)adr); inppw_buffer (Port, P, len+1); @@ -710,7 +736,7 @@ void io_outw(ADAPTER * a, void * adr, word data) void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len) { byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); - byte* P = (byte*)buffer; + byte* P = (byte*)buffer; if ((long)adr & 1) { outppw(Port+4, (word)(unsigned long)adr); outpp(Port, *P); @@ -839,21 +865,21 @@ void CALLBACK(ADAPTER * a, ENTITY * e) /* -------------------------------------------------------------------------- routines for aligned reading and writing on RISC -------------------------------------------------------------------------- */ -void outp_words_from_buffer (word* adr, byte* P, word len) +void outp_words_from_buffer (word* adr, byte* P, dword len) { - word i = 0; + dword i = 0; word w; - while (i < (len & 0xfffe)) { + while (i < (len & 0xfffffffe)) { w = P[i++]; w += (P[i++])<<8; outppw (adr, w); } } -void inp_words_to_buffer (word* adr, byte* P, word len) +void inp_words_to_buffer (word* adr, byte* P, dword len) { - word i = 0; + dword i = 0; word w; - while (i < (len & 0xfffe)) { + while (i < (len & 0xfffffffe)) { w = inppw (adr); P[i++] = (byte)(w); P[i++] = (byte)(w>>8); diff --git a/drivers/isdn/hardware/eicon/io.h b/drivers/isdn/hardware/eicon/io.h index 3e5403983..32ce17dfe 100644 --- a/drivers/isdn/hardware/eicon/io.h +++ b/drivers/isdn/hardware/eicon/io.h @@ -39,6 +39,14 @@ typedef struct { DEVICE_NAME DeviceName[4] ; PISDN_ADAPTER QuadroAdapter[4] ; } ADAPTER_LIST_ENTRY, *PADAPTER_LIST_ENTRY ; +/* -------------------------------------------------------------------------- + Special OS memory support structures + -------------------------------------------------------------------------- */ +#define MAX_MAPPED_ENTRIES 8 +typedef struct { + void * Address; + dword Length; +} ADAPTER_MEMORY ; /* -------------------------------------------------------------------------- Configuration of XDI clients carried by XDI -------------------------------------------------------------------------- */ @@ -52,6 +60,7 @@ typedef struct _diva_xdi_capi_cfg { -------------------------------------------------------------------------- */ struct _ISDN_ADAPTER { void (* DIRequest)(PISDN_ADAPTER, ENTITY *) ; + int State ; /* from NT4 1.srv, a good idea, but a poor achievment */ int Initialized ; int RegisteredWithDidd ; int Unavailable ; /* callback function possible? */ @@ -63,6 +72,7 @@ struct _ISDN_ADAPTER { /* remember mapped memory areas */ + ADAPTER_MEMORY MappedMemory[MAX_MAPPED_ENTRIES] ; CARD_PROPERTIES Properties ; dword cardType ; dword protocol_id ; /* configured protocol identifier */ @@ -87,15 +97,15 @@ struct _ISDN_ADAPTER { dword downloadAddrTable[4] ; /* add. for MultiMaster */ dword MemoryBase ; dword MemorySize ; - byte *Address ; + byte *Address ; byte *Config ; byte *Control ; - byte *reset ; - byte *port ; - byte *ram ; - byte *cfg ; - byte *prom ; - byte *ctlReg ; + byte *reset ; + byte *port ; + byte *ram ; + byte *cfg ; + byte *prom ; + byte *ctlReg ; struct pc_maint *pcm ; diva_os_dependent_devica_name_t os_name; byte Name[32] ; @@ -105,6 +115,7 @@ struct _ISDN_ADAPTER { char *ProtocolSuffix ; /* internal protocolfile table */ char Archive[32] ; char Protocol[32] ; + char AddDownload[32] ; /* Dsp- or other additional download files */ char Oad1[ISDN_MAX_NUM_LEN] ; char Osa1[ISDN_MAX_NUM_LEN] ; char Oad2[ISDN_MAX_NUM_LEN] ; @@ -153,8 +164,26 @@ struct _ISDN_ADAPTER { byte ModemCarrierWaitTimeSec; byte ModemCarrierLossWaitTimeTenthSec; byte PiafsLinkTurnaroundInFrames; + byte DiscAfterProgress; + byte AniDniLimiter[3]; + byte TxAttenuation; /* PRI/E1 only: attenuate TX signal */ word QsigFeatures; dword GenerateRingtone ; + dword SupplementaryServicesFeatures; + dword R2Dialect; + dword R2CasOptions; + dword FaxV34Options; + dword DisabledDspMask; + dword AdapterTestMask; + dword DspImageLength; + word AlertToIn20mSecTicks; + word ModemEyeSetup; + byte R2CtryLength; + byte CCBSRelTimer; + byte *PcCfgBufferFile;/* flexible parameter via file */ + byte *PcCfgBuffer ; /* flexible parameter via multistring */ + diva_os_dump_file_t dump_file; /* dump memory to file at lowest irq level */ + diva_os_board_trace_t board_trace ; /* traces from the board */ diva_os_spin_lock_t isr_spin_lock; diva_os_spin_lock_t data_spin_lock; diva_os_soft_isr_t req_soft_isr; @@ -180,15 +209,21 @@ struct _ISDN_ADAPTER { void (* stop)(PISDN_ADAPTER) ; void (* rstFnc)(PISDN_ADAPTER) ; void (* trapFnc)(PISDN_ADAPTER) ; + dword (* DetectDsps)(PISDN_ADAPTER) ; void (* os_trap_nfy_Fnc)(PISDN_ADAPTER, dword) ; diva_os_isr_callback_t diva_isr_handler; - dword sdram_bar; + dword sdram_bar; /* must be 32 bit */ dword fpga_features; volatile int pcm_pending; - volatile unsigned long pcm_data; + volatile void * pcm_data; diva_xdi_capi_cfg_t capi_cfg; dword tasks; - void* dma_map; + void *dma_map; + int (*DivaAdapterTestProc)(PISDN_ADAPTER); + void *AdapterTestMemoryStart; + dword AdapterTestMemoryLength; + const byte* cfg_lib_memory_init; + dword cfg_lib_memory_init_length; }; /* --------------------------------------------------------------------- Entity table @@ -219,8 +254,8 @@ struct s_load { /* --------------------------------------------------------------------- Functions for port io --------------------------------------------------------------------- */ -void outp_words_from_buffer (word* adr, byte* P, word len); -void inp_words_to_buffer (word* adr, byte* P, word len); +void outp_words_from_buffer (word* adr, byte* P, dword len); +void inp_words_to_buffer (word* adr, byte* P, dword len); /* --------------------------------------------------------------------- platform specific conversions --------------------------------------------------------------------- */ @@ -240,6 +275,10 @@ void io_out(ADAPTER * a, void * adr, byte data); void io_outw(ADAPTER * a, void * adr, word data); void io_out_buffer(ADAPTER * a, void * adr, void * P, word length); void io_inc(ADAPTER * a, void * adr); +void bri_in_buffer (PISDN_ADAPTER IoAdapter, dword Pos, + void *Buf, dword Len); +int bri_out_buffer (PISDN_ADAPTER IoAdapter, dword Pos, + void *Buf, dword Len, int Verify); /* --------------------------------------------------------------------- ram access functions for memory mapped cards --------------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c index 8bef29b8b..a1ed7786d 100644 --- a/drivers/isdn/hardware/eicon/maintidi.c +++ b/drivers/isdn/hardware/eicon/maintidi.c @@ -115,7 +115,7 @@ diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter, return NULL; } - pmem += sizeof(*pLib); + pmem += sizeof(*pLib); memset(pLib, 0x00, sizeof(*pLib)); pLib->Adapter = Adapter; @@ -337,13 +337,60 @@ static int SuperTraceMessageInput (void* hLib) { pLib->e.RNum = 1; pLib->e.R->P = (byte*)&pLib->buffer[0]; pLib->e.R->PLength = (word)(sizeof(pLib->buffer) - 1); + } else { /* Indication reception complete, process it now */ byte* p = (byte*)&pLib->buffer[0]; pLib->buffer[pLib->e.R->PLength] = 0; /* terminate I.E. with zero */ + switch (Ind) { + case MAN_COMBI_IND: { + int total_length = pLib->e.R->PLength; + word this_ind_length; + + while (total_length > 3 && *p) { + Ind = *p++; + this_ind_length = (word)p[0] | ((word)p[1] << 8); + p += 2; + + switch (Ind) { + case MAN_INFO_IND: + if (process_idi_info (pLib, (diva_man_var_header_t*)p)) { + return (-1); + } + break; + case MAN_EVENT_IND: + if (process_idi_event (pLib, (diva_man_var_header_t*)p)) { + return (-1); + } + break; + case MAN_TRACE_IND: + if (pLib->trace_on == 1) { + /* + Ignore first trace event that is result of + EVENT_ON operation + */ + pLib->trace_on++; + } else { + /* + Delivery XLOG buffer to application + */ + if (pLib->user_proc_table.trace_proc) { + (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context, + &pLib->instance, pLib->Adapter, + p, this_ind_length); + } + } + break; + default: + diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind (DMA mode): %02x", Ind); + } + p += (this_ind_length+1); + total_length -= (4 + this_ind_length); + } + } break; case MAN_INFO_IND: if (process_idi_info (pLib, (diva_man_var_header_t*)p)) { return (-1); @@ -806,7 +853,7 @@ static int ScheduleNextTraceRequest (diva_strace_context_t* pLib) { } static int process_idi_event (diva_strace_context_t* pLib, - diva_man_var_header_t* pVar) { + diva_man_var_header_t* pVar) { const char* path = (char*)&pVar->path_length+1; char name[64]; int i; diff --git a/drivers/isdn/hardware/eicon/maintidi.h b/drivers/isdn/hardware/eicon/maintidi.h index 184142cdf..4f0629496 100644 --- a/drivers/isdn/hardware/eicon/maintidi.h +++ b/drivers/isdn/hardware/eicon/maintidi.h @@ -49,6 +49,8 @@ typedef struct _diva_strace_path2action { void* variable; /* Variable that will receive value */ } diva_strace_path2action_t; +#define DIVA_MAX_MANAGEMENT_TRANSFER_SIZE 4096 + typedef struct _diva_strace_context { diva_strace_library_interface_t instance; @@ -62,7 +64,7 @@ typedef struct _diva_strace_context { IDI_CALL request; BUFFERS XData; BUFFERS RData; - byte buffer[2048+512+1]; + byte buffer[DIVA_MAX_MANAGEMENT_TRANSFER_SIZE + 1]; int removal_state; int general_b_ch_event; int general_fax_event; diff --git a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c index c94229904..29492451a 100644 --- a/drivers/isdn/hardware/eicon/mntfunc.c +++ b/drivers/isdn/hardware/eicon/mntfunc.c @@ -1,4 +1,4 @@ -/* $Id: mntfunc.c,v 1.19 2004/01/09 21:22:03 armin Exp $ +/* $Id: mntfunc.c,v 1.19.6.2 2004/08/28 20:03:53 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * Maint module @@ -23,17 +23,12 @@ extern char *DRIVERRELEASE_MNT; extern void DIVA_DIDD_Read(void *, int); -#define MAX_DESCRIPTORS 32 - static dword notify_handle; static DESCRIPTOR DAdapter; static DESCRIPTOR MAdapter; static DESCRIPTOR MaintDescriptor = { IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp }; -extern void *diva_os_malloc_tbuffer(unsigned long flags, - unsigned long size); -extern void diva_os_free_tbuffer(unsigned long flags, void *ptr); extern int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src, int length); extern int diva_os_copy_from_user(void *os_handle, void *dst, @@ -46,16 +41,6 @@ static void no_printf(unsigned char *x, ...) #include "debuglib.c" -/* - * stop debug - */ -static void stop_dbg(void) -{ - DbgDeregister(); - memset(&MAdapter, 0, sizeof(MAdapter)); - dprintf = no_printf; -} - /* * DIDD callback function */ @@ -66,7 +51,9 @@ static void *didd_callback(void *context, DESCRIPTOR * adapter, DBG_ERR(("cb: Change in DAdapter ? Oops ?.")); } else if (adapter->type == IDI_DIMAINT) { if (removal) { - stop_dbg(); + DbgDeregister(); + memset(&MAdapter, 0, sizeof(MAdapter)); + dprintf = no_printf; } else { memcpy(&MAdapter, adapter, sizeof(MAdapter)); dprintf = (DIVA_DI_PRINTF) MAdapter.request; @@ -131,8 +118,6 @@ static void DIVA_EXIT_FUNCTION disconnect_didd(void) { IDI_SYNC_REQ req; - stop_dbg(); - req.didd_notify.e.Req = 0; req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; req.didd_notify.info.handle = notify_handle; @@ -193,34 +178,63 @@ int maint_read_write(void __user *buf, int count) } break; + /* + Filter commands will ignore the ID due to fact that filtering affects + the B- channel and Audio Tap trace levels only. Also MAINT driver will + select the right trace ID by itself + */ + case DITRACE_WRITE_SELECTIVE_TRACE_FILTER: + if (!mask) { + ret = diva_set_trace_filter (1, "*"); + } else if (mask < sizeof(data)) { + if (copy_from_user(data, (char __user *)buf+12, mask)) { + ret = -EFAULT; + } else { + ret = diva_set_trace_filter ((int)mask, data); + } + } else { + ret = -EINVAL; + } + break; + + case DITRACE_READ_SELECTIVE_TRACE_FILTER: + if ((ret = diva_get_trace_filter (sizeof(data), data)) > 0) { + if (copy_to_user (buf, data, ret)) + ret = -EFAULT; + } else { + ret = -ENODEV; + } + break; + case DITRACE_READ_TRACE_ENTRY:{ diva_os_spin_lock_magic_t old_irql; word size; diva_dbg_entry_head_t *pmsg; byte *pbuf; - if ((pmsg = diva_maint_get_message(&size, &old_irql))) { + if (!(pbuf = diva_os_malloc(0, mask))) { + return (-ENOMEM); + } + + for(;;) { + if (!(pmsg = + diva_maint_get_message(&size, &old_irql))) { + break; + } if (size > mask) { diva_maint_ack_message(0, &old_irql); ret = -EINVAL; - } else { - if (!(pbuf = diva_os_malloc_tbuffer(0, size))) - { - diva_maint_ack_message(0, &old_irql); - ret = -ENOMEM; - } else { - ret = size; - memcpy(pbuf, pmsg, size); - diva_maint_ack_message(1, &old_irql); - if ((count < size) || diva_os_copy_to_user (NULL, buf, - (void *) pbuf, size)) - ret = -EFAULT; - diva_os_free_tbuffer(0, pbuf); - } + break; } - } else { - ret = 0; + ret = size; + memcpy(pbuf, pmsg, size); + diva_maint_ack_message(1, &old_irql); + if ((count < size) || + diva_os_copy_to_user (NULL, buf, (void *) pbuf, size)) + ret = -EFAULT; + break; } + diva_os_free(0, pbuf); } break; @@ -235,7 +249,7 @@ int maint_read_write(void __user *buf, int count) ret = -EINVAL; break; } - if (!(pbuf = diva_os_malloc_tbuffer(0, mask))) { + if (!(pbuf = diva_os_malloc(0, mask))) { return (-ENOMEM); } @@ -273,7 +287,7 @@ int maint_read_write(void __user *buf, int count) } else { ret = written; } - diva_os_free_tbuffer(0, pbuf); + diva_os_free(0, pbuf); } break; @@ -302,7 +316,7 @@ int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, } else { while ((*buffer_length >= (64 * 1024)) && - (!(*buffer = diva_os_malloc_tbuffer(0, *buffer_length)))) { + (!(*buffer = diva_os_malloc (0, *buffer_length)))) { *buffer_length -= 1024; } @@ -314,7 +328,7 @@ int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, if (diva_maint_init(*buffer, *buffer_length, (diva_dbg_mem == 0))) { if (!diva_dbg_mem) { - diva_os_free_tbuffer(0, *buffer); + diva_os_free (0, *buffer); } DBG_ERR(("init: maint init failed")); return (0); @@ -324,7 +338,7 @@ int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, DBG_ERR(("init: failed to connect to DIDD.")); diva_maint_finit(); if (!diva_dbg_mem) { - diva_os_free_tbuffer(0, *buffer); + diva_os_free (0, *buffer); } return (0); } @@ -339,6 +353,8 @@ void DIVA_EXIT_FUNCTION mntfunc_finit(void) void *buffer; int i = 100; + DbgDeregister(); + while (diva_mnt_shutdown_xdi_adapters() && i--) { diva_os_sleep(10); } @@ -346,6 +362,9 @@ void DIVA_EXIT_FUNCTION mntfunc_finit(void) disconnect_didd(); if ((buffer = diva_maint_finit())) { - diva_os_free_tbuffer(0, buffer); + diva_os_free (0, buffer); } + + memset(&MAdapter, 0, sizeof(MAdapter)); + dprintf = no_printf; } diff --git a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h index a65550605..1c6945768 100644 --- a/drivers/isdn/hardware/eicon/pc.h +++ b/drivers/isdn/hardware/eicon/pc.h @@ -143,6 +143,7 @@ struct dual #define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ #define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ #define N_XON 15 /* clear RNR state */ +#define N_COMBI_IND N_XON /* combined indication */ #define N_Q_BIT 0x10 /* Q-bit for req/ind */ #define N_M_BIT 0x20 /* M-bit for req/ind */ #define N_D_BIT 0x40 /* D-bit for req/ind */ @@ -228,6 +229,10 @@ struct dual #define VSWITCH_IND 66 /* capifunctions for D-CH-switching */ #define MWI_POLL 67 /* Message Waiting Status Request fkt */ #define CALL_PEND_NOTIFY 68 /* notify capi to set new listen */ +#define DO_NOTHING 69 /* dont do somethin if you get this */ +#define INT_CT_REJ 70 /* ECT rejected internal command */ +#define CALL_HOLD_COMPLETE 71 /* In NT Mode indicate hold complete */ +#define CALL_RETRIEVE_COMPLETE 72 /* In NT Mode indicate retrieve complete */ /*------------------------------------------------------------------*/ /* management service primitives */ /*------------------------------------------------------------------*/ @@ -241,6 +246,7 @@ struct dual #define MAN_INFO_IND 2 #define MAN_EVENT_IND 3 #define MAN_TRACE_IND 4 +#define MAN_COMBI_IND 9 #define MAN_ESC 0x80 /*------------------------------------------------------------------*/ /* return code coding */ @@ -265,6 +271,7 @@ struct dual /*------------------------------------------------------------------*/ #define SHIFT 0x90 /* codeset shift */ #define MORE 0xa0 /* more data */ +#define SDNCMPL 0xa1 /* sending complete */ #define CL 0xb0 /* congestion level */ /* codeset 0 */ #define SMSG 0x00 /* segmented message */ @@ -288,6 +295,8 @@ struct dual #define RDX 0x73 /* redirecting number extended */ #define RDN 0x74 /* redirecting number */ #define RIN 0x76 /* redirection number */ +#define IUP 0x76 /* VN6 rerouter->PCS (codeset 6) */ +#define IPU 0x77 /* VN6 PCS->rerouter (codeset 6) */ #define RI 0x79 /* restart indicator */ #define MIE 0x7a /* management info element */ #define LLC 0x7c /* low layer compatibility */ @@ -296,6 +305,8 @@ struct dual #define ESC 0x7f /* escape extension */ #define DLC 0x20 /* data link layer configuration */ #define NLC 0x21 /* network layer configuration */ +#define REDIRECT_IE 0x22 /* redirection request/indication data */ +#define REDIRECT_NET_IE 0x23 /* redirection network override data */ /* codeset 6 */ #define SIN 0x01 /* service indicator */ #define CIF 0x02 /* charging information */ @@ -306,6 +317,7 @@ struct dual /*------------------------------------------------------------------*/ #define MSGTYPEIE 0x7a /* Messagetype info element */ #define CRIE 0x7b /* INFO info element */ +#define CODESET6IE 0xec /* Tunnel for Codeset 6 IEs */ #define VSWITCHIE 0xed /* VSwitch info element */ #define SSEXTIE 0xee /* Supplem. Service info element */ #define PROFILEIE 0xef /* Profile info element */ @@ -344,6 +356,13 @@ struct dual #define CCBS_REQUEST 0x32 #define CCBS_DEACTIVATE 0x33 #define CCBS_INTERROGATE 0x34 +#define CCBS_STATUS 0x35 +#define CCBS_ERASE 0x36 +#define CCBS_B_FREE 0x37 +#define CCNR_INFO_RETAIN 0x38 +#define CCBS_REMOTE_USER_FREE 0x39 +#define CCNR_REQUEST 0x3a +#define CCNR_INTERROGATE 0x3b #define GET_SUPPORTED_SERVICES 0xff #define DIVERSION_PROCEDURE_CFU 0x70 #define DIVERSION_PROCEDURE_CFB 0x71 @@ -362,6 +381,7 @@ struct dual #define SMASK_3PTY 0x00000008 #define SMASK_CALL_FORWARDING 0x00000010 #define SMASK_CALL_DEFLECTION 0x00000020 +#define SMASK_MCID 0x00000040 #define SMASK_CCBS 0x00000080 #define SMASK_MWI 0x00000100 #define SMASK_CCNR 0x00000200 @@ -406,6 +426,8 @@ struct dual #define RTPL2_IN 13 /* RTP layer-2 protocol, incomming */ #define RTPL2 14 /* RTP layer-2 protocol */ #define V120_V42BIS 15 /* V.120 asynchronous mode supporting V.42bis compression */ +#define LISTENER 27 /* Layer 2 to listen line */ +#define MTP2 28 /* MTP2 Layer 2 */ #define PIAFS_CRC 29 /* PIAFS Layer 2 with CRC calculation at L2 */ /* ------------------------------------------------------ PIAFS DLC DEFINITIONS @@ -506,6 +528,22 @@ Byte | 8 7 6 5 4 3 2 1 | | | data transfer. | +---------------------+------+-----------------------------------------+ */ +/* ------------------------------------------------------ + LISTENER DLC DEFINITIONS + ------------------------------------------------------ */ +#define LISTENER_FEATURE_MASK_CUMMULATIVE 0x0001 +/* ------------------------------------------------------ + LISTENER META-FRAME CODE/PRIMITIVE DEFINITIONS + ------------------------------------------------------ */ +#define META_CODE_LL_UDATA_RX 0x01 +#define META_CODE_LL_UDATA_TX 0x02 +#define META_CODE_LL_DATA_RX 0x03 +#define META_CODE_LL_DATA_TX 0x04 +#define META_CODE_LL_MDATA_RX 0x05 +#define META_CODE_LL_MDATA_TX 0x06 +#define META_CODE_EMPTY 0x10 +#define META_CODE_LOST_FRAMES 0x11 +#define META_FLAG_TRUNCATED 0x0001 /*------------------------------------------------------------------*/ /* CAPI-like profile to indicate features on LAW_REQ */ /*------------------------------------------------------------------*/ @@ -577,6 +615,14 @@ Byte | 8 7 6 5 4 3 2 1 #define MANUFACTURER_FEATURE_DMACONNECT 0x04000000L #define MANUFACTURER_FEATURE_AUDIO_TAP 0x08000000L #define MANUFACTURER_FEATURE_FAX_NONSTANDARD 0x10000000L +#define MANUFACTURER_FEATURE_SS7 0x20000000L +#define MANUFACTURER_FEATURE_MADAPTER 0x40000000L +#define MANUFACTURER_FEATURE_MEASURE 0x80000000L +#define MANUFACTURER_FEATURE2_LISTENING 0x00000001L +#define MANUFACTURER_FEATURE2_SS_DIFFCONTPOSSIBLE 0x00000002L +#define MANUFACTURER_FEATURE2_GENERIC_TONE 0x00000004L +#define MANUFACTURER_FEATURE2_COLOR_FAX 0x00000008L +#define MANUFACTURER_FEATURE2_SS_ECT_DIFFCONTPOSSIBLE 0x00000010L #define RTP_PRIM_PAYLOAD_PCMU_8000 0 #define RTP_PRIM_PAYLOAD_1016_8000 1 #define RTP_PRIM_PAYLOAD_G726_32_8000 2 @@ -624,6 +670,15 @@ Byte | 8 7 6 5 4 3 2 1 #define VSINVOKEID 4 #define VSCLMRKS 5 #define VSTBCTIDENT 6 +#define VSETSILINKID 7 +#define VSSAMECONTROLLER 8 +/* Errorcodes for VSETSILINKID begin */ +#define VSETSILINKIDRRWC 1 +#define VSETSILINKIDREJECT 2 +#define VSETSILINKIDTIMEOUT 3 +#define VSETSILINKIDFAILCOUNT 4 +#define VSETSILINKIDERROR 5 +/* Errorcodes for VSETSILINKID end */ /* -----------------------------------------------------------** ** The PROTOCOL_FEATURE_STRING in feature.h (included ** ** in prstart.sx and astart.sx) defines capabilities and ** @@ -647,5 +702,37 @@ Byte | 8 7 6 5 4 3 2 1 #define PROTCAP_FREE13 0x2000 /* not used */ #define PROTCAP_FREE14 0x4000 /* not used */ #define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ +/* -----------------------------------------------------------* */ +/* Onhook data transmission ETS30065901 */ +/* Message Type */ +/*#define RESERVED4 0x4*/ +#define CALL_SETUP 0x80 +#define MESSAGE_WAITING_INDICATOR 0x82 +/*#define RESERVED84 0x84*/ +/*#define RESERVED85 0x85*/ +#define ADVICE_OF_CHARGE 0x86 +/*1111 0001 +to +1111 1111 +F1H - Reserved for network operator use +to +FFH*/ +/* Parameter Types */ +#define DATE_AND_TIME 1 +#define CLI_PARAMETER_TYPE 2 +#define CALLED_DIRECTORY_NUMBER_PARAMETER_TYPE 3 +#define REASON_FOR_ABSENCE_OF_CLI_PARAMETER_TYPE 4 +#define NAME_PARAMETER_TYPE 7 +#define REASON_FOR_ABSENCE_OF_CALLING_PARTY_NAME_PARAMETER_TYPE 8 +#define VISUAL_INDICATOR_PARAMETER_TYPE 0xb +#define COMPLEMENTARY_CLI_PARAMETER_TYPE 0x10 +#define CALL_TYPE_PARAMETER_TYPE 0x11 +#define FIRST_CALLED_LINE_DIRECTORY_NUMBER_PARAMETER_TYPE 0x12 +#define NETWORK_MESSAGE_SYSTEM_STATUS_PARAMETER_TYPE 0x13 +#define FORWARDED_CALL_TYPE_PARAMETER_TYPE 0x15 +#define TYPE_OF_CALLING_USER_PARAMETER_TYPE 0x16 +#define REDIRECTING_NUMBER_PARAMETER_TYPE 0x1a +#define EXTENSION_FOR_NETWORK_OPERATOR_USE_PARAMETER_TYPE 0xe0 +/* -----------------------------------------------------------* */ #else #endif /* PC_H_INCLUDED } */ diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h index 31299feb7..0457682b0 100644 --- a/drivers/isdn/hardware/eicon/platform.h +++ b/drivers/isdn/hardware/eicon/platform.h @@ -1,4 +1,4 @@ -/* $Id: platform.h,v 1.37.4.1 2004/07/28 14:47:21 armin Exp $ +/* $Id: platform.h,v 1.37.4.2 2004/08/28 20:03:53 armin Exp $ * * platform.h * @@ -269,20 +269,6 @@ static __inline__ void diva_os_leave_spin_lock (diva_os_spin_lock_t* a, \ diva_os_spin_lock_magic_t* old_irql, \ void* dbg) { spin_unlock_bh(a); } -static __inline__ void diva_os_enter_spin_lock_hard (diva_os_spin_lock_t* a, \ - diva_os_spin_lock_magic_t* old_irql, \ - void* dbg) { \ - unsigned long flags; \ - spin_lock_irqsave (a, flags); \ - *old_irql = (diva_os_spin_lock_magic_t)flags; \ -} -static __inline__ void diva_os_leave_spin_lock_hard (diva_os_spin_lock_t* a, \ - diva_os_spin_lock_magic_t* old_irql, \ - void* dbg) { \ - unsigned long flags = (unsigned long)*old_irql; \ - spin_unlock_irqrestore (a, flags); \ -} - #define diva_os_destroy_spin_lock(a,b) do { } while(0) /* @@ -347,12 +333,18 @@ diva_os_atomic_decrement(diva_os_atomic_t* pv) #define DIVA_IDI_RX_DMA 1 +/* +** endian macros +*/ #define READ_WORD(addr) readw(addr) #define READ_DWORD(addr) readl(addr) #define WRITE_WORD(addr,v) writew(v,addr) #define WRITE_DWORD(addr,v) writel(v,addr) +/* +** 32/64 bit macors +*/ #ifdef BITS_PER_LONG #if BITS_PER_LONG > 32 #define PLATFORM_GT_32BIT @@ -360,8 +352,23 @@ diva_os_atomic_decrement(diva_os_atomic_t* pv) #endif #endif +/* +** undef os definitions of macros we use +*/ #undef ID_MASK #undef N_DATA #undef ADDR +/* +** dump file +*/ +#define diva_os_dump_file_t char +#define diva_os_board_trace_t char +#define diva_os_dump_file(__x__) do { } while(0) + +/* +** size of internal arrays +*/ +#define MAX_DESCRIPTORS 64 + #endif /* __PLATFORM_H__ */ diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 235f28a46..3a6acdead 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/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index f6a21dffa..f410f628a 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -265,7 +265,7 @@ setup_bkm_a4t(struct IsdnCard *card) char tmp[64]; u_int pci_memaddr = 0, found = 0; I20_REGISTER_FILE *pI20_Regs; -#if CONFIG_PCI +#ifdef CONFIG_PCI #endif strcpy(tmp, bkm_a4t_revision); @@ -275,7 +275,7 @@ setup_bkm_a4t(struct IsdnCard *card) } else return (0); -#if CONFIG_PCI +#ifdef CONFIG_PCI while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { u16 sub_sys; diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 0c32d3700..94bb83ce7 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -21,7 +21,7 @@ #include #include "bkm_ax.h" -#if CONFIG_PCI +#ifdef CONFIG_PCI #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ @@ -285,7 +285,7 @@ static u_char pci_irq __initdata = 0; int __init setup_sct_quadro(struct IsdnCard *card) { -#if CONFIG_PCI +#ifdef CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; u_char pci_rev_id; diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 2b54e7d6f..394d481e0 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1027,7 +1027,7 @@ setup_diva(struct IsdnCard *card) } } #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->subtyp = 0; if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index b33678129..3b526d704 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -1022,7 +1022,7 @@ setup_elsa(struct IsdnCard *card) cs->hw.elsa.base, cs->irq); } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->subtyp = 0; if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c index a7acf9bd6..1cc4d11e0 100644 --- a/drivers/isdn/hisax/enternow_pci.c +++ b/drivers/isdn/hisax/enternow_pci.c @@ -299,7 +299,7 @@ setup_enternow_pci(struct IsdnCard *card) struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI +#ifdef CONFIG_PCI #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 0d5931798..24a05a43f 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -634,7 +634,7 @@ setup_gazel(struct IsdnCard *card) return (0); } else { -#if CONFIG_PCI +#ifdef CONFIG_PCI if (setup_gazelpci(cs)) return (0); #else diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 20042fda8..3946536d1 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -65,7 +65,7 @@ static const PCI_ENTRY id_list[] = }; -#if CONFIG_PCI +#ifdef CONFIG_PCI /******************************************/ /* free hardware resources used by driver */ @@ -1655,7 +1655,7 @@ setup_hfcpci(struct IsdnCard *card) #endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->hw.hfcpci.int_s1 = 0; cs->dc.hfcpci.ph_state = 0; cs->hw.hfcpci.fifo = 255; diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 88cce430c..cf77d8360 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -309,7 +309,7 @@ setup_niccy(struct IsdnCard *card) return (0); } } else { -#if CONFIG_PCI +#ifdef CONFIG_PCI u_int pci_ioaddr; cs->subtyp = 0; if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index 8b5822c42..fd664697f 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -167,7 +167,7 @@ setup_netjet_s(struct IsdnCard *card) return(0); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI +#ifdef CONFIG_PCI for ( ;; ) { diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c index efb5d8fbf..3d6441e96 100644 --- a/drivers/isdn/hisax/nj_u.c +++ b/drivers/isdn/hisax/nj_u.c @@ -137,7 +137,7 @@ setup_netjet_u(struct IsdnCard *card) int bytecnt; struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI +#ifdef CONFIG_PCI #endif #ifdef __BIG_ENDIAN #error "not running on big endian machines now" @@ -148,7 +148,7 @@ setup_netjet_u(struct IsdnCard *card) return(0); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI +#ifdef CONFIG_PCI for ( ;; ) { diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 863bfa50b..3393370ce 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -618,7 +618,7 @@ setup_sedlbauer(struct IsdnCard *card) } #endif /* Probe for Sedlbauer speed pci */ -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { if (pci_enable_device(dev_sedl)) diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 04f9c5ce2..478b1a17b 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -143,9 +143,6 @@ static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs) if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ le16_to_cpus(&ctrl_msg->dr.wIndex); - usb_endpoint_running(adapter->usb_dev, - ctrl_msg->dr.wIndex & ~USB_DIR_IN, - (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0); /* toggle is reset on clear */ usb_settoggle(adapter->usb_dev, diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 5e305554d..7713c467e 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -300,7 +300,7 @@ setup_telespci(struct IsdnCard *card) printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) return (0); -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) return(0); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index cfe876043..36cfc4a48 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1012,7 +1012,7 @@ setup_w6692(struct IsdnCard *card) printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) return (0); -#if CONFIG_PCI +#ifdef CONFIG_PCI while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 69c6884e9..964d5c975 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1369,7 +1369,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN); - eth = skb->mac.ethernet; + eth = eth_hdr(skb); if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 02b912ab1..921c3c2ab 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -296,10 +296,7 @@ isdn_tty_tint(modem_info * info) info->send_outstanding++; info->msr &= ~UART_MSR_CTS; info->lsr &= ~UART_LSR_TEMT; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); return; } if (slen < 0) { @@ -1174,10 +1171,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co /* If DLE decoding results in zero-transmit, but * c originally was non-zero, do a wakeup. */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; } @@ -1290,9 +1284,7 @@ isdn_tty_flush_buffer(struct tty_struct *tty) isdn_tty_cleanup_xmit(info); info->xmit_count = 0; wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); } static void @@ -1747,10 +1739,10 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) } dev->modempoll--; isdn_tty_shutdown(info); + if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); info->tty = NULL; info->ncarrier = 0; tty->closing = 0; @@ -2681,8 +2673,7 @@ isdn_tty_modem_result(int code, modem_info * info) if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { return; } - if (info->tty->ldisc.flush_buffer) - info->tty->ldisc.flush_buffer(info->tty); + tty_ldisc_flush(info->tty); if ((info->flags & ISDN_ASYNC_CHECK_CD) && (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { diff --git a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c index 91392c469..b418d37c7 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 c0ab8589b..d3b8f819e 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -74,15 +74,135 @@ static struct notifier_block adbhid_adb_notifier = { #define ADB_KEY_POWER_OLD 0x7e #define ADB_KEY_POWER 0x7f -unsigned char adb_to_linux_keycodes[128] = { - 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19, - 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, - 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, - 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0, - 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, - 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,124, 89,121, - 63, 64, 65, 61, 66, 67,123, 87,122, 99, 0, 70, 0, 68,101, 88, - 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,126,116 +u8 adb_to_linux_keycodes[128] = { + /* 0x00 */ KEY_A, /* 30 */ + /* 0x01 */ KEY_S, /* 31 */ + /* 0x02 */ KEY_D, /* 32 */ + /* 0x03 */ KEY_F, /* 33 */ + /* 0x04 */ KEY_H, /* 35 */ + /* 0x05 */ KEY_G, /* 34 */ + /* 0x06 */ KEY_Z, /* 44 */ + /* 0x07 */ KEY_X, /* 45 */ + /* 0x08 */ KEY_C, /* 46 */ + /* 0x09 */ KEY_V, /* 47 */ + /* 0x0a */ KEY_102ND, /* 86 */ + /* 0x0b */ KEY_B, /* 48 */ + /* 0x0c */ KEY_Q, /* 16 */ + /* 0x0d */ KEY_W, /* 17 */ + /* 0x0e */ KEY_E, /* 18 */ + /* 0x0f */ KEY_R, /* 19 */ + /* 0x10 */ KEY_Y, /* 21 */ + /* 0x11 */ KEY_T, /* 20 */ + /* 0x12 */ KEY_1, /* 2 */ + /* 0x13 */ KEY_2, /* 3 */ + /* 0x14 */ KEY_3, /* 4 */ + /* 0x15 */ KEY_4, /* 5 */ + /* 0x16 */ KEY_6, /* 7 */ + /* 0x17 */ KEY_5, /* 6 */ + /* 0x18 */ KEY_EQUAL, /* 13 */ + /* 0x19 */ KEY_9, /* 10 */ + /* 0x1a */ KEY_7, /* 8 */ + /* 0x1b */ KEY_MINUS, /* 12 */ + /* 0x1c */ KEY_8, /* 9 */ + /* 0x1d */ KEY_0, /* 11 */ + /* 0x1e */ KEY_RIGHTBRACE, /* 27 */ + /* 0x1f */ KEY_O, /* 24 */ + /* 0x20 */ KEY_U, /* 22 */ + /* 0x21 */ KEY_LEFTBRACE, /* 26 */ + /* 0x22 */ KEY_I, /* 23 */ + /* 0x23 */ KEY_P, /* 25 */ + /* 0x24 */ KEY_ENTER, /* 28 */ + /* 0x25 */ KEY_L, /* 38 */ + /* 0x26 */ KEY_J, /* 36 */ + /* 0x27 */ KEY_APOSTROPHE, /* 40 */ + /* 0x28 */ KEY_K, /* 37 */ + /* 0x29 */ KEY_SEMICOLON, /* 39 */ + /* 0x2a */ KEY_BACKSLASH, /* 43 */ + /* 0x2b */ KEY_COMMA, /* 51 */ + /* 0x2c */ KEY_SLASH, /* 53 */ + /* 0x2d */ KEY_N, /* 49 */ + /* 0x2e */ KEY_M, /* 50 */ + /* 0x2f */ KEY_DOT, /* 52 */ + /* 0x30 */ KEY_TAB, /* 15 */ + /* 0x31 */ KEY_SPACE, /* 57 */ + /* 0x32 */ KEY_GRAVE, /* 41 */ + /* 0x33 */ KEY_BACKSPACE, /* 14 */ + /* 0x34 */ KEY_KPENTER, /* 96 */ + /* 0x35 */ KEY_ESC, /* 1 */ + /* 0x36 */ KEY_LEFTCTRL, /* 29 */ + /* 0x37 */ KEY_LEFTMETA, /* 125 */ + /* 0x38 */ KEY_LEFTSHIFT, /* 42 */ + /* 0x39 */ KEY_CAPSLOCK, /* 58 */ + /* 0x3a */ KEY_LEFTALT, /* 56 */ + /* 0x3b */ KEY_LEFT, /* 105 */ + /* 0x3c */ KEY_RIGHT, /* 106 */ + /* 0x3d */ KEY_DOWN, /* 108 */ + /* 0x3e */ KEY_UP, /* 103 */ + /* 0x3f */ 0, + /* 0x40 */ 0, + /* 0x41 */ KEY_KPDOT, /* 83 */ + /* 0x42 */ 0, + /* 0x43 */ KEY_KPASTERISK, /* 55 */ + /* 0x44 */ 0, + /* 0x45 */ KEY_KPPLUS, /* 78 */ + /* 0x46 */ 0, + /* 0x47 */ KEY_NUMLOCK, /* 69 */ + /* 0x48 */ 0, + /* 0x49 */ 0, + /* 0x4a */ 0, + /* 0x4b */ KEY_KPSLASH, /* 98 */ + /* 0x4c */ KEY_KPENTER, /* 96 */ + /* 0x4d */ 0, + /* 0x4e */ KEY_KPMINUS, /* 74 */ + /* 0x4f */ 0, + /* 0x50 */ 0, + /* 0x51 */ KEY_KPEQUAL, /* 117 */ + /* 0x52 */ KEY_KP0, /* 82 */ + /* 0x53 */ KEY_KP1, /* 79 */ + /* 0x54 */ KEY_KP2, /* 80 */ + /* 0x55 */ KEY_KP3, /* 81 */ + /* 0x56 */ KEY_KP4, /* 75 */ + /* 0x57 */ KEY_KP5, /* 76 */ + /* 0x58 */ KEY_KP6, /* 77 */ + /* 0x59 */ KEY_KP7, /* 71 */ + /* 0x5a */ 0, + /* 0x5b */ KEY_KP8, /* 72 */ + /* 0x5c */ KEY_KP9, /* 73 */ + /* 0x5d */ KEY_YEN, /* 124 */ + /* 0x5e */ KEY_RO, /* 89 */ + /* 0x5f */ KEY_KPCOMMA, /* 121 */ + /* 0x60 */ KEY_F5, /* 63 */ + /* 0x61 */ KEY_F6, /* 64 */ + /* 0x62 */ KEY_F7, /* 65 */ + /* 0x63 */ KEY_F3, /* 61 */ + /* 0x64 */ KEY_F8, /* 66 */ + /* 0x65 */ KEY_F9, /* 67 */ + /* 0x66 */ KEY_HANJA, /* 123 */ + /* 0x67 */ KEY_F11, /* 87 */ + /* 0x68 */ KEY_HANGUEL, /* 122 */ + /* 0x69 */ KEY_SYSRQ, /* 99 */ + /* 0x6a */ 0, + /* 0x6b */ KEY_SCROLLLOCK, /* 70 */ + /* 0x6c */ 0, + /* 0x6d */ KEY_F10, /* 68 */ + /* 0x6e */ KEY_COMPOSE, /* 127 */ + /* 0x6f */ KEY_F12, /* 88 */ + /* 0x70 */ 0, + /* 0x71 */ KEY_PAUSE, /* 119 */ + /* 0x72 */ KEY_INSERT, /* 110 */ + /* 0x73 */ KEY_HOME, /* 102 */ + /* 0x74 */ KEY_PAGEUP, /* 104 */ + /* 0x75 */ KEY_DELETE, /* 111 */ + /* 0x76 */ KEY_F4, /* 62 */ + /* 0x77 */ KEY_END, /* 107 */ + /* 0x78 */ KEY_F2, /* 60 */ + /* 0x79 */ KEY_PAGEDOWN, /* 109 */ + /* 0x7a */ KEY_F1, /* 59 */ + /* 0x7b */ KEY_RIGHTSHIFT, /* 54 */ + /* 0x7c */ KEY_RIGHTALT, /* 100 */ + /* 0x7d */ KEY_RIGHTCTRL, /* 97 */ + /* 0x7e */ KEY_RIGHTMETA, /* 126 */ + /* 0x7f */ KEY_POWER, /* 116 */ }; struct adbhid { @@ -326,7 +446,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, @@ -453,7 +573,7 @@ static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; static void leds_done(struct adb_request *req) { - int leds, device; + int leds = 0, device = 0, pending = 0; unsigned long flags; spin_lock_irqsave(&leds_lock, flags); @@ -464,11 +584,11 @@ static void leds_done(struct adb_request *req) leds_pending[device] = 0; pending_led_start++; pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + pending = leds_req_pending; } else leds_req_pending = 0; - spin_unlock_irqrestore(&leds_lock, flags); - if (leds_req_pending) + if (pending) adb_request(&led_request, leds_done, 0, 3, ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds); } diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index 0e130f598..26bdcd7da 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -9,6 +9,8 @@ #include #include #include +#include + #include #include #include @@ -154,7 +156,7 @@ anslcd_init(void) retval = misc_register(&anslcd_dev); if(retval < 0){ printk(KERN_INFO "LCD: misc_register failed\n"); - iounmap(anslcd_ptr); + iounmap((void *)anslcd_ptr); return retval; } @@ -177,7 +179,7 @@ static void __exit anslcd_exit(void) { misc_deregister(&anslcd_dev); - iounmap(anslcd_ptr); + iounmap((void *)anslcd_ptr); } module_init(anslcd_init); diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 1d61a9af6..a3a5372f7 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -713,12 +713,8 @@ static void do_softint(void *private_) if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); } static int startup(struct mac_serial * info) @@ -1564,10 +1560,7 @@ static void rs_flush_buffer(struct tty_struct *tty) spin_lock_irqsave(&info->lock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&info->lock, flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1994,16 +1987,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); + msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } @@ -2048,8 +2039,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (timeout) char_time = min_t(unsigned long, char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 37f06c81d..8feba3846 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -28,6 +28,7 @@ #include #include #include +#include #undef DEBUG @@ -53,7 +54,7 @@ MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and Powerbook G4 A MODULE_LICENSE("GPL"); MODULE_PARM(limit_adjust,"i"); -MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50°C cpu, 70°C gpu) by N °C."); +MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 cpu, 70 gpu) by N degrees."); MODULE_PARM(fan_speed,"i"); MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)"); @@ -70,9 +71,7 @@ static enum {ADT7460, ADT7467} therm_type; static int therm_bus, therm_address; static struct of_device * of_dev; static struct thermostat* thermostat; -static pid_t monitor_thread_id; -static int monitor_running; -static struct completion monitor_task_compl; +static struct task_struct *thread_therm = NULL; static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno); static void write_both_fan_speed(struct thermostat *th, int speed); @@ -136,13 +135,12 @@ detach_thermostat(struct i2c_adapter *adapter) th = thermostat; - if (monitor_running) { - monitor_running = 0; - wait_for_completion(&monitor_task_compl); + if (thread_therm != NULL) { + kthread_stop(thread_therm); } printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d," - " to %d, %d, %d, (°C)\n", + " to %d, %d, %d\n", th->limits[0], th->limits[1], th->limits[2], th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]); @@ -178,7 +176,8 @@ static int read_fan_speed(struct thermostat *th, u8 addr) tmp[0] = read_reg(th, addr + 1); res = tmp[1] + (tmp[0] << 8); - return (90000*60)/res; + /* "a value of 0xffff means that the fan has stopped" */ + return (res == 0xffff ? 0 : (90000*60)/res); } static void write_both_fan_speed(struct thermostat *th, int speed) @@ -237,16 +236,9 @@ static int monitor_task(void *arg) #ifdef DEBUG int mfan_speed; #endif - - lock_kernel(); - daemonize("kfand"); - unlock_kernel(); - strcpy(current->comm, "thermostat"); - monitor_running = 1; - - while(monitor_running) + while(!kthread_should_stop()) { - msleep(2000); + msleep_interruptible(2000); /* Check status */ /* local : chip */ @@ -270,14 +262,14 @@ static int monitor_task(void *arg) int var = temps[i] - lims[i]; if (var > 8) { if (th->overriding[fan_number] == 0) - printk(KERN_INFO "adt746x: Limit exceeded by %d°C, overriding specified fan speed for %s.\n", + printk(KERN_INFO "adt746x: Limit exceeded by %d, overriding specified fan speed for %s.\n", var, fan_number?"GPU":"CPU"); th->overriding[fan_number] = 1; write_fan_speed(th, 255, fan_number); started = 1; } else if ((!th->overriding[fan_number] || var < 6) && var > 0) { if (th->overriding[fan_number] == 1) - printk(KERN_INFO "adt746x: Limit exceeded by %d°C, setting speed to specified for %s.\n", + printk(KERN_INFO "adt746x: Limit exceeded by %d, setting speed to specified for %s.\n", var, fan_number?"GPU":"CPU"); th->overriding[fan_number] = 0; write_fan_speed(th, fan_speed, fan_number); @@ -308,8 +300,8 @@ static int monitor_task(void *arg) || temps[1] != th->cached_temp[1] || temps[2] != th->cached_temp[2]) { printk(KERN_INFO "adt746x: Temperature infos:" - " thermostats: %d,%d,%d °C;" - " limits: %d,%d,%d °C;" + " thermostats: %d,%d,%d;" + " limits: %d,%d,%d;" " fan speed: %d RPM\n", temps[0], temps[1], temps[2], lims[0], lims[1], lims[2], @@ -321,7 +313,6 @@ static int monitor_task(void *arg) #endif } - complete_and_exit(&monitor_task_compl, 0); return 0; } @@ -380,14 +371,14 @@ attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno) } printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" - " to %d, %d, %d (°C)\n", + " to %d, %d, %d\n", th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], th->limits[0], th->limits[1], th->limits[2]); thermostat = th; if (i2c_attach_client(&th->clt)) { - printk("adt746x: Thermostat failed to attach client !\n"); + printk(KERN_INFO "adt746x: Thermostat failed to attach client !\n"); thermostat = NULL; kfree(th); return -ENODEV; @@ -403,10 +394,13 @@ attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno) write_both_fan_speed(th, -1); } - init_completion(&monitor_task_compl); - - monitor_thread_id = kernel_thread(monitor_task, th, - SIGCHLD | CLONE_KERNEL); + thread_therm = kthread_run(monitor_task, th, "kfand"); + + if (thread_therm == ERR_PTR(-ENOMEM)) { + printk(KERN_INFO "adt746x: Kthread creation failed\n"); + thread_therm = NULL; + return -ENOMEM; + } return 0; } @@ -417,17 +411,21 @@ attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno) * choice but implement a bunch of them... * */ -#define BUILD_SHOW_FUNC_DEG(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - return sprintf(buf, "%d°C\n", data); \ -} #define BUILD_SHOW_FUNC_INT(name, data) \ static ssize_t show_##name(struct device *dev, char *buf) \ { \ return sprintf(buf, "%d\n", data); \ } +#define BUILD_SHOW_FUNC_FAN(name, data) \ +static ssize_t show_##name(struct device *dev, char *buf) \ +{ \ + return sprintf(buf, "%d (%d rpm)\n", \ + thermostat->last_speed[data], \ + read_fan_speed(thermostat, FAN_SPEED[data]) \ + ); \ +} + #define BUILD_STORE_FUNC_DEG(name, data) \ static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ { \ @@ -448,19 +446,19 @@ static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ val = simple_strtoul(buf, NULL, 10); \ if (val < 0 || val > 255) \ return -EINVAL; \ - printk(KERN_INFO "Setting fan speed to %d\n", val); \ + printk(KERN_INFO "Setting specified fan speed to %d\n", val); \ data = val; \ return n; \ } -BUILD_SHOW_FUNC_DEG(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) -BUILD_SHOW_FUNC_DEG(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) -BUILD_SHOW_FUNC_DEG(cpu_limit, thermostat->limits[1]) -BUILD_SHOW_FUNC_DEG(gpu_limit, thermostat->limits[2]) +BUILD_SHOW_FUNC_INT(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) +BUILD_SHOW_FUNC_INT(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) +BUILD_SHOW_FUNC_INT(cpu_limit, thermostat->limits[1]) +BUILD_SHOW_FUNC_INT(gpu_limit, thermostat->limits[2]) BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) -BUILD_SHOW_FUNC_INT(cpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[0]))) -BUILD_SHOW_FUNC_INT(gpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[1]))) +BUILD_SHOW_FUNC_FAN(cpu_fan_speed, 0) +BUILD_SHOW_FUNC_FAN(gpu_fan_speed, 1) BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index f4a1777c6..7dbc5cb4d 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -292,8 +292,7 @@ control_loop( void *dummy ) while( x.running ) { up( &x.lock ); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout( 8*HZ ); + msleep_interruptible(8000); down( &x.lock ); poll_temp(); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 27e14a726..9f4147e3d 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -138,7 +137,6 @@ static int data_len; static volatile int adb_int_pending; static volatile int disable_poll; static struct adb_request bright_req_1, bright_req_2; -static unsigned long async_req_locks; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; @@ -155,6 +153,7 @@ static int drop_interrupts; static int option_lid_wakeup = 1; static int sleep_in_progress; static int can_sleep; +static unsigned long async_req_locks; #endif /* CONFIG_PMAC_PBOOK */ static unsigned int pmu_irq_stats[11]; @@ -494,12 +493,9 @@ static int __init via_pmu_dev_init(void) /* Create /proc/pmu */ proc_pmu_root = proc_mkdir("pmu", NULL); if (proc_pmu_root) { - int i; - proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root, - proc_get_info, NULL); - proc_pmu_irqstats = create_proc_read_entry("interrupts", 0, proc_pmu_root, - proc_get_irqstats, NULL); #ifdef CONFIG_PMAC_PBOOK + int i; + for (i=0; inlink = 1; @@ -746,6 +747,8 @@ done_battery_state_smart(struct adb_request* req) pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + capa = max = amperage = voltage = 0; + if (req->reply[1] & 0x04) { bat_flags |= PMU_BATT_PRESENT; switch(req->reply[0]) { @@ -765,8 +768,7 @@ done_battery_state_smart(struct adb_request* req) req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]); break; } - } else - capa = max = amperage = voltage = 0; + } if ((req->reply[1] & 0x01) && (amperage > 0)) bat_flags |= PMU_BATT_CHARGING; @@ -1445,7 +1447,7 @@ static struct adb_request* __pmac pmu_sr_intr(struct pt_regs *regs) { struct adb_request *req; - int bite; + int bite = 0; if (via[B] & TREQ) { printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 87261d37f..2bf58c928 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 c8feb8346..e1b176505 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -10,7 +10,7 @@ raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \ raid6int1.o raid6int2.o raid6int4.o \ raid6int8.o raid6int16.o raid6int32.o \ raid6mmx.o raid6sse1.o raid6sse2.o -host-progs := mktables +hostprogs-y := mktables # Note: link order is important. All raid personalities # and xor.o must come before md.o, as they each initialise @@ -20,6 +20,7 @@ host-progs := 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/dm-log.c b/drivers/md/dm-log.c index 7a1c77dee..43a12285d 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -140,6 +140,13 @@ struct log_c { int sync_search; + /* Resync flag */ + enum sync { + DEFAULTSYNC, /* Synchronize if necessary */ + NOSYNC, /* Devices known to be already in sync */ + FORCESYNC, /* Force a sync to happen */ + } sync; + /* * Disk log fields */ @@ -205,7 +212,8 @@ static int read_header(struct log_c *log) header_from_disk(&log->header, log->disk_header); - if (log->header.magic != MIRROR_MAGIC) { + /* New log required? */ + if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) { log->header.magic = MIRROR_MAGIC; log->header.version = MIRROR_DISK_VERSION; log->header.nr_regions = 0; @@ -273,22 +281,38 @@ static int write_bits(struct log_c *log) } /*---------------------------------------------------------------- - * constructor/destructor + * core log constructor/destructor + * + * argv contains region_size followed optionally by [no]sync *--------------------------------------------------------------*/ #define BYTE_SHIFT 3 static int core_ctr(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv) { + enum sync sync = DEFAULTSYNC; + struct log_c *lc; sector_t region_size; unsigned int region_count; size_t bitset_size; - if (argc != 1) { - DMWARN("wrong number of arguments to log_c"); + if (argc < 1 || argc > 2) { + DMWARN("wrong number of arguments to mirror log"); return -EINVAL; } + if (argc > 1) { + if (!strcmp(argv[1], "sync")) + sync = FORCESYNC; + else if (!strcmp(argv[1], "nosync")) + sync = NOSYNC; + else { + DMWARN("unrecognised sync argument to mirror log: %s", + argv[1]); + return -EINVAL; + } + } + if (sscanf(argv[0], SECTOR_FORMAT, ®ion_size) != 1) { DMWARN("invalid region size string"); return -EINVAL; @@ -306,6 +330,7 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, lc->touched = 0; lc->region_size = region_size; lc->region_count = region_count; + lc->sync = sync; /* * Work out how many words we need to hold the bitset. @@ -330,8 +355,8 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, kfree(lc); return -ENOMEM; } - memset(lc->sync_bits, 0, bitset_size); - lc->sync_count = 0; + memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); + lc->sync_count = (sync == NOSYNC) ? region_count : 0; lc->recovering_bits = vmalloc(bitset_size); if (!lc->recovering_bits) { @@ -356,6 +381,11 @@ static void core_dtr(struct dirty_log *log) kfree(lc); } +/*---------------------------------------------------------------- + * disk log constructor/destructor + * + * argv contains log_device region_size followed optionally by [no]sync + *--------------------------------------------------------------*/ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv) { @@ -364,8 +394,8 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, struct log_c *lc; struct dm_dev *dev; - if (argc != 2) { - DMWARN("wrong number of arguments to log_d"); + if (argc < 2 || argc > 3) { + DMWARN("wrong number of arguments to disk mirror log"); return -EINVAL; } @@ -452,10 +482,15 @@ static int disk_resume(struct dirty_log *log) if (r) return r; - /* zero any new bits if the mirror has grown */ - for (i = lc->header.nr_regions; i < lc->region_count; i++) - /* FIXME: amazingly inefficient */ - log_clear_bit(lc, lc->clean_bits, i); + /* set or clear any new bits */ + if (lc->sync == NOSYNC) + for (i = lc->header.nr_regions; i < lc->region_count; i++) + /* FIXME: amazingly inefficient */ + log_set_bit(lc, lc->clean_bits, i); + else + for (i = lc->header.nr_regions; i < lc->region_count; i++) + /* FIXME: amazingly inefficient */ + log_clear_bit(lc, lc->clean_bits, i); /* copy clean across to sync */ memcpy(lc->sync_bits, lc->clean_bits, size); @@ -566,6 +601,51 @@ static region_t core_get_sync_count(struct dirty_log *log) return lc->sync_count; } +#define DMEMIT_SYNC \ + if (lc->sync != DEFAULTSYNC) \ + DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "") + +static int core_status(struct dirty_log *log, status_type_t status, + char *result, unsigned int maxlen) +{ + int sz = 0; + struct log_c *lc = log->context; + + switch(status) { + case STATUSTYPE_INFO: + break; + + case STATUSTYPE_TABLE: + DMEMIT("%s %u " SECTOR_FORMAT " ", log->type->name, + lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size); + DMEMIT_SYNC; + } + + return sz; +} + +static int disk_status(struct dirty_log *log, status_type_t status, + char *result, unsigned int maxlen) +{ + int sz = 0; + char buffer[16]; + struct log_c *lc = log->context; + + switch(status) { + case STATUSTYPE_INFO: + break; + + case STATUSTYPE_TABLE: + format_dev_t(buffer, lc->log_dev->bdev->bd_dev); + DMEMIT("%s %u %s " SECTOR_FORMAT " ", log->type->name, + lc->sync == DEFAULTSYNC ? 2 : 3, buffer, + lc->region_size); + DMEMIT_SYNC; + } + + return sz; +} + static struct dirty_log_type _core_type = { .name = "core", .module = THIS_MODULE, @@ -579,7 +659,8 @@ static struct dirty_log_type _core_type = { .clear_region = core_clear_region, .get_resync_work = core_get_resync_work, .complete_resync_work = core_complete_resync_work, - .get_sync_count = core_get_sync_count + .get_sync_count = core_get_sync_count, + .status = core_status, }; static struct dirty_log_type _disk_type = { @@ -597,7 +678,8 @@ static struct dirty_log_type _disk_type = { .clear_region = core_clear_region, .get_resync_work = core_get_resync_work, .complete_resync_work = core_complete_resync_work, - .get_sync_count = core_get_sync_count + .get_sync_count = core_get_sync_count, + .status = disk_status, }; int __init dm_dirty_log_init(void) diff --git a/drivers/md/dm-log.h b/drivers/md/dm-log.h index ced4ebacd..05ef594b5 100644 --- a/drivers/md/dm-log.h +++ b/drivers/md/dm-log.h @@ -101,6 +101,12 @@ struct dirty_log_type { * Returns the number of regions that are in sync. */ region_t (*get_sync_count)(struct dirty_log *log); + + /* + * Support function for mirror status requests. + */ + int (*status)(struct dirty_log *log, status_type_t status_type, + char *result, unsigned int maxlen); }; int dm_register_dirty_log_type(struct dirty_log_type *type); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 92792bb7d..abab26516 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1009,8 +1009,8 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti, * log_type #log_params * #mirrors [mirror_path offset]{2,} * - * For now, #log_params = 1, log_type = "core" - * + * log_type is "core" or "disk" + * #log_params is between 1 and 3 */ #define DM_IO_PAGES 64 static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) @@ -1182,35 +1182,30 @@ static int mirror_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { char buffer[32]; - unsigned int m, sz = 0; + unsigned int m, sz; struct mirror_set *ms = (struct mirror_set *) ti->private; -#define EMIT(x...) sz += ((sz >= maxlen) ? \ - 0 : scnprintf(result + sz, maxlen - sz, x)) + sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen); switch (type) { case STATUSTYPE_INFO: - EMIT("%d ", ms->nr_mirrors); - + DMEMIT("%d ", ms->nr_mirrors); for (m = 0; m < ms->nr_mirrors; m++) { format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); - EMIT("%s ", buffer); + DMEMIT("%s ", buffer); } - EMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, - ms->rh.log->type->get_sync_count(ms->rh.log), - ms->nr_regions); + DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, + ms->rh.log->type->get_sync_count(ms->rh.log), + ms->nr_regions); break; case STATUSTYPE_TABLE: - EMIT("%s 1 " SECTOR_FORMAT " %d ", - ms->rh.log->type->name, ms->rh.region_size, - ms->nr_mirrors); - + DMEMIT("%d ", ms->nr_mirrors); for (m = 0; m < ms->nr_mirrors; m++) { format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); - EMIT("%s " SECTOR_FORMAT " ", - buffer, ms->mirror[m].offset); + DMEMIT("%s " SECTOR_FORMAT " ", + buffer, ms->mirror[m].offset); } } diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index b5bacd717..6a3b9454c 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -191,20 +191,17 @@ static int stripe_status(struct dm_target *ti, unsigned int i; char buffer[32]; -#define EMIT(x...) sz += ((sz >= maxlen) ? \ - 0 : scnprintf(result + sz, maxlen - sz, x)) - switch (type) { case STATUSTYPE_INFO: result[0] = '\0'; break; case STATUSTYPE_TABLE: - EMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1); + DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1); for (i = 0; i < sc->stripes; i++) { format_dev_t(buffer, sc->stripe[i].dev->bdev->bd_dev); - EMIT(" %s " SECTOR_FORMAT, buffer, - sc->stripe[i].physical_start); + DMEMIT(" %s " SECTOR_FORMAT, buffer, + sc->stripe[i].physical_start); } break; } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index d189f8549..a6c24847d 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -825,7 +825,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) * Make sure we obey the optimistic sub devices * restrictions. */ - q->max_sectors = t->limits.max_sectors; + blk_queue_max_sectors(q, t->limits.max_sectors); q->max_phys_segments = t->limits.max_phys_segments; q->max_hw_segments = t->limits.max_hw_segments; q->hardsect_size = t->limits.hardsect_size; @@ -900,6 +900,28 @@ void dm_table_unplug_all(struct dm_table *t) } } +int dm_table_flush_all(struct dm_table *t) +{ + struct list_head *d, *devices = dm_table_get_devices(t); + int ret = 0; + + for (d = devices->next; d != devices; d = d->next) { + struct dm_dev *dd = list_entry(d, struct dm_dev, list); + request_queue_t *q = bdev_get_queue(dd->bdev); + int err; + + if (!q->issue_flush_fn) + err = -EOPNOTSUPP; + else + err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL); + + if (!ret) + ret = err; + } + + return ret; +} + EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); @@ -908,3 +930,4 @@ EXPORT_SYMBOL(dm_table_get_mode); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); EXPORT_SYMBOL(dm_table_unplug_all); +EXPORT_SYMBOL(dm_table_flush_all); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 01794ed39..4d3c1d32a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -15,15 +15,13 @@ #include #include #include +#include static const char *_name = DM_NAME; static unsigned int major = 0; static unsigned int _major = 0; -static int realloc_minor_bits(unsigned long requested_minor); -static void free_minor_bits(void); - /* * One of these is allocated per bio. */ @@ -113,19 +111,11 @@ static int __init local_init(void) return -ENOMEM; } - r = realloc_minor_bits(1024); - if (r < 0) { - kmem_cache_destroy(_tio_cache); - kmem_cache_destroy(_io_cache); - return r; - } - _major = major; r = register_blkdev(_major, _name); if (r < 0) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); return r; } @@ -139,7 +129,6 @@ static void local_exit(void) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); if (unregister_blkdev(_major, _name) < 0) DMERR("devfs_unregister_blkdev failed"); @@ -597,6 +586,21 @@ static int dm_request(request_queue_t *q, struct bio *bio) return 0; } +static int dm_flush_all(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + int ret = -ENXIO; + + if (map) { + ret = dm_table_flush_all(md->map); + dm_table_put(map); + } + + return ret; +} + static void dm_unplug_all(request_queue_t *q) { struct mapped_device *md = q->queuedata; @@ -624,59 +628,15 @@ static int dm_any_congested(void *congested_data, int bdi_bits) } /*----------------------------------------------------------------- - * A bitset is used to keep track of allocated minor numbers. + * An IDR is used to keep track of allocated minor numbers. *---------------------------------------------------------------*/ static DECLARE_MUTEX(_minor_lock); -static unsigned long *_minor_bits = NULL; -static unsigned long _max_minors = 0; - -#define MINORS_SIZE(minors) ((minors / BITS_PER_LONG) * sizeof(unsigned long)) - -static int realloc_minor_bits(unsigned long requested_minor) -{ - unsigned long max_minors; - unsigned long *minor_bits, *tmp; - - if (requested_minor < _max_minors) - return -EINVAL; - - /* Round up the requested minor to the next power-of-2. */ - max_minors = 1 << fls(requested_minor - 1); - if (max_minors > (1 << MINORBITS)) - return -EINVAL; - - minor_bits = kmalloc(MINORS_SIZE(max_minors), GFP_KERNEL); - if (!minor_bits) - return -ENOMEM; - memset(minor_bits, 0, MINORS_SIZE(max_minors)); - - /* Copy the existing bit-set to the new one. */ - if (_minor_bits) - memcpy(minor_bits, _minor_bits, MINORS_SIZE(_max_minors)); - - tmp = _minor_bits; - _minor_bits = minor_bits; - _max_minors = max_minors; - if (tmp) - kfree(tmp); - - return 0; -} - -static void free_minor_bits(void) -{ - down(&_minor_lock); - kfree(_minor_bits); - _minor_bits = NULL; - _max_minors = 0; - up(&_minor_lock); -} +static DEFINE_IDR(_minor_idr); static void free_minor(unsigned int minor) { down(&_minor_lock); - if (minor < _max_minors) - clear_bit(minor, _minor_bits); + idr_remove(&_minor_idr, minor); up(&_minor_lock); } @@ -685,24 +645,37 @@ static void free_minor(unsigned int minor) */ static int specific_minor(unsigned int minor) { - int r = 0; + int r, m; - if (minor > (1 << MINORBITS)) + if (minor >= (1 << MINORBITS)) return -EINVAL; down(&_minor_lock); - if (minor >= _max_minors) { - r = realloc_minor_bits(minor); - if (r) { - up(&_minor_lock); - return r; - } + + if (idr_find(&_minor_idr, minor)) { + r = -EBUSY; + goto out; + } + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m); + if (r) { + goto out; } - if (test_and_set_bit(minor, _minor_bits)) + if (m != minor) { + idr_remove(&_minor_idr, m); r = -EBUSY; - up(&_minor_lock); + goto out; + } +out: + up(&_minor_lock); return r; } @@ -712,21 +685,29 @@ static int next_free_minor(unsigned int *minor) unsigned int m; down(&_minor_lock); - m = find_first_zero_bit(_minor_bits, _max_minors); - if (m >= _max_minors) { - r = realloc_minor_bits(_max_minors * 2); - if (r) { - up(&_minor_lock); - return r; - } - m = find_first_zero_bit(_minor_bits, _max_minors); + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new(&_minor_idr, next_free_minor, &m); + if (r) { + goto out; + } + + if (m >= (1 << MINORBITS)) { + idr_remove(&_minor_idr, m); + r = -ENOSPC; + goto out; } - set_bit(m, _minor_bits); *minor = m; - up(&_minor_lock); - return 0; +out: + up(&_minor_lock); + return r; } static struct block_device_operations dm_blk_dops; @@ -764,6 +745,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) md->queue->backing_dev_info.congested_data = md; blk_queue_make_request(md->queue, dm_request); md->queue->unplug_fn = dm_unplug_all; + md->queue->issue_flush_fn = dm_flush_all; md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab, mempool_free_slab, _io_cache); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index b4b915fbd..2daa03332 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -19,6 +19,9 @@ #define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x) #define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x) +#define DMEMIT(x...) sz += ((sz >= maxlen) ? \ + 0 : scnprintf(result + sz, maxlen - sz, x)) + /* * FIXME: I think this should be with the definition of sector_t * in types.h. @@ -113,6 +116,7 @@ void dm_table_suspend_targets(struct dm_table *t); void dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); void dm_table_unplug_all(struct dm_table *t); +int dm_table_flush_all(struct dm_table *t); /*----------------------------------------------------------------- * A registry of target types. diff --git a/drivers/md/linear.c b/drivers/md/linear.c index e0aa017a2..0f57e5edd 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -47,7 +47,6 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) return hash->dev0; } - /** * linear_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue @@ -93,6 +92,27 @@ static void linear_unplug(request_queue_t *q) } } +static int linear_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + linear_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; i < mddev->raid_disks; i++) { + struct block_device *bdev = conf->disks[i].rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + return ret; +} static int linear_run (mddev_t *mddev) { @@ -137,7 +157,7 @@ static int linear_run (mddev_t *mddev) */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->size = rdev->size; mddev->array_size += rdev->size; @@ -200,6 +220,7 @@ static int linear_run (mddev_t *mddev) blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->unplug_fn = linear_unplug; + mddev->queue->issue_flush_fn = linear_issue_flush; return 0; out: diff --git a/drivers/md/md.c b/drivers/md/md.c index 77cd6e9f3..745f7e7bd 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -154,6 +154,39 @@ static spinlock_t all_mddevs_lock = SPIN_LOCK_UNLOCKED; tmp = tmp->next;}) \ ) +int md_flush_mddev(mddev_t *mddev, sector_t *error_sector) +{ + struct list_head *tmp; + mdk_rdev_t *rdev; + int ret = 0; + + /* + * this list iteration is done without any locking in md?! + */ + ITERATE_RDEV(mddev, rdev, tmp) { + request_queue_t *r_queue = bdev_get_queue(rdev->bdev); + int err; + + if (!r_queue->issue_flush_fn) + err = -EOPNOTSUPP; + else + err = r_queue->issue_flush_fn(r_queue, rdev->bdev->bd_disk, error_sector); + + if (!ret) + ret = err; + } + + return ret; +} + +static int md_flush_all(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + + return md_flush_mddev(mddev, error_sector); +} + static int md_fail_request (request_queue_t *q, struct bio *bio) { bio_io_error(bio, bio->bi_size); @@ -373,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; } @@ -439,6 +472,31 @@ static unsigned int calc_sb_csum(mdp_super_t * sb) return csum; } +/* csum_partial is not consistent between different architectures. + * Some (i386) do a 32bit csum. Some (alpha) do 16 bit. + * This makes it hard for user-space to know what to do. + * So we use calc_sb_csum to set the checksum to allow working + * with older kernels, but allow calc_sb_csum_common to + * be used when checking if a checksum is correct, to + * make life easier for user-space tools that might write + * a superblock. + */ +static unsigned int calc_sb_csum_common(mdp_super_t *super) +{ + unsigned int disk_csum = super->sb_csum; + unsigned long long newcsum = 0; + unsigned int csum; + int i; + unsigned int *superc = (int*) super; + super->sb_csum = 0; + + for (i=0; i>32); + super->sb_csum = disk_csum; + return csum; +} + /* * Handle superblock details. * We want to be able to handle multiple superblock formats @@ -521,7 +579,8 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version if (sb->raid_disks <= 0) goto abort; - if (calc_sb_csum(sb) != sb->sb_csum) { + if (calc_sb_csum(sb) != sb->sb_csum && + calc_sb_csum_common(sb) != sb->sb_csum) { printk(KERN_WARNING "md: invalid superblock checksum on %s\n", b); goto abort; @@ -745,11 +804,21 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) { unsigned int disk_csum, csum; + unsigned long long newcsum; int size = 256 + sb->max_dev*2; + unsigned int *isuper = (unsigned int*)sb; + int i; disk_csum = sb->sb_csum; sb->sb_csum = 0; - csum = csum_partial((void *)sb, size, 0); + newcsum = 0; + for (i=0; size>=4; size -= 4 ) + newcsum += le32_to_cpu(*isuper++); + + if (size == 2) + newcsum += le16_to_cpu(*(unsigned short*) isuper); + + csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; return csum; } @@ -1042,20 +1111,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; } @@ -1117,10 +1190,7 @@ static void export_array(mddev_t *mddev) static void print_desc(mdp_disk_t *desc) { - char b[BDEVNAME_SIZE]; - - printk(" DISK\n", desc->number, - __bdevname(MKDEV(desc->major, desc->minor), b), + printk(" DISK\n", desc->number, desc->major,desc->minor,desc->raid_disk,desc->state); } @@ -1312,8 +1382,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)); @@ -1322,11 +1391,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; @@ -1615,6 +1682,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"); @@ -1645,6 +1714,7 @@ static int do_md_run(mddev_t * mddev) */ mddev->queue->queuedata = mddev; mddev->queue->make_request_fn = mddev->pers->make_request; + mddev->queue->issue_flush_fn = md_flush_all; mddev->changed = 1; return 0; @@ -1881,11 +1951,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); @@ -1916,12 +1984,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); } @@ -2153,42 +2218,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]; @@ -2197,9 +2226,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; @@ -2227,9 +2253,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", @@ -2489,7 +2512,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; @@ -2548,8 +2570,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; @@ -2690,9 +2711,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; @@ -2876,7 +2895,7 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev, return thread; } -void md_interrupt_thread(mdk_thread_t *thread) +static void md_interrupt_thread(mdk_thread_t *thread) { if (!thread->tsk) { MD_BUG(); @@ -2919,6 +2938,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); } @@ -2951,7 +2971,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. @@ -3187,11 +3211,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; @@ -3204,8 +3223,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; } @@ -3339,7 +3362,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:" @@ -3697,7 +3727,6 @@ void md_autodetect_dev(dev_t dev) static void autostart_arrays(int part) { - char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; int i; @@ -3707,11 +3736,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; @@ -3762,7 +3789,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); @@ -3771,6 +3797,5 @@ EXPORT_SYMBOL(md_register_thread); EXPORT_SYMBOL(md_unregister_thread); EXPORT_SYMBOL(md_wakeup_thread); EXPORT_SYMBOL(md_print_devices); -EXPORT_SYMBOL(md_interrupt_thread); EXPORT_SYMBOL(md_check_recovery); MODULE_LICENSE("GPL"); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index a9df710da..9d79b2aba 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -99,12 +99,12 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh) * operation and are ready to return a success/failure code to the buffer * cache layer. */ -static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate) +static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) { struct bio *bio = mp_bh->master_bio; multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); + bio_endio(bio, bio->bi_size, err); mempool_free(mp_bh, conf->pool); } @@ -119,8 +119,8 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error) return 1; if (uptodate) - multipath_end_bh_io(mp_bh, uptodate); - else if ((bio->bi_rw & (1 << BIO_RW_AHEAD)) == 0) { + multipath_end_bh_io(mp_bh, 0); + else if (!bio_rw_ahead(bio)) { /* * oops, IO error: */ @@ -131,7 +131,7 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error) (unsigned long long)bio->bi_sector); multipath_reschedule_retry(mp_bh); } else - multipath_end_bh_io(mp_bh, 0); + multipath_end_bh_io(mp_bh, error); rdev_dec_pending(rdev, conf->mddev); return 0; } @@ -217,6 +217,31 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev) seq_printf (seq, "]"); } +static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + multipath_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->multipaths[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 = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} /* * Careful, this can execute in IRQ contexts as well! @@ -300,7 +325,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); conf->working_disks++; rdev->raid_disk = path; @@ -377,7 +402,7 @@ static void multipathd (mddev_t *mddev) " error for block %llu\n", bdevname(bio->bi_bdev,b), (unsigned long long)bio->bi_sector); - multipath_end_bh_io(mp_bh, 0); + multipath_end_bh_io(mp_bh, -EIO); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", @@ -435,6 +460,8 @@ static int multipath_run (mddev_t *mddev) mddev->queue->unplug_fn = multipath_unplug; + mddev->queue->issue_flush_fn = multipath_issue_flush; + conf->working_disks = 0; ITERATE_RDEV(mddev,rdev,tmp) { disk_idx = rdev->raid_disk; @@ -452,7 +479,7 @@ static int multipath_run (mddev_t *mddev) * a merge_bvec_fn to be involved in multipath */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!rdev->faulty) conf->working_disks++; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 5f4b8bfef..ae45ae92a 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -40,6 +40,31 @@ static void raid0_unplug(request_queue_t *q) } } +static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid0_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t **devlist = conf->strip_zone[0].dev; + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + struct block_device *bdev = devlist[i]->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret =r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + return ret; +} + + static int create_strip_zones (mddev_t *mddev) { int i, c, j; @@ -137,7 +162,7 @@ static int create_strip_zones (mddev_t *mddev) if (rdev1->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!smallest || (rdev1->size size)) smallest = rdev1; @@ -219,6 +244,8 @@ static int create_strip_zones (mddev_t *mddev) mddev->queue->unplug_fn = raid0_unplug; + mddev->queue->issue_flush_fn = raid0_issue_flush; + printk("raid0: done.\n"); return 0; abort: diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 04b2aef4a..1ed82ea4b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -24,10 +24,6 @@ #include -#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; @@ -481,6 +451,32 @@ static void raid1_unplug(request_queue_t *q) unplug_slaves(q->queuedata); } +static int raid1_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; iraid_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. @@ -545,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; @@ -746,7 +753,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); p->head_position = 0; rdev->raid_disk = mirror; @@ -877,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); } @@ -925,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), @@ -935,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; @@ -1117,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); @@ -1168,6 +1177,7 @@ static int run(mddev_t *mddev) mddev->queue->unplug_fn = raid1_unplug; + mddev->queue->issue_flush_fn = raid1_issue_flush; ITERATE_RDEV(mddev, rdev, tmp) { disk_idx = rdev->raid_disk; @@ -1186,7 +1196,7 @@ static int run(mddev_t *mddev) */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; if (!rdev->faulty && rdev->in_sync) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c new file mode 100644 index 000000000..6c3fde9ba --- /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 + +/* + * 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; iraid_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; iraid_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; icopies; 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; icopies; 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<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 ; iraid_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; jcopies;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; kcopies; 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; icopies; 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; icopies; 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 b28f29005..d1f54a9ad 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -477,8 +477,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) if (!rdev->faulty) { mddev->sb_dirty = 1; - conf->working_disks--; if (rdev->in_sync) { + conf->working_disks--; mddev->degraded++; conf->failed_disks++; rdev->in_sync = 0; @@ -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", @@ -1339,6 +1340,39 @@ static void raid5_unplug_device(request_queue_t *q) unplug_slaves(mddev); } +static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->disks[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue; + + if (!bdev) + continue; + + r_queue = bdev_get_queue(bdev); + if (!r_queue) + continue; + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} + static inline void raid5_plug_device(raid5_conf_t *conf) { spin_lock_irq(&conf->device_lock); @@ -1545,6 +1579,7 @@ static int run (mddev_t *mddev) atomic_set(&conf->preread_active_stripes, 0); mddev->queue->unplug_fn = raid5_unplug_device; + mddev->queue->issue_flush_fn = raid5_issue_flush; PRINTK("raid5: run(%s) called.\n", mdname(mddev)); diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 1ad99be9c..aea1a1be5 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -498,8 +498,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) if (!rdev->faulty) { mddev->sb_dirty = 1; - conf->working_disks--; if (rdev->in_sync) { + conf->working_disks--; mddev->degraded++; conf->failed_disks++; rdev->in_sync = 0; @@ -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", @@ -1501,6 +1502,39 @@ static void raid6_unplug_device(request_queue_t *q) unplug_slaves(mddev); } +static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid6_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->disks[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue; + + if (!bdev) + continue; + + r_queue = bdev_get_queue(bdev); + if (!r_queue) + continue; + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} + static inline void raid6_plug_device(raid6_conf_t *conf) { spin_lock_irq(&conf->device_lock); @@ -1708,6 +1742,7 @@ static int run (mddev_t *mddev) atomic_set(&conf->preread_active_stripes, 0); mddev->queue->unplug_fn = raid6_unplug_device; + mddev->queue->issue_flush_fn = raid6_issue_flush; PRINTK("raid6: run(%s) called.\n", mdname(mddev)); diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 18bc5b671..118cace19 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -1,13 +1,6 @@ #include #include -/* helper function */ -static void my_wait(struct saa7146_dev *dev, long ms) -{ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout((((ms+10)/10)*HZ)/1000); -} - u32 saa7146_i2c_func(struct i2c_adapter *adapter) { //fm DEB_I2C(("'%s'.\n", adapter->name)); @@ -136,12 +129,12 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) /* set "ABORT-OPERATION"-bit (bit 7)*/ saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); /* clear all error-bits pending; this is needed because p.123, note 1 */ saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); } /* check if any error is (still) present. (this can be necessary because p.123, note 1) */ @@ -155,18 +148,18 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) after serious protocol errors caused by e.g. the SAA7740 */ saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); /* clear all error-bits pending */ saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); /* the data sheet says it might be necessary to clear the status twice after an abort */ saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - my_wait(dev,SAA7146_I2C_DELAY); + msleep(SAA7146_I2C_DELAY); } /* if any error is still present, a fatal error has occured ... */ @@ -243,7 +236,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d if ((++trial < 20) && short_delay) udelay(10); else - my_wait(dev,1); + msleep(1); } } @@ -345,7 +338,7 @@ int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg msgs[], i } /* delay a bit before retrying */ - my_wait(dev, 10); + msleep(10); } while (err != num && retries--); diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c index 940f6a862..0a8d61c49 100644 --- a/drivers/media/dvb/b2c2/skystar2.c +++ b/drivers/media/dvb/b2c2/skystar2.c @@ -2345,7 +2345,7 @@ static struct pci_device_id skystar2_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl); static struct pci_driver skystar2_pci_driver = { - .name = "Technisat SkyStar2 driver", + .name = "SkyStar2", .id_table = skystar2_pci_tbl, .probe = skystar2_probe, .remove = skystar2_remove, diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 1619f4c3f..7f7ec3314 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -417,6 +417,8 @@ static int __devinit bt878_probe(struct pci_dev *dev, printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); + if (pci_enable_device(dev)) + return -EIO; bt = &bt878[bt878_num]; bt->dev = dev; @@ -426,11 +428,10 @@ static int __devinit bt878_probe(struct pci_dev *dev, bt->id = dev->device; bt->irq = dev->irq; bt->bt878_adr = pci_resource_start(dev, 0); - if (pci_enable_device(dev)) - return -EIO; if (!request_mem_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0), "bt878")) { - return -EBUSY; + result = -EBUSY; + goto fail0; } pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision); @@ -501,6 +502,8 @@ static int __devinit bt878_probe(struct pci_dev *dev, fail1: release_mem_region(pci_resource_start(bt->dev, 0), pci_resource_len(bt->dev, 0)); + fail0: + pci_disable_device(dev); return result; } @@ -517,7 +520,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) /* first disable interrupts before unmapping the memory! */ btwrite(0, BT878_AINT_MASK); - btwrite(~0x0UL, BT878_AINT_STAT); + btwrite(~0U, BT878_AINT_STAT); /* disable PCI bus-mastering */ pci_read_config_byte(bt->dev, PCI_COMMAND, &command); @@ -540,6 +543,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) bt878_mem_free(bt); pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); return; } diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index a4c3794a1..e3af0c025 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]; @@ -1484,21 +1484,20 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) static struct file_operations dvb_ca_fops = { - owner: THIS_MODULE, - read: dvb_ca_en50221_io_read, - write: dvb_ca_en50221_io_write, - ioctl: dvb_ca_en50221_io_ioctl, - open: dvb_ca_en50221_io_open, - release: dvb_ca_en50221_io_release, - poll: dvb_ca_en50221_io_poll, + .owner = THIS_MODULE, + .read = dvb_ca_en50221_io_read, + .write = dvb_ca_en50221_io_write, + .ioctl = dvb_ca_en50221_io_ioctl, + .open = dvb_ca_en50221_io_open, + .release = dvb_ca_en50221_io_release, + .poll = dvb_ca_en50221_io_poll, }; static struct dvb_device dvbdev_ca = { - priv: NULL, - users: 1, - readers: 1, - writers: 1, - fops: &dvb_ca_fops, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &dvb_ca_fops, }; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index dfa5be4e2..ab18a9193 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -142,7 +142,7 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); - eth= skb->mac.ethernet; + eth = eth_hdr(skb); if (*eth->h_dest & 1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) @@ -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/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c index cf165f2d5..8ca5b0289 100644 --- a/drivers/media/dvb/frontends/alps_tdlb7.c +++ b/drivers/media/dvb/frontends/alps_tdlb7.c @@ -54,9 +54,6 @@ static int debug = 0; /* starting point for firmware in file 'Sc_main.mc' */ #define SP8870_FIRMWARE_OFFSET 0x0A - -static int errno; - static struct dvb_frontend_info tdlb7_info = { .name = "Alps TDLB7", .type = FE_OFDM, diff --git a/drivers/media/dvb/frontends/dst.c b/drivers/media/dvb/frontends/dst.c index 431ea9253..4834db951 100644 --- a/drivers/media/dvb/frontends/dst.c +++ b/drivers/media/dvb/frontends/dst.c @@ -1145,8 +1145,8 @@ static int dst_attach (struct dvb_i2c_bus *i2c, void **data) } dst_init (dst); - dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, - (u32)dst, (u32)(dst->bt), (u32)(dst->i2c)); + dprintk("%s: register dst %p bt %p i2c %p\n", __FUNCTION__, + dst, dst->bt, dst->i2c); info = &dst_info_sat; if (dst->dst_type == DST_TYPE_IS_TERR) @@ -1162,7 +1162,7 @@ static int dst_attach (struct dvb_i2c_bus *i2c, void **data) static void dst_detach (struct dvb_i2c_bus *i2c, void *data) { dvb_unregister_frontend (dst_ioctl, i2c); - dprintk("%s: unregister dst %8.8x\n", __FUNCTION__, (u32)(data)); + dprintk("%s: unregister dst %p\n", __FUNCTION__, data); if (data) kfree(data); } diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 53ebf4a69..0aeb8124c 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -67,8 +67,6 @@ struct dvb_frontend_info sp887x_info = { FE_CAN_RECOVER }; -static int errno; - static int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len) { diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index c6a98de01..17c1dd32a 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -319,7 +319,7 @@ static int stv0299_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len) static int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len) { int ret; - struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = len }; + struct i2c_msg msg = { .addr = addr, .buf = data, .len = len }; stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ @@ -1257,12 +1257,12 @@ static long probe_tuner (struct dvb_i2c_bus *i2c) u8 stat [] = { 0 }; u8 tda6100_buf [] = { 0, 0 }; int ret; - struct i2c_msg msg1 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, + struct i2c_msg msg1 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - struct i2c_msg msg2 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, + struct i2c_msg msg2 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - struct i2c_msg msg3 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, - { .addr = 0x60, .flags = 0, .buf = tda6100_buf, .len = 2 }}; + struct i2c_msg msg3 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, + { .addr = 0x60, .buf = tda6100_buf, .len = 2 }}; stv0299_writereg (i2c, 0x01, 0x15); stv0299_writereg (i2c, 0x02, 0x30); @@ -1271,7 +1271,7 @@ static long probe_tuner (struct dvb_i2c_bus *i2c) printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name); - if ( strcmp(adapter->name, "Technisat SkyStar2 driver") == 0 ) + if ( strcmp(adapter->name, "SkyStar2") == 0 ) { printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__); diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 28dc299a8..deeb8ab70 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -188,8 +188,6 @@ static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwi static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} }; static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo); -static int errno; - static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data) { diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 99647b5ff..a5ff5ec02 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/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 2e8403b89..043468a1d 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -host-progs := fdump +hostprogs-y := fdump ifdef CONFIG_DVB_AV7110_FIRMWARE $(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 5e3f5eacc..cc48a65e8 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/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c index 6b11044e7..df79d5e0a 100644 --- a/drivers/media/radio/miropcm20-rds.c +++ b/drivers/media/radio/miropcm20-rds.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "miropcm20-rds-core.h" @@ -60,8 +61,7 @@ static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, char c; char bits[8]; - current->state=TASK_UNINTERRUPTIBLE; - schedule_timeout(2*HZ); + msleep(2000); aci_rds_cmd(RDS_STATUS, &c, 1); print_matrix(&c, bits); if (copy_to_user(buffer, bits, 8)) diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index c6e648753..7aab2ed62 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -63,12 +63,7 @@ static void sleep_delay(long n) if(!d) udelay(n); else - { - /* Yield CPU time */ - unsigned long x=jiffies; - while((jiffies-x)<=d) - schedule(); - } + msleep(jiffies_to_msecs(d)); } static void rt_decvol(void) diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 8cc5191ac..abb03c53d 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -69,8 +69,7 @@ static int cadet_getrds(void) outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */ spin_unlock(&cadet_io_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); spin_lock(&cadet_io_lock); outb(3,io); /* Select Decoder Control/Status */ @@ -243,8 +242,7 @@ static void cadet_setfreq(unsigned freq) outb(curvol,io+1); spin_unlock(&cadet_io_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); cadet_gettune(); if((tunestat & 0x40) == 0) { /* Tuned */ diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 6a18c0088..b226aa437 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -93,27 +93,6 @@ static struct radio_device struct semaphore lock; } radio_unit = {0, 0, 0, 0, }; -static void sleep_125ms(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ >> 3); -} - -static void udelay2(void) -{ - udelay(2); -} - -static void udelay4(void) -{ - udelay(4); -} - -static void udelay16(void) -{ - udelay(16); -} - static __u32 radio_bits_get(struct radio_device *dev) { register __u16 io=dev->io, l, rdata; @@ -122,14 +101,15 @@ static __u32 radio_bits_get(struct radio_device *dev) omask = inw(io + IO_MASK); outw(~(STR_CLK | STR_WREN), io + IO_MASK); outw(0, io); - udelay16(); + udelay(16); + for (l=24;l--;) { outw(STR_CLK, io); /* HI state */ - udelay2(); + udelay(2); if(!l) dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff; outw(0, io); /* LO state */ - udelay2(); + udelay(2); data <<= 1; /* shift data */ rdata = inw(io); if(!l) @@ -138,11 +118,11 @@ static __u32 radio_bits_get(struct radio_device *dev) else if(rdata & STR_DATA) data++; - udelay2(); + udelay(2); } if(dev->muted) outw(STR_WREN, io); - udelay4(); + udelay(4); outw(omask, io + IO_MASK); return data & 0x3ffe; } @@ -155,23 +135,23 @@ static void radio_bits_set(struct radio_device *dev, __u32 data) odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); outw(odir | STR_DATA, io + IO_DIR); outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); - udelay16(); + udelay(16); for (l=25;l;l--) { bits = ((data >> 18) & STR_DATA) | STR_WREN ; data <<= 1; /* shift data */ outw(bits, io); /* start strobe */ - udelay2(); + udelay(2); outw(bits | STR_CLK, io); /* HI level */ - udelay2(); + udelay(2); outw(bits, io); /* LO level */ - udelay4(); + udelay(4); } if(!dev->muted) outw(0, io); - udelay4(); + udelay(4); outw(omask, io + IO_MASK); outw(odir, io + IO_DIR); - sleep_125ms(); + msleep(125); } inline static int radio_function(struct inode *inode, struct file *file, @@ -238,9 +218,9 @@ inline static int radio_function(struct inode *inode, struct file *file, outw(~STR_WREN, io + IO_MASK); outw((card->muted = v->flags & VIDEO_AUDIO_MUTE) ? STR_WREN : 0, io); - udelay4(); + udelay(4); outw(omask, io + IO_MASK); - sleep_125ms(); + msleep(125); return 0; } } @@ -270,7 +250,7 @@ static int radio_ioctl(struct inode *inode, struct file *file, return ret; } -inline static __u16 radio_install(struct pci_dev *pcidev); +static __u16 radio_install(struct pci_dev *pcidev); MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); @@ -315,7 +295,7 @@ inline static __u16 radio_power_on(struct radio_device *dev) outw(odir, io + IO_DIR); outw(~(STR_WREN | STR_CLK), io + IO_MASK); outw(dev->muted ? 0 : STR_WREN, io); - udelay16(); + udelay(16); outw(omask, io + IO_MASK); ofreq = radio_bits_get(dev); if((ofreqFREQ2BITS(FREQ_HI))) @@ -324,7 +304,7 @@ inline static __u16 radio_power_on(struct radio_device *dev) return (ofreq == radio_bits_get(dev)); } -inline static __u16 radio_install(struct pci_dev *pcidev) +static __u16 radio_install(struct pci_dev *pcidev) { if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) return 0; diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index c2fa20d77..c3c62095f 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -104,13 +104,6 @@ static struct radio_device } radio_unit = {0, 0, 0, 0, }; -static void sleep_125ms(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ >> 3); -} - - static void outbit(unsigned long bit, __u16 io) { if(bit != 0) @@ -228,7 +221,7 @@ inline static int radio_function(struct inode *inode, struct file *file, return -EINVAL; card->freq = *freq; set_freq(card->io, FREQ2BITS(card->freq)); - sleep_125ms(); + msleep(125); return 0; } case VIDIOCGAUDIO: { diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 9962c43c7..f0575fb2c 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -89,8 +89,7 @@ static inline int fmi_setfreq(struct fmi_device *dev) outbits(16, RSF16_ENCODE(freq), myport); outbits(8, 0xC0, myport); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/7); + msleep(143); /* was schedule_timeout(HZ/7) */ up(&lock); if (dev->curvol) fmi_unmute(myport); return 0; @@ -107,8 +106,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev) val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ outb(val, myport); outb(val | 0x10, myport); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/7); + msleep(143); /* was schedule_timeout(HZ/7) */ res = (int)inb(myport+1); outb(val, myport); diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index aa49c8e5c..7e980d15f 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -55,19 +55,6 @@ static int radio_nr = -1; #define RSF16_MINFREQ 87*16000 #define RSF16_MAXFREQ 108*16000 -/* from radio-aimslab */ -static void sleep_delay(unsigned long n) -{ - unsigned d=n/(1000000U/HZ); - if (!d) - udelay(n); - else - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(d); - } -} - static inline void wait(int n,int port) { for (;n;--n) inb(port); @@ -153,7 +140,7 @@ static int fmr2_setfreq(struct fmr2_device *dev) fmr2_unmute(port); /* wait 0.11 sec */ - sleep_delay(110000LU); + msleep(110); /* NOTE if mute this stop radio you must set freq on unmute */ diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index db5270b73..d22dd93e5 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -155,7 +155,7 @@ config VIDEO_STRADIS config VIDEO_ZORAN tristate "Zoran ZR36057/36067 Video For Linux" - depends on VIDEO_DEV && PCI && I2C + depends on VIDEO_DEV && PCI && I2C_ALGOBIT help Say Y for support for MJPEG capture cards based on the Zoran 36057/36067 PCI controller chipset. This includes the Iomega diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 16bfdb9ec..74fefc2df 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -156,6 +156,22 @@ adv7175_write_block (struct i2c_client *client, return ret; } +static void +set_subcarrier_freq (struct i2c_client *client, + int pass_through) +{ + /* for some reason pass_through NTSC needs + * a different sub-carrier freq to remain stable. */ + if(pass_through) + adv7175_write(client, 0x02, 0x00); + else + adv7175_write(client, 0x02, 0x55); + + adv7175_write(client, 0x03, 0x55); + adv7175_write(client, 0x04, 0x55); + adv7175_write(client, 0x05, 0x25); +} + #ifdef ENCODER_DUMP static void dump (struct i2c_client *client) @@ -322,6 +338,10 @@ adv7175_command (struct i2c_client *client, case 0: adv7175_write(client, 0x01, 0x00); + + if (encoder->norm == VIDEO_MODE_NTSC) + set_subcarrier_freq(client, 1); + adv7175_write(client, 0x0c, TR1CAPT); /* TR1 */ if (encoder->norm == VIDEO_MODE_SECAM) adv7175_write(client, 0x0d, 0x49); // Disable genlock @@ -334,6 +354,10 @@ adv7175_command (struct i2c_client *client, case 1: adv7175_write(client, 0x01, 0x00); + + if (encoder->norm == VIDEO_MODE_NTSC) + set_subcarrier_freq(client, 0); + adv7175_write(client, 0x0c, TR1PLAY); /* TR1 */ adv7175_write(client, 0x0d, 0x49); adv7175_write(client, 0x07, TR0MODE | TR0RST); @@ -343,6 +367,10 @@ adv7175_command (struct i2c_client *client, case 2: adv7175_write(client, 0x01, 0x80); + + if (encoder->norm == VIDEO_MODE_NTSC) + set_subcarrier_freq(client, 0); + adv7175_write(client, 0x0d, 0x49); adv7175_write(client, 0x07, TR0MODE | TR0RST); adv7175_write(client, 0x07, TR0MODE); diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 7ea762f35..a5a24309c 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -31,7 +31,7 @@ #include #include #include -#ifdef CONFIG_FW_LOADER +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) # include #endif @@ -74,6 +74,9 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input); static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input); static void picolo_tetra_init(struct bttv *btv); +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); + static int terratec_active_radio_upgrade(struct bttv *btv); static int tea5757_read(struct bttv *btv); static int tea5757_write(struct bttv *btv, int value); @@ -170,6 +173,7 @@ static struct CARD { { 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0x6607107d, BTTV_WINFASTVC100, "Leadtek WinFast VC 100" }, + { 0x6609107d, BTTV_WINFAST2000, "Leadtek TV 2000 XP" }, { 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, @@ -224,6 +228,7 @@ static struct CARD { { 0x1431aa00, BTTV_PV143, "Provideo PV143B" }, { 0x1432aa00, BTTV_PV143, "Provideo PV143C" }, { 0x1433aa00, BTTV_PV143, "Provideo PV143D" }, + { 0x1433aa03, BTTV_PV143, "Security Eyes" }, { 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" }, { 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" }, @@ -265,6 +270,7 @@ static struct CARD { { 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" }, { 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, + { 0xa0501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, { 0x18511851, BTTV_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, { 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, { 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, @@ -297,7 +303,7 @@ static struct CARD { // DVB cards (using pci function .1 for mpeg data xfer) { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x07611461, BTTV_NEBULA_DIGITV, "AverMedia AverTV DVB-T" }, + { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T" }, { 0x002611bd, BTTV_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB-T" }, { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, @@ -2078,6 +2084,69 @@ struct tvcard bttv_tvcards[] = { #if 0 /* untested */ .has_remote = 1, #endif +},{ + /* ---- card 0x7c ---------------------------------- */ + /* Matt Jesson */ + /* Based on the Nebula card data - added remote and new card number - BTTV_AVDVBT_761, see also ir-kbd-gpio.c */ + .name = "AverMedia AverTV DVB-T 761", + .video_inputs = 1, + .tuner = -1, + .svhs = -1, + .muxsel = { 2, 3, 1, 0}, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = -1, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, +},{ + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SQ", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0x0, + .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }, + .muxsel_hook = sigmaSQ_muxsel, + .audiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, +},{ + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SLC", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0x0, + .muxsel = { 2, 2, 2, 2 }, + .muxsel_hook = sigmaSLC_muxsel, + .audiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, +},{ + /* BTTV_APAC_VIEWCOMP */ + /* Attila Kondoros */ + /* bt878 TV + FM 0x00000000 subsystem ID */ + .name = "APAC Viewcomp 878(AMAX)", + .video_inputs = 2, + .audio_inputs = 1, + .tuner = 0, + .svhs = -1, + .gpiomask = 0xFF, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 2, 0, 0, 0, 10}, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ + .has_radio = 1, /* not every card has radio */ }}; const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -2405,6 +2474,19 @@ static void init_lmlbt4x(struct bttv *btv) gpio_write(0x000000); } +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 8; + gpio_inout( 0xf, 0xf ); + gpio_bits( 0xf, inmux ); +} + +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 4; + gpio_inout( 3<<9, 3<<9 ); + gpio_bits( 3<<9, inmux<<9 ); +} /* ----------------------------------------------------------------------- */ @@ -2859,7 +2941,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen) return 0; } -#ifndef CONFIG_FW_LOADER +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) /* old 2.4.x way -- via soundcore's mod_firmware_load */ static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf"; @@ -4063,7 +4145,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input) return; } - rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); + rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),0); if (!(rc & PX_CFG_PXC200F)) { printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); return; diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index e7ffe1841..f0d54c5f2 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1051,11 +1051,6 @@ static void init_bt848(struct bttv *btv) btwrite(whitecrush_upper, BT848_WC_UP); btwrite(whitecrush_lower, BT848_WC_DOWN); - bt848_bright(btv, btv->bright); - bt848_hue(btv, btv->hue); - bt848_contrast(btv, btv->contrast); - bt848_sat(btv, btv->saturation); - if (btv->opt_lumafilter) { btwrite(0, BT848_E_CONTROL); btwrite(0, BT848_O_CONTROL); @@ -1064,6 +1059,11 @@ static void init_bt848(struct bttv *btv) btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); } + bt848_bright(btv, btv->bright); + bt848_hue(btv, btv->hue); + bt848_contrast(btv, btv->contrast); + bt848_sat(btv, btv->saturation); + /* interrupt */ init_irqreg(btv); } @@ -1861,6 +1861,8 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, if (NULL == fh->ovfmt) return -EINVAL; + if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup); if (0 != retval) return retval; @@ -2052,6 +2054,7 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c index 01ce7bc32..585f67dde 100644 --- a/drivers/media/video/bttv-gpio.c +++ b/drivers/media/video/bttv-gpio.c @@ -106,6 +106,20 @@ void bttv_gpio_irq(struct bttv_core *core) } } +void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach) +{ + struct bttv_sub_driver *drv; + struct bttv_sub_device *dev; + struct list_head *item; + + list_for_each(item,&core->subs) { + dev = list_entry(item,struct bttv_sub_device,list); + drv = to_bttv_sub_drv(dev->dev.driver); + if (drv && drv->i2c_info) + drv->i2c_info(dev,client,attach); + } +} + /* ----------------------------------------------------------------------- */ /* external: sub-driver register/unregister */ diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index c07a0d9c0..5eb88fcad 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -40,6 +40,7 @@ static void bttv_inc_use(struct i2c_adapter *adap); static void bttv_dec_use(struct i2c_adapter *adap); #endif static int attach_inform(struct i2c_client *client); +static int detach_inform(struct i2c_client *client); static int i2c_debug = 0; static int i2c_hw = 0; @@ -114,6 +115,7 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = { I2C_DEVNAME("bt848"), .id = I2C_HW_B_BT848, .client_register = attach_inform, + .client_unregister = detach_inform, }; /* ----------------------------------------------------------------------- */ @@ -298,6 +300,7 @@ static struct i2c_adapter bttv_i2c_adap_hw_template = { .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, .algo = &bttv_algo, .client_register = attach_inform, + .client_unregister = detach_inform, }; /* ----------------------------------------------------------------------- */ @@ -324,6 +327,7 @@ static int attach_inform(struct i2c_client *client) if (btv->pinnacle_id != UNSET) bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); + bttv_i2c_info(&btv->c, client, 1); if (bttv_debug) printk("bttv%d: i2c attach [client=%s]\n", @@ -331,6 +335,14 @@ static int attach_inform(struct i2c_client *client) return 0; } +static int detach_inform(struct i2c_client *client) +{ + struct bttv *btv = i2c_get_adapdata(client->adapter); + + bttv_i2c_info(&btv->c, client, 0); + return 0; +} + void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) { if (0 != btv->i2c_rc) diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index 769c7e365..3731d2c9a 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -55,6 +55,8 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, instructions += 2; if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) return rc; + dprintk("bttv%d: risc packed: bpl %d lines %d instr %d size %d ptr %p\n", + btv->c.nr, bpl, lines, instructions, risc->size, risc->cpu); /* sync instruction */ rp = risc->cpu; @@ -99,8 +101,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, offset += todo; } offset += padding; + dprintk("bttv%d: risc packed: line %d ptr %p\n", + btv->c.nr, line, rp); } - dprintk("bttv%d: risc planar: %d sglist elems\n", btv->c.nr, (int)(sg-sglist)); + dprintk("bttv%d: risc packed: %d sglist elems\n", btv->c.nr, (int)(sg-sglist)); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -121,6 +125,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *ysg; struct scatterlist *usg; struct scatterlist *vsg; + int topfield = (0 == yoffset); int rc; /* estimate risc mem: worst case is one write per page border + @@ -145,11 +150,26 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, (line >= (ylines - VCR_HACK_LINES))) continue; switch (vshift) { - case 0: chroma = 1; break; - case 1: chroma = !(line & 1); break; - case 2: chroma = !(line & 3); break; - default: chroma = 0; + case 0: + chroma = 1; + break; + case 1: + if (topfield) + chroma = (line & 1) == 0; + else + chroma = (line & 1) == 1; + break; + case 2: + if (topfield) + chroma = (line & 3) == 0; + else + chroma = (line & 3) == 2; + break; + default: + chroma = 0; + break; } + for (todo = ybpl; todo > 0; todo -= ylen) { /* go to next sg entry if needed */ while (yoffset && yoffset >= sg_dma_len(ysg)) { diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index 33d56aa9d..5b8199b79 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -126,6 +126,10 @@ #define BTTV_LMLBT4 0x76 #define BTTV_PICOLO_TETRA_CHIP 0x79 #define BTTV_AVDVBT_771 0x7b +#define BTTV_AVDVBT_761 0x7c +#define BTTV_MATRIX_VISIONSQ 0x7d +#define BTTV_MATRIX_VISIONSLC 0x7e +#define BTTV_APAC_VIEWCOMP 0x7f /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -298,6 +302,8 @@ struct bttv_sub_driver { struct device_driver drv; char wanted[BUS_ID_SIZE]; void (*gpio_irq)(struct bttv_sub_device *sub); + void (*i2c_info)(struct bttv_sub_device *sub, + struct i2c_client *client, int attach); }; #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index fae428ea4..943f8136a 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -225,6 +225,7 @@ extern struct bus_type bttv_sub_bus_type; int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); void bttv_gpio_irq(struct bttv_core *core); +void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach); /* ---------------------------------------------------------- */ diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 02c012dbc..21db4b390 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,15 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("video"); #endif +static unsigned short colorspace_conv = 0; +module_param(colorspace_conv, ushort, 0444); +MODULE_PARM_DESC(colorspace_conv, + "\n Colorspace conversion:" + "\n0 = disable" + "\n1 = enable" + "\nDefault value is 0" + "\n"); + #define ABOUT "V4L-Driver for Vision CPiA based cameras" #ifndef VID_HARDWARE_CPIA @@ -1428,14 +1438,19 @@ static void __exit proc_cpia_destroy(void) /* supported frame palettes and depths */ static inline int valid_mode(u16 palette, u16 depth) { - return (palette == VIDEO_PALETTE_GREY && depth == 8) || - (palette == VIDEO_PALETTE_RGB555 && depth == 16) || - (palette == VIDEO_PALETTE_RGB565 && depth == 16) || - (palette == VIDEO_PALETTE_RGB24 && depth == 24) || - (palette == VIDEO_PALETTE_RGB32 && depth == 32) || - (palette == VIDEO_PALETTE_YUV422 && depth == 16) || - (palette == VIDEO_PALETTE_YUYV && depth == 16) || - (palette == VIDEO_PALETTE_UYVY && depth == 16); + if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) || + (palette == VIDEO_PALETTE_YUYV && depth == 16)) + return 1; + + if (colorspace_conv) + return (palette == VIDEO_PALETTE_GREY && depth == 8) || + (palette == VIDEO_PALETTE_RGB555 && depth == 16) || + (palette == VIDEO_PALETTE_RGB565 && depth == 16) || + (palette == VIDEO_PALETTE_RGB24 && depth == 24) || + (palette == VIDEO_PALETTE_RGB32 && depth == 32) || + (palette == VIDEO_PALETTE_UYVY && depth == 16); + + return 0; } static int match_videosize( int width, int height ) @@ -4040,6 +4055,13 @@ static int __init cpia_init(void) { printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); + + printk(KERN_WARNING "Since in-kernel colorspace conversion is not " + "allowed, it is disabled by default now. Users should fix the " + "applications in case they don't work without conversion " + "reenabled by setting the 'colorspace_conv' module " + "parameter to 1"); + #ifdef CONFIG_PROC_FS proc_cpia_create(); #endif diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c index 3944f3f6a..d54244413 100644 --- a/drivers/media/video/dpc7146.c +++ b/drivers/media/video/dpc7146.c @@ -123,6 +123,7 @@ static int dpc_probe(struct saa7146_dev* dev) /* check if all devices are present */ if( 0 == dpc->saa7111a ) { DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n")); + i2c_del_adapter(&dpc->i2c_adapter); kfree(dpc); return -ENODEV; } diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 6f3fe234e..a586b1bc9 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/media/video/msp3400.c b/drivers/media/video/msp3400.c index 41adfef5c..b60609616 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -1552,13 +1552,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) /* ----------------------------------------------------------------------- */ -static int msp3400_init_module(void) +static int __init msp3400_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void msp3400_cleanup_module(void) +static void __exit msp3400_cleanup_module(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 3343e4133..092fd358c 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -387,13 +387,12 @@ static struct i2c_client client_template = .driver = &driver, }; -static int saa6752hs_init_module(void) +static int __init saa6752hs_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void saa6752hs_cleanup_module(void) +static void __exit saa6752hs_cleanup_module(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 5bb99d716..74b8f0b95 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -154,6 +154,26 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x8000, }, }, + [SAA7134_BOARD_FLYTVPLATINUM] = { + /* "Arnaud Quette" */ + .name = "LifeView FlyTV Platinum", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_SECAM, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", @@ -177,7 +197,6 @@ struct saa7134_board saa7134_boards[] = { .name = name_radio, .amux = LINE2, }, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -243,7 +262,7 @@ struct saa7134_board saa7134_boards[] = { .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -278,7 +297,7 @@ struct saa7134_board saa7134_boards[] = { .name = "KNC One TV-Station DVR", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x820000, .inputs = {{ .name = name_tv, @@ -302,7 +321,6 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x20000, }, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -333,7 +351,7 @@ struct saa7134_board saa7134_boards[] = { .name = "Medion 5044", .audio_clock = 0x00187de7, // was: 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -414,7 +432,7 @@ struct saa7134_board saa7134_boards[] = { //.audio_clock = 0x00200000, .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -440,7 +458,7 @@ struct saa7134_board saa7134_boards[] = { .name = "Typhoon TV+Radio 90031", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -503,7 +521,7 @@ struct saa7134_board saa7134_boards[] = { .name = "ASUS TV-FM 7134", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -607,7 +625,6 @@ struct saa7134_board saa7134_boards[] = { .vmux = 8, .amux = LINE1, }}, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -666,7 +683,7 @@ struct saa7134_board saa7134_boards[] = { .name = "AverMedia M156 / Medion 2819", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -709,7 +726,6 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .tv = 1, }}, - .i2s_rate = 48000, .has_ts = 1, .video_out = CCIR656, }, @@ -719,7 +735,7 @@ struct saa7134_board saa7134_boards[] = { // probably wrong, the 7133 one is the NTSC version ... // .tuner_type = TUNER_PHILIPS_FM1236_MK3 .tuner_type = TUNER_LG_NTSC_NEW_TAPC, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -743,7 +759,7 @@ struct saa7134_board saa7134_boards[] = { .name = "Pinnacle PCTV Stereo (saa7134)", .audio_clock = 0x00187de7, .tuner_type = TUNER_MT2032, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 3, @@ -957,7 +973,7 @@ struct saa7134_board saa7134_boards[] = { .name = "AverMedia 305", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, @@ -989,7 +1005,7 @@ struct saa7134_board saa7134_boards[] = { .name = "UPMOST PURPLE TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .need_tda9887 = 1, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 7, @@ -1000,7 +1016,7 @@ struct saa7134_board saa7134_boards[] = { .vmux = 7, .amux = LINE1, }}, - }, + }, [SAA7134_BOARD_ITEMS_MTV005] = { /* Norman Jonas */ .name = "Items MuchTV Plus / IT-005", @@ -1025,6 +1041,56 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }, }, + [SAA7134_BOARD_CINERGY200] = { + .name = "Terratec Cinergy 200 TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + }}, + .mute = { + .name = name_mute, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_VIDEOMATE_TV_PVR] = { + /* Alain St-Denis */ + .name = "Compro VideoMate TV PVR/FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .gpiomask = 0x808c0080, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x00080 + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x00080 + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + .gpio = 0x00080 + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x80000 + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x40000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -1086,6 +1152,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x5168, .subdevice = 0x0138, .driver_data = SAA7134_BOARD_FLYVIDEO2000, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .subvendor = 0x5168, + .subdevice = 0x0212, + .driver_data = SAA7134_BOARD_FLYTVPLATINUM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -1219,6 +1291,19 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x12ab, .subdevice = 0x0800, .driver_data = SAA7133_BOARD_UPMOST_PURPLE_TV, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x153B, + .subdevice = 0x1152, + .driver_data = SAA7134_BOARD_CINERGY200, + + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x185b, + .subdevice = 0xc100, + .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, },{ /* --- boards without eeprom + subsystem ID --- */ @@ -1297,6 +1382,7 @@ static struct { static void board_flyvideo(struct saa7134_dev *dev) { #if 0 + /* non-working attempt to detect the correct tuner type ... */ u32 value; int index; @@ -1307,6 +1393,10 @@ static void board_flyvideo(struct saa7134_dev *dev) fly_list[index].tuner_type); dev->tuner_type = fly_list[index].tuner_type; #endif + printk("%s: there are different flyvideo cards with different tuners\n" + "%s: out there, you might have to use the tuner= insmod\n" + "%s: option to override the default value.\n", + dev->name, dev->name, dev->name); } /* ----------------------------------------------------------- */ @@ -1321,8 +1411,10 @@ int saa7134_board_init(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: case SAA7134_BOARD_FLYVIDEO3000: - board_flyvideo(dev); dev->has_remote = 1; + /* fall throuth */ + case SAA7134_BOARD_FLYTVPLATINUM: + board_flyvideo(dev); break; case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: @@ -1333,6 +1425,12 @@ int saa7134_board_init(struct saa7134_dev *dev) case SAA7134_BOARD_AVACSSMARTTV: dev->has_remote = 1; break; + case SAA7134_BOARD_MD5044: + printk("%s: seems there are two different versions of the MD5044\n" + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name,dev->name,dev->name); + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index cf87dda32..d5cfa5d5e 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -868,7 +868,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, must_configure_manually(); dev->board = SAA7134_BOARD_UNKNOWN; } - dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[saa7134_devcount]) dev->tuner_type = tuner[saa7134_devcount]; printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", @@ -919,7 +920,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* load i2c helpers */ if (TUNER_ABSENT != dev->tuner_type) request_module("tuner"); - if (saa7134_boards[dev->board].need_tda9887) + if (dev->tda9887_conf) request_module("tda9887"); if (card_has_ts(dev)) request_module("saa6752hs"); @@ -949,7 +950,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->name); goto fail4; } - printk(KERN_INFO "%s: registered device video%d [ts]\n", + printk(KERN_INFO "%s: registered device video%d [mpeg]\n", dev->name,dev->ts_dev->minor & 0x1f); } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 61305cf18..7dc44eaa4 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -327,8 +327,10 @@ static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; + int conf = dev->tda9887_conf; saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner); + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&conf); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 63b32ab17..1066f4eb1 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -776,8 +776,6 @@ int saa7134_oss_init1(struct saa7134_dev *dev) dev->oss.rate = 32000; if (oss_rate) dev->oss.rate = oss_rate; - if (saa7134_boards[dev->board].i2s_rate) - dev->oss.rate = saa7134_boards[dev->board].i2s_rate; dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000; /* mixer */ diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 261d92040..bce58a247 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -504,7 +504,8 @@ static int tvaudio_thread(void *data) dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); dev->tvaudio = NULL; tvaudio_init(dev); - dev->automute = 1; + if (dev->ctl_automute) + dev->automute = 1; mute_input_7134(dev); /* give the tuner some time */ @@ -924,8 +925,9 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) int (*my_thread)(void *data) = NULL; /* enable I2S audio output */ - if (saa7134_boards[dev->board].i2s_rate) { - int i2sform = (32000 == saa7134_boards[dev->board].i2s_rate) ? 0x00 : 0x01; + if (saa7134_boards[dev->board].has_ts) { + int i2sform = (48000 == dev->oss.rate) + ? 0x01 : 0x00; /* enable I2S output */ saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index ec4c286df..0cd39439d 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -272,7 +272,8 @@ static struct saa7134_tvnorm tvnorms[] = { #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) static const struct v4l2_queryctrl no_ctrl = { .name = "42", @@ -356,6 +357,13 @@ static const struct v4l2_queryctrl video_ctrls[] = { .maximum = 128, .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_AUTOMUTE, + .name = "automute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, } }; static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); @@ -433,10 +441,11 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux; + int luma_control,sync_control,mux,nosignal; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; + nosignal = (0 == (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)); mux = card_in(dev,dev->ctl_input).vmux; luma_control = norm->luma_control; @@ -444,7 +453,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) if (mux > 5) luma_control |= 0x80; /* svideo */ - if (noninterlaced) + if (noninterlaced || nosignal) sync_control |= 0x20; /* setup cropping */ @@ -1043,6 +1052,9 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) case V4L2_CID_PRIVATE_Y_ODD: c->value = dev->ctl_y_odd; break; + case V4L2_CID_PRIVATE_AUTOMUTE: + c->value = dev->ctl_automute; + break; default: return -EINVAL; } @@ -1118,6 +1130,17 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, dev->ctl_y_odd = c->value; restart_overlay = 1; break; + case V4L2_CID_PRIVATE_AUTOMUTE: + dev->ctl_automute = c->value; + if (dev->tda9887_conf) { + if (dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; + else + dev->tda9887_conf &= ~TDA9887_AUTOMUTE; + saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, + &dev->tda9887_conf); + } + break; default: return -EINVAL; } @@ -1820,7 +1843,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_frequency *f = arg; memset(f,0,sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; return 0; } @@ -1830,7 +1853,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (0 != f->tuner) return -EINVAL; - if (V4L2_TUNER_ANALOG_TV != f->type) + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) return -EINVAL; down(&dev->lock); dev->ctl_freq = f->frequency; @@ -2244,9 +2269,12 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; + dev->ctl_mute = ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; + dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; + dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; - dev->ctl_invert = 0; - dev->ctl_mute = 1; + if (dev->tda9887_conf && dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; dev->automute = 0; INIT_LIST_HEAD(&dev->video_q.queue); @@ -2300,10 +2328,14 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev) if (0 != norm) { /* wake up tvaudio audio carrier scan thread */ saa7134_tvaudio_do_scan(dev); + if (!noninterlaced) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); } else { /* no video signal -> mute audio */ - dev->automute = 1; + if (dev->ctl_automute) + dev->automute = 1; saa7134_tvaudio_setmute(dev); + saa_setb(SAA7134_SYNC_CTRL, 0x20); } } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index f4d346949..b6d738274 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -156,6 +156,9 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_305 35 #define SAA7133_BOARD_UPMOST_PURPLE_TV 36 #define SAA7134_BOARD_ITEMS_MTV005 37 +#define SAA7134_BOARD_CINERGY200 38 +#define SAA7134_BOARD_FLYTVPLATINUM 39 +#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40 #define SAA7134_INPUT_MAX 8 @@ -178,13 +181,12 @@ struct saa7134_board { struct saa7134_input mute; /* peripheral I/O */ - unsigned int i2s_rate; unsigned int has_ts; enum saa7134_video_out video_out; /* i2c chip info */ unsigned int tuner_type; - unsigned int need_tda9887:1; + unsigned int tda9887_conf; }; #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) @@ -362,6 +364,7 @@ struct saa7134_dev { /* config info */ unsigned int board; unsigned int tuner_type; + unsigned int tda9887_conf; unsigned int gpio_value; /* i2c i/o */ @@ -397,6 +400,7 @@ struct saa7134_dev { int ctl_mirror; int ctl_y_odd; int ctl_y_even; + int ctl_automute; /* crop */ struct v4l2_rect crop_bounds; diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 4365d9485..20051a00c 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -532,17 +532,17 @@ static struct i2c_client client_template = .driver = &driver, }; -static int tda7432_init(void) +static int __init tda7432_init(void) { if ( (loudness < 0) || (loudness > 15) ) { printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n"); return -EINVAL; } - i2c_add_driver(&driver); - return 0; + + return i2c_add_driver(&driver); } -static void tda7432_fini(void) +static void __exit tda7432_fini(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index ae5fd316f..41327c3f7 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -403,13 +403,12 @@ static struct i2c_client client_template = .driver = &driver, }; -static int tda9875_init(void) +static int __init tda9875_init(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tda9875_fini(void) +static void __exit tda9875_fini(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 9768829bd..e46fbdbc4 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -8,6 +8,7 @@ #include #include +#include #include /* Chips: @@ -47,6 +48,7 @@ struct tda9887 { struct i2c_client client; v4l2_std_id std; unsigned int radio; + unsigned int config; unsigned int pinnacle_id; unsigned int using_v4l2; }; @@ -397,6 +399,36 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf) return 0; } +static int tda9887_set_config(struct tda9887 *t, char *buf) +{ + if (t->config & TDA9887_PORT1) + buf[1] |= cOutputPort1Inactive; + if (t->config & TDA9887_PORT2) + buf[1] |= cOutputPort2Inactive; + if (t->config & TDA9887_QSS) + buf[1] |= cQSS; + if (t->config & TDA9887_INTERCARRIER) + buf[1] &= ~cQSS; + + if (t->config & TDA9887_AUTOMUTE) + buf[1] |= cAutoMuteFmActive; + if (t->config & TDA9887_DEEMPHASIS_MASK) { + buf[2] &= ~0x60; + switch (t->config & TDA9887_DEEMPHASIS_MASK) { + case TDA9887_DEEMPHASIS_NONE: + buf[2] |= cDeemphasisOFF; + break; + case TDA9887_DEEMPHASIS_50: + buf[2] |= cDeemphasisON | cDeemphasis50; + break; + case TDA9887_DEEMPHASIS_75: + buf[2] |= cDeemphasisON | cDeemphasis75; + break; + } + } + return 0; +} + /* ---------------------------------------------------------------------- */ static int tda9887_set_pinnacle(struct tda9887 *t, char *buf) @@ -499,6 +531,7 @@ static int tda9887_configure(struct tda9887 *t) if (UNSET != t->pinnacle_id) { tda9887_set_pinnacle(t,buf); } + tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", @@ -594,6 +627,14 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) tda9887_configure(t); break; } + case TDA9887_SET_CONFIG: + { + int *i = arg; + + t->config = *i; + tda9887_configure(t); + break; + } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -644,6 +685,25 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) t->radio = 1; } tda9887_configure(t); + break; + } + case VIDIOC_G_TUNER: + { + static int AFC_BITS_2_kHz[] = { + -12500, -37500, -62500, -97500, + -112500, -137500, -162500, -187500, + 187500, 162500, 137500, 112500, + 97500 , 62500, 37500 , 12500 + }; + struct v4l2_tuner* tuner = arg; + + if (t->radio) { + __u8 reg = 0; + tuner->afc=0; + if (1 == i2c_master_recv(&t->client,®,1)) + tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; + } + break; } default: /* nothing */ @@ -670,13 +730,12 @@ static struct i2c_client client_template = .driver = &driver, }; -static int tda9887_init_module(void) +static int __init tda9887_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tda9887_cleanup_module(void) +static void __exit tda9887_cleanup_module(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c index 18e1118df..bac17a3dc 100644 --- a/drivers/media/video/tuner.c +++ b/drivers/media/video/tuner.c @@ -208,7 +208,7 @@ static struct tunertype tuners[] = { { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ - 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940) + 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, @@ -229,7 +229,7 @@ static struct tunertype tuners[] = { 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, { "HITACHI V7-J180AT", HITACHI, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x00,0x8e,940 }, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, { "Philips PAL_MK (FI1216 MK)", Philips, PAL, 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, @@ -241,6 +241,13 @@ static struct tunertype tuners[] = { 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, { "Microtune 4049 FM5",Microtune,PAL, 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, + { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, + 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, + { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, + 16*170.00, 16*450.00, 0x01,0x02,0x04,0x8e,732 }, + + { "Tenna TNF 8831 BGFF)", Philips, PAL, + 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, }; #define TUNERS ARRAY_SIZE(tuners) @@ -934,6 +941,9 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_PHILIPS_FM1236_MK3: buffer[3] = 0x19; break; + case TUNER_LG_PAL_FM: + buffer[3] = 0xa5; + break; default: buffer[3] = 0xa4; break; @@ -1300,13 +1310,12 @@ static struct i2c_client client_template = .driver = &driver, }; -static int tuner_init_module(void) +static int __init tuner_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tuner_cleanup_module(void) +static void __exit tuner_cleanup_module(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index bf5017a77..b435bcef9 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1651,7 +1651,7 @@ static struct i2c_client client_template = .driver = &driver, }; -static int audiochip_init_module(void) +static int __init audiochip_init_module(void) { struct CHIPDESC *desc; printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); @@ -1659,11 +1659,11 @@ static int audiochip_init_module(void) for (desc = chiplist; desc->name != NULL; desc++) printk("%s%s", (desc == chiplist) ? "" : ",",desc->name); printk("\n"); - i2c_add_driver(&driver); - return 0; + + return i2c_add_driver(&driver); } -static void audiochip_cleanup_module(void) +static void __exit audiochip_cleanup_module(void) { i2c_del_driver(&driver); } diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 48b2f822e..20cb7647f 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -330,17 +330,17 @@ static int tvmixer_clients(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static int tvmixer_init_module(void) +static int __init tvmixer_init_module(void) { int i; for (i = 0; i < DEV_MAX; i++) devices[i].minor = -1; - i2c_add_driver(&driver); - return 0; + + return i2c_add_driver(&driver); } -static void tvmixer_cleanup_module(void) +static void __exit tvmixer_cleanup_module(void) { int i; diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index fbc5cb1e2..9d4c74f25 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -254,7 +254,7 @@ int video_exclusive_release(struct inode *inode, struct file *file) return 0; } -extern struct file_operations video_fops; +static struct file_operations video_fops; /** * video_register_device - register video4linux devices diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index 705cff870..a35d518e2 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -1105,8 +1105,7 @@ zr36057_enable_jpg (struct zoran *zr, ZR36057_ISR); btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ / 20); + msleep(50); set_videobus_dir(zr, 0); set_frame(zr, 1); // /FRAME diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 28f1a8d05..d6294bd79 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -2265,8 +2265,8 @@ zoran_do_ioctl (struct inode *inode, dprintk(3, KERN_DEBUG - "%s: VIDIOCSFBUF - base=0x%x, w=%d, h=%d, depth=%d, bpl=%d\n", - ZR_DEVNAME(zr), (u32) vbuf->base, vbuf->width, + "%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n", + ZR_DEVNAME(zr), vbuf->base, vbuf->width, vbuf->height, vbuf->depth, vbuf->bytesperline); for (i = 0; i < zoran_num_formats; i++) diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig index aa1c657dd..070abf63d 100644 --- a/drivers/message/fusion/Kconfig +++ b/drivers/message/fusion/Kconfig @@ -27,39 +27,6 @@ config FUSION_MAX_SGE necessary (or recommended) unless the user will be running large I/O's via the raw interface. -config FUSION_ISENSE - tristate "Enhanced SCSI error reporting" - depends on MODULES && FUSION && m - ---help--- - The isense module (roughly stands for Interpret SENSE data) is - completely optional. It simply provides extra English readable - strings in SCSI Error Report(s) that might be generated from the - Fusion MPT SCSI Host driver, for example when a target device - returns a SCSI check condition on a I/O. Without this module - loaded you might see: - - SCSI Error Report =-=-= (ioc0,scsi5:0) - SCSI_Status=02h (CHECK_CONDITION) - Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 - SenseKey=2h (NOT READY); FRU=02h - ASC/ASCQ=29h/00h - - Where otherwise, if this module had been loaded, you would see: - - SCSI Error Report =-=-= (ioc0,scsi5:0) - SCSI_Status=02h (CHECK_CONDITION) - Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)" - SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 - SenseKey=2h (NOT READY); FRU=02h - ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" - - Say M for "Enhanced SCSI error reporting" to compile this optional module, - creating a driver named: isense. - - NOTE: Support for building this feature into the kernel is not - available, due to kernel size considerations. - config FUSION_CTL tristate "Fusion MPT misc device (ioctl) driver" depends on MODULES && FUSION && m diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index b709839fe..f6fdcaaef 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -2,7 +2,7 @@ # Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers. # # Note! If you want to turn on various debug defines for an extended period of -# time but don't want them lingering around in the Makefile when you pass it on +# time but don't want them lingering around in the Makefile when you pass it on # to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC @@ -48,6 +48,5 @@ EXTRA_CFLAGS += ${MPT_CFLAGS} #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC obj-$(CONFIG_FUSION) += mptbase.o mptscsih.o -obj-$(CONFIG_FUSION_ISENSE) += isense.o obj-$(CONFIG_FUSION_CTL) += mptctl.o obj-$(CONFIG_FUSION_LAN) += mptlan.o diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 75c07f89e..70a44c9d2 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -139,11 +139,6 @@ struct proc_dir_entry *mpt_proc_root_dir; DmpServices_t *DmpService; -void *mpt_v_ASCQ_TablePtr; -const char **mpt_ScsiOpcodesPtr; -int mpt_ASCQ_TableSz; - - #define WHOINIT_UNKNOWN 0xAA /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -165,7 +160,6 @@ static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS] static int FusionInitCalled = 0; static int mpt_base_index = -1; static int last_drv_idx = -1; -static int isense_idx = -1; static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); @@ -177,8 +171,8 @@ static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag); -static void mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev); -static void mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup); +static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev); +static void mpt_adapter_disable(MPT_ADAPTER *ioc); static void mpt_adapter_dispose(MPT_ADAPTER *ioc); static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); @@ -291,7 +285,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) int type; int freeme; - ioc = bus_id; + ioc = (MPT_ADAPTER *)bus_id; /* * Drain the reply FIFO! @@ -333,8 +327,8 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n", - ioc->name, mr)); + dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x\n", + ioc->name, mr, req_idx)); DBG_DUMP_REPLY_FRAME(mr) /* NEW! 20010301 -sralston @@ -358,7 +352,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) /* * Process turbo (context) reply... */ - dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa)); + dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { cb_idx = mpt_stm_index; @@ -506,7 +500,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) results = ProcessEventNotification(ioc, pEvReply, &evHandlers); if (results != evHandlers) { /* CHECKME! Any special handling needed here? */ - dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", + devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", ioc->name, evHandlers, results)); } @@ -659,8 +653,6 @@ mpt_deregister(int cb_idx) MptEvHandlers[cb_idx] = NULL; last_drv_idx++; - if (isense_idx != -1 && isense_idx <= cb_idx) - isense_idx++; } } @@ -803,56 +795,60 @@ mpt_device_driver_deregister(int cb_idx) * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) * allocated per MPT adapter. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * * Returns pointer to a MPT request frame or %NULL if none are available * or IOC is not active. */ MPT_FRAME_HDR* -mpt_get_msg_frame(int handle, MPT_ADAPTER *iocp) +mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) { MPT_FRAME_HDR *mf; unsigned long flags; + u16 req_idx; /* Request index */ + + /* validate handle and ioc identifier */ #ifdef MFCNT - if (!iocp->active) + if (!ioc->active) printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n"); #endif /* If interrupts are not attached, do not return a request frame */ - if (!iocp->active) + if (!ioc->active) return NULL; - spin_lock_irqsave(&iocp->FreeQlock, flags); - if (! Q_IS_EMPTY(&iocp->FreeQ)) { + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (! Q_IS_EMPTY(&ioc->FreeQ)) { int req_offset; - mf = iocp->FreeQ.head; + mf = ioc->FreeQ.head; Q_DEL_ITEM(&mf->u.frame.linkage); mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ - req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; /* u16! */ - mf->u.frame.hwhdr.msgctxu.fld.req_idx = - cpu_to_le16(req_offset / iocp->req_sz); + req_idx = cpu_to_le16(req_offset / ioc->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.req_idx = req_idx; mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */ #ifdef MFCNT - iocp->mfcnt++; + ioc->mfcnt++; #endif } else mf = NULL; - spin_unlock_irqrestore(&iocp->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); #ifdef MFCNT if (mf == NULL) - printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth); + printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth); mfcounter++; if (mfcounter == PRINT_MF_COUNT) - printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth); + printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth); #endif dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", - iocp->name, handle, iocid, mf)); + ioc->name, handle, ioc->id, mf)); return mf; } @@ -861,23 +857,25 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *iocp) * mpt_put_msg_frame - Send a protocol specific MPT request frame * to a IOC. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine posts a MPT request frame to the request post FIFO of a * specific MPT adapter. */ void -mpt_put_msg_frame(int handle, MPT_ADAPTER *iocp, MPT_FRAME_HDR *mf) +mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { u32 mf_dma_addr; int req_offset; + u16 req_idx; /* Request index */ /* ensure values are reset properly! */ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ - req_offset = (u8 *)mf - (u8 *)iocp->req_frames; - /* u16! */ - mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz); + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; + /* u16! */ + req_idx = cpu_to_le16(req_offset / ioc->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.req_idx = req_idx; mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; #ifdef MPT_DEBUG_MSG_FRAME @@ -886,8 +884,8 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *iocp, MPT_FRAME_HDR *mf) int ii, n; printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", - iocp->name, m); - n = iocp->req_sz/4 - 1; + ioc->name, m); + n = ioc->req_sz/4 - 1; while (m[n] == 0) n--; for (ii=0; ii<=n; ii++) { @@ -899,32 +897,33 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *iocp, MPT_FRAME_HDR *mf) } #endif - mf_dma_addr = iocp->req_frames_low_dma + req_offset; - CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; + dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx])); + CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_free_msg_frame - Place MPT request frame back on FreeQ. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. */ void -mpt_free_msg_frame(int handle, MPT_ADAPTER *iocp, MPT_FRAME_HDR *mf) +mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { unsigned long flags; /* Put Request back on FreeQ! */ - spin_lock_irqsave(&iocp->FreeQlock, flags); - Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); #ifdef MFCNT - iocp->mfcnt--; + ioc->mfcnt--; #endif - spin_unlock_irqrestore(&iocp->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -996,7 +995,7 @@ mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) * mpt_send_handshake_request - Send MPT request via doorbell * handshake method. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. @@ -1010,7 +1009,7 @@ mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) * Returns 0 for success, non-zero for failure. */ int -mpt_send_handshake_request(int handle, MPT_ADAPTER *iocp, int reqBytes, u32 *req, int sleepFlag) +mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) { int r = 0; u8 *req_as_bytes; @@ -1026,37 +1025,38 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *iocp, int reqBytes, u32 *req * setting cb_idx/req_idx. But ONLY if this request * is in proper (pre-alloc'd) request buffer range... */ - ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); - if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) { + ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); + if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; } /* Make sure there are no doorbells */ - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); - CHIPREG_WRITE32(&iocp->chip->Doorbell, + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + CHIPREG_WRITE32(&ioc->chip->Doorbell, ((MPI_FUNCTION_HANDSHAKE<chip->Doorbell) & MPI_DOORBELL_ACTIVE)) + if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) return -5; dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", - iocp->name, ii)); + ioc->name, ii)); - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - r = WaitForDoorbellAck(iocp, 5, sleepFlag); - if (r < 0) + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { return -2; - + } + /* Send request via doorbell handshake */ req_as_bytes = (u8 *) req; for (ii = 0; ii < reqBytes/4; ii++) { @@ -1066,21 +1066,21 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *iocp, int reqBytes, u32 *req (req_as_bytes[(ii*4) + 1] << 8) | (req_as_bytes[(ii*4) + 2] << 16) | (req_as_bytes[(ii*4) + 3] << 24)); - CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - r = WaitForDoorbellAck(iocp, 5, sleepFlag); - if (r < 0) { + CHIPREG_WRITE32(&ioc->chip->Doorbell, word); + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { r = -3; break; } } - if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0) + if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) r = 0; else r = -4; /* Make sure there are no doorbells */ - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + return r; } @@ -1141,11 +1141,15 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) u8 revision; u8 pcixcmd; static int mpt_ids = 0; +#ifdef CONFIG_PROC_FS struct proc_dir_entry *dent, *ent; +#endif if (pci_enable_device(pdev)) return r; + dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n")); + if (!pci_set_dma_mask(pdev, mask)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); @@ -1170,9 +1174,8 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; - + ioc->pcidev = pdev; - ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); @@ -1223,8 +1226,8 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -EINVAL; } - dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); - dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); + dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); + dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); mem = NULL; /* Get logical ptr for PciMem0 space */ @@ -1236,15 +1239,15 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -EINVAL; } ioc->memmap = mem; - dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); - dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", + dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", &ioc->facts, &ioc->pfacts[0])); ioc->mem_phys = mem_phys; ioc->chip = (SYSIF_REGS*)mem; - /* Save Port IO values incase we need to do downloadboot */ + /* Save Port IO values in case we need to do downloadboot */ { u8 *pmem = (u8*)port; ioc->pio_mem_phys = port; @@ -1314,7 +1317,6 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) sprintf(ioc->name, "ioc%d", ioc->id); - Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); spin_lock_init(&ioc->FreeQlock); /* Disable all! */ @@ -1337,7 +1339,6 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", ioc->name, __irq_itoa(pdev->irq)); #endif - Q_DEL_ITEM(ioc); list_del(&ioc->list); iounmap(mem); kfree(ioc); @@ -1369,7 +1370,6 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); - Q_DEL_ITEM(ioc); list_del(&ioc->list); free_irq(ioc->pci_irq, ioc); iounmap(mem); @@ -1386,6 +1386,7 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } +#ifdef CONFIG_PROC_FS /* * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. */ @@ -1402,6 +1403,7 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) ent->data = ioc; } } +#endif return 0; } @@ -1625,7 +1627,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) int hard_reset_done = 0; int alt_ioc_ready = 0; int hard; - int r; + int rc=0; int ii; int handlers; int ret = 0; @@ -1675,39 +1677,37 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * and 1 if a hard reset was performed. */ if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { - if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) + if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else printk(KERN_WARNING MYNAM - ": alt-%s: (%d) Not ready WARNING!\n", - ioc->alt_ioc->name, r); + ": alt-%s: Not ready WARNING!\n", + ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { - /* Get IOC facts! Allow 1 retry */ - if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) { - dinitprintk((MYIOC_s_INFO_FMT - "ii=%d IocFacts failed r=%x\n", ioc->name, ii, r)); - } else + /* Get IOC facts! Allow 5 retries */ + if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) break; } + - if (r) { - dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed r=%x\n", ioc->name, r)); + if (ii == 5) { + dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } - + if (alt_ioc_ready) { - if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { - dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed r=%x\n", ioc->name, r)); + if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); /* Retry - alt IOC was initialized once */ - r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); + rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } - if (r) { - dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed r=%x\n", ioc->name, r)); + if (rc) { + dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { @@ -1720,29 +1720,29 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ - if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0)) + if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ - if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0)) + if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4; // NEW! - if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) { + if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", - ioc->alt_ioc->name, r); + ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } if (alt_ioc_ready) { - if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { + if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n", - ioc->alt_ioc->name, r); + ioc->alt_ioc->name, rc); } } @@ -1754,18 +1754,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) /* Controller is not operational, cannot do upload */ if (ret == 0) { - r = mpt_do_upload(ioc, sleepFlag); - if (r != 0) - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); - } - - /* Handle the alt IOC too */ - if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){ - ddlprintk((MYIOC_s_INFO_FMT - "Alt-ioc firmware upload required!\n", - ioc->name)); - r = mpt_do_upload(ioc->alt_ioc, sleepFlag); - if (r != 0) + rc = mpt_do_upload(ioc, sleepFlag); + if (rc != 0) printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); } } @@ -1859,19 +1849,19 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * MptResetHandlers[] registered yet. */ if (hard_reset_done) { - r = handlers = 0; + rc = handlers = 0; for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { if ((ret == 0) && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); + rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); handlers++; } if (alt_ioc_ready && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); + rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); handlers++; } } @@ -1932,84 +1922,90 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) /* * mpt_adapter_disable - Disable misbehaving MPT adapter. * @this: Pointer to MPT adapter structure - * @free: Free up alloc'd reply, request, etc. */ static void -mpt_adapter_disable(MPT_ADAPTER *this, int freeup) +mpt_adapter_disable(MPT_ADAPTER *ioc) { - if (this != NULL) { - int sz=0; - int ret; - - if (this->cached_fw != NULL) { - ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n")); + int sz; + int ret; - if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", ret); - } + if (ioc->cached_fw != NULL) { + ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n")); + if ((ret = mpt_downloadboot(ioc, NO_SLEEP)) < 0) { + printk(KERN_WARNING MYNAM + ": firmware downloadboot failure (%d)!\n", ret); } + } - /* Disable adapter interrupts! */ - CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); - this->active = 0; - /* Clear any lingering interrupt */ - CHIPREG_WRITE32(&this->chip->IntStatus, 0); - - if (freeup && this->fifo_pool != NULL) { - pci_free_consistent(this->pcidev, - this->fifo_pool_sz, - this->fifo_pool, this->fifo_pool_dma); - this->reply_frames = NULL; - this->reply_alloc = NULL; - this->req_frames = NULL; - this->req_alloc = NULL; - this->chain_alloc = NULL; - this->fifo_pool = NULL; - this->alloc_total -= this->fifo_pool_sz; - } - if (freeup && this->sense_buf_pool != NULL) { - sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC); - pci_free_consistent(this->pcidev, sz, - this->sense_buf_pool, this->sense_buf_pool_dma); - this->sense_buf_pool = NULL; - this->alloc_total -= sz; - } + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if (freeup && this->events != NULL){ - sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); - kfree(this->events); - this->events = NULL; - this->alloc_total -= sz; - } + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; + dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n", + ioc->name, ioc->alloc, ioc->alloc_sz)); + pci_free_consistent(ioc->pcidev, sz, + ioc->alloc, ioc->alloc_dma); + ioc->reply_frames = NULL; + ioc->req_frames = NULL; + ioc->alloc = NULL; + ioc->alloc_total -= sz; + } - if (freeup && this->cached_fw != NULL) { + if (ioc->sense_buf_pool != NULL) { + sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); + pci_free_consistent(ioc->pcidev, sz, + ioc->sense_buf_pool, ioc->sense_buf_pool_dma); + ioc->sense_buf_pool = NULL; + ioc->alloc_total -= sz; + } - sz = this->facts.FWImageSize; - pci_free_consistent(this->pcidev, sz, - this->cached_fw, this->cached_fw_dma); - this->cached_fw = NULL; - this->alloc_total -= sz; - } + if (ioc->events != NULL){ + sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + kfree(ioc->events); + ioc->events = NULL; + ioc->alloc_total -= sz; + } - if (freeup && this->spi_data.nvram != NULL) { - kfree(this->spi_data.nvram); - this->spi_data.nvram = NULL; - } + if (ioc->cached_fw != NULL) { + sz = ioc->facts.FWImageSize; + pci_free_consistent(ioc->pcidev, sz, + ioc->cached_fw, ioc->cached_fw_dma); + ioc->cached_fw = NULL; + ioc->alloc_total -= sz; + } - if (freeup && this->spi_data.pIocPg3 != NULL) { - kfree(this->spi_data.pIocPg3); - this->spi_data.pIocPg3 = NULL; - } + if (ioc->spi_data.nvram != NULL) { + kfree(ioc->spi_data.nvram); + ioc->spi_data.nvram = NULL; + } - if (freeup && this->spi_data.pIocPg4 != NULL) { - sz = this->spi_data.IocPg4Sz; - pci_free_consistent(this->pcidev, sz, - this->spi_data.pIocPg4, - this->spi_data.IocPg4_dma); - this->spi_data.pIocPg4 = NULL; - this->alloc_total -= sz; - } + if (ioc->spi_data.pIocPg3 != NULL) { + kfree(ioc->spi_data.pIocPg3); + ioc->spi_data.pIocPg3 = NULL; + } + + if (ioc->spi_data.pIocPg4 != NULL) { + sz = ioc->spi_data.IocPg4Sz; + pci_free_consistent(ioc->pcidev, sz, + ioc->spi_data.pIocPg4, + ioc->spi_data.IocPg4_dma); + ioc->spi_data.pIocPg4 = NULL; + ioc->alloc_total -= sz; + } + + if (ioc->ReqToChain != NULL) { + kfree(ioc->ReqToChain); + kfree(ioc->RequestNB); + ioc->ReqToChain = NULL; + } + + if (ioc->ChainToChain != NULL) { + kfree(ioc->ChainToChain); + ioc->ChainToChain = NULL; } } @@ -2017,43 +2013,43 @@ mpt_adapter_disable(MPT_ADAPTER *this, int freeup) /* * mpt_adapter_dispose - Free all resources associated with a MPT * adapter. - * @this: Pointer to MPT adapter structure + * @ioc: Pointer to MPT adapter structure * * This routine unregisters h/w resources and frees all alloc'd memory * associated with a MPT adapter structure. */ static void -mpt_adapter_dispose(MPT_ADAPTER *this) +mpt_adapter_dispose(MPT_ADAPTER *ioc) { - if (this != NULL) { + if (ioc != NULL) { int sz_first, sz_last; - sz_first = this->alloc_total; + sz_first = ioc->alloc_total; - mpt_adapter_disable(this, 1); + mpt_adapter_disable(ioc); - if (this->pci_irq != -1) { - free_irq(this->pci_irq, this); - this->pci_irq = -1; + if (ioc->pci_irq != -1) { + free_irq(ioc->pci_irq, ioc); + ioc->pci_irq = -1; } - if (this->memmap != NULL) - iounmap((u8 *) this->memmap); + if (ioc->memmap != NULL) + iounmap((u8 *) ioc->memmap); #if defined(CONFIG_MTRR) && 0 - if (this->mtrr_reg > 0) { - mtrr_del(this->mtrr_reg, 0, 0); - dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name)); + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); } #endif /* Zap the adapter lookup ptr! */ - list_del(&this->list); + list_del(&ioc->list); - sz_last = this->alloc_total; + sz_last = ioc->alloc_total; dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", - this->name, sz_first-sz_last+(int)sizeof(*this), sz_first)); - kfree(this); + ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); + kfree(ioc); } } @@ -2228,13 +2224,13 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) ii++; cntdn--; if (!cntdn) { printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (ii+5)/HZ); + ioc->name, (int)((ii+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); } else { mdelay (1); /* 1 msec delay */ } @@ -2292,7 +2288,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) int r; int req_sz; int reply_sz; - u32 status; + int sz; + u32 status, vv; + u8 shiftFactor=1; /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { @@ -2315,7 +2313,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dinitprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name)); + dinitprintk((MYIOC_s_INFO_FMT + "Sending get IocFacts request req_sz=%d reply_sz=%d\n", + ioc->name, req_sz, reply_sz)); /* No non-zero fields in the get_facts request are greater than * 1 byte in size, so we can just fire it off as is. @@ -2388,6 +2388,13 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->FWImageSize = le32_to_cpu(facts->FWImageSize); } + sz = facts->FWImageSize; + if ( sz & 0x01 ) + sz += 1; + if ( sz & 0x02 ) + sz += 2; + facts->FWImageSize = sz; + if (!facts->RequestFrameSize) { /* Something is wrong! */ printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", @@ -2395,6 +2402,18 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) return -55; } + r = sz = le32_to_cpu(facts->BlockSize); + vv = ((63 / (sz * 4)) + 1) & 0x03; + ioc->NB_for_64_byte_frame = vv; + while ( sz ) + { + shiftFactor++; + sz = sz >> 1; + } + ioc->NBShiftFactor = shiftFactor; + dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", + ioc->name, vv, shiftFactor, r)); + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { /* * Set values for this IOC's request & reply frame sizes, @@ -2405,9 +2424,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); - dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", + dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); - dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", + dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", ioc->name, ioc->req_sz, ioc->req_depth)); /* Get port facts! */ @@ -2416,7 +2435,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; @@ -2465,7 +2484,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) get_pfacts.PortNumber = portnum; /* Assert: All other get_pfacts fields are zero! */ - dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", ioc->name, portnum)); /* No non-zero fields in the get_pfacts request are greater than @@ -2516,24 +2535,18 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) memset(&init_reply, 0, sizeof(init_reply)); ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; -/* ioc_init.ChainOffset = 0; */ ioc_init.Function = MPI_FUNCTION_IOC_INIT; -/* ioc_init.Flags = 0; */ /* If we are in a recovery mode and we uploaded the FW image, * then this pointer is not NULL. Skip the upload a second time. * Set this flag if cached_fw set for either IOC. */ - ioc->upload_fw = 0; - ioc_init.Flags = 0; - if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) - ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE; - else - ioc->upload_fw = 1; - } - ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", - ioc->name, ioc_init.Flags, ioc->upload_fw)); + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) + ioc->upload_fw = 1; + else + ioc->upload_fw = 0; + ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", + ioc->name, ioc->upload_fw, ioc->facts.Flags)); if ((int)ioc->chip_type <= (int)FC929) { ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; @@ -2542,17 +2555,13 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) } ioc_init.MaxBuses = MPT_MAX_BUS; -/* ioc_init.MsgFlags = 0; */ -/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - - ioc->facts.RequestFrameSize = ioc_init.ReplyFrameSize; if (sizeof(dma_addr_t) == sizeof(u64)) { /* Save the upper 32-bits of the request * (reply) and sense buffers. */ - ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); + ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32)); ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); } else { /* Force 32-bit addressing */ @@ -2591,14 +2600,14 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); } else { mdelay(1); } if (!cntdn) { printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", - ioc->name, (count+5)/HZ); + ioc->name, (int)((count+5)/HZ)); return -9; } @@ -2644,7 +2653,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) /* port_enable.MsgFlags = 0; */ /* port_enable.MsgContext = 0; */ - dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", ioc->name, portnum, &port_enable)); /* RAID FW may take a long time to enable @@ -2668,20 +2677,22 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) } /* - * Inputs: size - total FW bytes - * Outputs: frags - number of fragments needed - * Return NULL if failed. + * ioc: Pointer to MPT_ADAPTER structure + * size - total FW bytes */ void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) { - /* cached_fw - */ - - if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) - ioc->alloc_total += size; + if (ioc->cached_fw) + return; /* use already allocated memory */ + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ + ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; + } else { + if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) + ioc->alloc_total += size; + } } - /* * If alt_img is NULL, delete from ioc structure. * Else, delete a secondary image in same format. @@ -2692,6 +2703,8 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) int sz; sz = ioc->facts.FWImageSize; + dinitprintk((KERN_WARNING MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); ioc->cached_fw = NULL; @@ -2725,30 +2738,24 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) int sgeoffset; u32 flagsLength; int ii, sz, reply_sz; - int cmdStatus, freeMem = 0; + int cmdStatus; - /* If the image size is 0 or if the pointer is - * not NULL (error), we are done. + /* If the image size is 0, we are done. */ - if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw) + if ((sz = ioc->facts.FWImageSize) == 0) return 0; - if ( sz & 0x01 ) - sz += 1; - if ( sz & 0x02 ) - sz += 2; - mpt_alloc_fw_memory(ioc, sz); + dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + if (ioc->cached_fw == NULL) { /* Major Failure. */ return -ENOMEM; } - dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); - prequest = (FWUpload_t *)&request; preply = (FWUploadReply_t *)&reply; @@ -2797,23 +2804,11 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", ioc->name, cmdStatus)); - /* Check to see if we have a copy of this image in - * host memory already. - */ - if (cmdStatus == 0) { - ioc->upload_fw = 0; - if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) - freeMem = 1; - } - - /* We already have a copy of this image or - * we had some type of an error - either the handshake - * failed (i != 0) or the command did not complete successfully. - */ - if (cmdStatus || freeMem) { + + if (cmdStatus) { - ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n", - ioc->name, cmdStatus ? "incomplete" : "duplicate")); + ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n", + ioc->name)); mpt_free_fw_memory(ioc); } @@ -2841,28 +2836,26 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) MpiExtImageHeader_t *pExtImage; u32 fwSize; u32 diag0val; -#ifdef MPT_DEBUG - u32 diag1val = 0; -#endif - int count = 0; + int count; u32 *ptrFw; u32 diagRwData; u32 nextImage; u32 load_addr; - u32 ioc_state; + u32 ioc_state=0; ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x, ioc FW Ptr %p\n", ioc->name, ioc->facts.FWImageSize, ioc->cached_fw)); - /* Get dma_addr and data transfer size. - */ if ( ioc->facts.FWImageSize == 0 ) return -1; - /* Get the DMA from ioc or ioc->alt_ioc */ if (ioc->cached_fw == NULL) return -2; + /* prevent a second downloadboot and memory free with alt_ioc */ + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) + ioc->alt_ioc->cached_fw = NULL; + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); @@ -2870,18 +2863,17 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - diag0val |= (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); - /* wait 100 msec */ + /* wait 1 msec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); + schedule_timeout(1 * HZ / 1000); } else { - mdelay (100); + mdelay (1); } + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); for (count = 0; count < 30; count ++) { @@ -2894,7 +2886,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -2914,8 +2906,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); /* Set the DiagRwEn and Disable ARM bits */ - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, (diag0val | MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); pFwHeader = (MpiFwHeader_t *) ioc->cached_fw; fwSize = (pFwHeader->ImageSize + 3)/4; @@ -2961,15 +2952,6 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); - /* clear the PREVENT_IOC_BOOT bit */ - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT\n", - ioc->name, diag0val)); - diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", - ioc->name, diag0val)); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - /* Clear the internal flash bad bit - autoincrementing register, * so must do two writes. */ @@ -2980,28 +2962,13 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off DISABLE_ARM, RW_ENABLE, RESET_HISTORY\n", + ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT, DISABLE_ARM\n", ioc->name, diag0val)); - diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_RESET_HISTORY); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", ioc->name, diag0val)); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - /* wait 100 msec */ - if (sleepFlag == CAN_SLEEP) { - ddlprintk((MYIOC_s_INFO_FMT "CAN_SLEEP 100 msec before reset the sequencer\n", ioc->name)); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); - } else { - ddlprintk((MYIOC_s_INFO_FMT "mdelay 100 msec before reset the sequencer\n", ioc->name)); - mdelay (100); - } - - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - if ( diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM) ) { - ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed, diag0val=%x FLASH_BAD_SIG | DISABLE_ARM on\n ", - ioc->name, diag0val)); - } /* Write 0xFF to reset the sequencer */ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); @@ -3009,26 +2976,18 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) { ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n", ioc->name, count, ioc_state)); -/* if ((r = GetIocFacts(ioc, sleepFlag, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { - if ((r = GetIocFacts(ioc, sleepFlag, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { - ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed\n", - ioc->name)); - return -EFAULT; - } - } */ - /* wait 2 sec */ -/* if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(5000 * HZ / 1000); - } else { - mdelay (5000); - } */ - + if ((SendIocInit(ioc, sleepFlag)) != 0) { + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n", + ioc->name)); + return -EFAULT; + } + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n", + ioc->name)); return 0; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(10 * HZ / 1000); } else { mdelay (10); } @@ -3068,8 +3027,8 @@ static int KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) { int hard_reset_done = 0; - u32 ioc_state; - int cntdn, cnt = 0; + u32 ioc_state=0; + int cnt,cntdn; dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); if ((int)ioc->chip_type > (int)FC929) { @@ -3080,7 +3039,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -3090,26 +3049,27 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) if (hard_reset_done < 0) return hard_reset_done; - dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", + dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", ioc->name)); - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 20; /* 20 seconds */ + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ for (cnt=0; cntname, cnt)); + ioc_state = mpt_GetIocState(ioc, 1); + if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { + dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n", + ioc->name, cnt)); return hard_reset_done; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(10 * HZ / 1000); } else { mdelay (10); } } - printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n", - ioc->name); + printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", + ioc->name, ioc_state); return -1; } @@ -3199,12 +3159,6 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); #endif - /* Write the PreventIocBoot bit */ - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { - diag0val |= MPI_DIAG_PREVENT_IOC_BOOT; - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - } - /* * Disable the ARM (Bug fix) * @@ -3246,20 +3200,13 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* FIXME? Examine results here? */ } - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { + if (ioc->cached_fw) { /* If the DownloadBoot operation fails, the * IOC will be left unusable. This is a fatal error * case. _diag_reset will return < 0 */ for (count = 0; count < 30; count ++) { diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT - "DbG2b: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { break; } @@ -3267,7 +3214,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -3295,7 +3242,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout(1000 * HZ / 1000); } else { mdelay (1000); } @@ -3419,13 +3366,13 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) count *= 10; printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n", - ioc->name, (count+5)/HZ); + ioc->name, (int)((count+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); } else { mdelay (1); /* 1 msec delay */ } @@ -3443,35 +3390,45 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * PrimeIocFifos - Initialize IOC request and reply FIFOs. - * @ioc: Pointer to MPT_ADAPTER structure - * - * This routine allocates memory for the MPT reply and request frame - * pools (if necessary), and primes the IOC reply FIFO with - * reply frames. - * - * Returns 0 for success, non-zero for failure. + * initChainBuffers - Allocate memory for and initialize + * chain buffers, chain buffer control arrays and spinlock. + * @hd: Pointer to MPT_SCSI_HOST structure + * @init: If set, initialize the spin lock. */ static int -PrimeIocFifos(MPT_ADAPTER *ioc) +initChainBuffers(MPT_ADAPTER *ioc) { - MPT_FRAME_HDR *mf; - unsigned long b; - unsigned long flags; - dma_addr_t aligned_mem_dma; - u8 *aligned_mem; - int i, sz; - int chain_buffer_sz, reply_buffer_sz, request_buffer_sz; - int scale, num_sge, num_chain; + u8 *mem; + int sz, ii, num_chain; + int scale, num_sge, numSGE; - /* request buffer size, rounding UP to nearest 4-kB boundary */ - request_buffer_sz = (ioc->req_sz * ioc->req_depth) + 128; - request_buffer_sz = ((request_buffer_sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + /* ReqToChain size must equal the req_depth + * index = req_idx + */ + if (ioc->ReqToChain == NULL) { + sz = ioc->req_depth * sizeof(int); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; + + ioc->ReqToChain = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; - /* reply buffer size */ - reply_buffer_sz = (ioc->reply_sz * ioc->reply_depth) + 128; + ioc->RequestNB = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + } + for (ii = 0; ii < ioc->req_depth; ii++) { + ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; + } - /* chain buffer size, copied from from mptscsih_initChainBuffers() + /* ChainToChain size must equal the total number + * of chain buffers to be allocated. + * index = chain_idx * * Calculate the number of chain buffers needed(plus 1) per I/O * then multiply the the maximum number of simultaneous cmds @@ -3479,79 +3436,134 @@ PrimeIocFifos(MPT_ADAPTER *ioc) * num_sge = num sge in request frame + last chain buffer * scale = num sge per chain buffer if no chain element */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); if (sizeof(dma_addr_t) == sizeof(u64)) num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); else - num_sge = 1 + scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + + if (sizeof(dma_addr_t) == sizeof(u64)) { + numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + } else { + numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + } + dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n", + ioc->name, num_sge, numSGE)); + + if ( numSGE > MPT_SCSI_SG_DEPTH ) + numSGE = MPT_SCSI_SG_DEPTH; num_chain = 1; - while (MPT_SCSI_SG_DEPTH - num_sge > 0) { + while (numSGE - num_sge > 0) { num_chain++; num_sge += (scale - 1); } num_chain++; - if ((int)ioc->chip_type > (int) FC929) + dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n", + ioc->name, numSGE, num_sge, num_chain)); + + if ((int) ioc->chip_type > (int) FC929) num_chain *= MPT_SCSI_CAN_QUEUE; else num_chain *= MPT_FC_CAN_QUEUE; - chain_buffer_sz = num_chain * ioc->req_sz; + ioc->num_chain = num_chain; - if(ioc->fifo_pool == NULL) { + sz = num_chain * sizeof(int); + if (ioc->ChainToChain == NULL) { + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; - ioc->fifo_pool_sz = request_buffer_sz + - reply_buffer_sz + chain_buffer_sz; + ioc->ChainToChain = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + } else { + mem = (u8 *) ioc->ChainToChain; + } + memset(mem, 0xFF, sz); + return num_chain; +} - ioc->fifo_pool = pci_alloc_consistent(ioc->pcidev, - ioc->fifo_pool_sz, &ioc->fifo_pool_dma); +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine allocates memory for the MPT reply and request frame + * pools (if necessary), and primes the IOC reply FIFO with + * reply frames. + * + * Returns 0 for success, non-zero for failure. + */ +static int +PrimeIocFifos(MPT_ADAPTER *ioc) +{ + MPT_FRAME_HDR *mf; + unsigned long flags; + dma_addr_t alloc_dma; + u8 *mem; + int i, reply_sz, sz, total_size, num_chain; + + /* Prime reply FIFO... */ - if( ioc->fifo_pool == NULL) + if (ioc->reply_frames == NULL) { + if ( (num_chain = initChainBuffers(ioc)) < 0) + return -1; + + total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", + ioc->name, ioc->reply_sz, ioc->reply_depth)); + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n", + ioc->name, reply_sz, reply_sz)); + + sz = (ioc->req_sz * ioc->req_depth); + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n", + ioc->name, ioc->req_sz, ioc->req_depth)); + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n", + ioc->name, sz, sz)); + total_size += sz; + + sz = num_chain * ioc->req_sz; /* chain buffer pool size */ + dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n", + ioc->name, ioc->req_sz, num_chain)); + dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n", + ioc->name, sz, sz, num_chain)); + + total_size += sz; + mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma); + if (mem == NULL) { + printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n", + ioc->name); goto out_fail; + } + + dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); + + memset(mem, 0, total_size); + ioc->alloc_total += total_size; + ioc->alloc = mem; + ioc->alloc_dma = alloc_dma; + ioc->alloc_sz = total_size; + ioc->reply_frames = (MPT_FRAME_HDR *) mem; + ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); + + alloc_dma += reply_sz; + mem += reply_sz; - ioc->alloc_total += ioc->fifo_pool_sz; - memset(ioc->fifo_pool, 0, ioc->fifo_pool_sz); - - /* reply fifo pointers */ - ioc->reply_alloc = ioc->fifo_pool; - ioc->reply_alloc_dma = ioc->fifo_pool_dma; - /* request fifo pointers */ - ioc->req_alloc = ioc->reply_alloc+reply_buffer_sz; - ioc->req_alloc_dma = ioc->reply_alloc_dma+reply_buffer_sz; - /* chain buffer pointers */ - ioc->chain_alloc = ioc->req_alloc+request_buffer_sz; - ioc->chain_alloc_dma = ioc->req_alloc_dma+request_buffer_sz; - ioc->chain_alloc_sz = chain_buffer_sz; - - /* Prime reply FIFO... */ - dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%p], sz=%d bytes\n", - ioc->name, ioc->reply_alloc, - (void *)(ulong)ioc->reply_alloc_dma, reply_buffer_sz)); - - b = (unsigned long) ioc->reply_alloc; - b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ - aligned_mem = (u8 *) b; - ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem; - ioc->reply_frames_dma = - (ioc->reply_alloc_dma + (aligned_mem - ioc->reply_alloc)); - - ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF); - /* Request FIFO - WE manage this! */ - dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%p], sz=%d bytes\n", - ioc->name, ioc->req_alloc, - (void *)(ulong)ioc->req_alloc_dma, request_buffer_sz)); - b = (unsigned long) ioc->req_alloc; - b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ - aligned_mem = (u8 *) b; - ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem; - ioc->req_frames_dma = - (ioc->req_alloc_dma + (aligned_mem - ioc->req_alloc)); + ioc->req_frames = (MPT_FRAME_HDR *) mem; + ioc->req_frames_dma = alloc_dma; + + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffers @ %p[%p]\n", + ioc->name, mem, (void *)(ulong)alloc_dma)); - ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF); + ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); #if defined(CONFIG_MTRR) && 0 /* @@ -3559,79 +3571,93 @@ PrimeIocFifos(MPT_ADAPTER *ioc) * (at least as much as we can; "size and base must be * multiples of 4 kiB" */ - ioc->mtrr_reg = mtrr_add(ioc->fifo_pool, - ioc->fifo_pool_sz, + ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma, + sz, MTRR_TYPE_WRCOMB, 1); dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n", - ioc->name, ioc->fifo_pool, ioc->fifo_pool_sz)); + ioc->name, ioc->req_frames_dma, sz)); #endif - } /* ioc->fifo_pool == NULL */ - - /* Post Reply frames to FIFO - */ - aligned_mem_dma = ioc->reply_frames_dma; - dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n", - ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma)); + for (i = 0; i < ioc->req_depth; i++) { + alloc_dma += ioc->req_sz; + mem += ioc->req_sz; + } - for (i = 0; i < ioc->reply_depth; i++) { - /* Write each address to the IOC! */ - CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); - aligned_mem_dma += ioc->reply_sz; - } + ioc->ChainBuffer = mem; + ioc->ChainBufferDMA = alloc_dma; + dinitprintk((KERN_INFO MYNAM " :%s.ChainBuffers @ %p(%p)\n", + ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); - /* Initialize Request frames linked list - */ - aligned_mem_dma = ioc->req_frames_dma; - aligned_mem = (u8 *) ioc->req_frames; - dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%p]\n", - ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma)); + /* Initialize the free chain Q. + */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); - for (i = 0; i < ioc->req_depth; i++) { - mf = (MPT_FRAME_HDR *) aligned_mem; + Q_INIT(&ioc->FreeChainQ, MPT_FRAME_HDR); - /* Queue REQUESTs *internally*! */ - Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); - aligned_mem += ioc->req_sz; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + /* Post the chain buffers to the FreeChainQ. + */ + mem = (u8 *)ioc->ChainBuffer; + for (i=0; i < num_chain; i++) { + mf = (MPT_FRAME_HDR *) mem; + Q_ADD_TAIL(&ioc->FreeChainQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + mem += ioc->req_sz; + } + /* Initialize Request frames linked list + */ + alloc_dma = ioc->req_frames_dma; + mem = (u8 *) ioc->req_frames; + + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); + for (i = 0; i < ioc->req_depth; i++) { + mf = (MPT_FRAME_HDR *) mem; + + /* Queue REQUESTs *internally*! */ + Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + mem += ioc->req_sz; + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); - if (ioc->sense_buf_pool == NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); ioc->sense_buf_pool = - pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); - if (ioc->sense_buf_pool == NULL) + pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); + if (ioc->sense_buf_pool == NULL) { + printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n", + ioc->name); goto out_fail; + } ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); ioc->alloc_total += sz; + dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n", + ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); + + } + + /* Post Reply frames to FIFO + */ + alloc_dma = ioc->alloc_dma; + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n", + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); + + for (i = 0; i < ioc->reply_depth; i++) { + /* Write each address to the IOC! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma); + alloc_dma += ioc->reply_sz; } return 0; out_fail: - if (ioc->fifo_pool != NULL) { + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; pci_free_consistent(ioc->pcidev, - ioc->fifo_pool_sz, - ioc->fifo_pool, ioc->fifo_pool_dma); + sz, + ioc->alloc, ioc->alloc_dma); ioc->reply_frames = NULL; - ioc->reply_alloc = NULL; ioc->req_frames = NULL; - ioc->req_alloc = NULL; - ioc->chain_alloc = NULL; - ioc->fifo_pool = NULL; - ioc->alloc_total -= ioc->fifo_pool_sz; -#if defined(CONFIG_MTRR) && 0 - if (ioc->mtrr_reg > 0) { - mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n", - ioc->name)); - } -#endif + ioc->alloc_total -= sz; } if (ioc->sense_buf_pool != NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); @@ -3693,8 +3719,8 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; - dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n", - ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", + ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* Read doorbell and check for active bit */ if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) @@ -3728,7 +3754,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, failcnt++; } - dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); + dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); DBG_DUMP_REQUEST_FRAME_HDR(req) dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n", @@ -3783,7 +3809,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) break; set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); count++; } } else { @@ -3833,7 +3859,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) if (intstat & MPI_HIS_DOORBELL_INTERRUPT) break; set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout(1 * HZ / 1000); count++; } } else { @@ -3935,7 +3961,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } #endif - dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); + dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); DBG_DUMP_REPLY_FRAME(mptReply) dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", @@ -4282,9 +4308,11 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); - if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; - + dinitprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n", + ioc->name, pPP0->Capabilities)); + } ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; if (data) { @@ -4907,8 +4935,8 @@ int mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { ToolboxIstwiReadWriteRequest_t *pReq; - struct pci_dev *pdev; MPT_FRAME_HDR *mf; + struct pci_dev *pdev; unsigned long flags; int rc; u32 flagsLength; @@ -5226,12 +5254,6 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo if (drvname) len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); - /* - * Handle isense special case, because it - * doesn't do a formal mpt_register call. - */ - if (isense_idx == ii) - len += sprintf(buf+len, " Fusion MPT isense driver\n"); } } @@ -5286,7 +5308,7 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", - (void *)ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma); + (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); /* * Rounding UP to nearest 4-kB boundary here... */ @@ -5298,8 +5320,8 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo 4*ioc->facts.RequestFrameSize, ioc->facts.GlobalCredits); - len += sprintf(buf+len, " ReplyFrames @ 0x%p (Dma @ 0x%p)\n", - (void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma); + len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n", + (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); sz = (ioc->reply_sz * ioc->reply_depth) + 128; len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); @@ -5592,7 +5614,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply } evStr = EventDescriptionStr(event, evData0); - dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", + devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", ioc->name, evStr, event)); @@ -5664,7 +5686,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply */ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { if (MptEvHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", + devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", ioc->name, ii)); r += (*(MptEvHandlers[ii]))(ioc, pEventReply); handlers++; @@ -5677,8 +5699,8 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply */ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { if ((ii = SendEventAck(ioc, pEventReply)) != 0) { - printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n", - ioc->name, ii); + devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n", + ioc->name, ii)); } } @@ -5702,9 +5724,8 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" }; u8 subcl = (log_info >> 24) & 0x7; -// u32 SubCl = log_info & 0x27000000; - printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", + printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n", ioc->name, log_info, subcl_str[subcl]); } @@ -5907,50 +5928,6 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI - * OpCode strings from the (optional) isense module. - * @ascqTable: Pointer to ASCQ_Table_t structure - * @ascqtbl_sz: Number of entries in ASCQ_Table - * @opsTable: Pointer to array of SCSI OpCode strings (char pointers) - * - * Specialized driver registration routine for the isense driver. - */ -int -mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable) -{ - int r = 0; - - if (ascqTable && ascqtbl_sz && opsTable) { - mpt_v_ASCQ_TablePtr = ascqTable; - mpt_ASCQ_TableSz = ascqtbl_sz; - mpt_ScsiOpcodesPtr = opsTable; - printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n"); - isense_idx = last_drv_idx; - r = 1; - } - return r; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI - * OpCode strings from the isense driver. - * - * Specialized driver deregistration routine for the isense driver. - */ -void -mpt_deregister_ascqops_strings(void) -{ - mpt_v_ASCQ_TablePtr = NULL; - mpt_ASCQ_TableSz = 0; - mpt_ScsiOpcodesPtr = NULL; - printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); - isense_idx = -1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - EXPORT_SYMBOL(ioc_list); EXPORT_SYMBOL(mpt_proc_root_dir); EXPORT_SYMBOL(DmpService); @@ -5982,13 +5959,6 @@ EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); -EXPORT_SYMBOL(mpt_register_ascqops_strings); -EXPORT_SYMBOL(mpt_deregister_ascqops_strings); -EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr); -EXPORT_SYMBOL(mpt_ASCQ_TableSz); -EXPORT_SYMBOL(mpt_ScsiOpcodesPtr); - - static struct pci_driver mptbase_driver = { .name = "mptbase", .id_table = mptbase_pci_table, diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 8a84b72a3..4b9b4934d 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -60,8 +60,6 @@ #include #include -#include "scsi3.h" /* SCSI defines */ - #include "lsi/mpi_type.h" #include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ #include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */ @@ -85,8 +83,8 @@ #define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.01.09" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.09" +#define MPT_LINUX_VERSION_COMMON "3.01.16" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.16" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -320,17 +318,6 @@ typedef struct _Q_TRACKER { struct _Q_ITEM *tail; } Q_TRACKER; -typedef struct _MPT_DONE_Q { - struct _MPT_DONE_Q *forw; - struct _MPT_DONE_Q *back; - void *argp; -} MPT_DONE_Q; - -typedef struct _DONE_Q_TRACKER { - MPT_DONE_Q *head; - MPT_DONE_Q *tail; -} DONE_Q_TRACKER; - /* * Chip-specific stuff... FC929 delineates break between * FC and Parallel SCSI parts. Do NOT re-order. @@ -403,6 +390,11 @@ typedef struct _ScsiCmndTracker { void *tail; } ScsiCmndTracker; +/* VirtDevice negoFlags field */ +#define MPT_TARGET_NO_NEGO_WIDE 0x01 +#define MPT_TARGET_NO_NEGO_SYNC 0x02 +#define MPT_TARGET_NO_NEGO_QAS 0x04 +#define MPT_TAPE_NEGO_IDP 0x08 /* * VirtDevice - FC LUN device or SCSI target device @@ -420,8 +412,8 @@ typedef struct _VirtDevice { u8 bus_id; u8 minSyncFactor; /* 0xFF is async */ u8 maxOffset; /* 0 if async */ - u8 maxWidth; /* 0 if narrow, 1 if wide*/ - u8 negoFlags; /* bit field, 0 if WDTR/SDTR/QAS allowed */ + u8 maxWidth; /* 0 if narrow, 1 if wide */ + u8 negoFlags; /* bit field, see above */ u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ u8 cflags; /* controller flags */ @@ -460,10 +452,6 @@ typedef struct _VirtDevice { #define MPT_TARGET_FLAGS_VALID_56 0x10 #define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20 -#define MPT_TARGET_NO_NEGO_WIDE 0x01 -#define MPT_TARGET_NO_NEGO_SYNC 0x02 -#define MPT_TARGET_NO_NEGO_QAS 0x04 - typedef struct _VirtDevTracker { struct _VirtDevice *head; struct _VirtDevice *tail; @@ -523,6 +511,7 @@ typedef struct _MPT_IOCTL { u8 target; /* target for reset */ void *tmPtr; struct timer_list TMtimer; /* timer function for this adapter */ + struct semaphore sem_ioc; } MPT_IOCTL; /* @@ -592,33 +581,38 @@ typedef struct _MPT_ADAPTER int pci_irq; /* This irq */ char name[MPT_NAME_LENGTH]; /* "iocN" */ char *prod_name; /* "LSIFC9x9" */ - volatile SYSIF_REGS *chip; /* == c8817000 (mmap) */ - volatile SYSIF_REGS *pio_chip; /* Programmed IO (downloadboot) */ + SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */ + SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ u32 mem_phys; /* == f4020000 (mmap) */ u32 pio_mem_phys; /* Programmed IO (downloadboot) */ int mem_size; /* mmap memory size */ int alloc_total; u32 last_state; int active; - u8 *fifo_pool; /* dma pool for fifo's */ - dma_addr_t fifo_pool_dma; - int fifo_pool_sz; /* allocated size */ - u8 *chain_alloc; /* chain buffer alloc ptr */ - dma_addr_t chain_alloc_dma; - int chain_alloc_sz; - u8 *reply_alloc; /* Reply frames alloc ptr */ - dma_addr_t reply_alloc_dma; + u8 *alloc; /* frames alloc ptr */ + dma_addr_t alloc_dma; + u32 alloc_sz; MPT_FRAME_HDR *reply_frames; /* Reply msg frames - rounded up! */ - dma_addr_t reply_frames_dma; u32 reply_frames_low_dma; int reply_depth; /* Num Allocated reply frames */ int reply_sz; /* Reply frame size */ + int num_chain; /* Number of chain buffers */ + /* Pool of buffers for chaining. ReqToChain + * and ChainToChain track index of chain buffers. + * ChainBuffer (DMA) virt/phys addresses. + * FreeChainQ (lock) locking mechanisms. + */ + int *ReqToChain; + int *RequestNB; + int *ChainToChain; + u8 *ChainBuffer; + dma_addr_t ChainBufferDMA; + MPT_Q_TRACKER FreeChainQ; + spinlock_t FreeChainQlock; CHIP_TYPE chip_type; /* We (host driver) get to manage our own RequestQueue! */ - u8 *req_alloc; /* Request frames alloc ptr */ - dma_addr_t req_alloc_dma; - MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ dma_addr_t req_frames_dma; + MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ u32 req_frames_low_dma; int req_depth; /* Number of request frames */ int req_sz; /* Request frame size (bytes) */ @@ -661,6 +655,7 @@ typedef struct _MPT_ADAPTER #else u32 mfcnt; #endif + u32 NB_for_64_byte_frame; u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)]; u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)]; IOCFactsReply_t facts; @@ -674,8 +669,10 @@ typedef struct _MPT_ADAPTER u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ u8 reload_fw; /* Force a FW Reload on next reset */ - u8 pad1[5]; + u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ + u8 pad1[4]; struct list_head list; + struct net_device *netdev; } MPT_ADAPTER; @@ -757,10 +754,10 @@ typedef struct _mpt_sge { #define dexitprintk(x) #endif -#ifdef MPT_DEBUG_RESET -#define drsprintk(x) printk x +#if defined MPT_DEBUG_FAIL || defined (MPT_DEBUG_SG) +#define dfailprintk(x) printk x #else -#define drsprintk(x) +#define dfailprintk(x) #endif #ifdef MPT_DEBUG_HANDSHAKE @@ -769,11 +766,34 @@ typedef struct _mpt_sge { #define dhsprintk(x) #endif +#ifdef MPT_DEBUG_EVENTS +#define devtprintk(x) printk x +#else +#define devtprintk(x) +#endif + +#ifdef MPT_DEBUG_RESET +#define drsprintk(x) printk x +#else +#define drsprintk(x) +#endif + //#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) #if defined(MPT_DEBUG_MSG_FRAME) #define dmfprintk(x) printk x +#define DBG_DUMP_REQUEST_FRAME(mfp) \ + { int i, n = 24; \ + u32 *m = (u32 *)(mfp); \ + for (i=0; i> 16; \ + printk("TM_REPLY MessageLength=%d:\n", n); \ + for (i=0; iid])) + if (down_trylock(&ioc->ioctl->sem_ioc)) rc = -EAGAIN; } else { - if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) + if (down_interruptible(&ioc->ioctl->sem_ioc)) rc = -ERESTARTSYS; } dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); @@ -445,7 +447,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl) mptctl_free_tm_flags(ioctl->ioc); del_timer(&ioctl->TMtimer); - mpt_free_msg_frame(mptctl_id, ioctl->ioc, mf); + mpt_free_msg_frame(ioctl->ioc, mf); ioctl->tmPtr = NULL; } @@ -482,7 +484,7 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc) spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmState = TM_STATE_ERROR; + hd->tmState = TM_STATE_NONE; hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); @@ -520,7 +522,7 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)){ ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE; del_timer(&ioctl->TMtimer); - mpt_free_msg_frame(mptctl_id, ioc, ioctl->tmPtr); + mpt_free_msg_frame(ioc, ioctl->tmPtr); } } else { @@ -630,8 +632,7 @@ mptctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned else ret = -EINVAL; - - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } @@ -1807,7 +1808,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) struct buflist bufOut; /* data Out buffer */ dma_addr_t dma_addr_in; dma_addr_t dma_addr_out; - int dir; /* PCI data direction */ int sgSize = 0; /* Num SG elements */ int iocnum, flagsLength; int sz, rc = 0; @@ -2117,9 +2117,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Set up the dataOut memory allocation */ if (karg.dataOutSize > 0) { - dir = PCI_DMA_TODEVICE; if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size() ) << MPI_SGE_FLAGS_SHIFT; @@ -2158,7 +2158,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) } if (karg.dataInSize > 0) { - dir = PCI_DMA_FROMDEVICE; flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= karg.dataInSize; @@ -2196,6 +2195,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) add_timer(&ioc->ioctl->timer); if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { + DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); rc = mpt_send_handshake_request(mptctl_id, ioc, sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc == 0) { @@ -2206,7 +2206,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) del_timer(&ioc->ioctl->timer); ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE; ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED; - mpt_free_msg_frame(mptctl_id, ioc, mf); + mpt_free_msg_frame(ioc, mf); } } else { mpt_put_msg_frame(mptctl_id, ioc, mf); @@ -2324,7 +2324,7 @@ done_free_mem: * otherwise, failure occured after mf acquired. */ if (mf) - mpt_free_msg_frame(mptctl_id, ioc, mf); + mpt_free_msg_frame(ioc, mf); return rc; } @@ -2738,7 +2738,7 @@ compat_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } @@ -2792,55 +2792,91 @@ compat_mpt_command(unsigned int fd, unsigned int cmd, */ ret = mptctl_do_mpt_command (karg, &uarg->MF); - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } #endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int __init mptctl_init(void) +/* + * mptctl_probe - Installs ioctl devices per bus. + * @pdev: Pointer to pci_dev structure + * + * Returns 0 for success, non-zero for failure. + * + */ + +static int +mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; - int i; - int where = 1; int sz; u8 *mem; - MPT_ADAPTER *ioc = NULL; - int iocnum; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - show_mptmod_ver(my_NAME, my_VERSION); + /* + * Allocate and inite a MPT_IOCTL structure + */ + sz = sizeof (MPT_IOCTL); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) { + err = -ENOMEM; + goto out_fail; + } - for (i=0; iioctl = (MPT_IOCTL *) mem; + ioc->ioctl->ioc = ioc; + init_timer (&ioc->ioctl->timer); + ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->timer.function = mptctl_timer_expired; + init_timer (&ioc->ioctl->TMtimer); + ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->TMtimer.function = mptctl_timer_expired; + sema_init(&ioc->ioctl->sem_ioc, 1); + return 0; - ioc = NULL; - if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) || - (ioc == NULL)) { - continue; - } - else { - /* This adapter instance is found. - * Allocate and inite a MPT_IOCTL structure - */ - sz = sizeof (MPT_IOCTL); - mem = kmalloc(sz, GFP_KERNEL); - if (mem == NULL) { - err = -ENOMEM; - goto out_fail; - } +out_fail: - memset(mem, 0, sz); - ioc->ioctl = (MPT_IOCTL *) mem; - ioc->ioctl->ioc = ioc; - init_timer (&ioc->ioctl->timer); - ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; - ioc->ioctl->timer.function = mptctl_timer_expired; - init_timer (&ioc->ioctl->TMtimer); - ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl; - ioc->ioctl->TMtimer.function = mptctl_timer_expired; - } + mptctl_remove(pdev); + return err; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptctl_remove - Removed ioctl devices + * @pdev: Pointer to pci_dev structure + * + * + */ +static void +mptctl_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + kfree ( ioc->ioctl ); +} + +static struct mpt_pci_driver mptctl_driver = { + .probe = mptctl_probe, + .remove = mptctl_remove, +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int __init mptctl_init(void) +{ + int err; + int where = 1; + + show_mptmod_ver(my_NAME, my_VERSION); + + if(mpt_device_driver_register(&mptctl_driver, + MPTCTL_DRIVER) != 0 ) { + dprintk((KERN_INFO MYNAM + ": failed to register dd callbacks\n")); } #ifdef CONFIG_COMPAT @@ -2922,29 +2958,14 @@ out_fail: unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif - for (i=0; iioctl) { - kfree ( ioc->ioctl ); - ioc->ioctl = NULL; - } - } - } + mpt_device_driver_deregister(MPTCTL_DRIVER); + return err; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -void mptctl_exit(void) +static void mptctl_exit(void) { - int i; - MPT_ADAPTER *ioc; - int iocnum; - misc_deregister(&mptctl_miscdev); printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n", mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); @@ -2957,6 +2978,8 @@ void mptctl_exit(void) mpt_deregister(mptctl_id); printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + mpt_device_driver_deregister(MPTCTL_DRIVER); + #ifdef CONFIG_COMPAT unregister_ioctl32_conversion(MPTIOCINFO); unregister_ioctl32_conversion(MPTIOCINFO1); @@ -2973,20 +2996,6 @@ void mptctl_exit(void) unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif - /* Free allocated memory */ - for (i=0; iioctl) { - kfree ( ioc->ioctl ); - ioc->ioctl = NULL; - } - } - } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 80c9b97eb..5327c9215 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -177,11 +177,9 @@ static int LanCtx = -1; static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; -static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1]; - #ifdef QLOGIC_NAA_WORKAROUND static struct NAA_Hosed *mpt_bad_naa = NULL; -rwlock_t bad_naa_lock; +rwlock_t bad_naa_lock = RW_LOCK_UNLOCKED; #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -203,7 +201,7 @@ extern int mpt_lan_index; static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) { - struct net_device *dev = mpt_landev[ioc->id]; + struct net_device *dev = ioc->netdev; int FreeReqFrame = 0; dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n", @@ -336,7 +334,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) static int mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - struct net_device *dev = mpt_landev[ioc->id]; + struct net_device *dev = ioc->netdev; struct mpt_lan_priv *priv = netdev_priv(dev); dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", @@ -1334,7 +1332,7 @@ mpt_lan_post_receive_buckets(void *dev_id) if (pSimple == NULL) { /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", /**/ __FUNCTION__); - mpt_free_msg_frame(LanCtx, mpt_dev, mf); + mpt_free_msg_frame(mpt_dev, mf); goto out; } @@ -1451,20 +1449,74 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) return dev; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int __init mpt_lan_init (void) +static int +mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct net_device *dev; - MPT_ADAPTER *p; - int i, j; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct net_device *dev; + int i; + + for (i = 0; i < ioc->facts.NumberOfPorts; i++) { + printk(KERN_INFO MYNAM ": %s: PortNum=%x, " + "ProtocolFlags=%02Xh (%c%c%c%c)\n", + ioc->name, ioc->pfacts[i].PortNumber, + ioc->pfacts[i].ProtocolFlags, + MPT_PROTOCOL_FLAGS_c_c_c_c( + ioc->pfacts[i].ProtocolFlags)); + + if (!(ioc->pfacts[i].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_LAN)) { + printk(KERN_INFO MYNAM ": %s: Hmmm... LAN protocol " + "seems to be disabled on this adapter port!\n", + ioc->name); + continue; + } - show_mptmod_ver(LANAME, LANVER); + dev = mpt_register_lan_device(ioc, i); + if (!dev) { + printk(KERN_ERR MYNAM ": %s: Unable to register " + "port%d as a LAN device\n", ioc->name, + ioc->pfacts[i].PortNumber); + continue; + } + + printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " + "registered as '%s'\n", ioc->name, dev->name); + printk(KERN_INFO MYNAM ": %s/%s: " + "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + ioc->netdev = dev; -#ifdef QLOGIC_NAA_WORKAROUND - /* Init the global r/w lock for the bad_naa list. We want to do this - before any boards are initialized and may be used. */ - rwlock_init(&bad_naa_lock); -#endif + return 0; + } + + return -ENODEV; +} + +static void +mptlan_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct net_device *dev = ioc->netdev; + + if(dev != NULL) { + unregister_netdev(dev); + free_netdev(dev); + } +} + +static struct mpt_pci_driver mptlan_driver = { + .probe = mptlan_probe, + .remove = mptlan_remove, +}; + +static int __init mpt_lan_init (void) +{ + show_mptmod_ver(LANAME, LANVER); if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) { printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); @@ -1476,88 +1528,32 @@ static int __init mpt_lan_init (void) dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); - if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) { - dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - } else { + if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) { printk(KERN_ERR MYNAM ": Eieee! unable to register a reset " "handler with mptbase! The world is at an end! " "Everything is fading to black! Goodbye.\n"); return -EBUSY; } - for (j = 0; j < MPT_MAX_ADAPTERS; j++) { - mpt_landev[j] = NULL; - } - - list_for_each_entry(p, &ioc_list, list) { - for (i = 0; i < p->facts.NumberOfPorts; i++) { - printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n", - p->name, - p->pfacts[i].PortNumber, - p->pfacts[i].ProtocolFlags, - MPT_PROTOCOL_FLAGS_c_c_c_c(p->pfacts[i].ProtocolFlags)); - - if (!(p->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { - printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", - p->name); - continue; - } - - dev = mpt_register_lan_device (p, i); - if (!dev) { - printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", - p->name, - p->pfacts[i].PortNumber); - } - printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", - p->name, dev->name); - printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); -// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n", -// IOC_AND_NETDEV_NAMES_s_s(dev), -// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); - j = p->id; - mpt_landev[j] = dev; - dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", - dev, j, mpt_landev[j])); - - } - } - + dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); + + if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER)) + dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n")); return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void __exit mpt_lan_exit(void) { - int i; - + mpt_device_driver_deregister(MPTLAN_DRIVER); mpt_reset_deregister(LanCtx); - for (i = 0; mpt_landev[i] != NULL; i++) { - struct net_device *dev = mpt_landev[i]; - - printk (KERN_INFO ": %s/%s: Fusion MPT LAN device unregistered\n", - IOC_AND_NETDEV_NAMES_s_s(dev)); - unregister_netdev(dev); - free_netdev(dev); - mpt_landev[i] = NULL; - } - if (LanCtx >= 0) { mpt_deregister(LanCtx); LanCtx = -1; mpt_lan_index = 0; } - - /* deregister any send/receive handler structs. I2Oism? */ } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - module_init(mpt_lan_init); module_exit(mpt_lan_exit); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 8c82254b4..38c8fb77d 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -86,7 +86,6 @@ #include "mptbase.h" #include "mptscsih.h" -#include "isense.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define my_NAME "Fusion MPT SCSI Host driver" @@ -100,6 +99,7 @@ MODULE_LICENSE("GPL"); /* Set string for command line args from insmod */ #ifdef MODULE char *mptscsih = NULL; +MODULE_PARM(mptscsih, "s"); #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -114,6 +114,7 @@ typedef struct _BIG_SENSE_BUF { #define MPT_SCANDV_SOME_ERROR (0x00000004) #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) #define MPT_SCANDV_ISSUE_SENSE (0x00000010) +#define MPT_SCANDV_FALLBACK (0x00000020) #define MPT_SCANDV_MAX_RETRIES (10) @@ -161,15 +162,12 @@ static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR * static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); -static int mptscsih_AddSGE(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt, +static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx); -static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx); -static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init); +static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); static void copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc); -static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx); -static void post_pendingQ_commands(MPT_SCSI_HOST *hd); static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); @@ -178,7 +176,7 @@ static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); static void mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); -void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); +static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id); @@ -246,6 +244,7 @@ static struct work_struct mptscsih_dvTask; static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq); static int scandv_wait_done = 1; + /* Driver default setup */ static struct mptscsih_driver_setup @@ -323,44 +322,47 @@ mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mptscsih_getFreeChainBuffes - Function to get a free chain + * mptscsih_getFreeChainBuffer - Function to get a free chain * from the MPT_SCSI_HOST FreeChainQ. - * @hd: Pointer to the MPT_SCSI_HOST instance + * @ioc: Pointer to MPT_ADAPTER structure * @req_idx: Index of the SCSI IO request frame. (output) * * return SUCCESS or FAILED */ static inline int -mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) +mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) { MPT_FRAME_HDR *chainBuf; unsigned long flags; int rc; int chain_idx; - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (!Q_IS_EMPTY(&hd->FreeChainQ)) { + dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n", + ioc->name)); + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (!Q_IS_EMPTY(&ioc->FreeChainQ)) { int offset; - chainBuf = hd->FreeChainQ.head; + chainBuf = ioc->FreeChainQ.head; Q_DEL_ITEM(&chainBuf->u.frame.linkage); - offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; - chain_idx = offset / hd->ioc->req_sz; + offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; + chain_idx = offset / ioc->req_sz; rc = SUCCESS; + dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", + ioc->name, *retIndex, chainBuf)); } else { rc = FAILED; chain_idx = MPT_HOST_NO_CHAIN; + dfailprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", + ioc->name)); } - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); *retIndex = chain_idx; - dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", - hd->ioc->name, *retIndex, chainBuf)); - return rc; } /* mptscsih_getFreeChainBuffer() */ @@ -368,14 +370,14 @@ mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) /* * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the * SCSIIORequest_t Message Frame. - * @hd: Pointer to MPT_SCSI_HOST structure + * @ioc: Pointer to MPT_ADAPTER structure * @SCpnt: Pointer to scsi_cmnd structure * @pReq: Pointer to SCSIIORequest_t structure * * Returns ... */ static int -mptscsih_AddSGE(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt, +mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx) { char *psge; @@ -391,6 +393,7 @@ mptscsih_AddSGE(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt, int newIndex; int ii; dma_addr_t v2; + u32 RequestNB; sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { @@ -400,25 +403,25 @@ mptscsih_AddSGE(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt, } psge = (char *) &pReq->SGL; - frm_sz = hd->ioc->req_sz; + frm_sz = ioc->req_sz; /* Map the data portion, if any. * sges_left = 0 if no data transfer. */ if ( (sges_left = SCpnt->use_sg) ) { - sges_left = pci_map_sg(hd->ioc->pcidev, + sges_left = pci_map_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction); if (sges_left == 0) return FAILED; } else if (SCpnt->request_bufflen) { - SCpnt->SCp.dma_handle = pci_map_single(hd->ioc->pcidev, + SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->sc_data_direction); dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", - hd->ioc->name, SCpnt, SCpnt->request_bufflen)); + ioc->name, SCpnt, SCpnt->request_bufflen)); mptscsih_add_sge((char *) &pReq->SGL, 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen, SCpnt->SCp.dma_handle); @@ -493,12 +496,16 @@ nextSGEset: * Update the chain element * Offset and Length fields. */ - mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off); + mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); } else { /* The current buffer is the original MF * and there is no Chain buffer. */ pReq->ChainOffset = 0; + RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; + dsgprintk((MYIOC_s_ERR_FMT + "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); + ioc->RequestNB[req_idx] = RequestNB; } } else { /* At least one chain buffer is needed. @@ -513,7 +520,7 @@ nextSGEset: */ dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", - hd->ioc->name, sg_done)); + ioc->name, sg_done)); /* Set LAST_ELEMENT flag for last non-chain element * in the buffer. Since psge points at the NEXT @@ -537,13 +544,16 @@ nextSGEset: */ u8 nextChain = (u8) (sgeOffset >> 2); sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off); + mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); } else { /* The original MF buffer requires a chain buffer - * set the offset. * Last element in this MF is a chain element. */ pReq->ChainOffset = (u8) (sgeOffset >> 2); + RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; + dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); + ioc->RequestNB[req_idx] = RequestNB; } sges_left -= sg_done; @@ -552,19 +562,22 @@ nextSGEset: /* NOTE: psge points to the beginning of the chain element * in current buffer. Get a chain buffer. */ - if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) + dsgprintk((MYIOC_s_INFO_FMT + "calling getFreeChainBuffer SCSI cmd=%02x (%p)\n", + ioc->name, pReq->CDB[0], SCpnt)); + if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) return FAILED; /* Update the tracking arrays. * If chainSge == NULL, update ReqToChain, else ChainToChain */ if (chainSge) { - hd->ChainToChain[chain_idx] = newIndex; + ioc->ChainToChain[chain_idx] = newIndex; } else { - hd->ReqToChain[req_idx] = newIndex; + ioc->ReqToChain[req_idx] = newIndex; } chain_idx = newIndex; - chain_dma_off = hd->ioc->req_sz * chain_idx; + chain_dma_off = ioc->req_sz * chain_idx; /* Populate the chainSGE for the current buffer. * - Set chain buffer pointer to psge and fill @@ -576,7 +589,7 @@ nextSGEset: /* Start the SGE for the next buffer */ - psge = (char *) (hd->ChainBuffer + chain_dma_off); + psge = (char *) (ioc->ChainBuffer + chain_dma_off); sgeOffset = 0; sg_done = 0; @@ -631,7 +644,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name); - mptscsih_freeChainBuffers(hd, req_idx); + mptscsih_freeChainBuffers(ioc, req_idx); return 1; } @@ -674,14 +687,15 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; + scsi_status = pScsiReply->SCSIStatus; + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); - dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", + dreplyprintk((KERN_NOTICE " Reply (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], mf, mr, sc)); - dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" - ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", - status, scsi_state, pScsiReply->SCSIStatus, - le32_to_cpu(pScsiReply->IOCLogInfo))); + dreplyprintk((KERN_NOTICE "IOCStatus=%04xh SCSIState=%02xh" + " SCSIStatus=%02xh xfer_cnt=%08xh\n", + status, scsi_state, scsi_status, xfer_cnt)); if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) copy_sense_data(sc, hd, mf, pScsiReply); @@ -701,7 +715,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) * But not: DID_BUS_BUSY lest one risk * killing interrupt handler:-( */ - sc->result = STS_BUSY; + sc->result = SAM_STAT_BUSY; break; case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ @@ -731,13 +745,22 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ - sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | + sc->resid = sc->request_bufflen - xfer_cnt; + if ( xfer_cnt >= sc->underflow ) { + /* Sufficient data transfer occurred */ + sc->result = (DID_OK << 16) | scsi_status; + } else if ( xfer_cnt == 0 ) { + /* A CRC Error causes this condition; retry */ + sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); - sc->sense_buffer[0] = 0x70; - sc->sense_buffer[2] = NO_SENSE; - sc->sense_buffer[12] = 0; - sc->sense_buffer[13] = 0; - dprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target)); + sc->sense_buffer[0] = 0x70; + sc->sense_buffer[2] = NO_SENSE; + sc->sense_buffer[12] = 0; + sc->sense_buffer[13] = 0; + } else { + sc->result = DID_SOFT_ERROR << 16; + } + dreplyprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -745,9 +768,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) * Do upfront check for valid SenseData and give it * precedence! */ - scsi_status = pScsiReply->SCSIStatus; sc->result = (DID_OK << 16) | scsi_status; - xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* Have already saved the status and sense data */ @@ -769,12 +790,12 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) /* Give report and update residual count. */ - dprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", + dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); - dprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); + dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); sc->resid = sc->request_bufflen - xfer_cnt; - dprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); + dreplyprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); /* Report Queue Full */ @@ -785,7 +806,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; + scsi_status = pScsiReply->SCSIStatus; + sc->result = (DID_OK << 16) | scsi_status; if (scsi_state == 0) { ; } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { @@ -851,7 +873,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) } /* switch(status) */ - dprintk((KERN_NOTICE " sc->result set to %08xh\n", sc->result)); + dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result)); } /* end of address reply case */ /* Unmap the DMA buffers, if any. */ @@ -868,88 +890,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) sc->scsi_done(sc); /* Issue the command callback */ /* Free Chain buffers */ - mptscsih_freeChainBuffers(hd, req_idx); + mptscsih_freeChainBuffers(ioc, req_idx); return 1; } -/* - * Flush all commands on the doneQ. - * Lock Q when deleting/adding members - * Lock io_request_lock for OS callback. - */ -static void -flush_doneQ(MPT_SCSI_HOST *hd) -{ - MPT_DONE_Q *buffer; - struct scsi_cmnd *SCpnt; - unsigned long flags; - - /* Flush the doneQ. - */ - dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); - while (1) { - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (Q_IS_EMPTY(&hd->doneQ)) { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - break; - } - - buffer = hd->doneQ.head; - /* Delete from Q - */ - Q_DEL_ITEM(buffer); - - /* Set the struct scsi_cmnd pointer - */ - SCpnt = (struct scsi_cmnd *) buffer->argp; - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - - /* Do the OS callback. - */ - SCpnt->scsi_done(SCpnt); - } - - return; -} - -/* - * Search the doneQ for a specific command. If found, delete from Q. - * Calling function will finish processing. - */ -static void -search_doneQ_for_cmd(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt) -{ - unsigned long flags; - MPT_DONE_Q *buffer; - - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->doneQ)) { - buffer = hd->doneQ.head; - do { - struct scsi_cmnd *sc = (struct scsi_cmnd *) buffer->argp; - if (SCpnt == sc) { - Q_DEL_ITEM(buffer); - SCpnt->result = sc->result; - - /* Set the struct scsi_cmnd pointer - */ - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - break; - } - } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ); - } - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - return; -} /* * mptscsih_flush_running_cmds - For each command found, search @@ -964,12 +908,11 @@ search_doneQ_for_cmd(MPT_SCSI_HOST *hd, struct scsi_cmnd *SCpnt) static void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { + MPT_ADAPTER *ioc = hd->ioc; struct scsi_cmnd *SCpnt; MPT_FRAME_HDR *mf; - MPT_DONE_Q *buffer; int ii; - int max = hd->ioc->req_depth; - unsigned long flags; + int max = ioc->req_depth; dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); for (ii= 0; ii < max; ii++) { @@ -978,16 +921,11 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) /* Command found. */ - /* Search pendingQ, if found, - * delete from Q. - */ - mptscsih_search_pendingQ(hd, ii); - /* Null ScsiLookup index */ hd->ScsiLookup[ii] = NULL; - mf = MPT_INDEX_2_MFPTR(hd->ioc, ii); + mf = MPT_INDEX_2_MFPTR(ioc, ii); dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", mf, SCpnt)); @@ -997,12 +935,12 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) */ if (scsi_device_online(SCpnt->device)) { if (SCpnt->use_sg) { - pci_unmap_sg(hd->ioc->pcidev, + pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction); } else if (SCpnt->request_bufflen) { - pci_unmap_single(hd->ioc->pcidev, + pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, SCpnt->request_bufflen, SCpnt->sc_data_direction); @@ -1012,37 +950,12 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) SCpnt->host_scribble = NULL; /* Free Chain buffers */ - mptscsih_freeChainBuffers(hd, ii); + mptscsih_freeChainBuffers(ioc, ii); /* Free Message frames */ - mpt_free_msg_frame(ScsiDoneCtx, hd->ioc, mf); - -#if 1 - /* Post to doneQ, do not reply until POST phase - * of reset handler....prevents new commands from - * being queued. - */ - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->freeQ)) { - buffer = hd->freeQ.head; - Q_DEL_ITEM(buffer); + mpt_free_msg_frame(ioc, mf); - /* Set the struct scsi_cmnd pointer - */ - buffer->argp = (void *)SCpnt; - - /* Add to the doneQ - */ - Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - } else { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - SCpnt->scsi_done(SCpnt); - } -#else SCpnt->scsi_done(SCpnt); /* Issue the command callback */ -#endif - } } @@ -1087,119 +1000,14 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun) /* Cleanup */ hd->ScsiLookup[ii] = NULL; - mptscsih_freeChainBuffers(hd, ii); - mpt_free_msg_frame(ScsiDoneCtx, hd->ioc, (MPT_FRAME_HDR *)mf); + mptscsih_freeChainBuffers(hd->ioc, ii); + mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); } } return; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptscsih_initChainBuffers - Allocate memory for and initialize - * chain buffers, chain buffer control arrays and spinlock. - * @hd: Pointer to MPT_SCSI_HOST structure - * @init: If set, initialize the spin lock. - */ -static int -mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init) -{ - MPT_FRAME_HDR *chain; - u8 *mem; - unsigned long flags; - int sz, ii, num_chain; - int scale, num_sge; - - /* chain buffer allocation done from PrimeIocFifos */ - if (hd->ioc->fifo_pool == NULL) - return -1; - - hd->ChainBuffer = hd->ioc->chain_alloc; - hd->ChainBufferDMA = hd->ioc->chain_alloc_dma; - - dprintk((KERN_INFO " ChainBuffer @ %p(%p), sz=%d\n", - hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, hd->ioc->chain_alloc_sz)); - - /* ReqToChain size must equal the req_depth - * index = req_idx - */ - if (hd->ReqToChain == NULL) { - sz = hd->ioc->req_depth * sizeof(int); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) - return -1; - - hd->ReqToChain = (int *) mem; - } - for (ii = 0; ii < hd->ioc->req_depth; ii++) - hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN; - - /* ChainToChain size must equal the total number - * of chain buffers to be allocated. - * index = chain_idx - * - * Calculate the number of chain buffers needed(plus 1) per I/O - * then multiply the the maximum number of simultaneous cmds - * - * num_sge = num sge in request frame + last chain buffer - * scale = num sge per chain buffer if no chain element - */ - scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) - num_sge = scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); - else - num_sge = 1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); - - num_chain = 1; - while (hd->max_sge - num_sge > 0) { - num_chain++; - num_sge += (scale - 1); - } - num_chain++; - - if ((int) hd->ioc->chip_type > (int) FC929) - num_chain *= MPT_SCSI_CAN_QUEUE; - else - num_chain *= MPT_FC_CAN_QUEUE; - - hd->num_chain = num_chain; - - sz = num_chain * sizeof(int); - if (hd->ChainToChain == NULL) { - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) - return -1; - - hd->ChainToChain = (int *) mem; - } else { - mem = (u8 *) hd->ChainToChain; - } - memset(mem, 0xFF, sz); - - - /* Initialize the free chain Q. - */ - if (init) { - spin_lock_init(&hd->FreeChainQlock); - } - - spin_lock_irqsave (&hd->FreeChainQlock, flags); - Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR); - - /* Post the chain buffers to the FreeChainQ. - */ - mem = (u8 *)hd->ChainBuffer; - for (ii=0; ii < num_chain; ii++) { - chain = (MPT_FRAME_HDR *) mem; - Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); - mem += hd->ioc->req_sz; - } - spin_unlock_irqrestore(&hd->FreeChainQlock, flags); - - return 0; -} - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Hack! It might be nice to report if a device is returning QUEUE_FULL @@ -1254,7 +1062,6 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct Scsi_Host *sh; MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - MPT_DONE_Q *freedoneQ; unsigned long flags; int sz, ii; int numSGE = 0; @@ -1386,7 +1193,6 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = ioc; - hd->max_sge = sh->sg_tablesize; if ((int)ioc->chip_type > (int)FC929) hd->is_spi = 1; @@ -1399,7 +1205,7 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - sz = hd->ioc->req_depth * sizeof(void *); + sz = ioc->req_depth * sizeof(void *); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) { error = -ENOMEM; @@ -1412,37 +1218,6 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", ioc->name, hd->ScsiLookup, sz)); - if (mptscsih_initChainBuffers(hd, 1) < 0) { - error = -EINVAL; - goto mptscsih_probe_failed; - } - - /* Allocate memory for free and doneQ's - */ - sz = sh->can_queue * sizeof(MPT_DONE_Q); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } - - memset(mem, 0xFF, sz); - hd->memQ = mem; - - /* Initialize the free, done and pending Qs. - */ - Q_INIT(&hd->freeQ, MPT_DONE_Q); - Q_INIT(&hd->doneQ, MPT_DONE_Q); - Q_INIT(&hd->pendingQ, MPT_DONE_Q); - spin_lock_init(&hd->freedoneQlock); - - mem = hd->memQ; - for (ii=0; ii < sh->can_queue; ii++) { - freedoneQ = (MPT_DONE_Q *) mem; - Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); - mem += sizeof(MPT_DONE_Q); - } - /* Initialize this Scsi_Host * internal task Q. */ @@ -1474,8 +1249,7 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) hd->resetPending = 0; hd->abortSCpnt = NULL; hd->tmPtr = NULL; - hd->numTMrequests = 0; - + /* Clear the pointer used to store * single-threaded commands, i.e., those * issued during a bus scan, dv and @@ -1500,10 +1274,10 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* ioc->sh = sh; */ #ifdef MPTSCSIH_DBG_TIMEOUT - hd->ioc->timeout_hard = 0; - hd->ioc->timeout_delta = 30 * HZ; - hd->ioc->timeout_maxcnt = 0; - hd->ioc->timeout_cnt = 0; + ioc->timeout_hard = 0; + ioc->timeout_delta = 30 * HZ; + ioc->timeout_maxcnt = 0; + ioc->timeout_cnt = 0; for (ii=0; ii < 8; ii++) foo_to[ii] = NULL; #endif @@ -1511,47 +1285,41 @@ mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Update with the driver setup * values. */ - if (hd->ioc->spi_data.maxBusWidth > + if (ioc->spi_data.maxBusWidth > driver_setup.max_width) { - hd->ioc->spi_data.maxBusWidth = + ioc->spi_data.maxBusWidth = driver_setup.max_width; } - if (hd->ioc->spi_data.minSyncFactor < + if (ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac) { - hd->ioc->spi_data.minSyncFactor = + ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac; } - if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { - hd->ioc->spi_data.maxSyncOffset = 0; + if (ioc->spi_data.minSyncFactor == MPT_ASYNC) { + ioc->spi_data.maxSyncOffset = 0; } - hd->ioc->spi_data.Saf_Te = driver_setup.saf_te; + ioc->spi_data.Saf_Te = driver_setup.saf_te; hd->negoNvram = 0; #ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION hd->negoNvram = MPT_SCSICFG_USE_NVRAM; #endif - if (driver_setup.dv == 0) { - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; - } - - hd->ioc->spi_data.forceDv = 0; + ioc->spi_data.forceDv = 0; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - hd->ioc->spi_data.dvStatus[ii] = + ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE; } - if (hd->negoNvram == 0) { - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) - hd->ioc->spi_data.dvStatus[ii] |= - MPT_SCSICFG_DV_NOT_DONE; - } + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) + ioc->spi_data.dvStatus[ii] |= + MPT_SCSICFG_DV_NOT_DONE; ddvprintk((MYIOC_s_INFO_FMT "dv %x width %x factor %x saf_te %x\n", - hd->ioc->name, driver_setup.dv, + ioc->name, driver_setup.dv, driver_setup.max_width, driver_setup.min_sync_fac, driver_setup.saf_te)); @@ -1620,14 +1388,11 @@ mptscsih_remove(struct pci_dev *pdev) hd = (MPT_SCSI_HOST *)host->hostdata; if (hd != NULL) { - int sz1, sz2, sz3, sztarget=0; - int szr2chain = 0; - int szc2chain = 0; - int szQ = 0; + int sz1, sz3, sztarget=0; mptscsih_shutdown(&pdev->dev); - sz1 = sz2 = sz3 = 0; + sz1 = sz3 = 0; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); @@ -1635,24 +1400,6 @@ mptscsih_remove(struct pci_dev *pdev) hd->ScsiLookup = NULL; } - if (hd->ReqToChain != NULL) { - szr2chain = hd->ioc->req_depth * sizeof(int); - kfree(hd->ReqToChain); - hd->ReqToChain = NULL; - } - - if (hd->ChainToChain != NULL) { - szc2chain = hd->num_chain * sizeof(int); - kfree(hd->ChainToChain); - hd->ChainToChain = NULL; - } - - if (hd->memQ != NULL) { - szQ = host->can_queue * sizeof(MPT_DONE_Q); - kfree(hd->memQ); - hd->memQ = NULL; - } - if (hd->Targets != NULL) { int max, ii; @@ -1680,9 +1427,9 @@ mptscsih_remove(struct pci_dev *pdev) hd->Targets = NULL; } - dprintk((MYIOC_s_INFO_FMT - "Free'd ScsiLookup (%d) Target (%d+%d) memory\n", - hd->ioc->name, sz1, sz3, sztarget)); + dprintk((MYIOC_s_INFO_FMT + "Free'd ScsiLookup (%d) Target (%d+%d) memory\n", + hd->ioc->name, sz1, sz3, sztarget)); dprintk(("Free'd done and free Q (%d) memory\n", szQ)); /* NULL the Scsi_Host pointer @@ -1802,7 +1549,7 @@ mptscsih_init(void) ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER); if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { - dprintk((KERN_INFO MYNAM + devtprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); } @@ -1864,7 +1611,7 @@ mptscsih_exit(void) * * Returns pointer to buffer where information was written. */ -const char * +static const char * mptscsih_info(struct Scsi_Host *SChost) { MPT_SCSI_HOST *h; @@ -2079,7 +1826,8 @@ static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length) * hostno: scsi host number * func: if write = 1; if read = 0 */ -int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, +static int +mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; @@ -2114,15 +1862,13 @@ int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t * * Returns 0. (rtn value discarded by linux scsi mid-layer) */ -int +static int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *pTarget; - MPT_DONE_Q *buffer; - unsigned long flags; int target; int lun; u32 datalen; @@ -2147,16 +1893,9 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); if (hd->resetPending) { - /* Prevent new commands from being issued - * while reloading the FW. Reset timer to 60 seconds, - * as the FW can take some time to come ready. - * For New EH, cmds on doneQ posted to FW. - */ - did_errcode = 1; - mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); - goto did_error; + return SCSI_MLQUEUE_HOST_BUSY; } /* @@ -2165,8 +1904,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc)) == NULL) { dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", hd->ioc->name)); - did_errcode = 2; - goto did_error; + return SCSI_MLQUEUE_HOST_BUSY; } pScsiReq = (SCSIIORequest_t *) mf; @@ -2249,7 +1987,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ - rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx); + rc = mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx); } @@ -2283,7 +2021,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) } /* Trying to do DV to this target, extend timeout. - * Wait to issue intil flag is clear + * Wait to issue until flag is clear */ if (dvStatus & MPT_SCSICFG_DV_PENDING) { mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); @@ -2314,64 +2052,18 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", hd->ioc->name, SCpnt, mf, my_idx)); - } else { - ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n", - hd->ioc->name, SCpnt, my_idx)); - /* Place this command on the pendingQ if possible */ - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->freeQ)) { - buffer = hd->freeQ.head; - Q_DEL_ITEM(buffer); - - /* Save the mf pointer - */ - buffer->argp = (void *)mf; - - /* Add to the pendingQ - */ - Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - } else { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - SCpnt->result = (DID_BUS_BUSY << 16); - SCpnt->scsi_done(SCpnt); - } - } - } else { - mptscsih_freeChainBuffers(hd, my_idx); - mpt_free_msg_frame(ScsiDoneCtx, hd->ioc, mf); - did_errcode = 3; - goto did_error; - } + DBG_DUMP_REQUEST_FRAME(mf) + } else + goto fail; + } else + goto fail; return 0; -did_error: - dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n", - hd->ioc->name, did_errcode, SCpnt)); - /* Just wish OS to issue a retry */ - SCpnt->result = (DID_BUS_BUSY << 16); - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->freeQ)) { - dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n", - (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); - buffer = hd->freeQ.head; - Q_DEL_ITEM(buffer); - - /* Set the scsi_cmnd pointer - */ - buffer->argp = (void *)SCpnt; - - /* Add to the doneQ - */ - Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - } else { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - SCpnt->scsi_done(SCpnt); - } - - return 0; + fail: + mptscsih_freeChainBuffers(hd->ioc, my_idx); + mpt_free_msg_frame(hd->ioc, mf); + return SCSI_MLQUEUE_HOST_BUSY; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2385,7 +2077,7 @@ did_error: * No return. */ static void -mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx) +mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) { MPT_FRAME_HDR *chain; unsigned long flags; @@ -2395,28 +2087,28 @@ mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx) /* Get the first chain index and reset * tracker state. */ - chain_idx = hd->ReqToChain[req_idx]; - hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; + chain_idx = ioc->ReqToChain[req_idx]; + ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; while (chain_idx != MPT_HOST_NO_CHAIN) { /* Save the next chain buffer index */ - next = hd->ChainToChain[chain_idx]; + next = ioc->ChainToChain[chain_idx]; /* Free this chain buffer and reset * tracker */ - hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; + ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; - chain = (MPT_FRAME_HDR *) (hd->ChainBuffer - + (chain_idx * hd->ioc->req_sz)); - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - Q_ADD_TAIL(&hd->FreeChainQ.head, + chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer + + (chain_idx * ioc->req_sz)); + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n", - hd->ioc->name, chain_idx)); + ioc->name, chain_idx)); /* handle next */ chain_idx = next; @@ -2480,12 +2172,6 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in } spin_unlock_irqrestore(&ioc->diagLock, flags); - /* Do not do a Task Management if there are - * too many failed TMs on this adapter. - */ - if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM) - doTask = 0; - /* Wait a fixed amount of time for the TM pending flag to be cleared. * If we time out and not bus reset, then we return a FAILED status to the caller. * The call to mptscsih_tm_pending_wait() will set the pending flag if we are @@ -2593,7 +2279,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun /* Return Fail to calling function if no message frames available. */ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc)) == NULL) { - dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", + dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", hd->ioc->name)); //return FAILED; return -999; @@ -2624,29 +2310,30 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun pScsiTm->Reserved2[ii] = 0; pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n", - hd->ioc->name, ctx2abort, type)); /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake mpt_put_msg_frame(hd->ioc->id, mf); * Save the MF pointer in case the request times out. */ hd->tmPtr = mf; - hd->numTMrequests++; hd->TMtimer.expires = jiffies + timeout; add_timer(&hd->TMtimer); + dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n", + hd->ioc->name, ctx2abort, type)); + + DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); + if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc, sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag)) != 0) { - dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!" + dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf)); - hd->numTMrequests--; hd->tmPtr = NULL; del_timer(&hd->TMtimer); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc, mf); + mpt_free_msg_frame(hd->ioc, mf); } - + return retval; } @@ -2659,10 +2346,11 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_abort(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; @@ -2673,12 +2361,13 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); - dtmprintk((KERN_WARNING MYNAM ": mptscsih_abort: " + dfailprintk((KERN_WARNING MYNAM ": mptscsih_abort: " "Can't locate host! (sc=%p)\n", SCpnt)); return FAILED; } + ioc = hd->ioc; if (hd->resetPending) return FAILED; @@ -2691,11 +2380,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { - /* Cmd not found in ScsiLookup. If found in - * doneQ, delete from Q. Do OS callback. + /* Cmd not found in ScsiLookup. + * Do OS callback. */ - search_doneQ_for_cmd(hd, SCpnt); - SCpnt->result = DID_RESET << 16; dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " "Command not in the active list! (sc=%p)\n", @@ -2703,18 +2390,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) return SUCCESS; } - /* If this command is pended, then timeout/hang occurred - * during DV. Post command and flush pending Q - * and then following up with the reset request. - */ - if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { - mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); - post_pendingQ_commands(hd); - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Posting pended cmd! (sc=%p)\n", - hd->ioc->name, SCpnt)); - } - /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) * @@ -2724,7 +2399,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) */ mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; - + hd->abortSCpnt = SCpnt; spin_unlock_irq(host_lock); @@ -2743,12 +2418,26 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) */ hd->tmPending = 0; hd->tmState = TM_STATE_NONE; - + spin_lock_irq(host_lock); + + /* Unmap the DMA buffers, if any. */ + if (SCpnt->use_sg) { + pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, + SCpnt->use_sg, SCpnt->sc_data_direction); + } else if (SCpnt->request_bufflen) { + pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, + SCpnt->request_bufflen, SCpnt->sc_data_direction); + } + hd->ScsiLookup[scpnt_idx] = NULL; + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); /* Issue the command callback */ + mptscsih_freeChainBuffers(ioc, scpnt_idx); + mpt_free_msg_frame(ioc, mf); return FAILED; } spin_lock_irq(host_lock); - return FAILED; + return SUCCESS; } @@ -2761,7 +2450,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_dev_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; @@ -2816,7 +2505,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_bus_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; @@ -2839,9 +2528,6 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) /* We are now ready to execute the task management request. */ spin_unlock_irq(host_lock); -// printk("testing start : mptscsih_schedule_reset\n"); -// mptscsih_schedule_reset(hd); -// printk("testing end: mptscsih_schedule_reset\n"); if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, SCpnt->device->channel, 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) < 0){ @@ -2871,7 +2557,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) * * Returns SUCCESS or FAILED. */ -int +static int mptscsih_host_reset(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST * hd; @@ -2937,8 +2623,7 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + msleep(250); } while (--loop_count); return status; @@ -2965,9 +2650,10 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m SCSITaskMgmt_t *pScsiTmReq; MPT_SCSI_HOST *hd; unsigned long flags; - u8 tmType = 0; + u16 iocstatus; + u8 tmType; - dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n", + dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", ioc->name, mf, mr)); if (ioc->sh) { /* Depending on the thread, a timer is activated for @@ -2978,7 +2664,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m if (hd->tmPtr) { del_timer(&hd->TMtimer); } - dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n", + dtmprintk((MYIOC_s_WARN_FMT "taskQcnt (%d)\n", ioc->name, hd->taskQcnt)); } else { dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n", @@ -2997,18 +2683,15 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ tmType = pScsiTmReq->TaskType; - dtmprintk((KERN_INFO " TaskType = %d, TerminationCount=%d\n", - tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); + dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n", + ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); + DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n", + ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo))); /* Error? (anything non-zero?) */ - if (*(u32 *)&pScsiTmReply->Reserved2[0]) { - u16 iocstatus; - - iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dtmprintk((KERN_INFO " SCSI TaskMgmt (%d) - Oops!\n", tmType)); - dtmprintk((KERN_INFO " IOCStatus = %04xh\n", iocstatus)); - dtmprintk((KERN_INFO " IOCLogInfo = %08xh\n", - le32_to_cpu(pScsiTmReply->IOCLogInfo))); + if (iocstatus) { /* clear flags and continue. */ @@ -3029,11 +2712,9 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m } } } else { - dtmprintk((KERN_INFO " SCSI TaskMgmt SUCCESS!\n")); + dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); - hd->numTMrequests--; hd->abortSCpnt = NULL; - flush_doneQ(hd); } } @@ -3051,26 +2732,21 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m /* * This is anyones guess quite frankly. */ -int +static int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]) { int heads; int sectors; sector_t cylinders; -#ifdef CONFIG_LBD ulong dummy; -#endif heads = 64; sectors = 32; -#ifdef CONFIG_LBD + dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); -#else - cylinders = (ulong)capacity / (heads * sectors); -#endif /* * Handle extended translation size for logical drives @@ -3079,13 +2755,9 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, if ((ulong)capacity >= 0x200000) { heads = 255; sectors = 63; -#ifdef CONFIG_LBD dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); -#else - cylinders = (ulong)capacity / (heads * sectors); -#endif } /* return result */ @@ -3107,7 +2779,7 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, * Return non-zero if allocation fails. * Init memory once per id (not LUN). */ -int +static int mptscsih_slave_alloc(struct scsi_device *device) { struct Scsi_Host *host = device->host; @@ -3130,12 +2802,21 @@ mptscsih_slave_alloc(struct scsi_device *device) Q_INIT(&vdev->WaitQ, void); Q_INIT(&vdev->SentQ, void); Q_INIT(&vdev->DoneQ, void); - vdev->tflags = 0; + vdev->tflags = MPT_TARGET_FLAGS_Q_YES; vdev->ioc_id = hd->ioc->id; vdev->target_id = device->id; - vdev->bus_id = hd->port; - + vdev->bus_id = device->channel; + vdev->raidVolume = 0; hd->Targets[device->id] = vdev; + if (hd->is_spi) { + if (hd->ioc->spi_data.isRaid & (1 << device->id)) { + vdev->raidVolume = 1; + ddvtprintk((KERN_INFO + "RAID Volume @ id %d\n", device->id)); + } + } else { + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + } } } vdev->num_luns++; @@ -3147,7 +2828,7 @@ mptscsih_slave_alloc(struct scsi_device *device) * OS entry point to allow for host driver to free allocated memory * Called if no device present or device being unloaded */ -void +static void mptscsih_slave_destroy(struct scsi_device *device) { struct Scsi_Host *host = device->host; @@ -3176,15 +2857,15 @@ mptscsih_slave_destroy(struct scsi_device *device) kfree(hd->Targets[device->id]); hd->Targets[device->id] = NULL; - if (!hd->is_spi) + if (!hd->is_spi) return; if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) { int i; for(i=0;iioc->spi_data.pIocPg3->NumPhysDisks && raid_volume==0;i++) - - if(device->id == + + if(device->id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID) { raid_volume=1; hd->ioc->spi_data.forceDv |= @@ -3202,7 +2883,7 @@ mptscsih_slave_destroy(struct scsi_device *device) } } } - + return; } @@ -3212,7 +2893,7 @@ mptscsih_slave_destroy(struct scsi_device *device) * member to 1 if a device does not support Q tags. * Return non-zero if fails. */ -int +static int mptscsih_slave_configure(struct scsi_device *device) { struct Scsi_Host *sh = device->host; @@ -3240,8 +2921,16 @@ mptscsih_slave_configure(struct scsi_device *device) pTarget = hd->Targets[device->id]; if (pTarget == NULL) { - /* error case - don't know about this device */ - scsi_adjust_queue_depth(device, 0, 1); + /* Driver doesn't know about this device. + * Kernel may generate a "Dummy Lun 0" which + * may become a real Lun if a + * "scsi add-single-device" command is executed + * while the driver is active (hot-plug a + * device). LSI Raid controllers need + * queue_depth set to DEV_HIGH for this reason. + */ + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + MPT_SCSI_CMD_PER_DEV_HIGH); goto slave_configure_exit; } @@ -3302,8 +2991,6 @@ copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSI SCSIIORequest_t *pReq; u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); int index; - char devFoo[96]; - IO_Info_t thisIo; /* Get target structure */ @@ -3342,35 +3029,10 @@ copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSI ioc->eventContext++; } } - - /* Print an error report for the user. - */ - thisIo.cdbPtr = sc->cmnd; - thisIo.sensePtr = sc->sense_buffer; - thisIo.SCSIStatus = pScsiReply->SCSIStatus; - thisIo.DoDisplay = 1; - if (hd->is_multipath) - sprintf(devFoo, "%d:%d:%d", - hd->ioc->id, - pReq->TargetID, - pReq->LUN[1]); - else - sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->device->id, sc->device->lun); - thisIo.DevIDStr = devFoo; -/* fubar */ - thisIo.dataPtr = NULL; - thisIo.inqPtr = NULL; - if (sc->device) { - thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */ - } - (void) mpt_ScsiHost_ErrorReport(&thisIo); - } else { dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n", hd->ioc->name)); } - - return; } static u32 @@ -3390,102 +3052,6 @@ SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc) return -1; } - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Search the pendingQ for a command with specific index. - * If found, delete and return mf pointer - * If not found, return NULL - */ -static MPT_FRAME_HDR * -mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx) -{ - unsigned long flags; - MPT_DONE_Q *buffer; - MPT_FRAME_HDR *mf = NULL; - MPT_FRAME_HDR *cmdMfPtr; - - ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name)); - cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (!Q_IS_EMPTY(&hd->pendingQ)) { - buffer = hd->pendingQ.head; - do { - mf = (MPT_FRAME_HDR *) buffer->argp; - if (mf == cmdMfPtr) { - Q_DEL_ITEM(buffer); - - /* clear the arg pointer - */ - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - break; - } - mf = NULL; - } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ); - } - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - ddvtprintk((" ...return %p\n", mf)); - return mf; -} - -/* Post all commands on the pendingQ to the FW. - * Lock Q when deleting/adding members - * Lock io_request_lock for OS callback. - */ -static void -post_pendingQ_commands(MPT_SCSI_HOST *hd) -{ - MPT_FRAME_HDR *mf; - MPT_DONE_Q *buffer; - unsigned long flags; - - /* Flush the pendingQ. - */ - ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name)); - while (1) { - spin_lock_irqsave(&hd->freedoneQlock, flags); - if (Q_IS_EMPTY(&hd->pendingQ)) { - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - break; - } - - buffer = hd->pendingQ.head; - /* Delete from Q - */ - Q_DEL_ITEM(buffer); - - mf = (MPT_FRAME_HDR *) buffer->argp; - buffer->argp = NULL; - - /* Add to the freeQ - */ - Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); - spin_unlock_irqrestore(&hd->freedoneQlock, flags); - - if (!mf) { - /* This should never happen */ - printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, (void *) mf); - continue; - } - - mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); - -#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) - { - u16 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - struct scsi_cmnd *sc = hd->ScsiLookup[req_idx]; - printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n", - hd->ioc->name, sc, req_idx, mf); - } -#endif - } - - return; -} - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) @@ -3520,14 +3086,10 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name)); /* 2. Flush running commands - * Clean drop test code - if compiled * Clean ScsiLookup (and associated memory) * AND clean mytaskQ */ - /* 2a. Drop Test Command. - */ - /* 2b. Reply to OS all known outstanding I/O commands. */ mptscsih_flush_running_cmds(hd); @@ -3538,7 +3100,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) */ if (hd->cmdPtr) { del_timer(&hd->timer); - mpt_free_msg_frame(ScsiScanDvCtx, ioc, hd->cmdPtr); + mpt_free_msg_frame(ioc, hd->cmdPtr); } /* 2d. If a task management has not completed, @@ -3546,7 +3108,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) */ if (hd->tmPtr) { del_timer(&hd->TMtimer); - mpt_free_msg_frame(ScsiTaskCtx, ioc, hd->tmPtr); + mpt_free_msg_frame(ioc, hd->tmPtr); } #ifdef MPTSCSIH_DBG_TIMEOUT @@ -3573,7 +3135,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /* 2. Chain Buffer initialization */ - mptscsih_initChainBuffers(hd, 0); /* 3. tmPtr clear */ @@ -3583,8 +3144,10 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /* 4. Renegotiate to all devices, if SCSI */ - if (hd->is_spi) + if (hd->is_spi) { + dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n")); mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM); + } /* 5. Enable new commands to be posted */ @@ -3592,7 +3155,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); hd->resetPending = 0; - hd->numTMrequests = 0; hd->tmState = TM_STATE_NONE; /* 6. If there was an internal command, @@ -3609,11 +3171,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) hd->cmdPtr = NULL; } - /* 7. Flush doneQ - */ - flush_doneQ(hd); - - /* 8. Set flag to force DV and re-read IOC Page 3 + /* 7. Set flag to force DV and re-read IOC Page 3 */ if (hd->is_spi) { ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; @@ -3634,7 +3192,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", + devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); switch (event) { @@ -3766,394 +3324,6 @@ static struct scsi_host_template driver_template = { .use_clustering = ENABLE_CLUSTERING, }; - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - */ -static ASCQ_Table_t *mptscsih_ASCQ_TablePtr; - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* old symsense.c stuff... */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - * To protect ourselves against those that would pass us bogus pointers - */ -static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES] - = { 0x1F, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u8 dummySenseData[SCSI_STD_SENSE_BYTES] - = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; -static u8 dummyCDB[16] - = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u8 dummyScsiData[16] - = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -static char *ScsiStatusString[] = { - "GOOD", /* 00h */ - NULL, /* 01h */ - "CHECK CONDITION", /* 02h */ - NULL, /* 03h */ - "CONDITION MET", /* 04h */ - NULL, /* 05h */ - NULL, /* 06h */ - NULL, /* 07h */ - "BUSY", /* 08h */ - NULL, /* 09h */ - NULL, /* 0Ah */ - NULL, /* 0Bh */ - NULL, /* 0Ch */ - NULL, /* 0Dh */ - NULL, /* 0Eh */ - NULL, /* 0Fh */ - "INTERMEDIATE", /* 10h */ - NULL, /* 11h */ - NULL, /* 12h */ - NULL, /* 13h */ - "INTERMEDIATE-CONDITION MET", /* 14h */ - NULL, /* 15h */ - NULL, /* 16h */ - NULL, /* 17h */ - "RESERVATION CONFLICT", /* 18h */ - NULL, /* 19h */ - NULL, /* 1Ah */ - NULL, /* 1Bh */ - NULL, /* 1Ch */ - NULL, /* 1Dh */ - NULL, /* 1Eh */ - NULL, /* 1Fh */ - NULL, /* 20h */ - NULL, /* 21h */ - "COMMAND TERMINATED", /* 22h */ - NULL, /* 23h */ - NULL, /* 24h */ - NULL, /* 25h */ - NULL, /* 26h */ - NULL, /* 27h */ - "TASK SET FULL", /* 28h */ - NULL, /* 29h */ - NULL, /* 2Ah */ - NULL, /* 2Bh */ - NULL, /* 2Ch */ - NULL, /* 2Dh */ - NULL, /* 2Eh */ - NULL, /* 2Fh */ - "ACA ACTIVE", /* 30h */ - NULL -}; - -static const char *ScsiCommonOpString[] = { - "TEST UNIT READY", /* 00h */ - "REZERO UNIT (REWIND)", /* 01h */ - NULL, /* 02h */ - "REQUEST_SENSE", /* 03h */ - "FORMAT UNIT (MEDIUM)", /* 04h */ - "READ BLOCK LIMITS", /* 05h */ - NULL, /* 06h */ - "REASSIGN BLOCKS", /* 07h */ - "READ(6)", /* 08h */ - NULL, /* 09h */ - "WRITE(6)", /* 0Ah */ - "SEEK(6)", /* 0Bh */ - NULL, /* 0Ch */ - NULL, /* 0Dh */ - NULL, /* 0Eh */ - "READ REVERSE", /* 0Fh */ - "WRITE_FILEMARKS", /* 10h */ - "SPACE(6)", /* 11h */ - "INQUIRY", /* 12h */ - NULL -}; - -static const char *SenseKeyString[] = { - "NO SENSE", /* 0h */ - "RECOVERED ERROR", /* 1h */ - "NOT READY", /* 2h */ - "MEDIUM ERROR", /* 3h */ - "HARDWARE ERROR", /* 4h */ - "ILLEGAL REQUEST", /* 5h */ - "UNIT ATTENTION", /* 6h */ - "DATA PROTECT", /* 7h */ - "BLANK CHECK", /* 8h */ - "VENDOR-SPECIFIC", /* 9h */ - "ABORTED COPY", /* Ah */ - "ABORTED COMMAND", /* Bh */ - "EQUAL (obsolete)", /* Ch */ - "VOLUME OVERFLOW", /* Dh */ - "MISCOMPARE", /* Eh */ - "RESERVED", /* Fh */ - NULL -}; - -#define SPECIAL_ASCQ(c,q) \ - (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70)) - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int dump_cdb(char *foo, unsigned char *cdb) -{ - int i, grpCode, cdbLen; - int l = 0; - - grpCode = cdb[0] >> 5; - if (grpCode < 1) - cdbLen = 6; - else if (grpCode < 3) - cdbLen = 10; - else if (grpCode == 5) - cdbLen = 12; - else - cdbLen = 16; - - for (i=0; i < cdbLen; i++) - l += sprintf(foo+l, " %02X", cdb[i]); - - return l; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Do ASC/ASCQ lookup/grindage to English readable string(s) */ -static const char * ascq_set_strings_4max( - u8 ASC, u8 ASCQ, - const char **s1, const char **s2, const char **s3, const char **s4) -{ - static const char *asc_04_part1_string = "LOGICAL UNIT "; - static const char *asc_04_part2a_string = "NOT READY, "; - static const char *asc_04_part2b_string = "IS "; - static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */ - "CAUSE NOT REPORTABLE", /* 04 00 */ - "IN PROCESS OF BECOMING READY", /* 04 01 */ - "INITIALIZING CMD. REQUIRED", /* 04 02 */ - "MANUAL INTERVENTION REQUIRED", /* 04 03 */ - /* Add " IN PROGRESS" to all the following... */ - "FORMAT", /* 04 04 */ - "REBUILD", /* 04 05 */ - "RECALCULATION", /* 04 06 */ - "OPERATION", /* 04 07 */ - "LONG WRITE", /* 04 08 */ - "SELF-TEST", /* 04 09 */ - NULL - }; - static char *asc_04_part4_string = " IN PROGRESS"; - - static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */ - "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */ - "POWER ON OCCURRED", /* 29 01 */ - "SCSI BUS RESET OCCURRED", /* 29 02 */ - "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */ - "DEVICE INTERNAL RESET", /* 29 04 */ - "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */ - "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */ - NULL - }; - static char *ascq_vendor_uniq = "(Vendor Unique)"; - static char *ascq_noone = "(no matching ASC/ASCQ description found)"; - int idx; - - *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */ - - /* CHECKME! Need lock/sem? - * Update and examine for isense module presense. - */ - mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr; - - if (mptscsih_ASCQ_TablePtr == NULL) { - /* 2nd chances... */ - if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) { - *s1 = asc_04_part1_string; - *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string; - *s3 = asc_04_ascq_NN_part3_strings[ASCQ]; - /* check for " IN PROGRESS" ones */ - if (ASCQ >= 0x04) - *s4 = asc_04_part4_string; - } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1)) - *s1 = asc_29_ascq_NN_strings[ASCQ]; - /* - * Else { leave all *s[1-4] values pointing to the empty "" string } - */ - return *s1; - } - - /* - * Need to check ASC here; if it is "special," then - * the ASCQ is variable, and indicates failed component number. - * We must treat the ASCQ as a "don't care" while searching the - * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later - * on when we actually need to identify the failed component. - */ - if (SPECIAL_ASCQ(ASC,ASCQ)) - ASCQ = 0xFF; - - /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */ - for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++) - if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) { - *s1 = mptscsih_ASCQ_TablePtr[idx].Description; - return *s1; - } - - if ((ASC >= 0x80) || (ASCQ >= 0x80)) - *s1 = ascq_vendor_uniq; - else - *s1 = ascq_noone; - - return *s1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * SCSI Information Report; desired output format... - *--- -SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION) - Key=6h (UNIT ATTENTION); FRU=03h - ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" - CDB: 00 00 00 00 00 00 - TestUnitReady - *--- - */ -/* - * SCSI Error Report; desired output format... - *--- -SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) - SCSI_Status=02h (CHECK CONDITION) - Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady - SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00 - SenseKey=6h (UNIT ATTENTION); FRU=03h - ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" - *--- - */ - -int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) -{ - char foo[512]; - char buf2[32]; - char *statstr; - const char *opstr; - int sk = SD_Sense_Key(ioop->sensePtr); - const char *skstr = SenseKeyString[sk]; - unsigned char asc = SD_ASC(ioop->sensePtr); - unsigned char ascq = SD_ASCQ(ioop->sensePtr); - int l; - - /* Change the error logging to only report errors on - * read and write commands. Ignore errors on other commands. - * Should this be configurable via proc? - */ - switch (ioop->cdbPtr[0]) { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - break; - default: - return 0; - } - - /* - * More quiet mode. - * Filter out common, repetitive, warning-type errors... like: - * POWER ON (06,29/00 or 06,29/01), - * SPINNING UP (02,04/01), - * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc. - */ - if (sk == SK_NO_SENSE) { - return 0; - } - - if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) - || (sk==SK_NOT_READY && asc==0x04 && (ascq==0x01 || ascq==0x02)) - || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) - ) - { - /* Do nothing! */ - return 0; - } - - /* Prevent the system from continually writing to the log - * if a medium is not found: 02 3A 00 - * Changer issues: TUR, Read Capacity, Table of Contents continually - */ - if (sk==SK_NOT_READY && asc==0x3A) { - if (ioop->cdbPtr == NULL) { - return 0; - } else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) || - (ioop->cdbPtr[0] == CMD_ReadCapacity) || - (ioop->cdbPtr[0] == 0x43)) { - return 0; - } - } - if (sk==SK_UNIT_ATTENTION) { - if (ioop->cdbPtr == NULL) - return 0; - else if (ioop->cdbPtr[0] == CMD_TestUnitReady) - return 0; - } - - /* - * Protect ourselves... - */ - if (ioop->cdbPtr == NULL) - ioop->cdbPtr = dummyCDB; - if (ioop->sensePtr == NULL) - ioop->sensePtr = dummySenseData; - if (ioop->inqPtr == NULL) - ioop->inqPtr = dummyInqData; - if (ioop->dataPtr == NULL) - ioop->dataPtr = dummyScsiData; - - statstr = NULL; - if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) || - ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) { - (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus); - statstr = buf2; - } - - opstr = NULL; - if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*)) - opstr = ScsiCommonOpString[ioop->cdbPtr[0]]; - else if (mpt_ScsiOpcodesPtr) - opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; - - l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n", - ioop->DevIDStr, - ioop->SCSIStatus, - statstr); - l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", - sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); - { - const char *x1, *x2, *x3, *x4; - x1 = x2 = x3 = x4 = ""; - x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4); - if (x1 != NULL) { - if (x1[0] != '(') - l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4); - else - l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); - } - } - l += sprintf(foo+l, "\n CDB:"); - l += dump_cdb(foo+l, ioop->cdbPtr); - if (opstr) - l += sprintf(foo+l, " - \"%s\"", opstr); - l += sprintf(foo+l, "\n"); - - PrintF(("%s\n", foo)); - - return l; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_initTarget - Target, LUN alloc/free functionality. @@ -4176,48 +3346,33 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * { int indexed_lun, lun_index; VirtDevice *vdev; + ScsiCfgData *pSpi; char data_56; - dprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", + dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", hd->ioc->name, bus_id, target_id, lun, hd)); - /* Is LUN supported? If so, upper 3 bits will be 0 + /* Is LUN supported? If so, upper 2 bits will be 0 * in first byte of inquiry data. */ if (data[0] & 0xe0) return; - vdev = hd->Targets[target_id]; + if ((vdev = hd->Targets[target_id]) == NULL) { + return; + } lun_index = (lun >> 5); /* 32 luns per lun_index */ indexed_lun = (lun % 32); vdev->luns[lun_index] |= (1 << indexed_lun); - vdev->raidVolume = 0; if (hd->is_spi) { - if (hd->ioc->spi_data.isRaid & (1 << target_id)) { - vdev->raidVolume = 1; - ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id)); - } - } - - if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { - if ( dlen > 8 ) { - memcpy (vdev->inq_data, data, 8); - } else { - memcpy (vdev->inq_data, data, dlen); - } - vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; - - /* If LUN 0, tape and have not done DV, set the DV flag. - */ - if (hd->is_spi && (lun == 0) && (data[0] == SCSI_TYPE_TAPE)) { - ScsiCfgData *pSpi = &hd->ioc->spi_data; - if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) - pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; - } - - if ( (data[0] == SCSI_TYPE_PROC) && + if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { + /* Treat all Processors as SAF-TE if + * command line option is set */ + vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptscsih_writeIOCPage4(hd, target_id, bus_id); + }else if ((data[0] == TYPE_PROCESSOR) && !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { if ( dlen > 49 ) { vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; @@ -4230,30 +3385,51 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; mptscsih_writeIOCPage4(hd, target_id, bus_id); } - } else { - /* Treat all Processors as SAF-TE if - * command line option is set */ - if ( hd->ioc->spi_data.Saf_Te ) { - vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; - mptscsih_writeIOCPage4(hd, target_id, bus_id); - } } } + if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { + if ( dlen > 8 ) { + memcpy (vdev->inq_data, data, 8); + } else { + memcpy (vdev->inq_data, data, dlen); + } - data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */ - if (dlen > 56) { - if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { - /* Update the target capabilities + /* If have not done DV, set the DV flag. */ - data_56 = data[56]; - vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + pSpi = &hd->ioc->spi_data; + if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) { + if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) + pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; + } + + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + + + data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */ + if (dlen > 56) { + if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { + /* Update the target capabilities + */ + data_56 = data[56]; + vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + } + } + mptscsih_setTargetNegoParms(hd, vdev, data_56); + } else { + /* Initial Inquiry may not request enough data bytes to + * obtain byte 57. DV will; if target doesn't return + * at least 57 bytes, data[56] will be zero. */ + if (dlen > 56) { + if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { + /* Update the target capabilities + */ + data_56 = data[56]; + vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + mptscsih_setTargetNegoParms(hd, vdev, data_56); + } } } - mptscsih_setTargetNegoParms(hd, vdev, data_56); } - - dprintk((KERN_INFO " target = %p\n", vdev)); - return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -4262,12 +3438,12 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * * the Inquiry data, adapter capabilities, and NVRAM settings. * */ -void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) +static void +mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) { ScsiCfgData *pspi_data = &hd->ioc->spi_data; int id = (int) target->target_id; int nvram; - char canQ = 0; VirtDevice *vdev; int ii; u8 width = MPT_NARROW; @@ -4276,14 +3452,6 @@ void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byt u8 version, nfactor; u8 noQas = 1; - if (!hd->is_spi) { - if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { - if (target->inq_data[7] & 0x02) - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - } - return; - } - target->negoFlags = pspi_data->noQas; /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine @@ -4293,137 +3461,152 @@ void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byt /* Set flags based on Inquiry data */ - if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { - version = target->inq_data[2] & 0x07; - if (version < 2) { - width = 0; - factor = MPT_ULTRA2; - offset = pspi_data->maxSyncOffset; - } else { - if (target->inq_data[7] & 0x20) { - width = 1; - } + version = target->inq_data[2] & 0x07; + if (version < 2) { + width = 0; + factor = MPT_ULTRA2; + offset = pspi_data->maxSyncOffset; + target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; + } else { + if (target->inq_data[7] & 0x20) { + width = 1; + } - if (target->inq_data[7] & 0x10) { - /* bits 2 & 3 show Clocking support - */ + if (target->inq_data[7] & 0x10) { + factor = pspi_data->minSyncFactor; + if (target->tflags & MPT_TARGET_FLAGS_VALID_56) { + /* bits 2 & 3 show Clocking support */ if ((byte56 & 0x0C) == 0) factor = MPT_ULTRA2; else { if ((byte56 & 0x03) == 0) factor = MPT_ULTRA160; - else + else { factor = MPT_ULTRA320; - } - offset = pspi_data->maxSyncOffset; - - /* If RAID, never disable QAS - * else if non RAID, do not disable - * QAS if bit 1 is set - * bit 1 QAS support, non-raid only - * bit 0 IU support - */ - if ((target->raidVolume == 1) || (byte56 & 0x02)) { - noQas = 0; + if (byte56 & 0x02) + { + ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id)); + noQas = 0; + } + if (target->inq_data[0] == TYPE_TAPE) { + if (byte56 & 0x01) + target->negoFlags |= MPT_TAPE_NEGO_IDP; + } + } } } else { - factor = MPT_ASYNC; - offset = 0; + ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id)); + noQas = 0; } - } + + offset = pspi_data->maxSyncOffset; - if (target->inq_data[7] & 0x02) { - canQ = 1; + /* If RAID, never disable QAS + * else if non RAID, do not disable + * QAS if bit 1 is set + * bit 1 QAS support, non-raid only + * bit 0 IU support + */ + if (target->raidVolume == 1) { + noQas = 0; + } + } else { + factor = MPT_ASYNC; + offset = 0; } + } - /* Update tflags based on NVRAM settings. (SCSI only) - */ - if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { - nvram = pspi_data->nvram[id]; - nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + if ( (target->inq_data[7] & 0x02) == 0) { + target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; + } - if (width) - width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + /* Update tflags based on NVRAM settings. (SCSI only) + */ + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = pspi_data->nvram[id]; + nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; - if (offset > 0) { - /* Ensure factor is set to the - * maximum of: adapter, nvram, inquiry - */ - if (nfactor) { - if (nfactor < pspi_data->minSyncFactor ) - nfactor = pspi_data->minSyncFactor; + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; - factor = max(factor, nfactor); - if (factor == MPT_ASYNC) - offset = 0; - } else { + if (offset > 0) { + /* Ensure factor is set to the + * maximum of: adapter, nvram, inquiry + */ + if (nfactor) { + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; + + factor = max(factor, nfactor); + if (factor == MPT_ASYNC) offset = 0; - factor = MPT_ASYNC; - } } else { + offset = 0; factor = MPT_ASYNC; - } } - - /* Make sure data is consistent - */ - if ((!width) && (factor < MPT_ULTRA2)) { - factor = MPT_ULTRA2; + } else { + factor = MPT_ASYNC; } + } - /* Save the data to the target structure. - */ - target->minSyncFactor = factor; - target->maxOffset = offset; - target->maxWidth = width; - if (canQ) { - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - } + /* Make sure data is consistent + */ + if ((!width) && (factor < MPT_ULTRA2)) { + factor = MPT_ULTRA2; + } - target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + /* Save the data to the target structure. + */ + target->minSyncFactor = factor; + target->maxOffset = offset; + target->maxWidth = width; - /* Disable unused features. - */ - if (!width) - target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; - if (!offset) - target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + /* Disable unused features. + */ + if (!width) + target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; - /* GEM, processor WORKAROUND - */ - if (((target->inq_data[0] & 0x1F) == 0x03) - || ((target->inq_data[0] & 0x1F) > 0x08)) { - target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); - pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; - } else { - if (noQas && (pspi_data->noQas == 0)) { - pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; - target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + if (!offset) + target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; - /* Disable QAS in a mixed configuration case - */ + if ( factor > MPT_ULTRA320 ) + noQas = 0; - ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); - for (ii = 0; ii < id; ii++) { - if ( (vdev = hd->Targets[ii]) ) { - vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - } - } + /* GEM, processor WORKAROUND + */ + if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) { + target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); + pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; + } else { + if (noQas && (pspi_data->noQas == 0)) { + pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; + target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + + /* Disable QAS in a mixed configuration case + */ + + ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); + for (ii = 0; ii < id; ii++) { + if ( (vdev = hd->Targets[ii]) ) { + vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags); + } } } - - /* Write SDP1 on this I/O to this target */ - if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) { - mptscsih_writeSDP1(hd, 0, id, hd->negoNvram); - pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE; - } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) { - mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO); - pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO; - } } - return; + /* Write SDP1 on this I/O to this target */ + if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) { + ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id)); + mptscsih_writeSDP1(hd, 0, id, hd->negoNvram); + pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE; + } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) { + ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id)); + mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO); + pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO; + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -4437,14 +3620,18 @@ void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byt static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) { u8 cmd; + ScsiCfgData *pSpi; + ddvtprintk((" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n", + pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0])); + if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) return; cmd = pReq->CDB[0]; if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) { - ScsiCfgData *pSpi = &hd->ioc->spi_data; + pSpi = &hd->ioc->spi_data; if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) { /* Set NEED_DV for all hidden disks */ @@ -4510,6 +3697,8 @@ mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT); if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0) *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS; + if (flags & MPT_TAPE_NEGO_IDP) + *requestedPtr |= 0x08000000; } else if (factor < MPT_ULTRA2) { *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT; } @@ -4624,6 +3813,16 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) //negoFlags = MPT_TARGET_NO_NEGO_SYNC; } + /* If id is not a raid volume, get the updated + * transmission settings from the target structure. + */ + if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { + width = pTarget->maxWidth; + factor = pTarget->minSyncFactor; + offset = pTarget->maxOffset; + negoFlags = pTarget->negoFlags; + } + #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION /* Force to async and narrow if DV has not been executed * for this ID @@ -4635,21 +3834,13 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) } #endif - /* If id is not a raid volume, get the updated - * transmission settings from the target structure. - */ - if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { - width = pTarget->maxWidth; - factor = pTarget->minSyncFactor; - offset = pTarget->maxOffset; - negoFlags = pTarget->negoFlags; - } - if (flags & MPT_SCSICFG_BLK_NEGO) negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC; mptscsih_setDevicePage1Flags(width, factor, offset, &requested, &configuration, negoFlags); + dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", + target_id, width, factor, offset, negoFlags, requested, configuration)); /* Get a MF for this command. */ @@ -4754,9 +3945,6 @@ mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus) return -EAGAIN; } - ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n", - ioc->name, mf, target_id)); - /* Set the request and the data pointers. * Place data at end of MF. */ @@ -4793,9 +3981,9 @@ mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus) mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); - dsprintk((MYIOC_s_INFO_FMT - "writeIOCPage4: pgaddr 0x%x\n", - ioc->name, (target_id | (bus<<8)))); + dinitprintk((MYIOC_s_INFO_FMT + "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", + ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus)); mpt_put_msg_frame(ScsiDoneCtx, ioc, mf); @@ -4922,13 +4110,15 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) } else { SCSIIOReply_t *pReply; u16 status; + u8 scsi_status; pReply = (SCSIIOReply_t *) mr; status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_status = pReply->SCSIStatus; ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", - status, pReply->SCSIState, pReply->SCSIStatus, + status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo))); switch(status) { @@ -4973,7 +4163,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) /* save sense data in global structure */ completionCode = MPT_SCANDV_SENSE; - hd->pLocal->scsiStatus = pReply->SCSIStatus; + hd->pLocal->scsiStatus = scsi_status; sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_idx * MPT_SENSE_BUFFER_ALLOC)); @@ -4984,7 +4174,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n", sense_data)); } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { - if (pReq->CDB[0] == CMD_Inquiry) + if (pReq->CDB[0] == INQUIRY) completionCode = MPT_SCANDV_ISSUE_SENSE; else completionCode = MPT_SCANDV_DID_RESET; @@ -4994,11 +4184,8 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) completionCode = MPT_SCANDV_DID_RESET; else { - /* If no error, this will be equivalent - * to MPT_SCANDV_GOOD - */ completionCode = MPT_SCANDV_GOOD; - hd->pLocal->scsiStatus = pReply->SCSIStatus; + hd->pLocal->scsiStatus = scsi_status; } break; @@ -5025,7 +4212,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) */ wakeup: /* Free Chain buffers (will never chain) in scan or dv */ - //mptscsih_freeChainBuffers(hd, req_idx); + //mptscsih_freeChainBuffers(ioc, req_idx); /* * Wake up the original calling thread @@ -5197,7 +4384,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) /* Set command specific information */ switch (cmd) { - case CMD_Inquiry: + case INQUIRY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5205,13 +4392,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) cmdTimeout = 10; break; - case CMD_TestUnitReady: + case TEST_UNIT_READY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; cmdTimeout = 10; break; - case CMD_StartStopUnit: + case START_STOP: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5219,7 +4406,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) cmdTimeout = 15; break; - case CMD_RequestSense: + case REQUEST_SENSE: cmdLen = 6; CDB[0] = cmd; CDB[4] = io->size; @@ -5227,7 +4414,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) cmdTimeout = 10; break; - case CMD_ReadBuffer: + case READ_BUFFER: cmdLen = 10; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5246,7 +4433,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) cmdTimeout = 10; break; - case CMD_WriteBuffer: + case WRITE_BUFFER: cmdLen = 10; dir = MPI_SCSIIO_CONTROL_WRITE; CDB[0] = cmd; @@ -5261,21 +4448,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) cmdTimeout = 10; break; - case CMD_Reserve6: + case RESERVE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; cmdTimeout = 10; break; - case CMD_Release6: + case RELEASE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; cmdTimeout = 10; break; - case CMD_SynchronizeCache: + case SYNCHRONIZE_CACHE: cmdLen = 10; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; @@ -5331,7 +4518,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) else pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); - if (cmd == CMD_RequestSense) { + if (cmd == REQUEST_SENSE) { pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n", hd->ioc->name, cmd)); @@ -5439,7 +4626,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) /* Following parameters will not change * in this routine. */ - iocmd.cmd = CMD_SynchronizeCache; + iocmd.cmd = SYNCHRONIZE_CACHE; iocmd.flags = 0; iocmd.physDiskNum = -1; iocmd.data = NULL; @@ -5509,6 +4696,9 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) /* Force to async, narrow */ mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested, &configuration, flags); + dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC " + "offset=0 negoFlags=%x request=%x config=%x\n", + id, flags, requested, configuration)); pcfg1Data->RequestedParameters = le32_to_cpu(requested); pcfg1Data->Reserved = 0; pcfg1Data->Configuration = le32_to_cpu(configuration); @@ -5597,8 +4787,7 @@ mptscsih_domainValidation(void *arg) } spin_unlock_irqrestore(&dvtaskQ_lock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + msleep(250); /* DV only to SCSI adapters */ if ((int)ioc->chip_type <= (int)FC929) @@ -5646,8 +4835,7 @@ mptscsih_domainValidation(void *arg) hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING; hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + msleep(250); /* If hidden phys disk, block IO's to all * raid volumes @@ -5681,11 +4869,6 @@ mptscsih_domainValidation(void *arg) } } - /* Post OS IOs that were pended while - * DV running. - */ - post_pendingQ_commands(hd); - if (hd->ioc->spi_data.noQas) mptscsih_qas_check(hd, id); } @@ -5741,11 +4924,14 @@ static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id) if ((pTarget != NULL) && (!pTarget->raidVolume)) { if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) { pTarget->negoFlags |= hd->ioc->spi_data.noQas; + dnegoprintk(("writeSDP1: id=%d flags=0\n", id)); mptscsih_writeSDP1(hd, 0, ii, 0); } } else { - if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) + if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) { + dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id)); mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM); + } } } return; @@ -5824,7 +5010,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) lun = 0; bus = (u8) bus_number; ddvtprintk((MYIOC_s_NOTE_FMT - "DV started: bus=%d, id %d dv @ %p\n", + "DV started: bus=%d, id=%d dv @ %p\n", ioc->name, bus, id, &dv)); /* Prep DV structure @@ -5838,8 +5024,6 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) */ dv.cmd = MPT_GET_NVRAM_VALS; mptscsih_dv_parms(hd, &dv, NULL); - if ((!dv.max.width) && (!dv.max.offset)) - return 0; /* Prep SCSI IO structure */ @@ -5851,15 +5035,6 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) iocmd.rsvd = iocmd.rsvd2 = 0; pTarget = hd->Targets[id]; - if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { - /* Another GEM workaround. Check peripheral device type, - * if PROCESSOR, quit DV. - */ - if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) { - pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); - return 0; - } - } /* Use tagged commands if possible. */ @@ -5959,7 +5134,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* Finish iocmd inititialization - hidden or visible disk? */ if (ioc->spi_data.pIocPg3) { - /* Searc IOC page 3 for matching id + /* Search IOC page 3 for matching id */ Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; @@ -6001,7 +5176,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) */ hd->pLocal = NULL; readPage0 = 0; - sz = SCSI_STD_INQUIRY_BYTES; + sz = SCSI_MAX_INQUIRY_BYTES; rc = MPT_SCANDV_GOOD; while (1) { ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id)); @@ -6026,7 +5201,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) ((hd->ioc->facts.FWVersion.Word >= 0x01010000) && (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) { - iocmd.cmd = CMD_RequestSense; + iocmd.cmd = REQUEST_SENSE; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = 0x12; @@ -6046,10 +5221,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) goto target_done; } - iocmd.cmd = CMD_Inquiry; + iocmd.cmd = INQUIRY; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = sz; + memset(pbuf1, 0x00, sz); if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; else { @@ -6057,7 +5233,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) goto target_done; rc = hd->pLocal->completion; if (rc == MPT_SCANDV_GOOD) { - if (hd->pLocal->scsiStatus == STS_BUSY) { + if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) { if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0) retcode = 1; else @@ -6087,7 +5263,17 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* Another GEM workaround. Check peripheral device type, * if PROCESSOR, quit DV. */ - if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08)) + if (inq0 == TYPE_PROCESSOR) { + mptscsih_initTarget(hd, + bus, + id, + lun, + pbuf1, + sz); + goto target_done; + } + + if (inq0 > 0x08) goto target_done; if (mptscsih_do_cmd(hd, &iocmd) < 0) @@ -6111,6 +5297,9 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) if ((pbuf1[56] & 0x02) == 0) { pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; + ddvprintk((MYIOC_s_NOTE_FMT + "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n", + ioc->name, id, pbuf1[56])); } } } @@ -6127,10 +5316,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) if ((!dv.now.width) && (!dv.now.offset)) goto target_done; - iocmd.cmd = CMD_Inquiry; + iocmd.cmd = INQUIRY; iocmd.data_dma = buf2_dma; iocmd.data = pbuf2; iocmd.size = sz; + memset(pbuf2, 0x00, sz); if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; else if (hd->pLocal == NULL) @@ -6183,14 +5373,26 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) if (memcmp(pbuf1, pbuf2, sz) != 0) { if (!firstPass) doFallback = 1; - } else + } else { + ddvprintk((MYIOC_s_NOTE_FMT + "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id)); + hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE; + mptscsih_initTarget(hd, + bus, + id, + lun, + pbuf1, + sz); break; /* test complete */ + } } } else if (rc == MPT_SCANDV_ISSUE_SENSE) doFallback = 1; /* set fallback flag */ - else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE)) + else if ((rc == MPT_SCANDV_DID_RESET) || + (rc == MPT_SCANDV_SENSE) || + (rc == MPT_SCANDV_FALLBACK)) doFallback = 1; /* set fallback flag */ else goto target_done; @@ -6199,6 +5401,10 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } } ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id)); + + if (driver_setup.dv == 0) + goto target_done; + inq0 = (*pbuf1) & 0x1F; /* Continue only for disks @@ -6222,7 +5428,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; - iocmd.cmd = CMD_TestUnitReady; + iocmd.cmd = TEST_UNIT_READY; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6245,14 +5451,14 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, asc, ascq)); - if (skey == SK_UNIT_ATTENTION) + if (skey == UNIT_ATTENTION) notDone++; /* repeat */ - else if ((skey == SK_NOT_READY) && + else if ((skey == NOT_READY) && (asc == 0x04)&&(ascq == 0x01)) { /* wait then repeat */ mdelay (2000); notDone++; - } else if ((skey == SK_NOT_READY) && (asc == 0x3A)) { + } else if ((skey == NOT_READY) && (asc == 0x3A)) { /* no medium, try read test anyway */ notDone = 0; } else { @@ -6266,7 +5472,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) goto target_done; } - iocmd.cmd = CMD_ReadBuffer; + iocmd.cmd = READ_BUFFER; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = 4; @@ -6314,11 +5520,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) ddvprintk((MYIOC_s_INFO_FMT "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, asc, ascq)); - if (skey == SK_ILLEGAL_REQUEST) { + if (skey == ILLEGAL_REQUEST) { notDone = 0; - } else if (skey == SK_UNIT_ATTENTION) { + } else if (skey == UNIT_ATTENTION) { notDone++; /* repeat */ - } else if ((skey == SK_NOT_READY) && + } else if ((skey == NOT_READY) && (asc == 0x04)&&(ascq == 0x01)) { /* wait then repeat */ mdelay (2000); @@ -6373,14 +5579,14 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) for (patt = 0; patt < 4; patt++) { ddvprintk(("Pattern %d\n", patt)); if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) { - iocmd.cmd = CMD_TestUnitReady; + iocmd.cmd = TEST_UNIT_READY; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; - iocmd.cmd = CMD_Release6; + iocmd.cmd = RELEASE; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6402,7 +5608,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) repeat = 5; while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) { - iocmd.cmd = CMD_Reserve6; + iocmd.cmd = RESERVE; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6425,7 +5631,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", skey, asc, ascq)); - if ((skey == SK_NOT_READY) && (asc == 0x04)&& + if ((skey == NOT_READY) && (asc == 0x04)&& (ascq == 0x01)) { /* wait then repeat */ mdelay (2000); @@ -6444,7 +5650,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } mptscsih_fillbuf(pbuf1, sz, patt, 1); - iocmd.cmd = CMD_WriteBuffer; + iocmd.cmd = WRITE_BUFFER; iocmd.data_dma = buf1_dma; iocmd.data = pbuf1; iocmd.size = sz; @@ -6485,10 +5691,10 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) ddvprintk((MYIOC_s_INFO_FMT "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, hd->pLocal->sense[12], hd->pLocal->sense[13])); - if (skey == SK_UNIT_ATTENTION) { + if (skey == UNIT_ATTENTION) { patt = -1; continue; - } else if (skey == SK_ILLEGAL_REQUEST) { + } else if (skey == ILLEGAL_REQUEST) { if (iocmd.flags & MPT_ICFLAG_ECHO) { if (dataBufSize >= bufsize) { iocmd.flags &= ~MPT_ICFLAG_ECHO; @@ -6506,7 +5712,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } } - iocmd.cmd = CMD_ReadBuffer; + iocmd.cmd = READ_BUFFER; iocmd.data_dma = buf2_dma; iocmd.data = pbuf2; iocmd.size = sz; @@ -6581,7 +5787,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) ddvprintk((MYIOC_s_INFO_FMT "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, hd->pLocal->sense[12], hd->pLocal->sense[13])); - if (skey == SK_UNIT_ATTENTION) { + if (skey == UNIT_ATTENTION) { patt = -1; continue; } @@ -6597,7 +5803,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) target_done: if (iocmd.flags & MPT_ICFLAG_RESERVED) { - iocmd.cmd = CMD_Release6; + iocmd.cmd = RELEASE; iocmd.data_dma = -1; iocmd.data = NULL; iocmd.size = 0; @@ -6619,8 +5825,11 @@ target_done: if ((cfg.hdr != NULL) && (retcode == 0)){ /* If disk, not U320, disable QAS */ - if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) + if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) { hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; + ddvprintk((MYIOC_s_NOTE_FMT + "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor)); + } dv.cmd = MPT_SAVE; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); @@ -6649,8 +5858,8 @@ target_done: if (pDvBuf) pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma); - ddvtprintk((MYIOC_s_INFO_FMT "DV Done.\n", - ioc->name)); + ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n", + ioc->name, id)); return retcode; } @@ -6730,8 +5939,8 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) dv->max.offset = offset; dv->max.factor = factor; dv->max.flags = negoFlags; - ddvprintk((" width %d, factor %x, offset %x flags %x\n", - width, factor, offset, negoFlags)); + ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n", + id, width, factor, offset, negoFlags)); break; case MPT_UPDATE_MAX: @@ -6749,8 +5958,8 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) dv->now.width = dv->max.width; dv->now.offset = dv->max.offset; dv->now.factor = dv->max.factor; - ddvprintk(("width %d, factor %x, offset %x, flags %x\n", - dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); + ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); break; case MPT_SET_MAX: @@ -6766,14 +5975,15 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) if (pPage1) { mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor, dv->now.offset, &val, &configuration, dv->now.flags); + dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration)); pPage1->RequestedParameters = le32_to_cpu(val); pPage1->Reserved = 0; pPage1->Configuration = le32_to_cpu(configuration); - } - ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n", - dv->now.width, dv->now.factor, dv->now.offset, val, configuration)); + ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x request=%x configuration=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration)); break; case MPT_SET_MIN: @@ -6790,12 +6000,14 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) if (pPage1) { mptscsih_setDevicePage1Flags (width, factor, offset, &val, &configuration, negoFlags); + dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", + id, width, factor, offset, negoFlags, val, configuration)); pPage1->RequestedParameters = le32_to_cpu(val); pPage1->Reserved = 0; pPage1->Configuration = le32_to_cpu(configuration); } - ddvprintk(("width %d, factor %x, offset %x request %x config %x\n", - width, factor, offset, val, configuration)); + ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n", + id, width, factor, offset, val, configuration, negoFlags)); break; case MPT_FALLBACK: @@ -6855,6 +6067,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) factor = MPT_ASYNC; } dv->max.flags |= MPT_TARGET_NO_NEGO_QAS; + dv->max.flags &= ~MPT_TAPE_NEGO_IDP; dv->now.width = width; dv->now.offset = offset; @@ -6865,21 +6078,23 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) if (pPage1) { mptscsih_setDevicePage1Flags (width, factor, offset, &val, &configuration, dv->now.flags); + dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x flags=%x request=%x config=%x\n", + id, width, offset, factor, dv->now.flags, val, configuration)); pPage1->RequestedParameters = le32_to_cpu(val); pPage1->Reserved = 0; pPage1->Configuration = le32_to_cpu(configuration); } - ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n", - dv->now.offset, dv->now.factor, dv->now.width, val, configuration)); + ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n", + id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration)); break; case MPT_SAVE: ddvprintk((MYIOC_s_NOTE_FMT "Saving to Target structure: ", hd->ioc->name)); - ddvprintk(("offset %d, factor %x, width %d \n", - dv->now.offset, dv->now.factor, dv->now.width)); + ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n", + id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); /* Save these values to target structures * or overwrite nvram (phys disks only). diff --git a/drivers/message/i2o/Makefile b/drivers/message/i2o/Makefile index e3169dbd9..aabc6cdc3 100644 --- a/drivers/message/i2o/Makefile +++ b/drivers/message/i2o/Makefile @@ -5,6 +5,7 @@ # In the future, some of these should be built conditionally. # +i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o obj-$(CONFIG_I2O) += i2o_core.o obj-$(CONFIG_I2O_CONFIG)+= i2o_config.o obj-$(CONFIG_I2O_BLOCK) += i2o_block.o diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c new file mode 100644 index 000000000..7227a8a1e --- /dev/null +++ b/drivers/message/i2o/debug.c @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include + +static int verbose; +extern struct i2o_driver **i2o_drivers; +extern unsigned int i2o_max_drivers; +static void i2o_report_util_cmd(u8 cmd); +static void i2o_report_exec_cmd(u8 cmd); +void i2o_report_fail_status(u8 req_status, u32 * msg); +void i2o_report_common_status(u8 req_status); +static void i2o_report_common_dsc(u16 detailed_status); + +void i2o_dump_status_block(i2o_status_block * sb) +{ + pr_debug("Organization ID: %d\n", sb->org_id); + pr_debug("IOP ID: %d\n", sb->iop_id); + pr_debug("Host Unit ID: %d\n", sb->host_unit_id); + pr_debug("Segment Number: %d\n", sb->segment_number); + pr_debug("I2O Version: %d\n", sb->i2o_version); + pr_debug("IOP State: %d\n", sb->iop_state); + pr_debug("Messanger Type: %d\n", sb->msg_type); + pr_debug("Inbound Frame Size: %d\n", sb->inbound_frame_size); + pr_debug("Init Code: %d\n", sb->init_code); + pr_debug("Max Inbound MFrames: %d\n", sb->max_inbound_frames); + pr_debug("Current Inbound MFrames: %d\n", sb->cur_inbound_frames); + pr_debug("Max Outbound MFrames: %d\n", sb->max_outbound_frames); + pr_debug("Product ID String: %s\n", sb->product_id); + pr_debug("Expected LCT Size: %d\n", sb->expected_lct_size); + pr_debug("IOP Capabilities: %d\n", sb->iop_capabilities); + pr_debug("Desired Private MemSize: %d\n", sb->desired_mem_size); + pr_debug("Current Private MemSize: %d\n", sb->current_mem_size); + pr_debug("Current Private MemBase: %d\n", sb->current_mem_base); + pr_debug("Desired Private IO Size: %d\n", sb->desired_io_size); + pr_debug("Current Private IO Size: %d\n", sb->current_io_size); + pr_debug("Current Private IO Base: %d\n", sb->current_io_base); +}; + +/* + * Used for error reporting/debugging purposes. + * Report Cmd name, Request status, Detailed Status. + */ +void i2o_report_status(const char *severity, const char *str, + struct i2o_message *m) +{ + u32 *msg = (u32 *) m; + u8 cmd = (msg[1] >> 24) & 0xFF; + u8 req_status = (msg[4] >> 24) & 0xFF; + u16 detailed_status = msg[4] & 0xFFFF; + //struct i2o_driver *h = i2o_drivers[msg[2] & (i2o_max_drivers-1)]; + + if (cmd == I2O_CMD_UTIL_EVT_REGISTER) + return; // No status in this reply + + printk("%s%s: ", severity, str); + + if (cmd < 0x1F) // Utility cmd + i2o_report_util_cmd(cmd); + + else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd + i2o_report_exec_cmd(cmd); + else + printk("Cmd = %0#2x, ", cmd); // Other cmds + + if (msg[0] & MSG_FAIL) { + i2o_report_fail_status(req_status, msg); + return; + } + + i2o_report_common_status(req_status); + + if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF)) + i2o_report_common_dsc(detailed_status); + else + printk(" / DetailedStatus = %0#4x.\n", detailed_status); +} + +/* Used to dump a message to syslog during debugging */ +void i2o_dump_message(struct i2o_message *m) +{ +#ifdef DEBUG + u32 *msg = (u32 *) m; + int i; + printk(KERN_INFO "Dumping I2O message size %d @ %p\n", + msg[0] >> 16 & 0xffff, msg); + for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++) + printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]); +#endif +} + +/** + * i2o_report_controller_unit - print information about a tid + * @c: controller + * @d: device + * + * Dump an information block associated with a given unit (TID). The + * tables are read and a block of text is output to printk that is + * formatted intended for the user. + */ + +void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) +{ + char buf[64]; + char str[22]; + int ret; + + if (verbose == 0) + return; + + printk(KERN_INFO "Target ID %03x.\n", d->lct_data.tid); + if ((ret = i2o_parm_field_get(d, 0xF100, 3, buf, 16)) >= 0) { + buf[16] = 0; + printk(KERN_INFO " Vendor: %s\n", buf); + } + if ((ret = i2o_parm_field_get(d, 0xF100, 4, buf, 16)) >= 0) { + buf[16] = 0; + printk(KERN_INFO " Device: %s\n", buf); + } + if (i2o_parm_field_get(d, 0xF100, 5, buf, 16) >= 0) { + buf[16] = 0; + printk(KERN_INFO " Description: %s\n", buf); + } + if ((ret = i2o_parm_field_get(d, 0xF100, 6, buf, 8)) >= 0) { + buf[8] = 0; + printk(KERN_INFO " Rev: %s\n", buf); + } + + printk(KERN_INFO " Class: "); + //sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id)); + printk("%s\n", str); + + printk(KERN_INFO " Subclass: 0x%04X\n", d->lct_data.sub_class); + printk(KERN_INFO " Flags: "); + + if (d->lct_data.device_flags & (1 << 0)) + printk("C"); // ConfigDialog requested + if (d->lct_data.device_flags & (1 << 1)) + printk("U"); // Multi-user capable + if (!(d->lct_data.device_flags & (1 << 4))) + printk("P"); // Peer service enabled! + if (!(d->lct_data.device_flags & (1 << 5))) + printk("M"); // Mgmt service enabled! + printk("\n"); +} + +/* +MODULE_PARM(verbose, "i"); +MODULE_PARM_DESC(verbose, "Verbose diagnostics"); +*/ +/* + * Used for error reporting/debugging purposes. + * Following fail status are common to all classes. + * The preserved message must be handled in the reply handler. + */ +void i2o_report_fail_status(u8 req_status, u32 * msg) +{ + static char *FAIL_STATUS[] = { + "0x80", /* not used */ + "SERVICE_SUSPENDED", /* 0x81 */ + "SERVICE_TERMINATED", /* 0x82 */ + "CONGESTION", + "FAILURE", + "STATE_ERROR", + "TIME_OUT", + "ROUTING_FAILURE", + "INVALID_VERSION", + "INVALID_OFFSET", + "INVALID_MSG_FLAGS", + "FRAME_TOO_SMALL", + "FRAME_TOO_LARGE", + "INVALID_TARGET_ID", + "INVALID_INITIATOR_ID", + "INVALID_INITIATOR_CONTEX", /* 0x8F */ + "UNKNOWN_FAILURE" /* 0xFF */ + }; + + if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) + printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status); + else + printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]); + + /* Dump some details */ + + printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n", + (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); + printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n", + (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); + printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n", + msg[5] >> 16, msg[5] & 0xFFF); + + printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF); + if (msg[4] & (1 << 16)) + printk("(FormatError), " + "this msg can never be delivered/processed.\n"); + if (msg[4] & (1 << 17)) + printk("(PathError), " + "this msg can no longer be delivered/processed.\n"); + if (msg[4] & (1 << 18)) + printk("(PathState), " + "the system state does not allow delivery.\n"); + if (msg[4] & (1 << 19)) + printk("(Congestion), resources temporarily not available;" + "do not retry immediately.\n"); +} + +/* + * Used for error reporting/debugging purposes. + * Following reply status are common to all classes. + */ +void i2o_report_common_status(u8 req_status) +{ + static char *REPLY_STATUS[] = { + "SUCCESS", + "ABORT_DIRTY", + "ABORT_NO_DATA_TRANSFER", + "ABORT_PARTIAL_TRANSFER", + "ERROR_DIRTY", + "ERROR_NO_DATA_TRANSFER", + "ERROR_PARTIAL_TRANSFER", + "PROCESS_ABORT_DIRTY", + "PROCESS_ABORT_NO_DATA_TRANSFER", + "PROCESS_ABORT_PARTIAL_TRANSFER", + "TRANSACTION_ERROR", + "PROGRESS_REPORT" + }; + + if (req_status >= ARRAY_SIZE(REPLY_STATUS)) + printk("RequestStatus = %0#2x", req_status); + else + printk("%s", REPLY_STATUS[req_status]); +} + +/* + * Used for error reporting/debugging purposes. + * Following detailed status are valid for executive class, + * utility class, DDM class and for transaction error replies. + */ +static void i2o_report_common_dsc(u16 detailed_status) +{ + static char *COMMON_DSC[] = { + "SUCCESS", + "0x01", // not used + "BAD_KEY", + "TCL_ERROR", + "REPLY_BUFFER_FULL", + "NO_SUCH_PAGE", + "INSUFFICIENT_RESOURCE_SOFT", + "INSUFFICIENT_RESOURCE_HARD", + "0x08", // not used + "CHAIN_BUFFER_TOO_LARGE", + "UNSUPPORTED_FUNCTION", + "DEVICE_LOCKED", + "DEVICE_RESET", + "INAPPROPRIATE_FUNCTION", + "INVALID_INITIATOR_ADDRESS", + "INVALID_MESSAGE_FLAGS", + "INVALID_OFFSET", + "INVALID_PARAMETER", + "INVALID_REQUEST", + "INVALID_TARGET_ADDRESS", + "MESSAGE_TOO_LARGE", + "MESSAGE_TOO_SMALL", + "MISSING_PARAMETER", + "TIMEOUT", + "UNKNOWN_ERROR", + "UNKNOWN_FUNCTION", + "UNSUPPORTED_VERSION", + "DEVICE_BUSY", + "DEVICE_NOT_AVAILABLE" + }; + + if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE) + printk(" / DetailedStatus = %0#4x.\n", detailed_status); + else + printk(" / %s.\n", COMMON_DSC[detailed_status]); +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_util_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_UTIL_NOP: + printk("UTIL_NOP, "); + break; + case I2O_CMD_UTIL_ABORT: + printk("UTIL_ABORT, "); + break; + case I2O_CMD_UTIL_CLAIM: + printk("UTIL_CLAIM, "); + break; + case I2O_CMD_UTIL_RELEASE: + printk("UTIL_CLAIM_RELEASE, "); + break; + case I2O_CMD_UTIL_CONFIG_DIALOG: + printk("UTIL_CONFIG_DIALOG, "); + break; + case I2O_CMD_UTIL_DEVICE_RESERVE: + printk("UTIL_DEVICE_RESERVE, "); + break; + case I2O_CMD_UTIL_DEVICE_RELEASE: + printk("UTIL_DEVICE_RELEASE, "); + break; + case I2O_CMD_UTIL_EVT_ACK: + printk("UTIL_EVENT_ACKNOWLEDGE, "); + break; + case I2O_CMD_UTIL_EVT_REGISTER: + printk("UTIL_EVENT_REGISTER, "); + break; + case I2O_CMD_UTIL_LOCK: + printk("UTIL_LOCK, "); + break; + case I2O_CMD_UTIL_LOCK_RELEASE: + printk("UTIL_LOCK_RELEASE, "); + break; + case I2O_CMD_UTIL_PARAMS_GET: + printk("UTIL_PARAMS_GET, "); + break; + case I2O_CMD_UTIL_PARAMS_SET: + printk("UTIL_PARAMS_SET, "); + break; + case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: + printk("UTIL_REPLY_FAULT_NOTIFY, "); + break; + default: + printk("Cmd = %0#2x, ", cmd); + } +} + +/* + * Used for error reporting/debugging purposes + */ +static void i2o_report_exec_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_ADAPTER_ASSIGN: + printk("EXEC_ADAPTER_ASSIGN, "); + break; + case I2O_CMD_ADAPTER_READ: + printk("EXEC_ADAPTER_READ, "); + break; + case I2O_CMD_ADAPTER_RELEASE: + printk("EXEC_ADAPTER_RELEASE, "); + break; + case I2O_CMD_BIOS_INFO_SET: + printk("EXEC_BIOS_INFO_SET, "); + break; + case I2O_CMD_BOOT_DEVICE_SET: + printk("EXEC_BOOT_DEVICE_SET, "); + break; + case I2O_CMD_CONFIG_VALIDATE: + printk("EXEC_CONFIG_VALIDATE, "); + break; + case I2O_CMD_CONN_SETUP: + printk("EXEC_CONN_SETUP, "); + break; + case I2O_CMD_DDM_DESTROY: + printk("EXEC_DDM_DESTROY, "); + break; + case I2O_CMD_DDM_ENABLE: + printk("EXEC_DDM_ENABLE, "); + break; + case I2O_CMD_DDM_QUIESCE: + printk("EXEC_DDM_QUIESCE, "); + break; + case I2O_CMD_DDM_RESET: + printk("EXEC_DDM_RESET, "); + break; + case I2O_CMD_DDM_SUSPEND: + printk("EXEC_DDM_SUSPEND, "); + break; + case I2O_CMD_DEVICE_ASSIGN: + printk("EXEC_DEVICE_ASSIGN, "); + break; + case I2O_CMD_DEVICE_RELEASE: + printk("EXEC_DEVICE_RELEASE, "); + break; + case I2O_CMD_HRT_GET: + printk("EXEC_HRT_GET, "); + break; + case I2O_CMD_ADAPTER_CLEAR: + printk("EXEC_IOP_CLEAR, "); + break; + case I2O_CMD_ADAPTER_CONNECT: + printk("EXEC_IOP_CONNECT, "); + break; + case I2O_CMD_ADAPTER_RESET: + printk("EXEC_IOP_RESET, "); + break; + case I2O_CMD_LCT_NOTIFY: + printk("EXEC_LCT_NOTIFY, "); + break; + case I2O_CMD_OUTBOUND_INIT: + printk("EXEC_OUTBOUND_INIT, "); + break; + case I2O_CMD_PATH_ENABLE: + printk("EXEC_PATH_ENABLE, "); + break; + case I2O_CMD_PATH_QUIESCE: + printk("EXEC_PATH_QUIESCE, "); + break; + case I2O_CMD_PATH_RESET: + printk("EXEC_PATH_RESET, "); + break; + case I2O_CMD_STATIC_MF_CREATE: + printk("EXEC_STATIC_MF_CREATE, "); + break; + case I2O_CMD_STATIC_MF_RELEASE: + printk("EXEC_STATIC_MF_RELEASE, "); + break; + case I2O_CMD_STATUS_GET: + printk("EXEC_STATUS_GET, "); + break; + case I2O_CMD_SW_DOWNLOAD: + printk("EXEC_SW_DOWNLOAD, "); + break; + case I2O_CMD_SW_UPLOAD: + printk("EXEC_SW_UPLOAD, "); + break; + case I2O_CMD_SW_REMOVE: + printk("EXEC_SW_REMOVE, "); + break; + case I2O_CMD_SYS_ENABLE: + printk("EXEC_SYS_ENABLE, "); + break; + case I2O_CMD_SYS_MODIFY: + printk("EXEC_SYS_MODIFY, "); + break; + case I2O_CMD_SYS_QUIESCE: + printk("EXEC_SYS_QUIESCE, "); + break; + case I2O_CMD_SYS_TAB_SET: + printk("EXEC_SYS_TAB_SET, "); + break; + default: + printk("Cmd = %#02x, ", cmd); + } +} + +void i2o_debug_state(struct i2o_controller *c) +{ + printk(KERN_INFO "%s: State = ", c->name); + switch (((i2o_status_block *) c->status_block.virt)->iop_state) { + case 0x01: + printk("INIT\n"); + break; + case 0x02: + printk("RESET\n"); + break; + case 0x04: + printk("HOLD\n"); + break; + case 0x05: + printk("READY\n"); + break; + case 0x08: + printk("OPERATIONAL\n"); + break; + case 0x10: + printk("FAILED\n"); + break; + case 0x11: + printk("FAULTED\n"); + break; + default: + printk("%x (unknown !!)\n", + ((i2o_status_block *) c->status_block.virt)->iop_state); + } +}; + +void i2o_systab_debug(struct i2o_sys_tbl *sys_tbl) +{ + u32 *table; + int count; + u32 size; + + table = (u32 *) sys_tbl; + size = sizeof(struct i2o_sys_tbl) + sys_tbl->num_entries + * sizeof(struct i2o_sys_tbl_entry); + + for (count = 0; count < (size >> 2); count++) + printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); +} + +void i2o_dump_hrt(struct i2o_controller *c) +{ + u32 *rows = (u32 *) c->hrt.virt; + u8 *p = (u8 *) c->hrt.virt; + u8 *d; + int count; + int length; + int i; + int state; + + if (p[3] != 0) { + printk(KERN_ERR + "%s: HRT table for controller is too new a version.\n", + c->name); + return; + } + + count = p[0] | (p[1] << 8); + length = p[2]; + + printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n", + c->name, count, length << 2); + + rows += 2; + + for (i = 0; i < count; i++) { + printk(KERN_INFO "Adapter %08X: ", rows[0]); + p = (u8 *) (rows + 1); + d = (u8 *) (rows + 2); + state = p[1] << 8 | p[0]; + + printk("TID %04X:[", state & 0xFFF); + state >>= 12; + if (state & (1 << 0)) + printk("H"); /* Hidden */ + if (state & (1 << 2)) { + printk("P"); /* Present */ + if (state & (1 << 1)) + printk("C"); /* Controlled */ + } + if (state > 9) + printk("*"); /* Hard */ + + printk("]:"); + + switch (p[3] & 0xFFFF) { + case 0: + /* Adapter private bus - easy */ + printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", + p[2], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + case 1: + /* ISA bus */ + printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", + p[2], d[2], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + + case 2: /* EISA bus */ + printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + + case 3: /* MCA bus */ + printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4)); + break; + + case 4: /* PCI bus */ + printk("PCI %d: Bus %d Device %d Function %d", + p[2], d[2], d[1], d[0]); + break; + + case 0x80: /* Other */ + default: + printk("Unsupported bus type."); + break; + } + printk("\n"); + rows += length; + } +} + +EXPORT_SYMBOL(i2o_dump_status_block); +EXPORT_SYMBOL(i2o_dump_message); diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c new file mode 100644 index 000000000..ff4822ed4 --- /dev/null +++ b/drivers/message/i2o/device.c @@ -0,0 +1,674 @@ +/* + * Functions to handle I2O devices + * + * Copyright (C) 2004 Markus Lidel + * + * 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. + * + * Fixes/additions: + * Markus Lidel + * initial version. + */ + +#include +#include + +/* Exec OSM functions */ +extern struct bus_type i2o_bus_type; + +/** + * i2o_device_issue_claim - claim or release a device + * @dev: I2O device to claim or release + * @cmd: claim or release command + * @type: type of claim + * + * Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent + * is set by cmd. dev is the I2O device which should be claim or + * released and the type is the claim type (see the I2O spec). + * + * Returs 0 on success or negative error code on failure. + */ +static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, + u32 type) +{ + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); + writel(type, &msg->body[0]); + + return i2o_msg_post_wait(dev->iop, m, 60); +}; + +/** + * i2o_device_claim - claim a device for use by an OSM + * @dev: I2O device to claim + * @drv: I2O driver which wants to claim the device + * + * Do the leg work to assign a device to a given OSM. If the claim succeed + * the owner of the rimary. If the attempt fails a negative errno code + * is returned. On success zero is returned. + */ +int i2o_device_claim(struct i2o_device *dev) +{ + int rc = 0; + + down(&dev->lock); + + rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY); + if (!rc) + pr_debug("claim of device %d succeded\n", dev->lct_data.tid); + else + pr_debug("claim of device %d failed %d\n", dev->lct_data.tid, + rc); + + up(&dev->lock); + + return rc; +}; + +/** + * i2o_device_claim_release - release a device that the OSM is using + * @dev: device to release + * @drv: driver which claimed the device + * + * Drop a claim by an OSM on a given I2O device. + * + * AC - some devices seem to want to refuse an unclaim until they have + * finished internal processing. It makes sense since you don't want a + * new device to go reconfiguring the entire system until you are done. + * Thus we are prepared to wait briefly. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_device_claim_release(struct i2o_device *dev) +{ + int tries; + int rc = 0; + + down(&dev->lock); + + /* + * If the controller takes a nonblocking approach to + * releases we have to sleep/poll for a few times. + */ + for (tries = 0; tries < 10; tries++) { + rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE, + I2O_CLAIM_PRIMARY); + if (!rc) + break; + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } + + if (!rc) + pr_debug("claim release of device %d succeded\n", + dev->lct_data.tid); + else + pr_debug("claim release of device %d failed %d\n", + dev->lct_data.tid, rc); + + up(&dev->lock); + + return rc; +}; + +/** + * i2o_device_release - release the memory for a I2O device + * @dev: I2O device which should be released + * + * Release the allocated memory. This function is called if refcount of + * device reaches 0 automatically. + */ +static void i2o_device_release(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + + pr_debug("Release I2O device %s\n", dev->bus_id); + + kfree(i2o_dev); +}; + +/** + * i2o_device_class_release - Remove I2O device attributes + * @cd: I2O class device which is added to the I2O device class + * + * Removes attributes from the I2O device again. Also search each device + * on the controller for I2O devices which refert to this device as parent + * or user and remove this links also. + */ +static void i2o_device_class_release(struct class_device *cd) +{ + struct i2o_device *i2o_dev, *tmp; + struct i2o_controller *c; + + i2o_dev = to_i2o_device(cd->dev); + c = i2o_dev->iop; + + sysfs_remove_link(&i2o_dev->device.kobj, "parent"); + sysfs_remove_link(&i2o_dev->device.kobj, "user"); + + list_for_each_entry(tmp, &c->devices, list) { + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "parent"); + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "user"); + } +}; + +/* I2O device class */ +static struct class i2o_device_class = { + .name = "i2o_device", + .release = i2o_device_class_release +}; + +/** + * i2o_device_alloc - Allocate a I2O device and initialize it + * + * Allocate the memory for a I2O device and initialize locks and lists + * + * Returns the allocated I2O device or a negative error code if the device + * could not be allocated. + */ +static struct i2o_device *i2o_device_alloc(void) +{ + struct i2o_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + memset(dev, 0, sizeof(*dev)); + + INIT_LIST_HEAD(&dev->list); + init_MUTEX(&dev->lock); + + dev->device.bus = &i2o_bus_type; + dev->device.release = &i2o_device_release; + dev->classdev.class = &i2o_device_class; + dev->classdev.dev = &dev->device; + + return dev; +}; + +/** + * i2o_device_add - allocate a new I2O device and add it to the IOP + * @iop: I2O controller where the device is on + * @entry: LCT entry of the I2O device + * + * Allocate a new I2O device and initialize it with the LCT entry. The + * device is appended to the device list of the controller. + * + * Returns a pointer to the I2O device on success or negative error code + * on failure. + */ +struct i2o_device *i2o_device_add(struct i2o_controller *c, + i2o_lct_entry * entry) +{ + struct i2o_device *dev; + + dev = i2o_device_alloc(); + if (IS_ERR(dev)) { + printk(KERN_ERR "i2o: unable to allocate i2o device\n"); + return dev; + } + + dev->lct_data = *entry; + + snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, + dev->lct_data.tid); + + snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit, + dev->lct_data.tid); + + dev->iop = c; + dev->device.parent = &c->device; + + device_register(&dev->device); + + list_add_tail(&dev->list, &c->devices); + + class_device_register(&dev->classdev); + + i2o_driver_notify_device_add_all(dev); + + pr_debug("I2O device %s added\n", dev->device.bus_id); + + return dev; +}; + +/** + * i2o_device_remove - remove an I2O device from the I2O core + * @dev: I2O device which should be released + * + * Is used on I2O controller removal or LCT modification, when the device + * is removed from the system. Note that the device could still hang + * around until the refcount reaches 0. + */ +void i2o_device_remove(struct i2o_device *i2o_dev) +{ + i2o_driver_notify_device_remove_all(i2o_dev); + class_device_unregister(&i2o_dev->classdev); + list_del(&i2o_dev->list); + device_unregister(&i2o_dev->device); +}; + +/** + * i2o_device_parse_lct - Parse a previously fetched LCT and create devices + * @c: I2O controller from which the LCT should be parsed. + * + * The Logical Configuration Table tells us what we can talk to on the + * board. For every entry we create an I2O device, which is registered in + * the I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_device_parse_lct(struct i2o_controller *c) +{ + struct i2o_device *dev, *tmp; + i2o_lct *lct; + int i; + int max; + + down(&c->lct_lock); + + if (c->lct) + kfree(c->lct); + + lct = c->dlct.virt; + + c->lct = kmalloc(lct->table_size * 4, GFP_KERNEL); + if (!c->lct) { + up(&c->lct_lock); + return -ENOMEM; + } + + if (lct->table_size * 4 > c->dlct.len) { + memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len); + up(&c->lct_lock); + return -EAGAIN; + } + + memcpy_fromio(c->lct, c->dlct.virt, lct->table_size * 4); + + lct = c->lct; + + max = (lct->table_size - 3) / 9; + + pr_debug("LCT has %d entries (LCT size: %d)\n", max, lct->table_size); + + /* remove devices, which are not in the LCT anymore */ + list_for_each_entry_safe(dev, tmp, &c->devices, list) { + int found = 0; + + for (i = 0; i < max; i++) { + if (lct->lct_entry[i].tid == dev->lct_data.tid) { + found = 1; + break; + } + } + + if (!found) + i2o_device_remove(dev); + } + + /* add new devices, which are new in the LCT */ + for (i = 0; i < max; i++) { + int found = 0; + + list_for_each_entry_safe(dev, tmp, &c->devices, list) { + if (lct->lct_entry[i].tid == dev->lct_data.tid) { + found = 1; + break; + } + } + + if (!found) + i2o_device_add(c, &lct->lct_entry[i]); + } + up(&c->lct_lock); + + return 0; +}; + +/** + * i2o_device_class_show_class_id - Displays class id of I2O device + * @cd: class device of which the class id should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_class_show_class_id(struct class_device *cd, + char *buf) +{ + struct i2o_device *dev = to_i2o_device(cd->dev); + + sprintf(buf, "%03x\n", dev->lct_data.class_id); + return strlen(buf) + 1; +}; + +/** + * i2o_device_class_show_tid - Displays TID of I2O device + * @cd: class device of which the TID should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) +{ + struct i2o_device *dev = to_i2o_device(cd->dev); + + sprintf(buf, "%03x\n", dev->lct_data.tid); + return strlen(buf) + 1; +}; + +/* I2O device class attributes */ +static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, + NULL); +static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL); + +/** + * i2o_device_class_add - Adds attributes to the I2O device + * @cd: I2O class device which is added to the I2O device class + * + * This function get called when a I2O device is added to the class. It + * creates the attributes for each device and creates user/parent symlink + * if necessary. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_device_class_add(struct class_device *cd) +{ + struct i2o_device *i2o_dev, *tmp; + struct i2o_controller *c; + + i2o_dev = to_i2o_device(cd->dev); + c = i2o_dev->iop; + + class_device_create_file(cd, &class_device_attr_class_id); + class_device_create_file(cd, &class_device_attr_tid); + + /* create user entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); + if (tmp) + sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, + "user"); + + /* create user entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "user"); + + /* create parent entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); + if (tmp) + sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, + "parent"); + + /* create parent entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "parent"); + + return 0; +}; + +/* I2O device class interface */ +static struct class_interface i2o_device_class_interface = { + .class = &i2o_device_class, + .add = i2o_device_class_add +}; + +/* + * Run time support routines + */ + +/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET + * + * This function can be used for all UtilParamsGet/Set operations. + * The OperationList is given in oplist-buffer, + * and results are returned in reslist-buffer. + * Note that the minimum sized reslist is 8 bytes and contains + * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. + */ + +int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist, + int oplen, void *reslist, int reslen) +{ + struct i2o_message *msg; + u32 m; + u32 *res32 = (u32 *) reslist; + u32 *restmp = (u32 *) reslist; + int len = 0; + int i = 0; + int rc; + struct i2o_dma res; + struct i2o_controller *c = i2o_dev->iop; + struct device *dev = &c->pdev->dev; + + res.virt = NULL; + + if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL)) + return -ENOMEM; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) { + i2o_dma_free(dev, &res); + return -ETIMEDOUT; + } + + i = 0; + writel(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid, + &msg->u.head[1]); + writel(0, &msg->body[i++]); + writel(0x4C000000 | oplen, &msg->body[i++]); /* OperationList */ + memcpy_toio(&msg->body[i], oplist, oplen); + i += (oplen / 4 + (oplen % 4 ? 1 : 0)); + writel(0xD0000000 | res.len, &msg->body[i++]); /* ResultList */ + writel(res.phys, &msg->body[i++]); + + writel(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) | + SGL_OFFSET_5, &msg->u.head[0]); + + rc = i2o_msg_post_wait_mem(c, m, 10, &res); + + /* This only looks like a memory leak - don't "fix" it. */ + if (rc == -ETIMEDOUT) + return rc; + + memcpy_fromio(reslist, res.virt, res.len); + i2o_dma_free(dev, &res); + + /* Query failed */ + if (rc) + return rc; + /* + * Calculate number of bytes of Result LIST + * We need to loop through each Result BLOCK and grab the length + */ + restmp = res32 + 1; + len = 1; + for (i = 0; i < (res32[0] & 0X0000FFFF); i++) { + if (restmp[0] & 0x00FF0000) { /* BlockStatus != SUCCESS */ + printk(KERN_WARNING + "%s - Error:\n ErrorInfoSize = 0x%02x, " + "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", + (cmd == + I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" : + "PARAMS_GET", res32[1] >> 24, + (res32[1] >> 16) & 0xFF, res32[1] & 0xFFFF); + + /* + * If this is the only request,than we return an error + */ + if ((res32[0] & 0x0000FFFF) == 1) { + return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */ + } + } + len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ + restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ + } + return (len << 2); /* bytes used by result list */ +} + +/* + * Query one field group value or a whole scalar group. + */ +int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field, + void *buf, int buflen) +{ + u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; + u8 resblk[8 + buflen]; /* 8 bytes for header */ + int size; + + if (field == -1) /* whole group */ + opblk[4] = -1; + + size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk, + sizeof(opblk), resblk, sizeof(resblk)); + + memcpy(buf, resblk + 8, buflen); /* cut off header */ + + if (size > buflen) + return buflen; + + return size; +} + +/* + * Set a scalar group value or a whole group. + */ +int i2o_parm_field_set(struct i2o_device *i2o_dev, int group, int field, + void *buf, int buflen) +{ + u16 *opblk; + u8 resblk[8 + buflen]; /* 8 bytes for header */ + int size; + + opblk = kmalloc(buflen + 64, GFP_KERNEL); + if (opblk == NULL) { + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_FIELD_SET; + opblk[3] = group; + + if (field == -1) { /* whole group */ + opblk[4] = -1; + memcpy(opblk + 5, buf, buflen); + } else { /* single field */ + + opblk[4] = 1; + opblk[5] = field; + memcpy(opblk + 6, buf, buflen); + } + + size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_SET, opblk, + 12 + buflen, resblk, sizeof(resblk)); + + kfree(opblk); + if (size > buflen) + return buflen; + + return size; +} + +/* + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields + * ibuf and ibuflen are unused (use NULL, 0) + * else return specific fields + * ibuf contains fieldindexes + * + * if oper == I2O_PARAMS_LIST_GET, get from specific rows + * if fieldcount == -1 return all fields + * ibuf contains rowcount, keyvalues + * else return specific fields + * fieldcount is # of fieldindexes + * ibuf contains fieldindexes, rowcount, keyvalues + * + * You could also use directly function i2o_issue_params(). + */ +int i2o_parm_table_get(struct i2o_device *dev, int oper, int group, + int fieldcount, void *ibuf, int ibuflen, void *resblk, + int reslen) +{ + u16 *opblk; + int size; + + size = 10 + ibuflen; + if (size % 4) + size += 4 - size % 4; + + opblk = kmalloc(size, GFP_KERNEL); + if (opblk == NULL) { + printk(KERN_ERR "i2o: no memory for query buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = oper; + opblk[3] = group; + opblk[4] = fieldcount; + memcpy(opblk + 5, ibuf, ibuflen); /* other params */ + + size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk, + size, resblk, reslen); + + kfree(opblk); + if (size > reslen) + return reslen; + + return size; +} + +/** + * i2o_device_init - Initialize I2O devices + * + * Registers the I2O device class. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_device_init(void) +{ + int rc; + + rc = class_register(&i2o_device_class); + if (rc) + return rc; + + return class_interface_register(&i2o_device_class_interface); +}; + +/** + * i2o_device_exit - I2O devices exit function + * + * Unregisters the I2O device class. + */ +void i2o_device_exit(void) +{ + class_interface_register(&i2o_device_class_interface); + class_unregister(&i2o_device_class); +}; + +EXPORT_SYMBOL(i2o_device_claim); +EXPORT_SYMBOL(i2o_device_claim_release); +EXPORT_SYMBOL(i2o_parm_field_get); +EXPORT_SYMBOL(i2o_parm_field_set); +EXPORT_SYMBOL(i2o_parm_table_get); +EXPORT_SYMBOL(i2o_parm_issue); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c new file mode 100644 index 000000000..bc69d66c2 --- /dev/null +++ b/drivers/message/i2o/driver.c @@ -0,0 +1,367 @@ +/* + * Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs + * + * Copyright (C) 2004 Markus Lidel + * + * 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. + * + * Fixes/additions: + * Markus Lidel + * initial version. + */ + +#include +#include +#include +#include + + +/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */ +unsigned int i2o_max_drivers = I2O_MAX_DRIVERS; +module_param_named(max_drivers, i2o_max_drivers, uint, 0); +MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support"); + +/* I2O drivers lock and array */ +static spinlock_t i2o_drivers_lock = SPIN_LOCK_UNLOCKED; +static struct i2o_driver **i2o_drivers; + +/** + * i2o_bus_match - Tell if a I2O device class id match the class ids of + * the I2O driver (OSM) + * + * @dev: device which should be verified + * @drv: the driver to match against + * + * Used by the bus to check if the driver wants to handle the device. + * + * Returns 1 if the class ids of the driver match the class id of the + * device, otherwise 0. + */ +static int i2o_bus_match(struct device *dev, struct device_driver *drv) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_driver *i2o_drv = to_i2o_driver(drv); + struct i2o_class_id *ids = i2o_drv->classes; + + if (ids) + while (ids->class_id != I2O_CLASS_END) { + if (ids->class_id == i2o_dev->lct_data.class_id) + return 1; + ids++; + } + return 0; +}; + +/* I2O bus type */ +struct bus_type i2o_bus_type = { + .name = "i2o", + .match = i2o_bus_match, +}; + +/** + * i2o_driver_register - Register a I2O driver (OSM) in the I2O core + * @drv: I2O driver which should be registered + * + * Registers the OSM drv in the I2O core and creates an event queues if + * necessary. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_driver_register(struct i2o_driver *drv) +{ + struct i2o_controller *c; + int i; + int rc = 0; + unsigned long flags; + + pr_debug("Register driver %s\n", drv->name); + + if (drv->event) { + drv->event_queue = create_workqueue(drv->name); + if (!drv->event_queue) { + printk(KERN_ERR "i2o: Could not initialize event queue " + "for driver %s\n", drv->name); + return -EFAULT; + } + pr_debug("Event queue initialized for driver %s\n", drv->name); + } else + drv->event_queue = NULL; + + drv->driver.name = drv->name; + drv->driver.bus = &i2o_bus_type; + + spin_lock_irqsave(&i2o_drivers_lock, flags); + + for (i = 0; i2o_drivers[i]; i++) + if (i >= i2o_max_drivers) { + printk(KERN_ERR "i2o: too many drivers registered, " + "increase max_drivers\n"); + spin_unlock_irqrestore(&i2o_drivers_lock, flags); + return -EFAULT; + } + + drv->context = i; + i2o_drivers[i] = drv; + + spin_unlock_irqrestore(&i2o_drivers_lock, flags); + + pr_debug("driver %s gets context id %d\n", drv->name, drv->context); + + list_for_each_entry(c, &i2o_controllers, list) { + struct i2o_device *i2o_dev; + + i2o_driver_notify_controller_add(drv, c); + list_for_each_entry(i2o_dev, &c->devices, list) + i2o_driver_notify_device_add(drv, i2o_dev); + } + + + rc = driver_register(&drv->driver); + if (rc) + destroy_workqueue(drv->event_queue); + + return rc; +}; + +/** + * i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core + * @drv: I2O driver which should be unregistered + * + * Unregisters the OSM drv from the I2O core and cleanup event queues if + * necessary. + */ +void i2o_driver_unregister(struct i2o_driver *drv) +{ + struct i2o_controller *c; + unsigned long flags; + + pr_debug("unregister driver %s\n", drv->name); + + driver_unregister(&drv->driver); + + list_for_each_entry(c, &i2o_controllers, list) { + struct i2o_device *i2o_dev; + + list_for_each_entry(i2o_dev, &c->devices, list) + i2o_driver_notify_device_remove(drv, i2o_dev); + + i2o_driver_notify_controller_remove(drv, c); + } + + spin_lock_irqsave(&i2o_drivers_lock, flags); + i2o_drivers[drv->context] = NULL; + spin_unlock_irqrestore(&i2o_drivers_lock, flags); + + if (drv->event_queue) { + destroy_workqueue(drv->event_queue); + drv->event_queue = NULL; + pr_debug("event queue removed for %s\n", drv->name); + } +}; + +/** + * i2o_driver_dispatch - dispatch an I2O reply message + * @c: I2O controller of the message + * @m: I2O message number + * @msg: I2O message to be delivered + * + * The reply is delivered to the driver from which the original message + * was. This function is only called from interrupt context. + * + * Returns 0 on success and the message should not be flushed. Returns > 0 + * on success and if the message should be flushed afterwords. Returns + * negative error code on failure (the message will be flushed too). + */ +int i2o_driver_dispatch(struct i2o_controller *c, u32 m, + struct i2o_message *msg) +{ + struct i2o_driver *drv; + u32 context = readl(&msg->u.s.icntxt); + + if (likely(context < i2o_max_drivers)) { + spin_lock(&i2o_drivers_lock); + drv = i2o_drivers[context]; + spin_unlock(&i2o_drivers_lock); + + if (unlikely(!drv)) { + printk(KERN_WARNING "i2o: Spurious reply to unknown " + "driver %d\n", context); + return -EIO; + } + + if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) { + struct i2o_device *dev, *tmp; + struct i2o_event *evt; + u16 size; + u16 tid; + + tid = readl(&msg->u.head[1]) & 0x1fff; + + pr_debug("%s: event received from device %d\n", c->name, + tid); + + /* cut of header from message size (in 32-bit words) */ + size = (readl(&msg->u.head[0]) >> 16) - 5; + + evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC); + if (!evt) + return -ENOMEM; + memset(evt, 0, size * 4 + sizeof(*evt)); + + evt->size = size; + memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt, + (size + 2) * 4); + + list_for_each_entry_safe(dev, tmp, &c->devices, list) + if (dev->lct_data.tid == tid) { + evt->i2o_dev = dev; + break; + } + + INIT_WORK(&evt->work, (void (*)(void *))drv->event, + evt); + queue_work(drv->event_queue, &evt->work); + return 1; + } + + if (likely(drv->reply)) + return drv->reply(c, m, msg); + else + pr_debug("%s: Reply to driver %s, but no reply function" + " defined!\n", c->name, drv->name); + return -EIO; + } else + printk(KERN_WARNING "i2o: Spurious reply to unknown driver " + "%d\n", readl(&msg->u.s.icntxt)); + return -EIO; +} + +/** + * i2o_driver_notify_controller_add_all - Send notify of added controller + * to all I2O drivers + * + * Send notifications to all registered drivers that a new controller was + * added. + */ +void i2o_driver_notify_controller_add_all(struct i2o_controller *c) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_controller_add(drv, c); + } +} + +/** + * i2o_driver_notify_controller_remove_all - Send notify of removed + * controller to all I2O drivers + * + * Send notifications to all registered drivers that a controller was + * removed. + */ +void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_controller_remove(drv, c); + } +} + +/** + * i2o_driver_notify_device_add_all - Send notify of added device to all + * I2O drivers + * + * Send notifications to all registered drivers that a device was added. + */ +void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_device_add(drv, i2o_dev); + } +} + +/** + * i2o_driver_notify_device_remove_all - Send notify of removed device to + * all I2O drivers + * + * Send notifications to all registered drivers that a device was removed. + */ +void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev) { + int i; + struct i2o_driver *drv; + + for(i = 0; i < I2O_MAX_DRIVERS; i ++) { + drv = i2o_drivers[i]; + + if(drv) + i2o_driver_notify_device_remove(drv, i2o_dev); + } +} + +/** + * i2o_driver_init - initialize I2O drivers (OSMs) + * + * Registers the I2O bus and allocate memory for the array of OSMs. + * + * Returns 0 on success or negative error code on failure. + */ +int __init i2o_driver_init(void) +{ + int rc = 0; + + if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64) || + ((i2o_max_drivers ^ (i2o_max_drivers - 1)) != + (2 * i2o_max_drivers - 1))) { + printk(KERN_WARNING "i2o: max_drivers set to %d, but must be " + ">=2 and <= 64 and a power of 2\n", i2o_max_drivers); + i2o_max_drivers = I2O_MAX_DRIVERS; + } + printk(KERN_INFO "i2o: max_drivers=%d\n", i2o_max_drivers); + + i2o_drivers = + kmalloc(i2o_max_drivers * sizeof(*i2o_drivers), GFP_KERNEL); + if (!i2o_drivers) + return -ENOMEM; + + memset(i2o_drivers, 0, i2o_max_drivers * sizeof(*i2o_drivers)); + + rc = bus_register(&i2o_bus_type); + + if (rc < 0) + kfree(i2o_drivers); + + return rc; +}; + +/** + * i2o_driver_exit - clean up I2O drivers (OSMs) + * + * Unregisters the I2O bus and free driver array. + */ +void __exit i2o_driver_exit(void) +{ + bus_unregister(&i2o_bus_type); + kfree(i2o_drivers); +}; + +EXPORT_SYMBOL(i2o_driver_register); +EXPORT_SYMBOL(i2o_driver_unregister); +EXPORT_SYMBOL(i2o_driver_notify_controller_add_all); +EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all); +EXPORT_SYMBOL(i2o_driver_notify_device_add_all); +EXPORT_SYMBOL(i2o_driver_notify_device_remove_all); diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c new file mode 100644 index 000000000..117f26106 --- /dev/null +++ b/drivers/message/i2o/exec-osm.c @@ -0,0 +1,505 @@ +/* + * Executive OSM + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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. + * + * A lot of the I2O message side code from this is taken from the Red + * Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. + * Markus Lidel : + * Support for sysfs included. + */ + +#include +#include + +struct i2o_driver i2o_exec_driver; + +/* Module internal functions from other sources */ +extern int i2o_device_parse_lct(struct i2o_controller *); + +/* global wait list for POST WAIT */ +static LIST_HEAD(i2o_exec_wait_list); + +/* Wait struct needed for POST WAIT */ +struct i2o_exec_wait { + wait_queue_head_t *wq; /* Pointer to Wait queue */ + struct i2o_dma dma; /* DMA buffers to free on failure */ + u32 tcntxt; /* transaction context from reply */ + int complete; /* 1 if reply received otherwise 0 */ + u32 m; /* message id */ + struct i2o_message *msg; /* pointer to the reply message */ + struct list_head list; /* node in global wait list */ +}; + +/* Exec OSM class handling definition */ +static struct i2o_class_id i2o_exec_class_id[] = { + {I2O_CLASS_EXECUTIVE}, + {I2O_CLASS_END} +}; + +/** + * i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it + * + * Allocate the i2o_exec_wait struct and initialize the wait. + * + * Returns i2o_exec_wait pointer on success or negative error code on + * failure. + */ +static struct i2o_exec_wait *i2o_exec_wait_alloc(void) +{ + struct i2o_exec_wait *wait; + + wait = kmalloc(sizeof(*wait), GFP_KERNEL); + if (!wait) + return ERR_PTR(-ENOMEM); + + memset(wait, 0, sizeof(*wait)); + + INIT_LIST_HEAD(&wait->list); + + return wait; +}; + +/** + * i2o_exec_wait_free - Free a i2o_exec_wait struct + * @i2o_exec_wait: I2O wait data which should be cleaned up + */ +static void i2o_exec_wait_free(struct i2o_exec_wait *wait) +{ + kfree(wait); +}; + +/** + * i2o_msg_post_wait_mem - Post and wait a message with DMA buffers + * @c: controller + * @m: message to post + * @timeout: time in seconds to wait + * @dma: i2o_dma struct of the DMA buffer to free on failure + * + * This API allows an OSM to post a message and then be told whether or + * not the system received a successful reply. If the message times out + * then the value '-ETIMEDOUT' is returned. This is a special case. In + * this situation the message may (should) complete at an indefinite time + * in the future. When it completes it will use the memory buffer + * attached to the request. If -ETIMEDOUT is returned then the memory + * buffer must not be freed. Instead the event completion will free them + * for you. In all other cases the buffer are your problem. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long + timeout, struct i2o_dma *dma) +{ + DECLARE_WAIT_QUEUE_HEAD(wq); + DEFINE_WAIT(wait); + struct i2o_exec_wait *iwait; + static u32 tcntxt = 0x80000000; + struct i2o_message *msg = c->in_queue.virt + m; + int rc = 0; + + iwait = i2o_exec_wait_alloc(); + if (!iwait) + return -ENOMEM; + + if (tcntxt == 0xffffffff) + tcntxt = 0x80000000; + + if (dma) + iwait->dma = *dma; + + /* + * Fill in the message initiator context and transaction context. + * We will only use transaction contexts >= 0x80000000 for POST WAIT, + * so we could find a POST WAIT reply easier in the reply handler. + */ + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + iwait->tcntxt = tcntxt++; + writel(iwait->tcntxt, &msg->u.s.tcntxt); + + /* + * Post the message to the controller. At some point later it will + * return. If we time out before it returns then complete will be zero. + */ + i2o_msg_post(c, m); + + if (!iwait->complete) { + iwait->wq = &wq; + /* + * we add elements add the head, because if a entry in the list + * will never be removed, we have to iterate over it every time + */ + list_add(&iwait->list, &i2o_exec_wait_list); + + prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); + + if (!iwait->complete) + schedule_timeout(timeout * HZ); + + finish_wait(&wq, &wait); + + iwait->wq = NULL; + } + + barrier(); + + if (iwait->complete) { + if (readl(&iwait->msg->body[0]) >> 24) + rc = readl(&iwait->msg->body[0]) & 0xff; + i2o_flush_reply(c, iwait->m); + i2o_exec_wait_free(iwait); + } else { + /* + * We cannot remove it now. This is important. When it does + * terminate (which it must do if the controller has not + * died...) then it will otherwise scribble on stuff. + * + * FIXME: try abort message + */ + if (dma) + dma->virt = NULL; + + rc = -ETIMEDOUT; + } + + return rc; +}; + +/** + * i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP + * @c: I2O controller which answers + * @m: message id + * @msg: pointer to the I2O reply message + * + * This function is called in interrupt context only. If the reply reached + * before the timeout, the i2o_exec_wait struct is filled with the message + * and the task will be waked up. The task is now responsible for returning + * the message m back to the controller! If the message reaches us after + * the timeout clean up the i2o_exec_wait struct (including allocated + * DMA buffer). + * + * Return 0 on success and if the message m should not be given back to the + * I2O controller, or >0 on success and if the message should be given back + * afterwords. Returns negative error code on failure. In this case the + * message must also be given back to the controller. + */ +static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, + struct i2o_message *msg) +{ + struct i2o_exec_wait *wait, *tmp; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + int rc = 1; + u32 context; + + context = readl(&msg->u.s.tcntxt); + + /* + * We need to search through the i2o_exec_wait_list to see if the given + * message is still outstanding. If not, it means that the IOP took + * longer to respond to the message than we had allowed and timer has + * already expired. Not much we can do about that except log it for + * debug purposes, increase timeout, and recompile. + */ + spin_lock(&lock); + list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { + if (wait->tcntxt == context) { + list_del(&wait->list); + + wait->m = m; + wait->msg = msg; + wait->complete = 1; + + barrier(); + + if (wait->wq) { + wake_up_interruptible(wait->wq); + rc = 0; + } else { + struct device *dev; + + dev = &c->pdev->dev; + + pr_debug("timedout reply received!\n"); + i2o_dma_free(dev, &wait->dma); + i2o_exec_wait_free(wait); + rc = -1; + } + + spin_unlock(&lock); + + return rc; + } + } + + spin_unlock(&lock); + + pr_debug("i2o: Bogus reply in POST WAIT (tr-context: %08x)!\n", + context); + + return -1; +}; + +/** + * i2o_exec_probe - Called if a new I2O device (executive class) appears + * @dev: I2O device which should be probed + * + * Registers event notification for every event from Executive device. The + * return is always 0, because we want all devices of class Executive. + * + * Returns 0 on success. + */ +static int i2o_exec_probe(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + + i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + + i2o_dev->iop->exec = i2o_dev; + + return 0; +}; + +/** + * i2o_exec_remove - Called on I2O device removal + * @dev: I2O device which was removed + * + * Unregisters event notification from Executive I2O device. + * + * Returns 0 on success. + */ +static int i2o_exec_remove(struct device *dev) +{ + i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); + + return 0; +}; + +/** + * i2o_exec_lct_modified - Called on LCT NOTIFY reply + * @c: I2O controller on which the LCT has modified + * + * This function handles asynchronus LCT NOTIFY replies. It parses the + * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY + * again. + */ +static void i2o_exec_lct_modified(struct i2o_controller *c) +{ + if (i2o_device_parse_lct(c) == -EAGAIN) + i2o_exec_lct_notify(c, 0); +}; + +/** + * i2o_exec_reply - I2O Executive reply handler + * @c: I2O controller from which the reply comes + * @m: message id + * @msg: pointer to the I2O reply message + * + * This function is always called from interrupt context. If a POST WAIT + * reply was received, pass it to the complete function. If a LCT NOTIFY + * reply was received, a new event is created to handle the update. + * + * Returns 0 on success and if the reply should not be flushed or > 0 + * on success and if the reply should be flushed. Returns negative error + * code on failure and if the reply should be flushed. + */ +static int i2o_exec_reply(struct i2o_controller *c, u32 m, + struct i2o_message *msg) +{ + if (readl(&msg->u.head[0]) & MSG_FAIL) { // Fail bit is set + struct i2o_message *pmsg; /* preserved message */ + u32 pm; + + pm = readl(&msg->body[3]); + + pmsg = c->in_queue.virt + pm; + + i2o_report_status(KERN_INFO, "i2o_core", msg); + + /* Release the preserved msg by resubmitting it as a NOP */ + i2o_msg_nop(c, pm); + + /* If reply to i2o_post_wait failed, return causes a timeout */ + return -1; + } + + if (readl(&msg->u.s.tcntxt) & 0x80000000) + return i2o_msg_post_wait_complete(c, m, msg); + + if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) { + struct work_struct *work; + + pr_debug("%s: LCT notify received\n", c->name); + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) + return -ENOMEM; + + INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c); + queue_work(i2o_exec_driver.event_queue, work); + return 1; + } + + /* + * If this happens, we want to dump the message to the syslog so + * it can be sent back to the card manufacturer by the end user + * to aid in debugging. + * + */ + printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" + "Message dumped to syslog\n", c->name); + i2o_dump_message(msg); + + return -EFAULT; +} + +/** + * i2o_exec_event - Event handling function + * @evt: Event which occurs + * + * Handles events send by the Executive device. At the moment does not do + * anything useful. + */ +static void i2o_exec_event(struct i2o_event *evt) +{ + printk(KERN_INFO "Event received from device: %d\n", + evt->i2o_dev->lct_data.tid); + kfree(evt); +}; + +/** + * i2o_exec_lct_get - Get the IOP's Logical Configuration Table + * @c: I2O controller from which the LCT should be fetched + * + * Send a LCT NOTIFY request to the controller, and wait + * I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is + * to large, retry it. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_exec_lct_get(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + int i = 0; + int rc = -EAGAIN; + + for (i = 1; i <= I2O_LCT_GET_TRIES; i++) { + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(0xffffffff, &msg->body[0]); + writel(0x00000000, &msg->body[1]); + writel(0xd0000000 | c->dlct.len, &msg->body[2]); + writel(c->dlct.phys, &msg->body[3]); + + rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET); + if (rc < 0) + break; + + rc = i2o_device_parse_lct(c); + if (rc != -EAGAIN) + break; + } + + return rc; +} + +/** + * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request + * @c: I2O controller to which the request should be send + * @change_ind: change indicator + * + * This function sends a LCT NOTIFY request to the I2O controller with + * the change indicator change_ind. If the change_ind == 0 the controller + * replies immediately after the request. If change_ind > 0 the reply is + * send after change indicator of the LCT is > change_ind. + */ +int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) +{ + i2o_status_block *sb = c->status_block.virt; + struct device *dev; + struct i2o_message *msg; + u32 m; + + dev = &c->pdev->dev; + + if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL)) + return -ENOMEM; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0, &msg->u.s.tcntxt); /* FIXME */ + writel(0xffffffff, &msg->body[0]); + writel(change_ind, &msg->body[1]); + writel(0xd0000000 | c->dlct.len, &msg->body[2]); + writel(c->dlct.phys, &msg->body[3]); + + i2o_msg_post(c, m); + + return 0; +}; + +/* Exec OSM driver struct */ +struct i2o_driver i2o_exec_driver = { + .name = "exec-osm", + .reply = i2o_exec_reply, + .event = i2o_exec_event, + .classes = i2o_exec_class_id, + .driver = { + .probe = i2o_exec_probe, + .remove = i2o_exec_remove, + }, +}; + +/** + * i2o_exec_init - Registers the Exec OSM + * + * Registers the Exec OSM in the I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +int __init i2o_exec_init(void) +{ + return i2o_driver_register(&i2o_exec_driver); +}; + +/** + * i2o_exec_exit - Removes the Exec OSM + * + * Unregisters the Exec OSM from the I2O core. + */ +void __exit i2o_exec_exit(void) +{ + i2o_driver_unregister(&i2o_exec_driver); +}; + +EXPORT_SYMBOL(i2o_msg_post_wait_mem); +EXPORT_SYMBOL(i2o_exec_lct_get); +EXPORT_SYMBOL(i2o_exec_lct_notify); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 36dc0e9d1..102fb8316 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -1,463 +1,426 @@ /* - * I2O Random Block Storage Class OSM + * Block OSM * - * (C) Copyright 1999-2002 Red Hat - * - * Written by Alan Cox, Building Number Three Ltd + * Copyright (C) 1999-2002 Red Hat Software * - * 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. + * Written by Alan Cox, Building Number Three Ltd * - * 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. + * 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. * - * For the purpose of avoiding doubt the preferred form of the work - * for making modifications shall be a standards compliant form such - * gzipped tar and not one requiring a proprietary or patent encumbered - * tool to unpack. + * 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. * - * This is a beta test release. Most of the good code was taken - * from the nbd driver by Pavel Machek, who in turn took some of it - * from loop.c. Isn't free software great for reusability 8) + * For the purpose of avoiding doubt the preferred form of the work + * for making modifications shall be a standards compliant form such + * gzipped tar and not one requiring a proprietary or patent encumbered + * tool to unpack. * - * Fixes/additions: - * Steve Ralston: - * Multiple device handling error fixes, - * Added a queue depth. - * Alan Cox: - * FC920 has an rmw bug. Dont or in the end marker. - * Removed queue walk, fixed for 64bitness. - * Rewrote much of the code over time - * Added indirect block lists - * Handle 64K limits on many controllers - * Don't use indirects on the Promise (breaks) - * Heavily chop down the queue depths - * Deepak Saxena: - * Independent queues per IOP - * Support for dynamic device creation/deletion - * Code cleanup - * Support for larger I/Os through merge* functions - * (taken from DAC960 driver) - * Boji T Kannanthanam: - * Set the I2O Block devices to be detected in increasing - * order of TIDs during boot. - * Search and set the I2O block device that we boot off from as - * the first device to be claimed (as /dev/i2o/hda) - * Properly attach/detach I2O gendisk structure from the system - * gendisk list. The I2O block devices now appear in - * /proc/partitions. - * Markus Lidel : - * Minor bugfixes for 2.6. - * - * To do: - * Serial number scanning to find duplicates for FC multipathing + * Fixes/additions: + * Steve Ralston: + * Multiple device handling error fixes, + * Added a queue depth. + * Alan Cox: + * FC920 has an rmw bug. Dont or in the end marker. + * Removed queue walk, fixed for 64bitness. + * Rewrote much of the code over time + * Added indirect block lists + * Handle 64K limits on many controllers + * Don't use indirects on the Promise (breaks) + * Heavily chop down the queue depths + * Deepak Saxena: + * Independent queues per IOP + * Support for dynamic device creation/deletion + * Code cleanup + * Support for larger I/Os through merge* functions + * (taken from DAC960 driver) + * Boji T Kannanthanam: + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off + * from as the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the + * system gendisk list. The I2O block devices now appear in + * /proc/partitions. + * Markus Lidel : + * Minor bugfixes for 2.6. */ -#include - #include -#include -#include -#include -#include -#include -#include -#include -#include #include + +#include + +#include #include -#include -#include #include -#include -#include -#include -#include +#include "i2o_block.h" -#include -#include -#include -#include -#include -#include +static struct i2o_driver i2o_block_driver; -#define MAJOR_NR I2O_MAJOR +/* global Block OSM request mempool */ +static struct i2o_block_mempool i2o_blk_req_pool; -#define MAX_I2OB 16 +/* Block OSM class handling definition */ +static struct i2o_class_id i2o_block_class_id[] = { + {I2O_CLASS_RANDOM_BLOCK_STORAGE}, + {I2O_CLASS_END} +}; + +/** + * i2o_block_device_free - free the memory of the I2O Block device + * @dev: I2O Block device, which should be cleaned up + * + * Frees the request queue, gendisk and the i2o_block_device structure. + */ +static void i2o_block_device_free(struct i2o_block_device *dev) +{ + blk_cleanup_queue(dev->gd->queue); -#define MAX_I2OB_DEPTH 8 -#define MAX_I2OB_RETRIES 4 + put_disk(dev->gd); -//#define DRIVERDEBUG -#ifdef DRIVERDEBUG -#define DEBUG( s ) printk( s ) -#else -#define DEBUG( s ) -#endif + kfree(dev); +}; -/* - * Events that this OSM is interested in +/** + * i2o_block_remove - remove the I2O Block device from the system again + * @dev: I2O Block device which should be removed + * + * Remove gendisk from system and free all allocated memory. + * + * Always returns 0. */ -#define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ - I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ - I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ - I2O_EVT_IND_BSA_CAPACITY_CHANGE | \ - I2O_EVT_IND_BSA_SCSI_SMART ) +static int i2o_block_remove(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev); + printk(KERN_INFO "block-osm: Device removed %s\n", + i2o_blk_dev->gd->disk_name); -/* - * Some of these can be made smaller later - */ + i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0); -static int i2ob_context; -static struct block_device_operations i2ob_fops; + del_gendisk(i2o_blk_dev->gd); -/* - * I2O Block device descriptor + dev_set_drvdata(dev, NULL); + + i2o_device_claim_release(i2o_dev); + + i2o_block_device_free(i2o_blk_dev); + + return 0; +}; + +/** + * i2o_block_device flush - Flush all dirty data of I2O device dev + * @dev: I2O device which should be flushed + * + * Flushes all dirty data on device dev. + * + * Returns 0 on success or negative error code on failure. */ -struct i2ob_device +static int i2o_block_device_flush(struct i2o_device *dev) { - struct i2o_controller *controller; - struct i2o_device *i2odev; - int unit; - int tid; - int flags; - int refcnt; - struct request *head, *tail; - request_queue_t *req_queue; - int max_segments; - int max_direct; /* Not yet used properly */ - int done_flag; - int depth; - int rcache; - int wcache; - int power; - int index; - int media_change_flag; - u32 max_sectors; - struct gendisk *gd; + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(60 << 16, &msg->body[0]); + pr_debug("Flushing...\n"); + + return i2o_msg_post_wait(dev->iop, m, 60); }; -/* - * FIXME: - * We should cache align these to avoid ping-ponging lines on SMP - * boxes under heavy I/O load... +/** + * i2o_block_device_mount - Mount (load) the media of device dev + * @dev: I2O device which should receive the mount request + * @media_id: Media Identifier + * + * Load a media into drive. Identifier should be set to -1, because the + * spec does not support any other value. + * + * Returns 0 on success or negative error code on failure. */ - -struct i2ob_request +static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id) { - struct i2ob_request *next; - struct request *req; - int num; - int sg_dma_direction; - int sg_nents; - struct scatterlist sg_table[16]; + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(-1, &msg->body[0]); + writel(0, &msg->body[1]); + pr_debug("Mounting...\n"); + + return i2o_msg_post_wait(dev->iop, m, 2); }; -/* - * Per IOP request queue information +/** + * i2o_block_device_lock - Locks the media of device dev + * @dev: I2O device which should receive the lock request + * @media_id: Media Identifier + * + * Lock media of device dev to prevent removal. The media identifier + * should be set to -1, because the spec does not support any other value. * - * We have a separate request_queue_t per IOP so that a heavilly - * loaded I2O block device on an IOP does not starve block devices - * across all I2O controllers. - * + * Returns 0 on success or negative error code on failure. */ -struct i2ob_iop_queue +static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id) { - unsigned int queue_depth; - struct i2ob_request request_queue[MAX_I2OB_DEPTH]; - struct i2ob_request *i2ob_qhead; - request_queue_t *req_queue; - spinlock_t lock; + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(-1, &msg->body[0]); + pr_debug("Locking...\n"); + + return i2o_msg_post_wait(dev->iop, m, 2); }; -static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS]; -/* - * Each I2O disk is one of these. +/** + * i2o_block_device_unlock - Unlocks the media of device dev + * @dev: I2O device which should receive the unlocked request + * @media_id: Media Identifier + * + * Unlocks the media in device dev. The media identifier should be set to + * -1, because the spec does not support any other value. + * + * Returns 0 on success or negative error code on failure. */ +static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id) +{ + struct i2o_message *msg; + u32 m; -static struct i2ob_device i2ob_dev[MAX_I2OB]; -static int i2ob_dev_count = 0; + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; -/* - * Mutex and spin lock for event handling synchronization - * evt_msg contains the last event. - */ -static DECLARE_MUTEX_LOCKED(i2ob_evt_sem); -static DECLARE_COMPLETION(i2ob_thread_dead); -static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; -static u32 evt_msg[MSG_FRAME_SIZE]; - -static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); -static void i2ob_new_device(struct i2o_controller *, struct i2o_device *); -static void i2ob_del_device(struct i2o_controller *, struct i2o_device *); -static void i2ob_reboot_event(void); -static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); -static void i2ob_end_request(struct request *); -static void i2ob_request(request_queue_t *); -static int i2ob_init_iop(unsigned int); -static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); -static int i2ob_evt(void *); - -static int evt_pid = 0; -static int evt_running = 0; -static int scan_unit = 0; + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + writel(media_id, &msg->body[0]); + pr_debug("Unlocking...\n"); -/* - * I2O OSM registration structure...keeps getting bigger and bigger :) + return i2o_msg_post_wait(dev->iop, m, 2); +}; + +/** + * i2o_block_device_power - Power management for device dev + * @dev: I2O device which should receive the power management request + * @operation: Operation which should be send + * + * Send a power management request to the device dev. + * + * Returns 0 on success or negative error code on failure. */ -static struct i2o_handler i2o_block_handler = +static int i2o_block_device_power(struct i2o_block_device *dev, u8 op) { - i2o_block_reply, - i2ob_new_device, - i2ob_del_device, - i2ob_reboot_event, - "I2O Block OSM", - 0, - I2O_CLASS_RANDOM_BLOCK_STORAGE + struct i2o_device *i2o_dev = dev->i2o_dev; + struct i2o_controller *c = i2o_dev->iop; + struct i2o_message *msg; + u32 m; + int rc; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->lct_data. + tid, &msg->u.head[1]); + writel(op << 24, &msg->body[0]); + pr_debug("Power...\n"); + + rc = i2o_msg_post_wait(c, m, 60); + if (!rc) + dev->power = op; + + return rc; }; /** - * i2ob_get - Get an I2O message - * @dev: I2O block device + * i2o_block_request_alloc - Allocate an I2O block request struct + * + * Allocates an I2O block request struct and initialize the list. * - * Get a message from the FIFO used for this block device. The message is returned - * or the I2O 'no message' value of 0xFFFFFFFF if nothing is available. + * Returns a i2o_block_request pointer on success or negative error code + * on failure. */ +static inline struct i2o_block_request *i2o_block_request_alloc(void) +{ + struct i2o_block_request *ireq; + + ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC); + if (!ireq) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&ireq->queue); + + return ireq; +}; -static u32 i2ob_get(struct i2ob_device *dev) +/** + * i2o_block_request_free - Frees a I2O block request + * @ireq: I2O block request which should be freed + * + * Fres the allocated memory (give it back to the request mempool). + */ +static inline void i2o_block_request_free(struct i2o_block_request *ireq) { - struct i2o_controller *c=dev->controller; - return I2O_POST_READ32(c); -} + mempool_free(ireq, i2o_blk_req_pool.pool); +}; -static int i2ob_build_sglist(struct i2ob_device *dev, struct i2ob_request *ireq) +/** + * i2o_block_sglist_alloc - Allocate the SG list and map it + * @ireq: I2O block request + * + * Builds the SG list and map it into to be accessable by the controller. + * + * Returns the number of elements in the SG list or 0 on failure. + */ +static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq) { - struct scatterlist *sg = ireq->sg_table; + struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev; int nents; - nents = blk_rq_map_sg(dev->req_queue, ireq->req, ireq->sg_table); - + nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table); + if (rq_data_dir(ireq->req) == READ) ireq->sg_dma_direction = PCI_DMA_FROMDEVICE; else ireq->sg_dma_direction = PCI_DMA_TODEVICE; - ireq->sg_nents = pci_map_sg(dev->controller->pdev, sg, nents, ireq->sg_dma_direction); + ireq->sg_nents = dma_map_sg(dev, ireq->sg_table, nents, + ireq->sg_dma_direction); + return ireq->sg_nents; -} +}; -void i2ob_free_sglist(struct i2ob_device *dev, struct i2ob_request *ireq) -{ - struct pci_dev *pdev = dev->controller->pdev; - struct scatterlist *sg = ireq->sg_table; - int nents = ireq->sg_nents; - pci_unmap_sg(pdev, sg, nents, ireq->sg_dma_direction); -} - /** - * i2ob_send - Turn a request into a message and send it - * @m: Message offset - * @dev: I2O device - * @ireq: Request structure - * @unit: Device identity + * i2o_block_sglist_free - Frees the SG list + * @ireq: I2O block request from which the SG should be freed * - * Generate an I2O BSAREAD request. This interface function is called for devices that - * appear to explode when they are fed indirect chain pointers (notably right now this - * appears to afflict Promise hardwre, so be careful what you feed the hardware - * - * No cleanup is done by this interface. It is done on the interrupt side when the - * reply arrives + * Frees the SG list from the I2O block request. */ - -static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, int unit) +static inline void i2o_block_sglist_free(struct i2o_block_request *ireq) { - struct i2o_controller *c = dev->controller; - int tid = dev->tid; - void *msg; - void *mptr; - u64 offset; - struct request *req = ireq->req; - int count = req->nr_sectors<<9; - struct scatterlist *sg; - int sgnum; - int i; + struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev; - // printk(KERN_INFO "i2ob_send called\n"); - /* Map the message to a virtual address */ - msg = c->msg_virt + m; - - sgnum = i2ob_build_sglist(dev, ireq); - - /* FIXME: if we have no resources how should we get out of this */ - if(sgnum == 0) - BUG(); - - /* - * Build the message based on the request. - */ - i2o_raw_writel(i2ob_context|(unit<<8), msg+8); - i2o_raw_writel(ireq->num, msg+12); - i2o_raw_writel(req->nr_sectors << 9, msg+20); + dma_unmap_sg(dev, ireq->sg_table, ireq->sg_nents, + ireq->sg_dma_direction); +}; - /* - * Mask out partitions from now on - */ - - /* This can be optimised later - just want to be sure its right for - starters */ - offset = ((u64)req->sector) << 9; - i2o_raw_writel( offset & 0xFFFFFFFF, msg+24); - i2o_raw_writel(offset>>32, msg+28); - mptr=msg+32; - - sg = ireq->sg_table; - if(rq_data_dir(req) == READ) - { - DEBUG("READ\n"); - i2o_raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); - for(i = sgnum; i > 0; i--) - { - if(i != 1) - i2o_raw_writel(0x10000000|sg_dma_len(sg), mptr); - else - i2o_raw_writel(0xD0000000|sg_dma_len(sg), mptr); - i2o_raw_writel(sg_dma_address(sg), mptr+4); - mptr += 8; - count -= sg_dma_len(sg); - sg++; - } - switch(dev->rcache) - { - case CACHE_NULL: - i2o_raw_writel(0, msg+16);break; - case CACHE_PREFETCH: - i2o_raw_writel(0x201F0008, msg+16);break; - case CACHE_SMARTFETCH: - if(req->nr_sectors > 16) - i2o_raw_writel(0x201F0008, msg+16); - else - i2o_raw_writel(0x001F0000, msg+16); - break; - } - -// printk("Reading %d entries %d bytes.\n", -// mptr-msg-8, req->nr_sectors<<9); +/** + * i2o_block_prep_req_fn - Allocates I2O block device specific struct + * @q: request queue for the request + * @req: the request to prepare + * + * Allocate the necessary i2o_block_request struct and connect it to + * the request. This is needed that we not loose the SG list later on. + * + * Returns BLKPREP_OK on success or BLKPREP_DEFER on failure. + */ +static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) +{ + struct i2o_block_device *i2o_blk_dev = q->queuedata; + struct i2o_block_request *ireq; + + /* request is already processed by us, so return */ + if (req->flags & REQ_SPECIAL) { + pr_debug("REQ_SPECIAL already set!\n"); + req->flags |= REQ_DONTPREP; + return BLKPREP_OK; } - else if(rq_data_dir(req) == WRITE) - { - DEBUG("WRITE\n"); - i2o_raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); - for(i = sgnum; i > 0; i--) - { - if(i != 1) - i2o_raw_writel(0x14000000|sg_dma_len(sg), mptr); - else - i2o_raw_writel(0xD4000000|sg_dma_len(sg), mptr); - i2o_raw_writel(sg_dma_address(sg), mptr+4); - mptr += 8; - count -= sg_dma_len(sg); - sg++; - } - switch(dev->wcache) - { - case CACHE_NULL: - i2o_raw_writel(0, msg+16);break; - case CACHE_WRITETHROUGH: - i2o_raw_writel(0x001F0008, msg+16);break; - case CACHE_WRITEBACK: - i2o_raw_writel(0x001F0010, msg+16);break; - case CACHE_SMARTBACK: - if(req->nr_sectors > 16) - i2o_raw_writel(0x001F0004, msg+16); - else - i2o_raw_writel(0x001F0010, msg+16); - break; - case CACHE_SMARTTHROUGH: - if(req->nr_sectors > 16) - i2o_raw_writel(0x001F0004, msg+16); - else - i2o_raw_writel(0x001F0010, msg+16); + /* connect the i2o_block_request to the request */ + if (!req->special) { + ireq = i2o_block_request_alloc(); + if (unlikely(IS_ERR(ireq))) { + pr_debug("unable to allocate i2o_block_request!\n"); + return BLKPREP_DEFER; } - -// printk("Writing %d entries %d bytes.\n", -// mptr-msg-8, req->nr_sectors<<9); - } - i2o_raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); - - if(count != 0) - { - printk(KERN_ERR "Request count botched by %d.\n", count); - } - i2o_post_message(c,m); - i2ob_queues[c->unit]->queue_depth ++; + ireq->i2o_blk_dev = i2o_blk_dev; + req->special = ireq; + ireq->req = req; + } else + ireq = req->special; - return 0; -} + /* do not come back here */ + req->flags |= REQ_DONTPREP | REQ_SPECIAL; -/* - * Remove a request from the _locked_ request list. We update both the - * list chain and if this is the last item the tail pointer. Caller - * must hold the lock. - */ - -static inline void i2ob_unhook_request(struct i2ob_request *ireq, - unsigned int iop) -{ - ireq->next = i2ob_queues[iop]->i2ob_qhead; - i2ob_queues[iop]->i2ob_qhead = ireq; -} + return BLKPREP_OK; +}; -/* - * Request completion handler +/** + * i2o_block_delayed_request_fn - delayed request queue function + * delayed_request: the delayed request with the queue to start + * + * If the request queue is stopped for a disk, and there is no open + * request, a new event is created, which calls this function to start + * the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never + * be started again. */ - -static inline void i2ob_end_request(struct request *req) +static void i2o_block_delayed_request_fn(void *delayed_request) { - /* FIXME - pci unmap the request */ - - /* - * Loop until all of the buffers that are linked - * to this request have been marked updated and - * unlocked. - */ - - while (end_that_request_first( req, !req->errors, req->hard_cur_sectors )); + struct i2o_block_delayed_request *dreq = delayed_request; + struct request_queue *q = dreq->queue; + unsigned long flags; - /* - * It is now ok to complete the request. - */ - end_that_request_last( req ); - DEBUG("IO COMPLETED\n"); -} + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + kfree(dreq); +}; -/* - * OSM reply handler. This gets all the message replies +/** + * i2o_block_reply - Block OSM reply handler. + * @c: I2O controller from which the message arrives + * @m: message id of reply + * qmsg: the actuall I2O message reply + * + * This function gets all the message replies. + * */ - -static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +static int i2o_block_reply(struct i2o_controller *c, u32 m, + struct i2o_message *msg) { - unsigned long flags; - struct i2ob_request *ireq = NULL; + struct i2o_block_request *ireq; + struct request *req; + struct i2o_block_device *dev; + struct request_queue *q; u8 st; - u32 *m = (u32 *)msg; - u8 unit = m[2]>>8; - struct i2ob_device *dev = &i2ob_dev[unit]; + unsigned long flags; - /* - * FAILed message - */ - if(m[0] & (1<<13)) - { - DEBUG("FAIL"); + /* FAILed message */ + if (unlikely(readl(&msg->u.head[0]) & (1 << 13))) { + struct i2o_message *pmsg; + u32 pm; + + printk(KERN_WARNING "FAIL"); /* * FAILed message from controller * We increment the error count and abort it @@ -468,65 +431,85 @@ static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, str * better be on the safe side since no one really follows * the spec to the book :) */ - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - ireq->req->errors++; - - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); - + pm = readl(&msg->body[3]); + pmsg = c->in_queue.virt + pm; + + req = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt)); + if (unlikely(!req)) { + printk(KERN_ERR "block-osm: NULL reply received!\n"); + return -1; + } + + ireq = req->special; + dev = ireq->i2o_blk_dev; + q = dev->gd->queue; + + req->errors++; + + spin_lock_irqsave(q->queue_lock, flags); + + while (end_that_request_chunk(req, !req->errors, + readl(&pmsg->body[1]))) ; + end_that_request_last(req); + + dev->open_queue_depth--; + list_del(&ireq->queue); + blk_start_queue(q); + + spin_unlock_irqrestore(q->queue_lock, flags); + /* Now flush the message by making it a NOP */ - m[0]&=0x00FFFFFF; - m[0]|=(I2O_CMD_UTIL_NOP)<<24; - i2o_post_message(c, (unsigned long) m - (unsigned long) c->msg_virt); + i2o_msg_nop(c, pm); - return; + return -1; } - if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) - { - spin_lock(&i2ob_evt_lock); - memcpy(evt_msg, msg, (m[0]>>16)<<2); - spin_unlock(&i2ob_evt_lock); - up(&i2ob_evt_sem); - return; + req = i2o_cntxt_list_get(c, readl(&msg->u.s.tcntxt)); + if (unlikely(!req)) { + printk(KERN_ERR "block-osm: NULL reply received!\n"); + return -1; } - if(!dev->i2odev) - { + ireq = req->special; + dev = ireq->i2o_blk_dev; + q = dev->gd->queue; + + if (unlikely(!dev->i2o_dev)) { /* * This is HACK, but Intel Integrated RAID allows user - * to delete a volume that is claimed, locked, and in use + * to delete a volume that is claimed, locked, and in use * by the OS. We have to check for a reply from a - * non-existent device and flag it as an error or the system + * non-existent device and flag it as an error or the system * goes kaput... */ - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - ireq->req->errors++; - printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n"); - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); - return; - } + req->errors++; + printk(KERN_WARNING + "I2O Block: Data transfer to deleted device!\n"); + spin_lock_irqsave(q->queue_lock, flags); + while (end_that_request_chunk + (req, !req->errors, readl(&msg->body[1]))) ; + end_that_request_last(req); + + dev->open_queue_depth--; + list_del(&ireq->queue); + blk_start_queue(q); + + spin_unlock_irqrestore(q->queue_lock, flags); + return -1; + } /* - * Lets see what is cooking. We stuffed the - * request in the context. + * Lets see what is cooking. We stuffed the + * request in the context. */ - - ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; - st=m[4]>>24; - if(st!=0) - { + st = readl(&msg->body[0]) >> 24; + + if (st != 0) { int err; - char *bsa_errors[] = - { - "Success", - "Media Error", + char *bsa_errors[] = { + "Success", + "Media Error", "Failure communicating to device", "Device Failure", "Device is not ready", @@ -540,61 +523,62 @@ static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, str "Device has reset", "Volume has changed, waiting for acknowledgement" }; - - err = m[4]&0xFFFF; - + + err = readl(&msg->body[0]) & 0xffff; + /* - * Device not ready means two things. One is that the - * the thing went offline (but not a removal media) + * Device not ready means two things. One is that the + * the thing went offline (but not a removal media) * - * The second is that you have a SuperTrak 100 and the - * firmware got constipated. Unlike standard i2o card - * setups the supertrak returns an error rather than - * blocking for the timeout in these cases. + * The second is that you have a SuperTrak 100 and the + * firmware got constipated. Unlike standard i2o card + * setups the supertrak returns an error rather than + * blocking for the timeout in these cases. * - * Don't stick a supertrak100 into cache aggressive modes + * Don't stick a supertrak100 into cache aggressive modes */ - - - printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, - bsa_errors[m[4]&0XFFFF]); - if(m[4]&0x00FF0000) - printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); + + printk(KERN_ERR "\n/dev/%s error: %s", dev->gd->disk_name, + bsa_errors[readl(&msg->body[0]) & 0xffff]); + if (readl(&msg->body[0]) & 0x00ff0000) + printk(" - DDM attempted %d retries", + (readl(&msg->body[0]) >> 16) & 0x00ff); printk(".\n"); - ireq->req->errors++; - } - else - ireq->req->errors = 0; + req->errors++; + } else + req->errors = 0; - /* - * Dequeue the request. We use irqsave locks as one day we - * may be running polled controllers from a BH... - */ - - i2ob_free_sglist(dev, ireq); - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - i2ob_unhook_request(ireq, c->unit); - i2ob_end_request(ireq->req); - i2ob_queues[c->unit]->queue_depth --; - - /* - * We may be able to do more I/O - */ - - i2ob_request(dev->gd->queue); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); -} + if (!end_that_request_chunk(req, !req->errors, readl(&msg->body[1]))) { + add_disk_randomness(req->rq_disk); + spin_lock_irqsave(q->queue_lock, flags); -/* - * Event handler. Needs to be a separate thread b/c we may have - * to do things like scan a partition table, or query parameters - * which cannot be done from an interrupt or from a bottom half. - */ -static int i2ob_evt(void *dummy) + end_that_request_last(req); + + dev->open_queue_depth--; + list_del(&ireq->queue); + blk_start_queue(q); + + spin_unlock_irqrestore(q->queue_lock, flags); + + i2o_block_sglist_free(ireq); + i2o_block_request_free(ireq); + } else + printk(KERN_ERR "still remaining chunks\n"); + + return 1; +}; + +static void i2o_block_event(struct i2o_event *evt) +{ + printk(KERN_INFO "block-osm: event received\n"); +}; + +#if 0 +static int i2o_block_event(void *dummy) { unsigned int evt; unsigned long flags; - struct i2ob_device *dev; + struct i2o_block_device *dev; int unit; //The only event that has data is the SCSI_SMART event. struct i2o_reply { @@ -604,24 +588,22 @@ static int i2ob_evt(void *dummy) u8 ASCQ; u16 pad; u8 data[16]; - } *evt_local; + } *evt_local; daemonize("i2oblock"); allow_signal(SIGKILL); evt_running = 1; - while(1) - { - if(down_interruptible(&i2ob_evt_sem)) - { + while (1) { + if (down_interruptible(&i2ob_evt_sem)) { evt_running = 0; printk("exiting..."); break; } /* - * Keep another CPU/interrupt from overwriting the + * Keep another CPU/interrupt from overwriting the * message while we're reading it * * We stuffed the unit in the TxContext and grab the event mask @@ -634,20 +616,19 @@ static int i2ob_evt(void *dummy) unit = le32_to_cpu(evt_local->header[3]); evt = le32_to_cpu(evt_local->evt_indicator); - dev = &i2ob_dev[unit]; - switch(evt) - { + dev = &i2o_blk_dev[unit]; + switch (evt) { /* * New volume loaded on same TID, so we just re-install. * The TID/controller don't change as it is the same * I2O device. It's just new media that we have to * rescan. */ - case I2O_EVT_IND_BSA_VOLUME_LOAD: + case I2O_EVT_IND_BSA_VOLUME_LOAD: { - i2ob_install_device(dev->i2odev->controller, - dev->i2odev, unit); - add_disk(dev->gd); + i2ob_install_device(dev->i2o_device->iop, + dev->i2o_device, unit); + add_disk(dev->gendisk); break; } @@ -657,144 +638,108 @@ static int i2ob_evt(void *dummy) * have media, so we don't want to clear the controller or * device pointer. */ - case I2O_EVT_IND_BSA_VOLUME_UNLOAD: + case I2O_EVT_IND_BSA_VOLUME_UNLOAD: { - struct gendisk *p = dev->gd; - blk_queue_max_sectors(dev->gd->queue, 0); + struct gendisk *p = dev->gendisk; + blk_queue_max_sectors(dev->gendisk->queue, 0); del_gendisk(p); put_disk(p); - dev->gd = NULL; + dev->gendisk = NULL; dev->media_change_flag = 1; break; } - case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: - printk(KERN_WARNING "%s: Attempt to eject locked media\n", - dev->i2odev->dev_name); - break; + case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: + printk(KERN_WARNING + "%s: Attempt to eject locked media\n", + dev->i2o_device->dev_name); + break; /* * The capacity has changed and we are going to be - * updating the max_sectors and other information + * updating the max_sectors and other information * about this disk. We try a revalidate first. If * the block device is in use, we don't want to * do that as there may be I/Os bound for the disk - * at the moment. In that case we read the size + * at the moment. In that case we read the size * from the device and update the information ourselves * and the user can later force a partition table * update through an ioctl. */ - case I2O_EVT_IND_BSA_CAPACITY_CHANGE: + case I2O_EVT_IND_BSA_CAPACITY_CHANGE: { u64 size; - if(i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) - i2ob_query_device(dev, 0x0000, 4, &size, 8); + if (i2ob_query_device(dev, 0x0004, 0, &size, 8) + != 0) + i2ob_query_device(dev, 0x0000, 4, &size, + 8); - spin_lock_irqsave(dev->req_queue->queue_lock, flags); - set_capacity(dev->gd, size>>9); - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); + spin_lock_irqsave(dev->req_queue->queue_lock, + flags); + set_capacity(dev->gendisk, size >> 9); + spin_unlock_irqrestore(dev->req_queue-> + queue_lock, flags); break; } - /* + /* * We got a SCSI SMART event, we just log the relevant * information and let the user decide what they want * to do with the information. */ - case I2O_EVT_IND_BSA_SCSI_SMART: + case I2O_EVT_IND_BSA_SCSI_SMART: { char buf[16]; - printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",dev->i2odev->dev_name); - evt_local->data[16]='\0'; - sprintf(buf,"%s",&evt_local->data[0]); - printk(KERN_INFO " Disk Serial#:%s\n",buf); - printk(KERN_INFO " ASC 0x%02x \n",evt_local->ASC); - printk(KERN_INFO " ASCQ 0x%02x \n",evt_local->ASCQ); + printk(KERN_INFO + "I2O Block: %s received a SCSI SMART Event\n", + dev->i2o_device->dev_name); + evt_local->data[16] = '\0'; + sprintf(buf, "%s", &evt_local->data[0]); + printk(KERN_INFO " Disk Serial#:%s\n", + buf); + printk(KERN_INFO " ASC 0x%02x \n", + evt_local->ASC); + printk(KERN_INFO " ASCQ 0x%02x \n", + evt_local->ASCQ); break; } - + /* - * Non event + * Non event */ - - case 0: - break; - + + case 0: + break; + /* * An event we didn't ask for. Call the card manufacturer * and tell them to fix their firmware :) */ - - case 0x20: - /* - * If a promise card reports 0x20 event then the brown stuff - * hit the fan big time. The card seems to recover but loses - * the pending writes. Deeply ungood except for testing fsck - */ - if(dev->i2odev->controller->promise) - panic("I2O controller firmware failed. Reboot and force a filesystem check.\n"); - default: - printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n" - KERN_INFO " Blame the I2O card manufacturer 8)\n", - dev->i2odev->dev_name, evt); - break; - } - }; - - complete_and_exit(&i2ob_thread_dead,0); - return 0; -} - -/* - * The I2O block driver is listed as one of those that pulls the - * front entry off the queue before processing it. This is important - * to remember here. If we drop the io lock then CURRENT will change - * on us. We must unlink CURRENT in this routine before we return, if - * we use it. - */ - -static void i2ob_request(request_queue_t *q) -{ - struct request *req; - struct i2ob_request *ireq; - struct i2ob_device *dev; - u32 m; - - while ((req = elv_next_request(q)) != NULL) { - dev = req->rq_disk->private_data; - - /* - * Queue depths probably belong with some kind of - * generic IOP commit control. Certainly it's not right - * its global! - */ - if(i2ob_queues[dev->unit]->queue_depth >= dev->depth) - break; - - /* Get a message */ - m = i2ob_get(dev); - if(m==0xFFFFFFFF) - { - if(i2ob_queues[dev->unit]->queue_depth == 0) - printk(KERN_ERR "i2o_block: message queue and request queue empty!!\n"); + case 0x20: + /* + * If a promise card reports 0x20 event then the brown stuff + * hit the fan big time. The card seems to recover but loses + * the pending writes. Deeply ungood except for testing fsck + */ + if (dev->i2o_device->iop->promise) + panic + ("I2O controller firmware failed. Reboot and force a filesystem check.\n"); + default: + printk(KERN_INFO + "%s: Received event 0x%X we didn't register for\n" + KERN_INFO + " Blame the I2O card manufacturer 8)\n", + dev->i2o_device->dev_name, evt); break; } - /* - * Everything ok, so pull from kernel queue onto our queue - */ - req->errors = 0; - blkdev_dequeue_request(req); - - ireq = i2ob_queues[dev->unit]->i2ob_qhead; - i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; - ireq->req = req; + }; - i2ob_send(m, dev, ireq, dev->index); - } + complete_and_exit(&i2ob_thread_dead, 0); + return 0; } - +#endif /* * SCSI-CAM for ioctl geometry mapping @@ -803,8 +748,8 @@ static void i2ob_request(request_queue_t *q) * * LBA -> CHS mapping table taken from: * - * "Incorporating the I2O Architecture into BIOS for Intel Architecture - * Platforms" + * "Incorporating the I2O Architecture into BIOS for Intel Architecture + * Platforms" * * This is an I2O document that is only available to I2O members, * not developers. @@ -825,865 +770,647 @@ static void i2ob_request(request_queue_t *q) #define BLOCK_SIZE_42G 8806400 #define BLOCK_SIZE_84G 17612800 -static void i2o_block_biosparam( - unsigned long capacity, - unsigned short *cyls, - unsigned char *hds, - unsigned char *secs) -{ - unsigned long heads, sectors, cylinders; +static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls, + unsigned char *hds, unsigned char *secs) +{ + unsigned long heads, sectors, cylinders; - sectors = 63L; /* Maximize sectors per track */ - if(capacity <= BLOCK_SIZE_528M) + sectors = 63L; /* Maximize sectors per track */ + if (capacity <= BLOCK_SIZE_528M) heads = 16; - else if(capacity <= BLOCK_SIZE_1G) + else if (capacity <= BLOCK_SIZE_1G) heads = 32; - else if(capacity <= BLOCK_SIZE_21G) + else if (capacity <= BLOCK_SIZE_21G) heads = 64; - else if(capacity <= BLOCK_SIZE_42G) + else if (capacity <= BLOCK_SIZE_42G) heads = 128; else heads = 255; cylinders = (unsigned long)capacity / (heads * sectors); - *cyls = (unsigned short) cylinders; /* Stuff return values */ - *secs = (unsigned char) sectors; - *hds = (unsigned char) heads; + *cyls = (unsigned short)cylinders; /* Stuff return values */ + *secs = (unsigned char)sectors; + *hds = (unsigned char)heads; } -/* - * Issue device specific ioctl calls. +/** + * i2o_block_open - Open the block device + * + * Power up the device, mount and lock the media. This function is called, + * if the block device is opened for access. + * + * Returns 0 on success or negative error code on failure. */ - -static int i2ob_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int i2o_block_open(struct inode *inode, struct file *file) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct i2ob_device *dev = disk->private_data; - void __user *argp = (void __user *)arg; + struct i2o_block_device *dev = inode->i_bdev->bd_disk->private_data; - /* Anyone capable of this syscall can do *real bad* things */ + if (!dev->i2o_dev) + return -ENODEV; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry g; - i2o_block_biosparam(get_capacity(disk), - &g.cylinders, &g.heads, &g.sectors); - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(argp, &g, sizeof(g))?-EFAULT:0; - } - - case BLKI2OGRSTRAT: - return put_user(dev->rcache, (int __user *)argp); - case BLKI2OGWSTRAT: - return put_user(dev->wcache, (int __user *)argp); - case BLKI2OSRSTRAT: - if(arg<0||arg>CACHE_SMARTFETCH) - return -EINVAL; - dev->rcache = arg; - break; - case BLKI2OSWSTRAT: - if(arg!=0 && (argCACHE_SMARTBACK)) - return -EINVAL; - dev->wcache = arg; - break; - } - return -ENOTTY; -} + if (dev->power > 0x1f) + i2o_block_device_power(dev, 0x02); -/* - * Close the block device down + i2o_block_device_mount(dev->i2o_dev, -1); + + i2o_block_device_lock(dev->i2o_dev, -1); + + pr_debug("Ready.\n"); + + return 0; +}; + +/** + * i2o_block_release - Release the I2O block device + * + * Unlock and unmount the media, and power down the device. Gets called if + * the block device is closed. + * + * Returns 0 on success or negative error code on failure. */ - -static int i2ob_release(struct inode *inode, struct file *file) +static int i2o_block_release(struct inode *inode, struct file *file) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct i2ob_device *dev = disk->private_data; + struct i2o_block_device *dev = disk->private_data; + u8 operation; /* * This is to deail with the case of an application * opening a device and then the device dissapears while * it's in use, and then the application tries to release - * it. ex: Unmounting a deleted RAID volume at reboot. + * it. ex: Unmounting a deleted RAID volume at reboot. * If we send messages, it will just cause FAILs since * the TID no longer exists. */ - if(!dev->i2odev) + if (!dev->i2o_dev) return 0; - if (dev->refcnt <= 0) - printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); - dev->refcnt--; - if(dev->refcnt==0) - { - /* - * Flush the onboard cache on unmount - */ - u32 msg[5]; - int *query_done = &dev->done_flag; - msg[0] = (FIVE_WORD_MSG_SIZE|SGL_OFFSET_0); - msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = 60<<16; - DEBUG("Flushing..."); - i2o_post_wait(dev->controller, msg, 20, 60); + i2o_block_device_flush(dev->i2o_dev); - /* - * Unlock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = -1; - DEBUG("Unlocking..."); - i2o_post_wait(dev->controller, msg, 20, 2); - DEBUG("Unlocked.\n"); - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid; - if(dev->flags & (1<<3|1<<4)) /* Removable */ - msg[4] = 0x21 << 24; - else - msg[4] = 0x24 << 24; - - if(i2o_post_wait(dev->controller, msg, 20, 60)==0) - dev->power = 0x24; + i2o_block_device_unlock(dev->i2o_dev, -1); - /* - * Now unclaim the device. - */ + if (dev->flags & (1 << 3 | 1 << 4)) /* Removable */ + operation = 0x21; + else + operation = 0x24; + + i2o_block_device_power(dev, operation); - if (i2o_release_device(dev->i2odev, &i2o_block_handler)) - printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); - - DEBUG("Unclaim\n"); - } return 0; } -/* - * Open the block device. +/** + * i2o_block_ioctl - Issue device specific ioctl calls. + * @cmd: ioctl command + * @arg: arg + * + * Handles ioctl request for the block device. + * + * Return 0 on success or negative error on failure. */ - -static int i2ob_open(struct inode *inode, struct file *file) +static int i2o_block_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct i2ob_device *dev = disk->private_data; + struct i2o_block_device *dev = disk->private_data; + void __user *argp = (void __user *)arg; - if(!dev->i2odev) - return -ENODEV; - - if(dev->refcnt++==0) - { - u32 msg[6]; - - DEBUG("Claim "); - if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) - { - dev->refcnt--; - printk(KERN_INFO "I2O Block: Could not open device\n"); - return -EBUSY; - } - DEBUG("Claimed "); - /* - * Power up if needed - */ + /* Anyone capable of this syscall can do *real bad* things */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; - if(dev->power > 0x1f) + switch (cmd) { + case HDIO_GETGEO: { - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid; - msg[4] = 0x02 << 24; - if(i2o_post_wait(dev->controller, msg, 20, 60) == 0) - dev->power = 0x02; + struct hd_geometry g; + i2o_block_biosparam(get_capacity(disk), + &g.cylinders, &g.heads, &g.sectors); + g.start = get_start_sect(inode->i_bdev); + return copy_to_user(argp, &g, sizeof(g)) ? -EFAULT : 0; } - /* - * Mount the media if needed. Note that we don't use - * the lock bit. Since we have to issue a lock if it - * refuses a mount (quite possible) then we might as - * well just send two messages out. - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; - msg[4] = -1; - msg[5] = 0; - DEBUG("Mount "); - i2o_post_wait(dev->controller, msg, 24, 2); - - /* - * Lock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; - msg[4] = -1; - DEBUG("Lock "); - i2o_post_wait(dev->controller, msg, 20, 2); - DEBUG("Ready.\n"); - } - return 0; -} + case BLKI2OGRSTRAT: + return put_user(dev->rcache, (int __user *)arg); + case BLKI2OGWSTRAT: + return put_user(dev->wcache, (int __user *)arg); + case BLKI2OSRSTRAT: + if (arg < 0 || arg > CACHE_SMARTFETCH) + return -EINVAL; + dev->rcache = arg; + break; + case BLKI2OSWSTRAT: + if (arg != 0 + && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK)) + return -EINVAL; + dev->wcache = arg; + break; + } + return -ENOTTY; +}; -/* - * Issue a device query +/** + * i2o_block_media_changed - Have we seen a media change? + * @disk: gendisk which should be verified + * + * Verifies if the media has changed. + * + * Returns 1 if the media was changed or 0 otherwise. */ - -static int i2ob_query_device(struct i2ob_device *dev, int table, - int field, void *buf, int buflen) +static int i2o_block_media_changed(struct gendisk *disk) { - return i2o_query_scalar(dev->controller, dev->tid, - table, field, buf, buflen); -} + struct i2o_block_device *p = disk->private_data; + if (p->media_change_flag) { + p->media_change_flag = 0; + return 1; + } + return 0; +} -/* - * Install the I2O block device we found. +/** + * i2o_block_transfer - Transfer a request to/from the I2O controller + * @req: the request which should be transfered + * + * This function converts the request into a I2O message. The necessary + * DMA buffers are allocated and after everything is setup post the message + * to the I2O controller. No cleanup is done by this function. It is done + * on the interrupt side when the reply arrives. + * + * Return 0 on success or negative error code on failure. */ - -static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit) +static int i2o_block_transfer(struct request *req) { - u64 size; - u32 blocksize; - u8 type; - u16 power; - u32 flags, status; - struct i2ob_device *dev=&i2ob_dev[unit]; - struct gendisk *disk; - request_queue_t *q; - int segments; - + struct i2o_block_device *dev = req->rq_disk->private_data; + struct i2o_controller *c = dev->i2o_dev->iop; + int tid = dev->i2o_dev->lct_data.tid; + struct i2o_message *msg; + void *mptr; + struct i2o_block_request *ireq = req->special; + struct scatterlist *sg; + int sgnum; + int i; + u32 m; + u32 tcntxt; + u32 sg_flags; + int rc; + + m = i2o_msg_get(c, &msg); + if (m == I2O_QUEUE_EMPTY) { + rc = -EBUSY; + goto exit; + } - /* - * For logging purposes... - */ - printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", - d->lct_data.tid, unit); + tcntxt = i2o_cntxt_list_add(c, req); + if (!tcntxt) { + rc = -ENOMEM; + goto nop_msg; + } - /* - * If this is the first I2O block device found on this IOP, - * we need to initialize all the queue data structures - * before any I/O can be performed. If it fails, this - * device is useless. - */ - if(!i2ob_queues[c->unit]) { - if(i2ob_init_iop(c->unit)) - return 1; + if ((sgnum = i2o_block_sglist_alloc(ireq)) <= 0) { + rc = -ENOMEM; + goto context_remove; } - q = i2ob_queues[c->unit]->req_queue; + /* Build the message based on the request. */ + writel(i2o_block_driver.context, &msg->u.s.icntxt); + writel(tcntxt, &msg->u.s.tcntxt); + writel(req->nr_sectors << 9, &msg->body[1]); - /* - * This will save one level of lookup/indirection in critical - * code so that we can directly get the queue ptr from the - * device instead of having to go the IOP data structure. - */ - dev->req_queue = q; + writel((((u64) req->sector) << 9) & 0xffffffff, &msg->body[2]); + writel(req->sector >> 23, &msg->body[3]); - /* - * Allocate a gendisk structure and initialize it - */ - disk = alloc_disk(16); - if (!disk) - return 1; + mptr = &msg->body[4]; - dev->gd = disk; - /* initialize gendik structure */ - disk->major = MAJOR_NR; - disk->first_minor = unit<<4; - disk->queue = q; - disk->fops = &i2ob_fops; - sprintf(disk->disk_name, "i2o/hd%c", 'a' + unit); - disk->private_data = dev; + sg = ireq->sg_table; - /* - * Ask for the current media data. If that isn't supported - * then we ask for the device capacity data - */ - if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 - || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) - { - i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); - i2ob_query_device(dev, 0x0000, 4, &size, 8); + if (rq_data_dir(req) == READ) { + writel(I2O_CMD_BLOCK_READ << 24 | HOST_TID << 12 | tid, + &msg->u.head[1]); + sg_flags = 0x10000000; + switch (dev->rcache) { + case CACHE_NULL: + writel(0, &msg->body[0]); + break; + case CACHE_PREFETCH: + writel(0x201F0008, &msg->body[0]); + break; + case CACHE_SMARTFETCH: + if (req->nr_sectors > 16) + writel(0x201F0008, &msg->body[0]); + else + writel(0x001F0000, &msg->body[0]); + break; + } + } else { + writel(I2O_CMD_BLOCK_WRITE << 24 | HOST_TID << 12 | tid, + &msg->u.head[1]); + sg_flags = 0x14000000; + switch (dev->wcache) { + case CACHE_NULL: + writel(0, &msg->body[0]); + break; + case CACHE_WRITETHROUGH: + writel(0x001F0008, &msg->body[0]); + break; + case CACHE_WRITEBACK: + writel(0x001F0010, &msg->body[0]); + break; + case CACHE_SMARTBACK: + if (req->nr_sectors > 16) + writel(0x001F0004, &msg->body[0]); + else + writel(0x001F0010, &msg->body[0]); + break; + case CACHE_SMARTTHROUGH: + if (req->nr_sectors > 16) + writel(0x001F0004, &msg->body[0]); + else + writel(0x001F0010, &msg->body[0]); + } } - - if(i2ob_query_device(dev, 0x0000, 2, &power, 2)!=0) - power = 0; - i2ob_query_device(dev, 0x0000, 5, &flags, 4); - i2ob_query_device(dev, 0x0000, 6, &status, 4); - set_capacity(disk, size>>9); - /* - * Max number of Scatter-Gather Elements - */ - - dev->power = power; /* Save power state in device proper */ - dev->flags = flags; - - segments = (d->controller->status_block->inbound_frame_size - 7) / 2; - - if(segments > 16) - segments = 16; - - dev->power = power; /* Save power state */ - dev->flags = flags; /* Keep the type info */ - - blk_queue_max_sectors(q, 96); /* 256 might be nicer but many controllers - explode on 65536 or higher */ - blk_queue_max_phys_segments(q, segments); - blk_queue_max_hw_segments(q, segments); - - dev->rcache = CACHE_SMARTFETCH; - dev->wcache = CACHE_WRITETHROUGH; - - if(d->controller->battery == 0) - dev->wcache = CACHE_WRITETHROUGH; - - if(d->controller->promise) - dev->wcache = CACHE_WRITETHROUGH; - - if(d->controller->short_req) - { - blk_queue_max_sectors(q, 8); - blk_queue_max_phys_segments(q, 8); - blk_queue_max_hw_segments(q, 8); + for (i = sgnum; i > 0; i--) { + if (i == 1) + sg_flags |= 0x80000000; + writel(sg_flags | sg_dma_len(sg), mptr); + writel(sg_dma_address(sg), mptr + 4); + mptr += 8; + sg++; } - strcpy(d->dev_name, disk->disk_name); - strcpy(disk->devfs_name, disk->disk_name); - - printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n", - d->dev_name, dev->max_segments, dev->depth, dev->max_sectors<<9); + writel(I2O_MESSAGE_SIZE + (((unsigned long)mptr - + (unsigned long)&msg->u.head[0]) >> 2) | SGL_OFFSET_8, + &msg->u.head[0]); - i2ob_query_device(dev, 0x0000, 0, &type, 1); - - printk(KERN_INFO "%s: ", d->dev_name); - switch(type) - { - case 0: printk("Disk Storage");break; - case 4: printk("WORM");break; - case 5: printk("CD-ROM");break; - case 7: printk("Optical device");break; - default: - printk("Type %d", type); - } - if(status&(1<<10)) - printk("(RAID)"); - - if((flags^status)&(1<<4|1<<3)) /* Missing media or device */ - { - printk(KERN_INFO " Not loaded.\n"); - /* Device missing ? */ - if((flags^status)&(1<<4)) - return 1; - } - else - { - printk(": %dMB, %d byte sectors", - (int)(size>>20), blocksize); - } - if(status&(1<<0)) - { - u32 cachesize; - i2ob_query_device(dev, 0x0003, 0, &cachesize, 4); - cachesize>>=10; - if(cachesize>4095) - printk(", %dMb cache", cachesize>>10); - else - printk(", %dKb cache", cachesize); - } - printk(".\n"); - printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", - d->dev_name, dev->max_sectors); + i2o_msg_post(c, m); - /* - * Register for the events we're interested in and that the - * device actually supports. - */ + list_add_tail(&ireq->queue, &dev->open_queue); + dev->open_queue_depth++; - i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, - (I2OB_EVENT_MASK & d->lct_data.event_capabilities)); return 0; -} - -/* - * Initialize IOP specific queue structures. This is called - * once for each IOP that has a block device sitting behind it. - */ -static int i2ob_init_iop(unsigned int unit) -{ - int i; - i2ob_queues[unit] = (struct i2ob_iop_queue *) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); - if(!i2ob_queues[unit]) - { - printk(KERN_WARNING "Could not allocate request queue for I2O block device!\n"); - return -1; - } - - for(i = 0; i< MAX_I2OB_DEPTH; i++) - { - i2ob_queues[unit]->request_queue[i].next = &i2ob_queues[unit]->request_queue[i+1]; - i2ob_queues[unit]->request_queue[i].num = i; - } - - /* Queue is MAX_I2OB + 1... */ - i2ob_queues[unit]->request_queue[i].next = NULL; - i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0]; - i2ob_queues[unit]->queue_depth = 0; - - i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED; - i2ob_queues[unit]->req_queue = blk_init_queue(i2ob_request, &i2ob_queues[unit]->lock); - if (!i2ob_queues[unit]->req_queue) { - kfree(i2ob_queues[unit]); - return -1; - } + context_remove: + i2o_cntxt_list_remove(c, req); - i2ob_queues[unit]->req_queue->queuedata = &i2ob_queues[unit]; + nop_msg: + i2o_msg_nop(c, m); - return 0; -} + exit: + return rc; +}; -/* - * Probe the I2O subsytem for block class devices +/** + * i2o_block_request_fn - request queue handling function + * q: request queue from which the request could be fetched + * + * Takes the next request from the queue, transfers it and if no error + * occurs dequeue it from the queue. On arrival of the reply the message + * will be processed further. If an error occurs requeue the request. */ -static void i2ob_scan(int bios) +static void i2o_block_request_fn(struct request_queue *q) { - int i; - int warned = 0; - - struct i2o_device *d, *b=NULL; - struct i2o_controller *c; - - for(i=0; i< MAX_I2O_CONTROLLERS; i++) - { - c=i2o_find_controller(i); - - if(c==NULL) - continue; + struct request *req; - /* - * The device list connected to the I2O Controller is doubly linked - * Here we traverse the end of the list , and start claiming devices - * from that end. This assures that within an I2O controller atleast - * the newly created volumes get claimed after the older ones, thus - * mapping to same major/minor (and hence device file name) after - * every reboot. - * The exception being: - * 1. If there was a TID reuse. - * 2. There was more than one I2O controller. - */ + while (!blk_queue_plugged(q)) { + req = elv_next_request(q); + if (!req) + break; - if(!bios) - { - for (d=c->devices;d!=NULL;d=d->next) - if(d->next == NULL) - b = d; - } - else - b = c->devices; + if (blk_fs_request(req)) { + struct i2o_block_delayed_request *dreq; + struct i2o_block_request *ireq = req->special; + unsigned int queue_depth; - while(b != NULL) - { - d=b; - if(bios) - b = b->next; - else - b = b->prev; + queue_depth = ireq->i2o_blk_dev->open_queue_depth; - if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) - continue; + if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) + if (!i2o_block_transfer(req)) { + blkdev_dequeue_request(req); + continue; + } - if(d->lct_data.user_tid != 0xFFF) - continue; + if (queue_depth) + break; - if(bios) - { - if(d->lct_data.bios_info != 0x80) - continue; - printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid); - } - else - { - if(d->lct_data.bios_info == 0x80) - continue; /*Already claimed on pass 1 */ - } + /* stop the queue and retry later */ + dreq = kmalloc(sizeof(*dreq), GFP_ATOMIC); + if (!dreq) + continue; - if(scan_unitqueue = q; + INIT_WORK(&dreq->work, i2o_block_delayed_request_fn, + dreq); + + printk(KERN_INFO "block-osm: transfer error\n"); + if (!queue_delayed_work(i2o_block_driver.event_queue, + &dreq->work, + I2O_BLOCK_RETRY_TIME)) + kfree(dreq); + else { + blk_stop_queue(q); + break; } - } - i2o_unlock_controller(c); + } else + end_request(req, 0); } -} +}; -static void i2ob_probe(void) +/* I2O Block device operations definition */ +static struct block_device_operations i2o_block_fops = { + .owner = THIS_MODULE, + .open = i2o_block_open, + .release = i2o_block_release, + .ioctl = i2o_block_ioctl, + .media_changed = i2o_block_media_changed +}; + +/** + * i2o_block_device_alloc - Allocate memory for a I2O Block device + * + * Allocate memory for the i2o_block_device struct, gendisk and request + * queue and initialize them as far as no additional information is needed. + * + * Returns a pointer to the allocated I2O Block device on succes or a + * negative error code on failure. + */ +static struct i2o_block_device *i2o_block_device_alloc(void) { - /* - * Some overhead/redundancy involved here, while trying to - * claim the first boot volume encountered as /dev/i2o/hda - * everytime. All the i2o_controllers are searched and the - * first i2o block device marked as bootable is claimed - * If an I2O block device was booted off , the bios sets - * its bios_info field to 0x80, this what we search for. - * Assuming that the bootable volume is /dev/i2o/hda - * everytime will prevent any kernel panic while mounting - * root partition - */ + struct i2o_block_device *dev; + struct gendisk *gd; + struct request_queue *queue; + int rc; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR "block-osm: Insufficient memory to allocate " + "I2O Block disk.\n"); + rc = -ENOMEM; + goto exit; + } + memset(dev, 0, sizeof(*dev)); + + INIT_LIST_HEAD(&dev->open_queue); + spin_lock_init(&dev->lock); + dev->rcache = CACHE_PREFETCH; + dev->wcache = CACHE_WRITEBACK; + + /* allocate a gendisk with 16 partitions */ + gd = alloc_disk(16); + if (!gd) { + printk(KERN_ERR "block-osm: Insufficient memory to allocate " + "gendisk.\n"); + rc = -ENOMEM; + goto cleanup_dev; + } - printk(KERN_INFO "i2o_block: Checking for Boot device...\n"); - i2ob_scan(1); + /* initialize the request queue */ + queue = blk_init_queue(i2o_block_request_fn, &dev->lock); + if (!queue) { + printk(KERN_ERR "block-osm: Insufficient memory to allocate " + "request queue.\n"); + rc = -ENOMEM; + goto cleanup_queue; + } - /* - * Now the remainder. - */ - printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n"); - i2ob_scan(0); -} + blk_queue_prep_rq(queue, i2o_block_prep_req_fn); + gd->major = I2O_MAJOR; + gd->queue = queue; + gd->fops = &i2o_block_fops; + gd->private_data = dev; -/* - * New device notification handler. Called whenever a new - * I2O block storage device is added to the system. - * - * Should we spin lock around this to keep multiple devs from - * getting updated at the same time? - * + dev->gd = gd; + + return dev; + + cleanup_queue: + put_disk(gd); + + cleanup_dev: + kfree(dev); + + exit: + return ERR_PTR(rc); +}; + +/** + * i2o_block_probe - verify if dev is a I2O Block device and install it + * @dev: device to verify if it is a I2O Block device + * + * We only verify if the user_tid of the device is 0xfff and then install + * the device. Otherwise it is used by some other device (e. g. RAID). + * + * Returns 0 on success or negative error code on failure. */ -void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d) +static int i2o_block_probe(struct device *dev) { - struct i2ob_device *dev; - int unit = 0; - - printk(KERN_INFO "i2o_block: New device detected\n"); - printk(KERN_INFO " Controller %d Tid %d\n",c->unit, d->lct_data.tid); + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_block_device *i2o_blk_dev; + struct i2o_controller *c = i2o_dev->iop; + struct gendisk *gd; + struct request_queue *queue; + static int unit = 0; + int rc; + u64 size; + u32 blocksize; + u16 power; + u32 flags, status; + int segments; - /* Check for available space */ - if(i2ob_dev_count>=MAX_I2OB) - { - printk(KERN_ERR "i2o_block: No more devices allowed!\n"); - return; + /* skip devices which are used by IOP */ + if (i2o_dev->lct_data.user_tid != 0xfff) { + pr_debug("skipping used device %03x\n", i2o_dev->lct_data.tid); + return -ENODEV; } - for(unit = 0; unit < MAX_I2OB; unit ++) - { - if(!i2ob_dev[unit].i2odev) - break; + + printk(KERN_INFO "block-osm: New device detected (TID: %03x)\n", + i2o_dev->lct_data.tid); + + if (i2o_device_claim(i2o_dev)) { + printk(KERN_WARNING "block-osm: Unable to claim device. " + "Installation aborted\n"); + rc = -EFAULT; + goto exit; } - if(i2o_claim_device(d, &i2o_block_handler)) - { - printk(KERN_INFO "i2o_block: Unable to claim device. Installation aborted\n"); - return; + i2o_blk_dev = i2o_block_device_alloc(); + if (IS_ERR(i2o_blk_dev)) { + printk(KERN_ERR "block-osm: could not alloc a new I2O block" + "device"); + rc = PTR_ERR(i2o_blk_dev); + goto claim_release; } - dev = &i2ob_dev[unit]; - dev->i2odev = d; - dev->controller = c; - dev->tid = d->lct_data.tid; - dev->unit = c->unit; + i2o_blk_dev->i2o_dev = i2o_dev; + dev_set_drvdata(dev, i2o_blk_dev); - if(i2ob_install_device(c,d,unit)) { - i2o_release_device(d, &i2o_block_handler); - printk(KERN_ERR "i2o_block: Could not install new device\n"); - } - else - { - i2o_release_device(d, &i2o_block_handler); - add_disk(dev->gd); - i2ob_dev_count++; - i2o_device_notify_on(d, &i2o_block_handler); - } + /* setup gendisk */ + gd = i2o_blk_dev->gd; + gd->first_minor = unit << 4; + sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit); + sprintf(gd->devfs_name, "i2o/hd%c", 'a' + unit); + gd->driverfs_dev = &i2o_dev->device; - return; -} + /* setup request queue */ + queue = gd->queue; + queue->queuedata = i2o_blk_dev; -/* - * Deleted device notification handler. Called when a device we - * are talking to has been deleted by the user or some other - * mysterious fource outside the kernel. - */ -void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d) -{ - int unit = 0; - unsigned long flags; - struct i2ob_device *dev; + blk_queue_max_phys_segments(queue, I2O_MAX_SEGMENTS); + blk_queue_max_sectors(queue, I2O_MAX_SECTORS); - for(unit = 0; unit < MAX_I2OB; unit ++) - { - dev = &i2ob_dev[unit]; - if(dev->i2odev == d) - { - printk(KERN_INFO " /dev/%s: Controller %d Tid %d\n", - d->dev_name, c->unit, d->lct_data.tid); - break; - } - } + if (c->short_req) + segments = 8; + else { + i2o_status_block *sb; - printk(KERN_INFO "I2O Block Device Deleted\n"); + sb = c->status_block.virt; - if(unit >= MAX_I2OB) - { - printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); - return; + segments = (sb->inbound_frame_size - + sizeof(struct i2o_message) / 4 - 4) / 2; } - spin_lock_irqsave(dev->req_queue->queue_lock, flags); + blk_queue_max_hw_segments(queue, segments); - /* - * Need to do this...we somtimes get two events from the IRTOS - * in a row and that causes lots of problems. - */ - i2o_device_notify_off(d, &i2o_block_handler); + pr_debug("max sectors: %d\n", I2O_MAX_SECTORS); + pr_debug("phys segments: %d\n", I2O_MAX_SEGMENTS); + pr_debug("hw segments: %d\n", segments); - /* - * This will force errors when i2ob_get_queue() is called - * by the kenrel. + /* + * Ask for the current media data. If that isn't supported + * then we ask for the device capacity data */ - if(dev->gd) { - struct gendisk *gd = dev->gd; - gd->queue = NULL; - del_gendisk(gd); - put_disk(gd); - dev->gd = NULL; + if (i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) != 0 + || i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) != 0) { + i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4); + i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8); } - spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); - dev->req_queue = NULL; - dev->i2odev = NULL; - dev->refcnt = 0; - dev->tid = 0; - - /* - * Do we need this? - * The media didn't really change...the device is just gone - */ - dev->media_change_flag = 1; + pr_debug("blocksize: %d\n", blocksize); - i2ob_dev_count--; -} + if (i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2)) + power = 0; + i2o_parm_field_get(i2o_dev, 0x0000, 5, &flags, 4); + i2o_parm_field_get(i2o_dev, 0x0000, 6, &status, 4); + + set_capacity(gd, size >> 9); + + i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff); + + add_disk(gd); + + unit++; -/* - * Have we seen a media change ? - */ -static int i2ob_media_change(struct gendisk *disk) -{ - struct i2ob_device *p = disk->private_data; - if(p->media_change_flag) - { - p->media_change_flag=0; - return 1; - } return 0; -} -static int i2ob_revalidate(struct gendisk *disk) -{ - struct i2ob_device *p = disk->private_data; - return i2ob_install_device(p->controller, p->i2odev, p->index); -} + claim_release: + i2o_device_claim_release(i2o_dev); -/* - * Reboot notifier. This is called by i2o_core when the system - * shuts down. - */ -static void i2ob_reboot_event(void) -{ - int i; - - for(i=0;irefcnt!=0) - { - /* - * Flush the onboard cache - */ - u32 msg[5]; - int *query_done = &dev->done_flag; - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = 60<<16; - - DEBUG("Flushing..."); - i2o_post_wait(dev->controller, msg, 20, 60); - - DEBUG("Unlocking..."); - /* - * Unlock the media - */ - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; - msg[4] = -1; - i2o_post_wait(dev->controller, msg, 20, 2); - - DEBUG("Unlocked.\n"); - } - } -} + exit: + return rc; +}; -static struct block_device_operations i2ob_fops = -{ - .owner = THIS_MODULE, - .open = i2ob_open, - .release = i2ob_release, - .ioctl = i2ob_ioctl, - .media_changed = i2ob_media_change, - .revalidate_disk= i2ob_revalidate, +/* Block OSM driver struct */ +static struct i2o_driver i2o_block_driver = { + .name = "block-osm", + .event = i2o_block_event, + .reply = i2o_block_reply, + .classes = i2o_block_class_id, + .driver = { + .probe = i2o_block_probe, + .remove = i2o_block_remove, + }, }; -/* - * And here should be modules and kernel interface - * (Just smiley confuses emacs :-) +/** + * i2o_block_init - Block OSM initialization function + * + * Allocate the slab and mempool for request structs, registers i2o_block + * block device and finally register the Block OSM in the I2O core. + * + * Returns 0 on success or negative error code on failure. */ - -static int i2o_block_init(void) +static int __init i2o_block_init(void) { - int i; + int rc; + int size; printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); printk(KERN_INFO " (c) Copyright 1999-2001 Red Hat Software.\n"); - - /* - * Register the block device interfaces - */ - if (register_blkdev(MAJOR_NR, "i2o_block")) - return -EIO; - -#ifdef MODULE - printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR); -#endif - /* - * Set up the queue - */ - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - i2ob_queues[i] = NULL; - - /* - * Now fill in the boiler plate - */ - - for (i = 0; i < MAX_I2OB; i++) { - struct i2ob_device *dev = &i2ob_dev[i]; - dev->index = i; - dev->refcnt = 0; - dev->flags = 0; - dev->controller = NULL; - dev->i2odev = NULL; - dev->tid = 0; - dev->head = NULL; - dev->tail = NULL; - dev->depth = MAX_I2OB_DEPTH; - dev->max_sectors = 2; - dev->gd = NULL; + /* Allocate request mempool and slab */ + size = sizeof(struct i2o_block_request); + i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0, + SLAB_HWCACHE_ALIGN, NULL, + NULL); + if (!i2o_blk_req_pool.slab) { + printk(KERN_ERR "block-osm: can't init request slab\n"); + rc = -ENOMEM; + goto exit; } - - /* - * Register the OSM handler as we will need this to probe for - * drives, geometry and other goodies. - */ - if(i2o_install_handler(&i2o_block_handler)<0) - { - unregister_blkdev(MAJOR_NR, "i2o_block"); - printk(KERN_ERR "i2o_block: unable to register OSM.\n"); - return -EINVAL; + i2o_blk_req_pool.pool = mempool_create(I2O_REQ_MEMPOOL_SIZE, + mempool_alloc_slab, + mempool_free_slab, + i2o_blk_req_pool.slab); + if (!i2o_blk_req_pool.pool) { + printk(KERN_ERR "block-osm: can't init request mempool\n"); + rc = -ENOMEM; + goto free_slab; } - i2ob_context = i2o_block_handler.context; - /* - * Initialize event handling thread - */ - init_MUTEX_LOCKED(&i2ob_evt_sem); - evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND); - if(evt_pid < 0) - { - printk(KERN_ERR "i2o_block: Could not initialize event thread. Aborting\n"); - i2o_remove_handler(&i2o_block_handler); - return 0; + /* Register the block device interfaces */ + rc = register_blkdev(I2O_MAJOR, "i2o_block"); + if (rc) { + printk(KERN_ERR "block-osm: unable to register block device\n"); + goto free_mempool; } +#ifdef MODULE + printk(KERN_INFO "block-osm: registered device at major %d\n", + I2O_MAJOR); +#endif - i2ob_probe(); + /* Register Block OSM into I2O core */ + rc = i2o_driver_register(&i2o_block_driver); + if (rc) { + printk(KERN_ERR "block-osm: Could not register Block driver\n"); + goto unregister_blkdev; + } return 0; - unregister_blkdev(MAJOR_NR, "i2o_block"); - return -ENOMEM; -} + unregister_blkdev: + unregister_blkdev(I2O_MAJOR, "i2o_block"); + free_mempool: + mempool_destroy(i2o_blk_req_pool.pool); -static void i2o_block_exit(void) -{ - int i; - - if(evt_running) { - printk(KERN_INFO "Killing I2O block threads..."); - i = kill_proc(evt_pid, SIGKILL, 1); - if(!i) { - printk("waiting...\n"); - } - /* Be sure it died */ - wait_for_completion(&i2ob_thread_dead); - printk("done.\n"); - } + free_slab: + kmem_cache_destroy(i2o_blk_req_pool.slab); - /* - * Unregister for updates from any devices..otherwise we still - * get them and the core jumps to random memory :O - */ - if(i2ob_dev_count) { - struct i2o_device *d; - for(i = 0; i < MAX_I2OB; i++) - if((d = i2ob_dev[i].i2odev)) - i2ob_del_device(d->controller, d); - } - - /* - * We may get further callbacks for ourself. The i2o_core - * code handles this case reasonably sanely. The problem here - * is we shouldn't get them .. but a couple of cards feel - * obliged to tell us stuff we don't care about. - * - * This isnt ideal at all but will do for now. - */ - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - - /* - * Flush the OSM - */ + exit: + return rc; +}; - i2o_remove_handler(&i2o_block_handler); +/** + * i2o_block_exit - Block OSM exit function + * + * Unregisters Block OSM from I2O core, unregisters i2o_block block device + * and frees the mempool and slab. + */ +static void __exit i2o_block_exit(void) +{ + /* Unregister I2O Block OSM from I2O core */ + i2o_driver_unregister(&i2o_block_driver); - /* - * Return the block device - */ - if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) - printk("i2o_block: cleanup_module failed\n"); + /* Unregister block device */ + unregister_blkdev(I2O_MAJOR, "i2o_block"); - /* - * release request queue - */ - for (i = 0; i < MAX_I2O_CONTROLLERS; i ++) - if(i2ob_queues[i]) { - blk_cleanup_queue(i2ob_queues[i]->req_queue); - kfree(i2ob_queues[i]); - } -} + /* Free request mempool and slab */ + mempool_destroy(i2o_blk_req_pool.pool); + kmem_cache_destroy(i2o_blk_req_pool.slab); +}; MODULE_AUTHOR("Red Hat"); MODULE_DESCRIPTION("I2O Block Device OSM"); diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h new file mode 100644 index 000000000..ddd9a1567 --- /dev/null +++ b/drivers/message/i2o/i2o_block.h @@ -0,0 +1,99 @@ +/* + * Block OSM structures/API + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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. + * + * For the purpose of avoiding doubt the preferred form of the work + * for making modifications shall be a standards compliant form such + * gzipped tar and not one requiring a proprietary or patent encumbered + * tool to unpack. + * + * Fixes/additions: + * Steve Ralston: + * Multiple device handling error fixes, + * Added a queue depth. + * Alan Cox: + * FC920 has an rmw bug. Dont or in the end marker. + * Removed queue walk, fixed for 64bitness. + * Rewrote much of the code over time + * Added indirect block lists + * Handle 64K limits on many controllers + * Don't use indirects on the Promise (breaks) + * Heavily chop down the queue depths + * Deepak Saxena: + * Independent queues per IOP + * Support for dynamic device creation/deletion + * Code cleanup + * Support for larger I/Os through merge* functions + * (taken from DAC960 driver) + * Boji T Kannanthanam: + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off + * from as the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the + * system gendisk list. The I2O block devices now appear in + * /proc/partitions. + * Markus Lidel : + * Minor bugfixes for 2.6. + */ + +#ifndef I2O_BLOCK_OSM_H +#define I2O_BLOCK_OSM_H + +#define I2O_BLOCK_RETRY_TIME HZ/4 +#define I2O_BLOCK_MAX_OPEN_REQUESTS 50 + +/* I2O Block OSM mempool struct */ +struct i2o_block_mempool { + kmem_cache_t *slab; + mempool_t *pool; +}; + +/* I2O Block device descriptor */ +struct i2o_block_device { + struct i2o_device *i2o_dev; /* pointer to I2O device */ + struct gendisk *gd; + spinlock_t lock; /* queue lock */ + struct list_head open_queue; /* list of transfered, but unfinished + requests */ + unsigned int open_queue_depth; /* number of requests in the queue */ + + int rcache; /* read cache flags */ + int wcache; /* write cache flags */ + int flags; + int power; /* power state */ + int media_change_flag; /* media changed flag */ +}; + +/* I2O Block device request */ +struct i2o_block_request +{ + struct list_head queue; + struct request *req; /* corresponding request */ + struct i2o_block_device *i2o_blk_dev; /* I2O block device */ + int sg_dma_direction; /* direction of DMA buffer read/write */ + int sg_nents; /* number of SG elements */ + struct scatterlist sg_table[I2O_MAX_SEGMENTS]; /* SG table */ +}; + +/* I2O Block device delayed request */ +struct i2o_block_delayed_request +{ + struct work_struct work; + struct request_queue *queue; +}; + +#endif diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c index a28c4423b..4c240102a 100644 --- a/drivers/message/i2o/i2o_config.c +++ b/drivers/message/i2o/i2o_config.c @@ -2,7 +2,7 @@ * I2O Configuration Interface Driver * * (C) Copyright 1999-2002 Red Hat - * + * * Written by Alan Cox, Building Number Three Ltd * * Fixes/additions: @@ -41,63 +41,53 @@ #include #include #include +#include +#include +#include #include #include -static int i2o_cfg_context = -1; -static void *page_buf; +extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int); + static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; #define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct sg_simple_element { - u32 flag_count; + u32 flag_count; u32 addr_bus; }; -struct i2o_cfg_info -{ - struct file* fp; +struct i2o_cfg_info { + struct file *fp; struct fasync_struct *fasync; struct i2o_evt_info event_q[I2O_EVT_Q_LEN]; - u16 q_in; // Queue head index - u16 q_out; // Queue tail index - u16 q_len; // Queue length - u16 q_lost; // Number of lost events - u32 q_id; // Event queue ID...used as tx_context - struct i2o_cfg_info *next; + u16 q_in; // Queue head index + u16 q_out; // Queue tail index + u16 q_len; // Queue length + u16 q_lost; // Number of lost events + ulong q_id; // Event queue ID...used as tx_context + struct i2o_cfg_info *next; }; static struct i2o_cfg_info *open_files = NULL; -static int i2o_cfg_info_id = 0; - -static int ioctl_getiops(unsigned long); -static int ioctl_gethrt(unsigned long); -static int ioctl_getlct(unsigned long); -static int ioctl_parms(unsigned long, unsigned int); -static int ioctl_html(unsigned long); -static int ioctl_swdl(unsigned long); -static int ioctl_swul(unsigned long); -static int ioctl_swdel(unsigned long); -static int ioctl_validate(unsigned long); -static int ioctl_evt_reg(unsigned long, struct file *); -static int ioctl_evt_get(unsigned long, struct file *); -static int ioctl_passthru(unsigned long); -static int cfg_fasync(int, struct file*, int); +static ulong i2o_cfg_info_id = 0; +#if 0 /* * This is the callback for any message we have posted. The message itself * will be returned to the message pool when we return from the IRQ * * This runs in irq context so be short and sweet. */ -static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) +static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, + struct i2o_message *m) { - u32 *msg = (u32 *)m; + u32 *msg = (u32 *) m; if (msg[0] & MSG_FAIL) { - u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]); + u32 *preserved_msg = (u32 *) (c->msg_virt + msg[7]); printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); @@ -109,26 +99,25 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc i2o_post_message(c, msg[7]); } - if (msg[4] >> 24) // ReqStatus != SUCCESS - i2o_report_status(KERN_INFO,"i2o_config", msg); + if (msg[4] >> 24) // ReqStatus != SUCCESS + i2o_report_status(KERN_INFO, "i2o_config", msg); - if(m->function == I2O_CMD_UTIL_EVT_REGISTER) - { + if (m->function == I2O_CMD_UTIL_EVT_REGISTER) { struct i2o_cfg_info *inf; - for(inf = open_files; inf; inf = inf->next) - if(inf->q_id == msg[3]) + for (inf = open_files; inf; inf = inf->next) + if (inf->q_id == i2o_cntxt_list_get(c, msg[3])) break; // // If this is the case, it means that we're getting // events for a file descriptor that's been close()'d // w/o the user unregistering for events first. - // The code currently assumes that the user will + // The code currently assumes that the user will // take care of unregistering for events before closing // a file. - // - // TODO: + // + // TODO: // Should we track event registartion and deregister // for events when a file is close()'d so this doesn't // happen? That would get rid of the search through @@ -137,8 +126,8 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc // it would mean having all sorts of tables to track // what each file is registered for...I think the // current method is simpler. - DS - // - if(!inf) + // + if (!inf) return; inf->event_q[inf->q_in].id.iop = c->unit; @@ -149,278 +138,167 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc // Data size = msg size - reply header // inf->event_q[inf->q_in].data_size = (m->size - 5) * 4; - if(inf->event_q[inf->q_in].data_size) - memcpy(inf->event_q[inf->q_in].evt_data, - (unsigned char *)(msg + 5), - inf->event_q[inf->q_in].data_size); + if (inf->event_q[inf->q_in].data_size) + memcpy(inf->event_q[inf->q_in].evt_data, + (unsigned char *)(msg + 5), + inf->event_q[inf->q_in].data_size); spin_lock(&i2o_config_lock); MODINC(inf->q_in, I2O_EVT_Q_LEN); - if(inf->q_len == I2O_EVT_Q_LEN) - { + if (inf->q_len == I2O_EVT_Q_LEN) { MODINC(inf->q_out, I2O_EVT_Q_LEN); inf->q_lost++; - } - else - { + } else { // Keep I2OEVTGET on another CPU from touching this inf->q_len++; } spin_unlock(&i2o_config_lock); - -// printk(KERN_INFO "File %p w/id %d has %d events\n", -// inf->fp, inf->q_id, inf->q_len); +// printk(KERN_INFO "File %p w/id %d has %d events\n", +// inf->fp, inf->q_id, inf->q_len); kill_fasync(&inf->fasync, SIGIO, POLL_IN); } return; } +#endif /* * Each of these describes an i2o message handler. They are * multiplexed by the i2o_core code */ - -struct i2o_handler cfg_handler= -{ - i2o_cfg_reply, - NULL, - NULL, - NULL, - "Configuration", - 0, - 0xffffffff // All classes -}; - -static ssize_t cfg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - printk(KERN_INFO "i2o_config write not yet supported\n"); - - return 0; -} +struct i2o_driver i2o_config_driver = { + .name = "Config-OSM" +}; -static ssize_t cfg_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) +static int i2o_cfg_getiops(unsigned long arg) { - return 0; -} - -/* - * IOCTL Handler - */ -static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, - unsigned long arg) -{ - int ret; - - switch(cmd) - { - case I2OGETIOPS: - ret = ioctl_getiops(arg); - break; - - case I2OHRTGET: - ret = ioctl_gethrt(arg); - break; - - case I2OLCTGET: - ret = ioctl_getlct(arg); - break; - - case I2OPARMSET: - ret = ioctl_parms(arg, I2OPARMSET); - break; - - case I2OPARMGET: - ret = ioctl_parms(arg, I2OPARMGET); - break; - - case I2OSWDL: - ret = ioctl_swdl(arg); - break; - - case I2OSWUL: - ret = ioctl_swul(arg); - break; - - case I2OSWDEL: - ret = ioctl_swdel(arg); - break; - - case I2OVALIDATE: - ret = ioctl_validate(arg); - break; - - case I2OHTML: - ret = ioctl_html(arg); - break; - - case I2OEVTREG: - ret = ioctl_evt_reg(arg, fp); - break; - - case I2OEVTGET: - ret = ioctl_evt_get(arg, fp); - break; - - case I2OPASSTHRU: - ret = ioctl_passthru(arg); - break; - - default: - ret = -EINVAL; - } - - return ret; -} + struct i2o_controller *c; + u8 __user *user_iop_table = (void __user *)arg; + u8 tmp[MAX_I2O_CONTROLLERS]; -int ioctl_getiops(unsigned long arg) -{ - u8 __user *user_iop_table = (void __user *)arg; - struct i2o_controller *c = NULL; - int i; - u8 foo[MAX_I2O_CONTROLLERS]; + memset(tmp, 0, MAX_I2O_CONTROLLERS); - if(!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) + if (!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) return -EFAULT; - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - c = i2o_find_controller(i); - if(c) - { - foo[i] = 1; - if(pci_set_dma_mask(c->pdev, 0xffffffff)) - { - printk(KERN_WARNING "i2o_config : No suitable DMA available on controller %d\n", i); - i2o_unlock_controller(c); - continue; - } - - i2o_unlock_controller(c); - } - else - { - foo[i] = 0; - } - } + list_for_each_entry(c, &i2o_controllers, list) + tmp[c->unit] = 1; + + __copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS); - __copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS); return 0; -} +}; -int ioctl_gethrt(unsigned long arg) +static int i2o_cfg_gethrt(unsigned long arg) { struct i2o_controller *c; - struct i2o_cmd_hrtlct __user *cmd = (void __user *)arg; + struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg; struct i2o_cmd_hrtlct kcmd; i2o_hrt *hrt; int len; u32 reslen; int ret = 0; - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) return -EFAULT; - if(get_user(reslen, kcmd.reslen) < 0) + if (get_user(reslen, kcmd.reslen) < 0) return -EFAULT; - if(kcmd.resbuf == NULL) + if (kcmd.resbuf == NULL) return -EFAULT; - c = i2o_find_controller(kcmd.iop); - if(!c) + c = i2o_find_iop(kcmd.iop); + if (!c) return -ENXIO; - - hrt = (i2o_hrt *)c->hrt; - i2o_unlock_controller(c); + hrt = (i2o_hrt *) c->hrt.virt; len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); - + /* We did a get user...so assuming mem is ok...is this bad? */ put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - if(copy_to_user(kcmd.resbuf, (void*)hrt, len)) + if (len > reslen) + ret = -ENOBUFS; + if (copy_to_user(kcmd.resbuf, (void *)hrt, len)) ret = -EFAULT; return ret; -} +}; -int ioctl_getlct(unsigned long arg) +static int i2o_cfg_getlct(unsigned long arg) { struct i2o_controller *c; - struct i2o_cmd_hrtlct __user *cmd = (void __user *)arg; + struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg; struct i2o_cmd_hrtlct kcmd; i2o_lct *lct; int len; int ret = 0; u32 reslen; - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) return -EFAULT; - if(get_user(reslen, kcmd.reslen) < 0) + if (get_user(reslen, kcmd.reslen) < 0) return -EFAULT; - if(kcmd.resbuf == NULL) + if (kcmd.resbuf == NULL) return -EFAULT; - c = i2o_find_controller(kcmd.iop); - if(!c) + c = i2o_find_iop(kcmd.iop); + if (!c) return -ENXIO; - lct = (i2o_lct *)c->lct; - i2o_unlock_controller(c); + lct = (i2o_lct *) c->lct; len = (unsigned int)lct->table_size << 2; put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOBUFS; - else if(copy_to_user(kcmd.resbuf, (void*)lct, len)) + if (len > reslen) + ret = -ENOBUFS; + else if (copy_to_user(kcmd.resbuf, lct, len)) ret = -EFAULT; return ret; -} +}; -static int ioctl_parms(unsigned long arg, unsigned int type) +static int i2o_cfg_parms(unsigned long arg, unsigned int type) { int ret = 0; struct i2o_controller *c; - struct i2o_cmd_psetget __user *cmd = (void __user *)arg; + struct i2o_device *dev; + struct i2o_cmd_psetget __user *cmd = + (struct i2o_cmd_psetget __user *)arg; struct i2o_cmd_psetget kcmd; u32 reslen; u8 *ops; u8 *res; - int len; + int len = 0; - u32 i2o_cmd = (type == I2OPARMGET ? - I2O_CMD_UTIL_PARAMS_GET : - I2O_CMD_UTIL_PARAMS_SET); + u32 i2o_cmd = (type == I2OPARMGET ? + I2O_CMD_UTIL_PARAMS_GET : I2O_CMD_UTIL_PARAMS_SET); - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) + if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) return -EFAULT; - if(get_user(reslen, kcmd.reslen)) + if (get_user(reslen, kcmd.reslen)) return -EFAULT; - c = i2o_find_controller(kcmd.iop); - if(!c) + c = i2o_find_iop(kcmd.iop); + if (!c) + return -ENXIO; + + dev = i2o_iop_find_device(c, kcmd.tid); + if (!dev) return -ENXIO; - ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL); - if(!ops) - { - i2o_unlock_controller(c); + ops = (u8 *) kmalloc(kcmd.oplen, GFP_KERNEL); + if (!ops) return -ENOMEM; - } - if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) - { - i2o_unlock_controller(c); + if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) { kfree(ops); return -EFAULT; } @@ -429,404 +307,309 @@ static int ioctl_parms(unsigned long arg, unsigned int type) * It's possible to have a _very_ large table * and that the user asks for all of it at once... */ - res = (u8*)kmalloc(65536, GFP_KERNEL); - if(!res) - { - i2o_unlock_controller(c); + res = (u8 *) kmalloc(65536, GFP_KERNEL); + if (!res) { kfree(ops); return -ENOMEM; } - len = i2o_issue_params(i2o_cmd, c, kcmd.tid, - ops, kcmd.oplen, res, 65536); - i2o_unlock_controller(c); + len = i2o_parm_issue(dev, i2o_cmd, ops, kcmd.oplen, res, 65536); kfree(ops); - + if (len < 0) { kfree(res); return -EAGAIN; } put_user(len, kcmd.reslen); - if(len > reslen) + if (len > reslen) ret = -ENOBUFS; - else if(copy_to_user(kcmd.resbuf, res, len)) + else if (copy_to_user(kcmd.resbuf, res, len)) ret = -EFAULT; kfree(res); return ret; -} - -int ioctl_html(unsigned long arg) -{ - struct i2o_html __user *cmd = (void __user *)arg; - struct i2o_html kcmd; - struct i2o_controller *c; - u8 *res = NULL; - void *query = NULL; - dma_addr_t query_phys, res_phys; - int ret = 0; - int token; - u32 len; - u32 reslen; - u32 msg[MSG_FRAME_SIZE]; - - if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html))) - { - printk(KERN_INFO "i2o_config: can't copy html cmd\n"); - return -EFAULT; - } - - if(get_user(reslen, kcmd.reslen) < 0) - { - printk(KERN_INFO "i2o_config: can't copy html reslen\n"); - return -EFAULT; - } - - if(!kcmd.resbuf) - { - printk(KERN_INFO "i2o_config: NULL html buffer\n"); - return -EFAULT; - } - - c = i2o_find_controller(kcmd.iop); - if(!c) - return -ENXIO; - - if(kcmd.qlen) /* Check for post data */ - { - query = pci_alloc_consistent(c->pdev, kcmd.qlen, &query_phys); - if(!query) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - if(copy_from_user(query, kcmd.qbuf, kcmd.qlen)) - { - i2o_unlock_controller(c); - printk(KERN_INFO "i2o_config: could not get query\n"); - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); - return -EFAULT; - } - } - - res = pci_alloc_consistent(c->pdev, 65536, &res_phys); - if(!res) - { - i2o_unlock_controller(c); - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); - return -ENOMEM; - } - - msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid; - msg[2] = i2o_cfg_context; - msg[3] = 0; - msg[4] = kcmd.page; - msg[5] = 0xD0000000|65536; - msg[6] = res_phys; - if(!kcmd.qlen) /* Check for post data */ - msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; - else - { - msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[5] = 0x50000000|65536; - msg[7] = 0xD4000000|(kcmd.qlen); - msg[8] = query_phys; - } - /* - Wait for a considerable time till the Controller - does its job before timing out. The controller might - take more time to process this request if there are - many devices connected to it. - */ - token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res, query_phys, res_phys, kcmd.qlen, 65536); - if(token < 0) - { - printk(KERN_DEBUG "token = %#10x\n", token); - i2o_unlock_controller(c); - - if(token != -ETIMEDOUT) - { - pci_free_consistent(c->pdev, 65536, res, res_phys); - if(kcmd.qlen) - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); - } - return token; - } - i2o_unlock_controller(c); - - len = strnlen(res, 65536); - put_user(len, kcmd.reslen); - if(len > reslen) - ret = -ENOMEM; - if(copy_to_user(kcmd.resbuf, res, len)) - ret = -EFAULT; - - pci_free_consistent(c->pdev, 65536, res, res_phys); - if(kcmd.qlen) - pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); +}; - return ret; -} - -int ioctl_swdl(unsigned long arg) +static int i2o_cfg_swdl(unsigned long arg) { struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer __user *pxfer = (void __user *)arg; + struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; unsigned char maxfrag = 0, curfrag = 1; - unsigned char *buffer; - u32 msg[9]; + struct i2o_dma buffer; + struct i2o_message *msg; + u32 m; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; - dma_addr_t buffer_phys; - if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; - if(get_user(swlen, kxfer.swlen) < 0) + if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; - if(get_user(maxfrag, kxfer.maxfrag) < 0) + if (get_user(maxfrag, kxfer.maxfrag) < 0) return -EFAULT; - if(get_user(curfrag, kxfer.curfrag) < 0) + if (get_user(curfrag, kxfer.curfrag) < 0) return -EFAULT; - if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; + if (curfrag == maxfrag) + fragsize = swlen - (maxfrag - 1) * 8192; - if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) + if (!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if(!c) + + c = i2o_find_iop(kxfer.iop); + if (!c) return -ENXIO; - buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); - if (buffer==NULL) - { - i2o_unlock_controller(c); + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { + i2o_msg_nop(c, m); return -ENOMEM; } - __copy_from_user(buffer, kxfer.buf, fragsize); - - msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; - msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) | - (((u32)maxfrag)<<8) | (((u32)curfrag)); - msg[5]= swlen; - msg[6]= kxfer.sw_id; - msg[7]= (0xD0000000 | fragsize); - msg[8]= buffer_phys; - -// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); - - i2o_unlock_controller(c); - if(status != -ETIMEDOUT) - pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); - - if (status != I2O_POST_WAIT_OK) - { + + __copy_from_user(buffer.virt, kxfer.buf, fragsize); + + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); + writel(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + writel((((u32) kxfer.flags) << 24) | (((u32) kxfer.sw_type) << 16) | + (((u32) maxfrag) << 8) | (((u32) curfrag)), &msg->body[0]); + writel(swlen, &msg->body[1]); + writel(kxfer.sw_id, &msg->body[2]); + writel(0xD0000000 | fragsize, &msg->body[3]); + writel(buffer.phys, &msg->body[4]); + +// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); + status = i2o_msg_post_wait_mem(c, m, 60, &buffer); + + if (status != -ETIMEDOUT) + i2o_dma_free(&c->pdev->dev, &buffer); + + if (status != I2O_POST_WAIT_OK) { // it fails if you try and send frags out of order // and for some yet unknown reasons too - printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); + printk(KERN_INFO + "i2o_config: swdl failed, DetailedStatus = %d\n", + status); return status; } return 0; -} +}; -int ioctl_swul(unsigned long arg) +static int i2o_cfg_swul(unsigned long arg) { struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer __user *pxfer = (void __user *)arg; + struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; unsigned char maxfrag = 0, curfrag = 1; - unsigned char *buffer; - u32 msg[9]; + struct i2o_dma buffer; + struct i2o_message *msg; + u32 m; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; - dma_addr_t buffer_phys; - - if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; - - if(get_user(swlen, kxfer.swlen) < 0) + + if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; - - if(get_user(maxfrag, kxfer.maxfrag) < 0) + + if (get_user(maxfrag, kxfer.maxfrag) < 0) return -EFAULT; - - if(get_user(curfrag, kxfer.curfrag) < 0) + + if (get_user(curfrag, kxfer.curfrag) < 0) return -EFAULT; - - if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; - - if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) + + if (curfrag == maxfrag) + fragsize = swlen - (maxfrag - 1) * 8192; + + if (!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) return -EFAULT; - - c = i2o_find_controller(kxfer.iop); - if(!c) + + c = i2o_find_iop(kxfer.iop); + if (!c) return -ENXIO; - - buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); - if (buffer==NULL) - { - i2o_unlock_controller(c); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { + i2o_msg_nop(c, m); return -ENOMEM; } - - msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; - msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag; - msg[5]= swlen; - msg[6]= kxfer.sw_id; - msg[7]= (0xD0000000 | fragsize); - msg[8]= buffer_phys; - -// printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); - i2o_unlock_controller(c); - - if (status != I2O_POST_WAIT_OK) - { - if(status != -ETIMEDOUT) - pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); - printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); + + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); + writel(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + writel((u32) kxfer.flags << 24 | (u32) kxfer. + sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag, + &msg->body[0]); + writel(swlen, &msg->body[1]); + writel(kxfer.sw_id, &msg->body[2]); + writel(0xD0000000 | fragsize, &msg->body[3]); + writel(buffer.phys, &msg->body[4]); + +// printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); + status = i2o_msg_post_wait_mem(c, m, 60, &buffer); + + if (status != I2O_POST_WAIT_OK) { + if (status != -ETIMEDOUT) + i2o_dma_free(&c->pdev->dev, &buffer); + + printk(KERN_INFO + "i2o_config: swul failed, DetailedStatus = %d\n", + status); return status; } - - __copy_to_user(kxfer.buf, buffer, fragsize); - pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); - + + __copy_to_user(kxfer.buf, buffer.virt, fragsize); + i2o_dma_free(&c->pdev->dev, &buffer); + return 0; -} +}; -int ioctl_swdel(unsigned long arg) +static int i2o_cfg_swdel(unsigned long arg) { struct i2o_controller *c; struct i2o_sw_xfer kxfer; - struct i2o_sw_xfer __user *pxfer = (void __user *)arg; - u32 msg[7]; + struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; + struct i2o_message *msg; + u32 m; unsigned int swlen; int token; - + if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; - + if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; - - c = i2o_find_controller(kxfer.iop); + + c = i2o_find_iop(kxfer.iop); if (!c) return -ENXIO; - msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = (u32)i2o_cfg_context; - msg[3] = 0; - msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16; - msg[5] = swlen; - msg[6] = kxfer.sw_id; - - token = i2o_post_wait(c, msg, sizeof(msg), 10); - i2o_unlock_controller(c); - - if (token != I2O_POST_WAIT_OK) - { - printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token); + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + writel(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + writel((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16, + &msg->body[0]); + writel(swlen, &msg->body[1]); + writel(kxfer.sw_id, &msg->body[2]); + + token = i2o_msg_post_wait(c, m, 10); + + if (token != I2O_POST_WAIT_OK) { + printk(KERN_INFO + "i2o_config: swdel failed, DetailedStatus = %d\n", + token); return -ETIMEDOUT; } - + return 0; -} +}; -int ioctl_validate(unsigned long arg) +static int i2o_cfg_validate(unsigned long arg) { - int token; - int iop = (int)arg; - u32 msg[4]; - struct i2o_controller *c; - - c=i2o_find_controller(iop); - if (!c) - return -ENXIO; - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop; - msg[2] = (u32)i2o_cfg_context; - msg[3] = 0; - - token = i2o_post_wait(c, msg, sizeof(msg), 10); - i2o_unlock_controller(c); - - if (token != I2O_POST_WAIT_OK) - { - printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n", - token); - return -ETIMEDOUT; - } - - return 0; -} - -static int ioctl_evt_reg(unsigned long arg, struct file *fp) + int token; + int iop = (int)arg; + struct i2o_message *msg; + u32 m; + struct i2o_controller *c; + + c = i2o_find_iop(iop); + if (!c) + return -ENXIO; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + + token = i2o_msg_post_wait(c, m, 10); + + if (token != I2O_POST_WAIT_OK) { + printk(KERN_INFO "Can't validate configuration, ErrorStatus = " + "%d\n", token); + return -ETIMEDOUT; + } + + return 0; +}; + +static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp) { - u32 msg[5]; - struct i2o_evt_id __user *pdesc = (void __user *)arg; + struct i2o_message *msg; + u32 m; + struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg; struct i2o_evt_id kdesc; - struct i2o_controller *iop; + struct i2o_controller *c; struct i2o_device *d; if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) return -EFAULT; /* IOP exists? */ - iop = i2o_find_controller(kdesc.iop); - if(!iop) + c = i2o_find_iop(kdesc.iop); + if (!c) return -ENXIO; - i2o_unlock_controller(iop); /* Device exists? */ - for(d = iop->devices; d; d = d->next) - if(d->lct_data.tid == kdesc.tid) - break; - - if(!d) + d = i2o_iop_find_device(c, kdesc.tid); + if (!d) return -ENODEV; - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid; - msg[2] = (u32)i2o_cfg_context; - msg[3] = (u32)fp->private_data; - msg[4] = kdesc.evt_mask; + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | kdesc.tid, + &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(i2o_cntxt_list_add(c, fp->private_data), &msg->u.head[3]); + writel(kdesc.evt_mask, &msg->body[0]); - i2o_post_this(iop, msg, 20); + i2o_msg_post(c, m); return 0; -} +} -static int ioctl_evt_get(unsigned long arg, struct file *fp) +static int i2o_cfg_evt_get(unsigned long arg, struct file *fp) { - u32 id = (u32)fp->private_data; struct i2o_cfg_info *p = NULL; - struct i2o_evt_get __user *uget = (void __user *)arg; + struct i2o_evt_get __user *uget = (struct i2o_evt_get __user *)arg; struct i2o_evt_get kget; unsigned long flags; - for(p = open_files; p; p = p->next) - if(p->q_id == id) + for (p = open_files; p; p = p->next) + if (p->q_id == (ulong) fp->private_data) break; - if(!p->q_len) - { + if (!p->q_len) return -ENOENT; - return 0; - } memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); MODINC(p->q_out, I2O_EVT_Q_LEN); @@ -836,16 +619,236 @@ static int ioctl_evt_get(unsigned long arg, struct file *fp) kget.lost = p->q_lost; spin_unlock_irqrestore(&i2o_config_lock, flags); - if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) + if (copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) return -EFAULT; return 0; } -static int ioctl_passthru(unsigned long arg) +#ifdef CONFIG_COMPAT +static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg, + struct file *file) { - struct i2o_cmd_passthru __user *cmd = (void __user *) arg; + struct i2o_cmd_passthru32 __user *cmd; + struct i2o_controller *c; + u32 __user *user_msg; + u32 *reply = NULL; + u32 __user *user_reply = NULL; + u32 size = 0; + u32 reply_size = 0; + u32 rcode = 0; + struct i2o_dma sg_list[SG_TABLESIZE]; + u32 sg_offset = 0; + u32 sg_count = 0; + u32 i = 0; + i2o_status_block *sb; + struct i2o_message *msg; + u32 m; + unsigned int iop; + + cmd = (struct i2o_cmd_passthru32 __user *)arg; + + if (get_user(iop, &cmd->iop) || get_user(i, &cmd->msg)) + return -EFAULT; + + user_msg = compat_ptr(i); + + c = i2o_find_iop(iop); + if (!c) { + pr_debug("controller %d not found\n", iop); + return -ENXIO; + } + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + + sb = c->status_block.virt; + + if (get_user(size, &user_msg[0])) { + printk(KERN_WARNING "unable to get size!\n"); + return -EFAULT; + } + size = size >> 16; + + if (size > sb->inbound_frame_size) { + pr_debug("size of message > inbound_frame_size"); + return -EFAULT; + } + + user_reply = &user_msg[size]; + + size <<= 2; // Convert to bytes + + /* Copy in the user's I2O command */ + if (copy_from_user(msg, user_msg, size)) { + printk(KERN_WARNING "unable to copy user message\n"); + return -EFAULT; + } + i2o_dump_message(msg); + + if (get_user(reply_size, &user_reply[0]) < 0) + return -EFAULT; + + reply_size >>= 16; + reply_size <<= 2; + + reply = kmalloc(reply_size, GFP_KERNEL); + if (!reply) { + printk(KERN_WARNING "%s: Could not allocate reply buffer\n", + c->name); + return -ENOMEM; + } + memset(reply, 0, reply_size); + + sg_offset = (msg->u.head[0] >> 4) & 0x0f; + + writel(i2o_config_driver.context, &msg->u.s.icntxt); + writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt); + + memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); + if (sg_offset) { + struct sg_simple_element *sg; + + if (sg_offset * 4 >= size) { + rcode = -EFAULT; + goto cleanup; + } + // TODO 64bit fix + sg = (struct sg_simple_element *)((&msg->u.head[0]) + + sg_offset); + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); + if (sg_count > SG_TABLESIZE) { + printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n", + c->name, sg_count); + kfree(reply); + return -EINVAL; + } + + for (i = 0; i < sg_count; i++) { + int sg_size; + struct i2o_dma *p; + + if (!(sg[i].flag_count & 0x10000000 + /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) { + printk(KERN_DEBUG + "%s:Bad SG element %d - not simple (%x)\n", + c->name, i, sg[i].flag_count); + rcode = -EINVAL; + goto cleanup; + } + sg_size = sg[i].flag_count & 0xffffff; + p = &(sg_list[i]); + /* Allocate memory for the transfer */ + if (i2o_dma_alloc + (&c->pdev->dev, p, sg_size, + PCI_DMA_BIDIRECTIONAL)) { + printk(KERN_DEBUG + "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", + c->name, sg_size, i, sg_count); + rcode = -ENOMEM; + goto cleanup; + } + /* Copy in the user's SG buffer if necessary */ + if (sg[i]. + flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { + // TODO 64bit fix + if (copy_from_user + (p->virt, (void __user *)(unsigned long)sg[i].addr_bus, + sg_size)) { + printk(KERN_DEBUG + "%s: Could not copy SG buf %d FROM user\n", + c->name, i); + rcode = -EFAULT; + goto cleanup; + } + } + //TODO 64bit fix + sg[i].addr_bus = (u32) p->phys; + } + } + + rcode = i2o_msg_post_wait(c, m, 60); + if (rcode) + goto cleanup; + + if (sg_offset) { + u32 msg[128]; + /* Copy back the Scatter Gather buffers back to user space */ + u32 j; + // TODO 64bit fix + struct sg_simple_element *sg; + int sg_size; + printk(KERN_INFO "sg_offset\n"); + + // re-acquire the original message to handle correctly the sg copy operation + memset(&msg, 0, MSG_FRAME_SIZE * 4); + // get user msg size in u32s + if (get_user(size, &user_msg[0])) { + rcode = -EFAULT; + goto cleanup; + } + size = size >> 16; + size *= 4; + /* Copy in the user's I2O command */ + if (copy_from_user(msg, user_msg, size)) { + rcode = -EFAULT; + goto cleanup; + } + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); + + // TODO 64bit fix + sg = (struct sg_simple_element *)(msg + sg_offset); + for (j = 0; j < sg_count; j++) { + /* Copy out the SG list to user's buffer if necessary */ + if (! + (sg[j]. + flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) { + sg_size = sg[j].flag_count & 0xffffff; + // TODO 64bit fix + if (copy_to_user + ((void __user *)(u64) sg[j].addr_bus, + sg_list[j].virt, sg_size)) { + printk(KERN_WARNING + "%s: Could not copy %p TO user %x\n", + c->name, sg_list[j].virt, + sg[j].addr_bus); + rcode = -EFAULT; + goto cleanup; + } + } + } + } + + /* Copy back the reply to user space */ + if (reply_size) { + // we wrote our own values for context - now restore the user supplied ones + printk(KERN_INFO "reply_size\n"); + if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) { + printk(KERN_WARNING + "%s: Could not copy message context FROM user\n", + c->name); + rcode = -EFAULT; + } + if (copy_to_user(user_reply, reply, reply_size)) { + printk(KERN_WARNING + "%s: Could not copy reply TO user\n", c->name); + rcode = -EFAULT; + } + } + + cleanup: + kfree(reply); + printk(KERN_INFO "rcode: %d\n", rcode); + return rcode; +} + +#else + +static int i2o_cfg_passthru(unsigned long arg) +{ + struct i2o_cmd_passthru __user *cmd = + (struct i2o_cmd_passthru __user *)arg; struct i2o_controller *c; - u32 msg[MSG_FRAME_SIZE]; u32 __user *user_msg; u32 *reply = NULL; u32 __user *user_reply = NULL; @@ -858,64 +861,88 @@ static int ioctl_passthru(unsigned long arg) int sg_index = 0; u32 i = 0; void *p = NULL; + i2o_status_block *sb; + struct i2o_message *msg; + u32 m; unsigned int iop; if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg)) return -EFAULT; - c = i2o_find_controller(iop); - if (!c) - return -ENXIO; + c = i2o_find_iop(iop); + if (!c) { + pr_debug("controller %d not found\n", iop); + return -ENXIO; + } + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + + sb = c->status_block.virt; - memset(&msg, 0, MSG_FRAME_SIZE*4); - if(get_user(size, &user_msg[0])) + if (get_user(size, &user_msg[0])) return -EFAULT; - size = size>>16; + size = size >> 16; - user_reply = &user_msg[size]; - if(size > MSG_FRAME_SIZE) + if (size > sb->inbound_frame_size) { + pr_debug("size of message > inbound_frame_size"); return -EFAULT; - size *= 4; // Convert to bytes + } + + user_reply = &user_msg[size]; + + size <<= 2; // Convert to bytes /* Copy in the user's I2O command */ - if(copy_from_user(msg, user_msg, size)) + if (copy_from_user(msg, user_msg, size)) return -EFAULT; - if(get_user(reply_size, &user_reply[0]) < 0) + + if (get_user(reply_size, &user_reply[0]) < 0) return -EFAULT; - reply_size = reply_size>>16; - reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); - if(!reply) { - printk(KERN_WARNING"%s: Could not allocate reply buffer\n",c->name); + reply_size >>= 16; + reply_size <<= 2; + + reply = kmalloc(reply_size, GFP_KERNEL); + if (!reply) { + printk(KERN_WARNING "%s: Could not allocate reply buffer\n", + c->name); return -ENOMEM; } - memset(reply, 0, REPLY_FRAME_SIZE*4); - sg_offset = (msg[0]>>4)&0x0f; - msg[2] = (u32)i2o_cfg_context; - msg[3] = (u32)reply; + memset(reply, 0, reply_size); + + sg_offset = (msg->u.head[0] >> 4) & 0x0f; - memset(sg_list,0, sizeof(sg_list[0])*SG_TABLESIZE); - if(sg_offset) { + writel(i2o_config_driver.context, &msg->u.s.icntxt); + writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt); + + memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); + if (sg_offset) { struct sg_simple_element *sg; - if(sg_offset * 4 >= size) { + if (sg_offset * 4 >= size) { rcode = -EFAULT; goto cleanup; } // TODO 64bit fix - sg = (struct sg_simple_element*) (msg+sg_offset); - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); + sg = (struct sg_simple_element *)((&msg->u.head[0]) + + sg_offset); + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); if (sg_count > SG_TABLESIZE) { - printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", c->name,sg_count); - kfree (reply); + printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n", + c->name, sg_count); + kfree(reply); return -EINVAL; } - for(i = 0; i < sg_count; i++) { + for (i = 0; i < sg_count; i++) { int sg_size; - if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) { - printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",c->name,i, sg[i].flag_count); + if (!(sg[i].flag_count & 0x10000000 + /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) { + printk(KERN_DEBUG + "%s:Bad SG element %d - not simple (%x)\n", + c->name, i, sg[i].flag_count); rcode = -EINVAL; goto cleanup; } @@ -923,61 +950,78 @@ static int ioctl_passthru(unsigned long arg) /* Allocate memory for the transfer */ p = kmalloc(sg_size, GFP_KERNEL); if (!p) { - printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", c->name,sg_size,i,sg_count); + printk(KERN_DEBUG + "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", + c->name, sg_size, i, sg_count); rcode = -ENOMEM; goto cleanup; } - sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. + sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. /* Copy in the user's SG buffer if necessary */ - if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) { + if (sg[i]. + flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { // TODO 64bit fix - if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) { - printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",c->name,i); + if (copy_from_user + (p, (void __user *)sg[i].addr_bus, + sg_size)) { + printk(KERN_DEBUG + "%s: Could not copy SG buf %d FROM user\n", + c->name, i); rcode = -EFAULT; goto cleanup; } } //TODO 64bit fix - sg[i].addr_bus = (u32)virt_to_bus(p); + sg[i].addr_bus = virt_to_bus(p); } } - rcode = i2o_post_wait(c, msg, size, 60); - if(rcode) + rcode = i2o_msg_post_wait(c, m, 60); + if (rcode) goto cleanup; - if(sg_offset) { + if (sg_offset) { + u32 msg[128]; /* Copy back the Scatter Gather buffers back to user space */ u32 j; // TODO 64bit fix - struct sg_simple_element* sg; + struct sg_simple_element *sg; int sg_size; + printk(KERN_INFO "sg_offset\n"); // re-acquire the original message to handle correctly the sg copy operation - memset(&msg, 0, MSG_FRAME_SIZE*4); + memset(&msg, 0, MSG_FRAME_SIZE * 4); // get user msg size in u32s if (get_user(size, &user_msg[0])) { rcode = -EFAULT; goto cleanup; } - size = size>>16; + size = size >> 16; size *= 4; /* Copy in the user's I2O command */ - if (copy_from_user (msg, user_msg, size)) { + if (copy_from_user(msg, user_msg, size)) { rcode = -EFAULT; goto cleanup; } - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); + sg_count = + (size - sg_offset * 4) / sizeof(struct sg_simple_element); - // TODO 64bit fix - sg = (struct sg_simple_element*)(msg + sg_offset); + // TODO 64bit fix + sg = (struct sg_simple_element *)(msg + sg_offset); for (j = 0; j < sg_count; j++) { /* Copy out the SG list to user's buffer if necessary */ - if (!(sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) { + if (! + (sg[j]. + flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) { sg_size = sg[j].flag_count & 0xffffff; // TODO 64bit fix - if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) { - printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",c->name, sg_list[j], sg[j].addr_bus); + if (copy_to_user + ((void __user *)sg[j].addr_bus, sg_list[j], + sg_size)) { + printk(KERN_WARNING + "%s: Could not copy %p TO user %x\n", + c->name, sg_list[j], + sg[j].addr_bus); rcode = -EFAULT; goto cleanup; } @@ -986,37 +1030,109 @@ static int ioctl_passthru(unsigned long arg) } /* Copy back the reply to user space */ - if (reply_size) { + if (reply_size) { // we wrote our own values for context - now restore the user supplied ones - if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) { - printk(KERN_WARNING"%s: Could not copy message context FROM user\n",c->name); + printk(KERN_INFO "reply_size\n"); + if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) { + printk(KERN_WARNING + "%s: Could not copy message context FROM user\n", + c->name); rcode = -EFAULT; } - if(copy_to_user(user_reply, reply, reply_size)) { - printk(KERN_WARNING"%s: Could not copy reply TO user\n",c->name); + if (copy_to_user(user_reply, reply, reply_size)) { + printk(KERN_WARNING + "%s: Could not copy reply TO user\n", c->name); rcode = -EFAULT; } } -cleanup: + cleanup: kfree(reply); - i2o_unlock_controller(c); return rcode; } +#endif + +/* + * IOCTL Handler + */ +static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int ret; + + switch (cmd) { + case I2OGETIOPS: + ret = i2o_cfg_getiops(arg); + break; + + case I2OHRTGET: + ret = i2o_cfg_gethrt(arg); + break; + + case I2OLCTGET: + ret = i2o_cfg_getlct(arg); + break; + + case I2OPARMSET: + ret = i2o_cfg_parms(arg, I2OPARMSET); + break; + + case I2OPARMGET: + ret = i2o_cfg_parms(arg, I2OPARMGET); + break; + + case I2OSWDL: + ret = i2o_cfg_swdl(arg); + break; + + case I2OSWUL: + ret = i2o_cfg_swul(arg); + break; + + case I2OSWDEL: + ret = i2o_cfg_swdel(arg); + break; + + case I2OVALIDATE: + ret = i2o_cfg_validate(arg); + break; + + case I2OEVTREG: + ret = i2o_cfg_evt_reg(arg, fp); + break; + + case I2OEVTGET: + ret = i2o_cfg_evt_get(arg, fp); + break; + +#ifndef CONFIG_COMPAT + case I2OPASSTHRU: + ret = i2o_cfg_passthru(arg); + break; +#endif + + default: + pr_debug("i2o_config: unknown ioctl called!\n"); + ret = -EINVAL; + } + + return ret; +} static int cfg_open(struct inode *inode, struct file *file) { - struct i2o_cfg_info *tmp = - (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); + struct i2o_cfg_info *tmp = + (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), + GFP_KERNEL); unsigned long flags; - if(!tmp) + if (!tmp) return -ENOMEM; - file->private_data = (void*)(i2o_cfg_info_id++); + file->private_data = (void *)(i2o_cfg_info_id++); tmp->fp = file; tmp->fasync = NULL; - tmp->q_id = (u32)file->private_data; + tmp->q_id = (ulong) file->private_data; tmp->q_len = 0; tmp->q_in = 0; tmp->q_out = 0; @@ -1026,13 +1142,28 @@ static int cfg_open(struct inode *inode, struct file *file) spin_lock_irqsave(&i2o_config_lock, flags); open_files = tmp; spin_unlock_irqrestore(&i2o_config_lock, flags); - + return 0; } +static int cfg_fasync(int fd, struct file *fp, int on) +{ + ulong id = (ulong) fp->private_data; + struct i2o_cfg_info *p; + + for (p = open_files; p; p = p->next) + if (p->q_id == id) + break; + + if (!p) + return -EBADF; + + return fasync_helper(fd, fp, on, &p->fasync); +} + static int cfg_release(struct inode *inode, struct file *file) { - u32 id = (u32)file->private_data; + ulong id = (ulong) file->private_data; struct i2o_cfg_info *p1, *p2; unsigned long flags; @@ -1040,14 +1171,12 @@ static int cfg_release(struct inode *inode, struct file *file) p1 = p2 = NULL; spin_lock_irqsave(&i2o_config_lock, flags); - for(p1 = open_files; p1; ) - { - if(p1->q_id == id) - { + for (p1 = open_files; p1;) { + if (p1->q_id == id) { - if(p1->fasync) + if (p1->fasync) cfg_fasync(-1, file, 0); - if(p2) + if (p2) p2->next = p1->next; else open_files = p1->next; @@ -1064,83 +1193,55 @@ static int cfg_release(struct inode *inode, struct file *file) return 0; } -static int cfg_fasync(int fd, struct file *fp, int on) -{ - u32 id = (u32)fp->private_data; - struct i2o_cfg_info *p; - - for(p = open_files; p; p = p->next) - if(p->q_id == id) - break; - - if(!p) - return -EBADF; - - return fasync_helper(fd, fp, on, &p->fasync); -} - -static struct file_operations config_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cfg_read, - .write = cfg_write, - .ioctl = cfg_ioctl, - .open = cfg_open, - .release = cfg_release, - .fasync = cfg_fasync, +static struct file_operations config_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = i2o_cfg_ioctl, + .open = cfg_open, + .release = cfg_release, + .fasync = cfg_fasync, }; static struct miscdevice i2o_miscdev = { I2O_MINOR, "i2octl", &config_fops -}; +}; static int __init i2o_config_init(void) { printk(KERN_INFO "I2O configuration manager v 0.04.\n"); printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); - - if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) - { - printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); - return -ENOBUFS; - } - if(misc_register(&i2o_miscdev) < 0) - { + + if (misc_register(&i2o_miscdev) < 0) { printk(KERN_ERR "i2o_config: can't register device.\n"); - kfree(page_buf); return -EBUSY; } /* - * Install our handler + * Install our handler */ - if(i2o_install_handler(&cfg_handler)<0) - { - kfree(page_buf); + if (i2o_driver_register(&i2o_config_driver)) { printk(KERN_ERR "i2o_config: handler register failed.\n"); misc_deregister(&i2o_miscdev); return -EBUSY; } - /* - * The low 16bits of the transaction context must match this - * for everything we post. Otherwise someone else gets our mail - */ - i2o_cfg_context = cfg_handler.context; +#ifdef CONFIG_COMPAT + register_ioctl32_conversion(I2OPASSTHRU32, i2o_cfg_passthru32); + register_ioctl32_conversion(I2OGETIOPS, (void *)sys_ioctl); +#endif return 0; } static void i2o_config_exit(void) { +#ifdef CONFIG_COMPAT + unregister_ioctl32_conversion(I2OPASSTHRU32); + unregister_ioctl32_conversion(I2OGETIOPS); +#endif misc_deregister(&i2o_miscdev); - - if(page_buf) - kfree(page_buf); - if(i2o_cfg_context != -1) - i2o_remove_handler(&cfg_handler); + i2o_driver_unregister(&i2o_config_driver); } - + MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Configuration"); MODULE_LICENSE("GPL"); diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index db85e21b9..a535c7a1f 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -1,39 +1,33 @@ /* - * procfs handler for Linux I2O subsystem + * procfs handler for Linux I2O subsystem * - * (c) Copyright 1999 Deepak Saxena - * - * Originally written by Deepak Saxena(deepak@plexity.net) + * (c) Copyright 1999 Deepak Saxena * - * 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. + * Originally written by Deepak Saxena(deepak@plexity.net) * - * This is an initial test release. The code is based on the design - * of the ide procfs system (drivers/block/ide-proc.c). Some code - * taken from i2o-core module by Alan Cox. + * 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. * - * DISCLAIMER: This code is still under development/test and may cause - * your system to behave unpredictably. Use at your own discretion. + * This is an initial test release. The code is based on the design of the + * ide procfs system (drivers/block/ide-proc.c). Some code taken from + * i2o-core module by Alan Cox. * - * LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), - * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) - * University of Helsinki, Department of Computer Science - */ - -/* - * set tabstop=3 - */ - -/* - * TODO List + * DISCLAIMER: This code is still under development/test and may cause + * your system to behave unpredictably. Use at your own discretion. * - * - Add support for any version 2.0 spec changes once 2.0 IRTOS is - * is available to test with - * - Clean up code to use official structure definitions + * + * Fixes/additions: + * Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), + * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) + * University of Helsinki, Department of Computer Science + * LAN entries + * Markus Lidel + * Changes for new I2O API */ +#define I2O_MAX_MODULES 4 // FIXME! #define FMT_U64_HEX "0x%08x%08x" #define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64)) @@ -54,188 +48,198 @@ #include #include -#include "i2o_lan.h" - -/* - * Structure used to define /proc entries - */ -typedef struct _i2o_proc_entry_t -{ - char *name; /* entry name */ - mode_t mode; /* mode */ - read_proc_t *read_proc; /* read func */ - write_proc_t *write_proc; /* write func */ - struct file_operations *fops_proc; /* file operations func */ +/* Structure used to define /proc entries */ +typedef struct _i2o_proc_entry_t { + char *name; /* entry name */ + mode_t mode; /* mode */ + struct file_operations *fops; /* open function */ } i2o_proc_entry; -// #define DRIVERDEBUG - -static int i2o_seq_show_lct(struct seq_file *, void *); -static int i2o_seq_show_hrt(struct seq_file *, void *); -static int i2o_seq_show_status(struct seq_file *, void *); - -static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *); - -static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *); - -static int print_serial_number(char *, int, u8 *, int); - -static int i2o_proc_create_entries(void *, i2o_proc_entry *, - struct proc_dir_entry *); -static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *); -static int i2o_proc_add_controller(struct i2o_controller *, - struct proc_dir_entry * ); -static void i2o_proc_remove_controller(struct i2o_controller *, - struct proc_dir_entry * ); -static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *); -static void i2o_proc_remove_device(struct i2o_device *); -static int create_i2o_procfs(void); -static int destroy_i2o_procfs(void); -static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *); -static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *); - -static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int, - int *, void *); -static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int, - int *, void *); -static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *, - void *); -static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *, - void *); - +/* global I2O /proc/i2o entry */ static struct proc_dir_entry *i2o_proc_dir_root; -/* - * I2O OSM descriptor - */ -static struct i2o_handler i2o_proc_handler = -{ - NULL, - i2o_proc_new_dev, - i2o_proc_dev_del, - NULL, - "I2O procfs Layer", - 0, - 0xffffffff // All classes +/* proc OSM driver struct */ +static struct i2o_driver i2o_proc_driver = { + .name = "proc-osm", }; -static int i2o_seq_open_hrt(struct inode *inode, struct file *file) +static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) { - return single_open(file, i2o_seq_show_hrt, PDE(inode)->data); -}; + int i; -struct file_operations i2o_seq_fops_hrt = { - .open = i2o_seq_open_hrt, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; + /* 19990419 -sralston + * The I2O v1.5 (and v2.0 so far) "official specification" + * got serial numbers WRONG! + * Apparently, and despite what Section 3.4.4 says and + * Figure 3-35 shows (pg 3-39 in the pdf doc), + * the convention / consensus seems to be: + * + First byte is SNFormat + * + Second byte is SNLen (but only if SNFormat==7 (?)) + * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format + */ + switch (serialno[0]) { + case I2O_SNFORMAT_BINARY: /* Binary */ + seq_printf(seq, "0x"); + for (i = 0; i < serialno[1]; i++) { + seq_printf(seq, "%02X", serialno[2 + i]); + } + break; -static int i2o_seq_open_lct(struct inode *inode, struct file *file) -{ - return single_open(file, i2o_seq_show_lct, PDE(inode)->data); -}; + case I2O_SNFORMAT_ASCII: /* ASCII */ + if (serialno[1] < ' ') { /* printable or SNLen? */ + /* sanity */ + max_len = + (max_len < serialno[1]) ? max_len : serialno[1]; + serialno[1 + max_len] = '\0'; -struct file_operations i2o_seq_fops_lct = { - .open = i2o_seq_open_lct, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; + /* just print it */ + seq_printf(seq, "%s", &serialno[2]); + } else { + /* print chars for specified length */ + for (i = 0; i < serialno[1]; i++) { + seq_printf(seq, "%c", serialno[2 + i]); + } + } + break; -static int i2o_seq_open_status(struct inode *inode, struct file *file) -{ - return single_open(file, i2o_seq_show_status, PDE(inode)->data); -}; + case I2O_SNFORMAT_UNICODE: /* UNICODE */ + seq_printf(seq, "UNICODE Format. Can't Display\n"); + break; -struct file_operations i2o_seq_fops_status = { - .open = i2o_seq_open_status, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; + case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ + seq_printf(seq, + "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", + serialno[2], serialno[3], + serialno[4], serialno[5], serialno[6], serialno[7]); + break; -/* - * IOP specific entries...write field just in case someone - * ever wants one. - */ -static i2o_proc_entry generic_iop_entries[] = -{ - {"hrt", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_hrt}, - {"lct", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_lct}, - {"status", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_status}, - {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL, NULL}, - {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL, NULL}, - {"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL, NULL}, - {"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; + case I2O_SNFORMAT_WAN: /* WAN MAC Address */ + /* FIXME: Figure out what a WAN access address looks like?? */ + seq_printf(seq, "WAN Access Address"); + break; -/* - * Device specific entries - */ -static i2o_proc_entry generic_dev_entries[] = -{ - {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL, NULL}, - {"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL, NULL}, - {"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL, NULL}, - {"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL, NULL}, - {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL, NULL}, - {"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL, NULL}, - {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL, NULL}, - {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL, NULL}, - {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL, NULL}, - {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL, NULL}, - {"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; +/* plus new in v2.0 */ + case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ + /* FIXME: Figure out what a LAN-64 address really looks like?? */ + seq_printf(seq, + "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", + serialno[8], serialno[9], + serialno[2], serialno[3], + serialno[4], serialno[5], serialno[6], serialno[7]); + break; + + case I2O_SNFORMAT_DDM: /* I2O DDM */ + seq_printf(seq, + "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", + *(u16 *) & serialno[2], + *(u16 *) & serialno[4], *(u16 *) & serialno[6]); + break; + + case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ + case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ + /* FIXME: Figure if this is even close?? */ + seq_printf(seq, + "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", + *(u32 *) & serialno[2], + *(u32 *) & serialno[6], + *(u32 *) & serialno[10], *(u32 *) & serialno[14]); + break; + + case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ + case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ + default: + seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]); + break; + } -/* - * Storage unit specific entries (SCSI Periph, BS) with device names + return 0; +} + +/** + * i2o_get_class_name - do i2o class name lookup + * @class: class number + * + * Return a descriptive string for an i2o class */ -static i2o_proc_entry rbs_dev_entries[] = +static const char *i2o_get_class_name(int class) { - {"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL, NULL}, - {NULL, 0, NULL, NULL} -}; + int idx = 16; + static char *i2o_class_name[] = { + "Executive", + "Device Driver Module", + "Block Device", + "Tape Device", + "LAN Interface", + "WAN Interface", + "Fibre Channel Port", + "Fibre Channel Device", + "SCSI Device", + "ATE Port", + "ATE Device", + "Floppy Controller", + "Floppy Device", + "Secondary Bus Port", + "Peer Transport Agent", + "Peer Transport", + "Unknown" + }; + + switch (class & 0xfff) { + case I2O_CLASS_EXECUTIVE: + idx = 0; + break; + case I2O_CLASS_DDM: + idx = 1; + break; + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + idx = 2; + break; + case I2O_CLASS_SEQUENTIAL_STORAGE: + idx = 3; + break; + case I2O_CLASS_LAN: + idx = 4; + break; + case I2O_CLASS_WAN: + idx = 5; + break; + case I2O_CLASS_FIBRE_CHANNEL_PORT: + idx = 6; + break; + case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: + idx = 7; + break; + case I2O_CLASS_SCSI_PERIPHERAL: + idx = 8; + break; + case I2O_CLASS_ATE_PORT: + idx = 9; + break; + case I2O_CLASS_ATE_PERIPHERAL: + idx = 10; + break; + case I2O_CLASS_FLOPPY_CONTROLLER: + idx = 11; + break; + case I2O_CLASS_FLOPPY_DEVICE: + idx = 12; + break; + case I2O_CLASS_BUS_ADAPTER_PORT: + idx = 13; + break; + case I2O_CLASS_PEER_TRANSPORT_AGENT: + idx = 14; + break; + case I2O_CLASS_PEER_TRANSPORT: + idx = 15; + break; + } + + return i2o_class_name[idx]; +} #define SCSI_TABLE_SIZE 13 -static char *scsi_devices[] = -{ +static char *scsi_devices[] = { "Direct-Access Read/Write", "Sequential-Access Storage", "Printer", @@ -251,307 +255,267 @@ static char *scsi_devices[] = "Array Controller Device" }; -/* private */ - -/* - * Generic LAN specific entries - * - * Should groups with r/w entries have their own subdirectory? - * - */ -static i2o_proc_entry lan_entries[] = -{ - {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL, NULL}, - {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL, NULL}, - {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_mcast_addr, NULL, NULL}, - {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_batch_control, NULL, NULL}, - {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL, NULL}, - {"lan_media_operation", S_IFREG|S_IRUGO, - i2o_proc_read_lan_media_operation, NULL, NULL}, - {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL, NULL}, - {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL, NULL}, - {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL, NULL}, - - {"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - -/* - * Port specific LAN entries - * - */ -static i2o_proc_entry lan_eth_entries[] = -{ - {"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - -static i2o_proc_entry lan_tr_entries[] = -{ - {"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - -static i2o_proc_entry lan_fddi_entries[] = -{ - {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; - - -static char *chtostr(u8 *chars, int n) +static char *chtostr(u8 * chars, int n) { char tmp[256]; tmp[0] = 0; - return strncat(tmp, (char *)chars, n); + return strncat(tmp, (char *)chars, n); } -static int i2o_report_query_status(char *buf, int block_status, char *group) +static int i2o_report_query_status(struct seq_file *seq, int block_status, + char *group) { - switch (block_status) - { + switch (block_status) { case -ETIMEDOUT: - return sprintf(buf, "Timeout reading group %s.\n",group); + return seq_printf(seq, "Timeout reading group %s.\n", group); case -ENOMEM: - return sprintf(buf, "No free memory to read the table.\n"); + return seq_printf(seq, "No free memory to read the table.\n"); case -I2O_PARAMS_STATUS_INVALID_GROUP_ID: - return sprintf(buf, "Group %s not supported.\n", group); + return seq_printf(seq, "Group %s not supported.\n", group); default: - return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n", - group, -block_status); + return seq_printf(seq, + "Error reading group %s. BlockStatus 0x%02X\n", + group, -block_status); } } -static char* bus_strings[] = -{ - "Local Bus", - "ISA", - "EISA", - "MCA", +static char *bus_strings[] = { + "Local Bus", + "ISA", + "EISA", + "MCA", "PCI", - "PCMCIA", - "NUBUS", + "PCMCIA", + "NUBUS", "CARDBUS" }; -static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; - int i2o_seq_show_hrt(struct seq_file *seq, void *v) { struct i2o_controller *c = (struct i2o_controller *)seq->private; - i2o_hrt *hrt = (i2o_hrt *)c->hrt; + i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt; u32 bus; int i; - if(hrt->hrt_version) - { - seq_printf(seq, "HRT table for controller is too new a version.\n"); + if (hrt->hrt_version) { + seq_printf(seq, + "HRT table for controller is too new a version.\n"); return 0; } seq_printf(seq, "HRT has %d entries of %d bytes each.\n", - hrt->num_entries, hrt->entry_len << 2); + hrt->num_entries, hrt->entry_len << 2); - for(i = 0; i < hrt->num_entries; i++) - { + for (i = 0; i < hrt->num_entries; i++) { seq_printf(seq, "Entry %d:\n", i); seq_printf(seq, " Adapter ID: %0#10x\n", - hrt->hrt_entry[i].adapter_id); + hrt->hrt_entry[i].adapter_id); seq_printf(seq, " Controlling tid: %0#6x\n", - hrt->hrt_entry[i].parent_tid); + hrt->hrt_entry[i].parent_tid); - if(hrt->hrt_entry[i].bus_type != 0x80) - { + if (hrt->hrt_entry[i].bus_type != 0x80) { bus = hrt->hrt_entry[i].bus_type; - seq_printf(seq, " %s Information\n", bus_strings[bus]); - - switch(bus) - { - case I2O_BUS_LOCAL: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x\n", - hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress); - break; - - case I2O_BUS_ISA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress); - seq_printf(seq, " CSN: %0#4x,", - hrt->hrt_entry[i].bus.isa_bus.CSN); - break; - - case I2O_BUS_EISA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress); - seq_printf(seq, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber); - break; - - case I2O_BUS_MCA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress); - seq_printf(seq, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber); - break; - - case I2O_BUS_PCI: - seq_printf(seq, " Bus: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciBusNumber); - seq_printf(seq, " Dev: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber); - seq_printf(seq, " Func: %0#4x", - hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber); - seq_printf(seq, " Vendor: %0#6x", - hrt->hrt_entry[i].bus.pci_bus.PciVendorID); - seq_printf(seq, " Device: %0#6x\n", - hrt->hrt_entry[i].bus.pci_bus.PciDeviceID); - break; - - default: - seq_printf(seq, " Unsupported Bus Type\n"); + seq_printf(seq, " %s Information\n", + bus_strings[bus]); + + switch (bus) { + case I2O_BUS_LOCAL: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.local_bus. + LbBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x\n", + hrt->hrt_entry[i].bus.local_bus. + LbBaseMemoryAddress); + break; + + case I2O_BUS_ISA: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.isa_bus. + IsaBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.isa_bus. + IsaBaseMemoryAddress); + seq_printf(seq, " CSN: %0#4x,", + hrt->hrt_entry[i].bus.isa_bus.CSN); + break; + + case I2O_BUS_EISA: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.eisa_bus. + EisaBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.eisa_bus. + EisaBaseMemoryAddress); + seq_printf(seq, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.eisa_bus. + EisaSlotNumber); + break; + + case I2O_BUS_MCA: + seq_printf(seq, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.mca_bus. + McaBaseIOPort); + seq_printf(seq, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.mca_bus. + McaBaseMemoryAddress); + seq_printf(seq, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.mca_bus. + McaSlotNumber); + break; + + case I2O_BUS_PCI: + seq_printf(seq, " Bus: %0#4x", + hrt->hrt_entry[i].bus.pci_bus. + PciBusNumber); + seq_printf(seq, " Dev: %0#4x", + hrt->hrt_entry[i].bus.pci_bus. + PciDeviceNumber); + seq_printf(seq, " Func: %0#4x", + hrt->hrt_entry[i].bus.pci_bus. + PciFunctionNumber); + seq_printf(seq, " Vendor: %0#6x", + hrt->hrt_entry[i].bus.pci_bus. + PciVendorID); + seq_printf(seq, " Device: %0#6x\n", + hrt->hrt_entry[i].bus.pci_bus. + PciDeviceID); + break; + + default: + seq_printf(seq, " Unsupported Bus Type\n"); } - } - else + } else seq_printf(seq, " Unknown Bus Type\n"); } - + return 0; } int i2o_seq_show_lct(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)seq->private; - i2o_lct *lct = (i2o_lct *)c->lct; + struct i2o_controller *c = (struct i2o_controller *)seq->private; + i2o_lct *lct = (i2o_lct *) c->lct; int entries; int i; #define BUS_TABLE_SIZE 3 - static char *bus_ports[] = - { + static char *bus_ports[] = { "Generic Bus", "SCSI Bus", "Fibre Channel Bus" }; - entries = (lct->table_size - 3)/9; + entries = (lct->table_size - 3) / 9; seq_printf(seq, "LCT contains %d %s\n", entries, - entries == 1 ? "entry" : "entries"); - if(lct->boot_tid) + entries == 1 ? "entry" : "entries"); + if (lct->boot_tid) seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid); seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind); - for(i = 0; i < entries; i++) - { + for (i = 0; i < entries; i++) { seq_printf(seq, "Entry %d\n", i); - seq_printf(seq, " Class, SubClass : %s", i2o_get_class_name(lct->lct_entry[i].class_id)); - + seq_printf(seq, " Class, SubClass : %s", + i2o_get_class_name(lct->lct_entry[i].class_id)); + /* - * Classes which we'll print subclass info for + * Classes which we'll print subclass info for */ - switch(lct->lct_entry[i].class_id & 0xFFF) - { - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - switch(lct->lct_entry[i].sub_class) - { - case 0x00: - seq_printf(seq, ", Direct-Access Read/Write"); - break; - - case 0x04: - seq_printf(seq, ", WORM Drive"); - break; - - case 0x05: - seq_printf(seq, ", CD-ROM Drive"); - break; - - case 0x07: - seq_printf(seq, ", Optical Memory Device"); - break; - - default: - seq_printf(seq, ", Unknown (0x%02x)", - lct->lct_entry[i].sub_class); - break; - } + switch (lct->lct_entry[i].class_id & 0xFFF) { + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + switch (lct->lct_entry[i].sub_class) { + case 0x00: + seq_printf(seq, ", Direct-Access Read/Write"); + break; + + case 0x04: + seq_printf(seq, ", WORM Drive"); break; - case I2O_CLASS_LAN: - switch(lct->lct_entry[i].sub_class & 0xFF) - { - case 0x30: - seq_printf(seq, ", Ethernet"); - break; - - case 0x40: - seq_printf(seq, ", 100base VG"); - break; - - case 0x50: - seq_printf(seq, ", IEEE 802.5/Token-Ring"); - break; - - case 0x60: - seq_printf(seq, ", ANSI X3T9.5 FDDI"); - break; - - case 0x70: - seq_printf(seq, ", Fibre Channel"); - break; - - default: - seq_printf(seq, ", Unknown Sub-Class (0x%02x)", - lct->lct_entry[i].sub_class & 0xFF); - break; - } + case 0x05: + seq_printf(seq, ", CD-ROM Drive"); break; - case I2O_CLASS_SCSI_PERIPHERAL: - if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) - seq_printf(seq, ", %s", - scsi_devices[lct->lct_entry[i].sub_class]); - else - seq_printf(seq, ", Unknown Device Type"); + case 0x07: + seq_printf(seq, ", Optical Memory Device"); break; - case I2O_CLASS_BUS_ADAPTER_PORT: - if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) - seq_printf(seq, ", %s", - bus_ports[lct->lct_entry[i].sub_class]); - else - seq_printf(seq, ", Unknown Bus Type"); + default: + seq_printf(seq, ", Unknown (0x%02x)", + lct->lct_entry[i].sub_class); break; + } + break; + + case I2O_CLASS_LAN: + switch (lct->lct_entry[i].sub_class & 0xFF) { + case 0x30: + seq_printf(seq, ", Ethernet"); + break; + + case 0x40: + seq_printf(seq, ", 100base VG"); + break; + + case 0x50: + seq_printf(seq, ", IEEE 802.5/Token-Ring"); + break; + + case 0x60: + seq_printf(seq, ", ANSI X3T9.5 FDDI"); + break; + + case 0x70: + seq_printf(seq, ", Fibre Channel"); + break; + + default: + seq_printf(seq, ", Unknown Sub-Class (0x%02x)", + lct->lct_entry[i].sub_class & 0xFF); + break; + } + break; + + case I2O_CLASS_SCSI_PERIPHERAL: + if (lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) + seq_printf(seq, ", %s", + scsi_devices[lct->lct_entry[i]. + sub_class]); + else + seq_printf(seq, ", Unknown Device Type"); + break; + + case I2O_CLASS_BUS_ADAPTER_PORT: + if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) + seq_printf(seq, ", %s", + bus_ports[lct->lct_entry[i]. + sub_class]); + else + seq_printf(seq, ", Unknown Bus Type"); + break; } seq_printf(seq, "\n"); - - seq_printf(seq, " Local TID : 0x%03x\n", lct->lct_entry[i].tid); - seq_printf(seq, " User TID : 0x%03x\n", lct->lct_entry[i].user_tid); + + seq_printf(seq, " Local TID : 0x%03x\n", + lct->lct_entry[i].tid); + seq_printf(seq, " User TID : 0x%03x\n", + lct->lct_entry[i].user_tid); seq_printf(seq, " Parent TID : 0x%03x\n", - lct->lct_entry[i].parent_tid); + lct->lct_entry[i].parent_tid); seq_printf(seq, " Identity Tag : 0x%x%x%x%x%x%x%x%x\n", - lct->lct_entry[i].identity_tag[0], - lct->lct_entry[i].identity_tag[1], - lct->lct_entry[i].identity_tag[2], - lct->lct_entry[i].identity_tag[3], - lct->lct_entry[i].identity_tag[4], - lct->lct_entry[i].identity_tag[5], - lct->lct_entry[i].identity_tag[6], - lct->lct_entry[i].identity_tag[7]); + lct->lct_entry[i].identity_tag[0], + lct->lct_entry[i].identity_tag[1], + lct->lct_entry[i].identity_tag[2], + lct->lct_entry[i].identity_tag[3], + lct->lct_entry[i].identity_tag[4], + lct->lct_entry[i].identity_tag[5], + lct->lct_entry[i].identity_tag[6], + lct->lct_entry[i].identity_tag[7]); seq_printf(seq, " Change Indicator : %0#10x\n", - lct->lct_entry[i].change_ind); + lct->lct_entry[i].change_ind); seq_printf(seq, " Event Capab Mask : %0#10x\n", - lct->lct_entry[i].device_flags); + lct->lct_entry[i].device_flags); } return 0; @@ -559,17 +523,17 @@ int i2o_seq_show_lct(struct seq_file *seq, void *v) int i2o_seq_show_status(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)seq->private; + struct i2o_controller *c = (struct i2o_controller *)seq->private; char prodstr[25]; int version; - - i2o_status_get(c); // reread the status block + i2o_status_block *sb = c->status_block.virt; + + i2o_status_get(c); // reread the status block + + seq_printf(seq, "Organization ID : %0#6x\n", sb->org_id); - seq_printf(seq, "Organization ID : %0#6x\n", - c->status_block->org_id); + version = sb->i2o_version; - version = c->status_block->i2o_version; - /* FIXME for Spec 2.0 if (version == 0x02) { seq_printf(seq, "Lowest I2O version supported: "); @@ -599,170 +563,171 @@ int i2o_seq_show_status(struct seq_file *seq, void *v) } } */ - seq_printf(seq, "IOP ID : %0#5x\n", - c->status_block->iop_id); - seq_printf(seq, "Host Unit ID : %0#6x\n", - c->status_block->host_unit_id); - seq_printf(seq, "Segment Number : %0#5x\n", - c->status_block->segment_number); + seq_printf(seq, "IOP ID : %0#5x\n", sb->iop_id); + seq_printf(seq, "Host Unit ID : %0#6x\n", sb->host_unit_id); + seq_printf(seq, "Segment Number : %0#5x\n", sb->segment_number); seq_printf(seq, "I2O version : "); switch (version) { - case 0x00: - seq_printf(seq, "1.0\n"); - break; - case 0x01: - seq_printf(seq, "1.5\n"); - break; - case 0x02: - seq_printf(seq, "2.0\n"); - break; - default: - seq_printf(seq, "Unknown version\n"); + case 0x00: + seq_printf(seq, "1.0\n"); + break; + case 0x01: + seq_printf(seq, "1.5\n"); + break; + case 0x02: + seq_printf(seq, "2.0\n"); + break; + default: + seq_printf(seq, "Unknown version\n"); } seq_printf(seq, "IOP State : "); - switch (c->status_block->iop_state) { - case 0x01: - seq_printf(seq, "INIT\n"); - break; + switch (sb->iop_state) { + case 0x01: + seq_printf(seq, "INIT\n"); + break; - case 0x02: - seq_printf(seq, "RESET\n"); - break; + case 0x02: + seq_printf(seq, "RESET\n"); + break; - case 0x04: - seq_printf(seq, "HOLD\n"); - break; + case 0x04: + seq_printf(seq, "HOLD\n"); + break; - case 0x05: - seq_printf(seq, "READY\n"); - break; + case 0x05: + seq_printf(seq, "READY\n"); + break; - case 0x08: - seq_printf(seq, "OPERATIONAL\n"); - break; + case 0x08: + seq_printf(seq, "OPERATIONAL\n"); + break; - case 0x10: - seq_printf(seq, "FAILED\n"); - break; + case 0x10: + seq_printf(seq, "FAILED\n"); + break; - case 0x11: - seq_printf(seq, "FAULTED\n"); - break; + case 0x11: + seq_printf(seq, "FAULTED\n"); + break; - default: - seq_printf(seq, "Unknown\n"); - break; + default: + seq_printf(seq, "Unknown\n"); + break; } seq_printf(seq, "Messenger Type : "); - switch (c->status_block->msg_type) { - case 0x00: - seq_printf(seq, "Memory mapped\n"); - break; - case 0x01: - seq_printf(seq, "Memory mapped only\n"); - break; - case 0x02: - seq_printf(seq,"Remote only\n"); - break; - case 0x03: - seq_printf(seq, "Memory mapped and remote\n"); - break; - default: - seq_printf(seq, "Unknown\n"); + switch (sb->msg_type) { + case 0x00: + seq_printf(seq, "Memory mapped\n"); + break; + case 0x01: + seq_printf(seq, "Memory mapped only\n"); + break; + case 0x02: + seq_printf(seq, "Remote only\n"); + break; + case 0x03: + seq_printf(seq, "Memory mapped and remote\n"); + break; + default: + seq_printf(seq, "Unknown\n"); } seq_printf(seq, "Inbound Frame Size : %d bytes\n", - c->status_block->inbound_frame_size<<2); + sb->inbound_frame_size << 2); seq_printf(seq, "Max Inbound Frames : %d\n", - c->status_block->max_inbound_frames); + sb->max_inbound_frames); seq_printf(seq, "Current Inbound Frames : %d\n", - c->status_block->cur_inbound_frames); + sb->cur_inbound_frames); seq_printf(seq, "Max Outbound Frames : %d\n", - c->status_block->max_outbound_frames); + sb->max_outbound_frames); /* Spec doesn't say if NULL terminated or not... */ - memcpy(prodstr, c->status_block->product_id, 24); + memcpy(prodstr, sb->product_id, 24); prodstr[24] = '\0'; seq_printf(seq, "Product ID : %s\n", prodstr); seq_printf(seq, "Expected LCT Size : %d bytes\n", - c->status_block->expected_lct_size); + sb->expected_lct_size); seq_printf(seq, "IOP Capabilities\n"); seq_printf(seq, " Context Field Size Support : "); - switch (c->status_block->iop_capabilities & 0x0000003) { - case 0: - seq_printf(seq, "Supports only 32-bit context fields\n"); - break; - case 1: - seq_printf(seq, "Supports only 64-bit context fields\n"); - break; - case 2: - seq_printf(seq, "Supports 32-bit and 64-bit context fields, " - "but not concurrently\n"); - break; - case 3: - seq_printf(seq, "Supports 32-bit and 64-bit context fields " - "concurrently\n"); - break; - default: - seq_printf(seq, "0x%08x\n",c->status_block->iop_capabilities); + switch (sb->iop_capabilities & 0x0000003) { + case 0: + seq_printf(seq, "Supports only 32-bit context fields\n"); + break; + case 1: + seq_printf(seq, "Supports only 64-bit context fields\n"); + break; + case 2: + seq_printf(seq, "Supports 32-bit and 64-bit context fields, " + "but not concurrently\n"); + break; + case 3: + seq_printf(seq, "Supports 32-bit and 64-bit context fields " + "concurrently\n"); + break; + default: + seq_printf(seq, "0x%08x\n", sb->iop_capabilities); } seq_printf(seq, " Current Context Field Size : "); - switch (c->status_block->iop_capabilities & 0x0000000C) { - case 0: - seq_printf(seq, "not configured\n"); - break; - case 4: - seq_printf(seq, "Supports only 32-bit context fields\n"); - break; - case 8: - seq_printf(seq, "Supports only 64-bit context fields\n"); - break; - case 12: - seq_printf(seq, "Supports both 32-bit or 64-bit context fields " - "concurrently\n"); - break; - default: - seq_printf(seq, "\n"); + switch (sb->iop_capabilities & 0x0000000C) { + case 0: + seq_printf(seq, "not configured\n"); + break; + case 4: + seq_printf(seq, "Supports only 32-bit context fields\n"); + break; + case 8: + seq_printf(seq, "Supports only 64-bit context fields\n"); + break; + case 12: + seq_printf(seq, "Supports both 32-bit or 64-bit context fields " + "concurrently\n"); + break; + default: + seq_printf(seq, "\n"); } seq_printf(seq, " Inbound Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported"); + (sb-> + iop_capabilities & 0x00000010) ? "Supported" : + "Not supported"); seq_printf(seq, " Outbound Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported"); + (sb-> + iop_capabilities & 0x00000020) ? "Supported" : + "Not supported"); seq_printf(seq, " Peer to Peer Support : %s\n", - (c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported"); + (sb-> + iop_capabilities & 0x00000040) ? "Supported" : + "Not supported"); seq_printf(seq, "Desired private memory size : %d kB\n", - c->status_block->desired_mem_size>>10); + sb->desired_mem_size >> 10); seq_printf(seq, "Allocated private memory size : %d kB\n", - c->status_block->current_mem_size>>10); + sb->current_mem_size >> 10); seq_printf(seq, "Private memory base address : %0#10x\n", - c->status_block->current_mem_base); + sb->current_mem_base); seq_printf(seq, "Desired private I/O size : %d kB\n", - c->status_block->desired_io_size>>10); + sb->desired_io_size >> 10); seq_printf(seq, "Allocated private I/O size : %d kB\n", - c->status_block->current_io_size>>10); + sb->current_io_size >> 10); seq_printf(seq, "Private I/O base address : %0#10x\n", - c->status_block->current_io_base); + sb->current_io_base); return 0; } -int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_hw(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; static u32 work32[5]; - static u8 *work8 = (u8*)work32; - static u16 *work16 = (u16*)work32; + static u8 *work8 = (u8 *) work32; + static u16 *work16 = (u16 *) work32; int token; u32 hwcap; - static char *cpu_table[] = - { + static char *cpu_table[] = { "Intel 80960 series", "AMD2900 series", "Motorola 68000 series", @@ -773,397 +738,350 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, "Intel x86 series" }; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32)); + token = + i2o_parm_field_get(c->exec, 0x0000, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0x0000 IOP Hardware"); + return 0; } - len += sprintf(buf+len, "I2O Vendor ID : %0#6x\n", work16[0]); - len += sprintf(buf+len, "Product ID : %0#6x\n", work16[1]); - len += sprintf(buf+len, "CPU : "); - if(work8[16] > 8) - len += sprintf(buf+len, "Unknown\n"); + seq_printf(seq, "I2O Vendor ID : %0#6x\n", work16[0]); + seq_printf(seq, "Product ID : %0#6x\n", work16[1]); + seq_printf(seq, "CPU : "); + if (work8[16] > 8) + seq_printf(seq, "Unknown\n"); else - len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]); + seq_printf(seq, "%s\n", cpu_table[work8[16]]); /* Anyone using ProcessorVersion? */ - - len += sprintf(buf+len, "RAM : %dkB\n", work32[1]>>10); - len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10); + + seq_printf(seq, "RAM : %dkB\n", work32[1] >> 10); + seq_printf(seq, "Non-Volatile Mem : %dkB\n", work32[2] >> 10); hwcap = work32[3]; - len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap); - len += sprintf(buf+len, " [%s] Self booting\n", - (hwcap&0x00000001) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Upgradable IRTOS\n", - (hwcap&0x00000002) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Supports downloading DDMs\n", - (hwcap&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Supports installing DDMs\n", - (hwcap&0x00000008) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Battery-backed RAM\n", - (hwcap&0x00000010) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - - return len; -} + seq_printf(seq, "Capabilities : 0x%08x\n", hwcap); + seq_printf(seq, " [%s] Self booting\n", + (hwcap & 0x00000001) ? "+" : "-"); + seq_printf(seq, " [%s] Upgradable IRTOS\n", + (hwcap & 0x00000002) ? "+" : "-"); + seq_printf(seq, " [%s] Supports downloading DDMs\n", + (hwcap & 0x00000004) ? "+" : "-"); + seq_printf(seq, " [%s] Supports installing DDMs\n", + (hwcap & 0x00000008) ? "+" : "-"); + seq_printf(seq, " [%s] Battery-backed RAM\n", + (hwcap & 0x00000010) ? "+" : "-"); + return 0; +} /* Executive group 0003h - Executing DDM List (table) */ -int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_ddm_table(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; int token; int i; typedef struct _i2o_exec_execute_ddm_table { u16 ddm_tid; - u8 module_type; - u8 reserved; + u8 module_type; + u8 reserved; u16 i2o_vendor_id; u16 module_id; - u8 module_name_version[28]; + u8 module_name_version[28]; u32 data_size; u32 code_size; } i2o_exec_execute_ddm_table; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; - i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES]; + i2o_exec_execute_ddm_table ddm_table[I2O_MAX_MODULES]; } *result; i2o_exec_execute_ddm_table ddm_table; result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) + if (!result) return -ENOMEM; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - c, ADAPTER_TID, - 0x0003, -1, - NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0003, -1, + NULL, 0, result, sizeof(*result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List"); + i2o_report_query_status(seq, token, + "0x0003 Executing DDM List"); goto out; } - len += sprintf(buf+len, "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n"); - ddm_table=result->ddm_table[0]; + seq_printf(seq, + "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n"); + ddm_table = result->ddm_table[0]; - for(i=0; i < result->row_count; ddm_table=result->ddm_table[++i]) - { - len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF); + for (i = 0; i < result->row_count; ddm_table = result->ddm_table[++i]) { + seq_printf(seq, "0x%03x ", ddm_table.ddm_tid & 0xFFF); - switch(ddm_table.module_type) - { + switch (ddm_table.module_type) { case 0x01: - len += sprintf(buf+len, "Downloaded DDM "); - break; + seq_printf(seq, "Downloaded DDM "); + break; case 0x22: - len += sprintf(buf+len, "Embedded DDM "); + seq_printf(seq, "Embedded DDM "); break; default: - len += sprintf(buf+len, " "); + seq_printf(seq, " "); } - len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id); - len += sprintf(buf+len, "%-#8x", ddm_table.module_id); - len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28)); - len += sprintf(buf+len, "%9d ", ddm_table.data_size); - len += sprintf(buf+len, "%8d", ddm_table.code_size); + seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id); + seq_printf(seq, "%-#8x", ddm_table.module_id); + seq_printf(seq, "%-29s", + chtostr(ddm_table.module_name_version, 28)); + seq_printf(seq, "%9d ", ddm_table.data_size); + seq_printf(seq, "%8d", ddm_table.code_size); - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); } -out: - spin_unlock(&i2o_proc_lock); + out: kfree(result); - return len; + return 0; } - /* Executive group 0004h - Driver Store (scalar) */ -int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_driver_store(struct seq_file *seq, void *v) { - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; u32 work32[8]; int token; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32)); + token = + i2o_parm_field_get(c->exec, 0x0004, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0x0004 Driver Store"); + return 0; } - len += sprintf(buf+len, "Module limit : %d\n" - "Module count : %d\n" - "Current space : %d kB\n" - "Free space : %d kB\n", - work32[0], work32[1], work32[2]>>10, work32[3]>>10); - - spin_unlock(&i2o_proc_lock); + seq_printf(seq, "Module limit : %d\n" + "Module count : %d\n" + "Current space : %d kB\n" + "Free space : %d kB\n", + work32[0], work32[1], work32[2] >> 10, work32[3] >> 10); - return len; + return 0; } - /* Executive group 0005h - Driver Store Table (table) */ -int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v) { typedef struct _i2o_driver_store { u16 stored_ddm_index; - u8 module_type; - u8 reserved; + u8 module_type; + u8 reserved; u16 i2o_vendor_id; u16 module_id; - u8 module_name_version[28]; - u8 date[8]; + u8 module_name_version[28]; + u8 date[8]; u32 module_size; u32 mpb_size; u32 module_flags; } i2o_driver_store_table; - struct i2o_controller *c = (struct i2o_controller*)data; + struct i2o_controller *c = (struct i2o_controller *)seq->private; int token; int i; - typedef struct - { + typedef struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; - i2o_driver_store_table dst[MAX_I2O_MODULES]; + i2o_driver_store_table dst[I2O_MAX_MODULES]; } i2o_driver_result_table; - + i2o_driver_result_table *result; i2o_driver_store_table *dst; - - len = 0; - result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL); - if(result == NULL) + if (result == NULL) return -ENOMEM; - spin_lock(&i2o_proc_lock); - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - c, ADAPTER_TID, 0x0005, -1, NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0005, -1, + NULL, 0, result, sizeof(*result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE"); - spin_unlock(&i2o_proc_lock); + i2o_report_query_status(seq, token, + "0x0005 DRIVER STORE TABLE"); kfree(result); - return len; + return 0; } - len += sprintf(buf+len, "# Module_type Vendor Mod_id Module_name Vrs" - "Date Mod_size Par_size Flags\n"); - for(i=0, dst=&result->dst[0]; i < result->row_count; dst=&result->dst[++i]) - { - len += sprintf(buf+len, "%-3d", dst->stored_ddm_index); - switch(dst->module_type) - { + seq_printf(seq, + "# Module_type Vendor Mod_id Module_name Vrs" + "Date Mod_size Par_size Flags\n"); + for (i = 0, dst = &result->dst[0]; i < result->row_count; + dst = &result->dst[++i]) { + seq_printf(seq, "%-3d", dst->stored_ddm_index); + switch (dst->module_type) { case 0x01: - len += sprintf(buf+len, "Downloaded DDM "); - break; + seq_printf(seq, "Downloaded DDM "); + break; case 0x22: - len += sprintf(buf+len, "Embedded DDM "); + seq_printf(seq, "Embedded DDM "); break; default: - len += sprintf(buf+len, " "); + seq_printf(seq, " "); } #if 0 - if(c->i2oversion == 0x02) - len += sprintf(buf+len, "%-d", dst->module_state); + if (c->i2oversion == 0x02) + seq_printf(seq, "%-d", dst->module_state); #endif - len += sprintf(buf+len, "%-#7x", dst->i2o_vendor_id); - len += sprintf(buf+len, "%-#8x", dst->module_id); - len += sprintf(buf+len, "%-29s", chtostr(dst->module_name_version,28)); - len += sprintf(buf+len, "%-9s", chtostr(dst->date,8)); - len += sprintf(buf+len, "%8d ", dst->module_size); - len += sprintf(buf+len, "%8d ", dst->mpb_size); - len += sprintf(buf+len, "0x%04x", dst->module_flags); + seq_printf(seq, "%-#7x", dst->i2o_vendor_id); + seq_printf(seq, "%-#8x", dst->module_id); + seq_printf(seq, "%-29s", chtostr(dst->module_name_version, 28)); + seq_printf(seq, "%-9s", chtostr(dst->date, 8)); + seq_printf(seq, "%8d ", dst->module_size); + seq_printf(seq, "%8d ", dst->mpb_size); + seq_printf(seq, "0x%04x", dst->module_flags); #if 0 - if(c->i2oversion == 0x02) - len += sprintf(buf+len, "%d", - dst->notification_level); + if (c->i2oversion == 0x02) + seq_printf(seq, "%d", dst->notification_level); #endif - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); } - spin_unlock(&i2o_proc_lock); kfree(result); - return len; + return 0; } - /* Generic group F000h - Params Descriptor (table) */ -int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_groups(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; u8 properties; - typedef struct _i2o_group_info - { + typedef struct _i2o_group_info { u16 group_number; u16 field_count; u16 row_count; - u8 properties; - u8 reserved; + u8 properties; + u8 reserved; } i2o_group_info; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; i2o_group_info group[256]; } *result; result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) + if (!result) return -ENOMEM; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0, + result, sizeof(*result)); if (token < 0) { - len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor"); + i2o_report_query_status(seq, token, "0xF000 Params Descriptor"); goto out; } - len += sprintf(buf+len, "# Group FieldCount RowCount Type Add Del Clear\n"); + seq_printf(seq, + "# Group FieldCount RowCount Type Add Del Clear\n"); - for (i=0; i < result->row_count; i++) - { - len += sprintf(buf+len, "%-3d", i); - len += sprintf(buf+len, "0x%04X ", result->group[i].group_number); - len += sprintf(buf+len, "%10d ", result->group[i].field_count); - len += sprintf(buf+len, "%8d ", result->group[i].row_count); + for (i = 0; i < result->row_count; i++) { + seq_printf(seq, "%-3d", i); + seq_printf(seq, "0x%04X ", result->group[i].group_number); + seq_printf(seq, "%10d ", result->group[i].field_count); + seq_printf(seq, "%8d ", result->group[i].row_count); properties = result->group[i].properties; - if (properties & 0x1) len += sprintf(buf+len, "Table "); - else len += sprintf(buf+len, "Scalar "); - if (properties & 0x2) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - if (properties & 0x4) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - if (properties & 0x8) len += sprintf(buf+len, " + "); - else len += sprintf(buf+len, " - "); - - len += sprintf(buf+len, "\n"); + if (properties & 0x1) + seq_printf(seq, "Table "); + else + seq_printf(seq, "Scalar "); + if (properties & 0x2) + seq_printf(seq, " + "); + else + seq_printf(seq, " - "); + if (properties & 0x4) + seq_printf(seq, " + "); + else + seq_printf(seq, " - "); + if (properties & 0x8) + seq_printf(seq, " + "); + else + seq_printf(seq, " - "); + + seq_printf(seq, "\n"); } if (result->more_flag) - len += sprintf(buf+len, "There is more...\n"); -out: - spin_unlock(&i2o_proc_lock); + seq_printf(seq, "There is more...\n"); + out: kfree(result); - return len; + return 0; } - /* Generic group F001h - Physical Device Table (table) */ -int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_phys_device(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; u32 adapter_id[64]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF001, -1, NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF001, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF001 Physical Device Table"); + return 0; } if (result.row_count) - len += sprintf(buf+len, "# AdapterId\n"); + seq_printf(seq, "# AdapterId\n"); - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]); + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%-2d", i); + seq_printf(seq, "%#7x\n", result.adapter_id[i]); } if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "There is more...\n"); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } /* Generic group F002h - Claimed Table (table) */ -int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_claimed(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; @@ -1171,434 +1089,356 @@ int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len, u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; u16 claimed_tid[64]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF002, -1, NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF002, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF002 Claimed Table"); + return 0; } if (result.row_count) - len += sprintf(buf+len, "# ClaimedTid\n"); + seq_printf(seq, "# ClaimedTid\n"); - for (i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]); + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%-2d", i); + seq_printf(seq, "%#7x\n", result.claimed_tid[i]); } if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "There is more...\n"); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } /* Generic group F003h - User Table (table) */ -int i2o_proc_read_users(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_users(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - typedef struct _i2o_user_table - { + typedef struct _i2o_user_table { u16 instance; u16 user_tid; u8 claim_type; - u8 reserved1; - u16 reserved2; + u8 reserved1; + u16 reserved2; } i2o_user_table; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; i2o_user_table user[64]; } *result; result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) + if (!result) return -ENOMEM; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF003, -1, NULL, 0, - result, sizeof(*result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF003, -1, NULL, 0, + result, sizeof(*result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF003 User Table"); + i2o_report_query_status(seq, token, "0xF003 User Table"); goto out; } - len += sprintf(buf+len, "# Instance UserTid ClaimType\n"); + seq_printf(seq, "# Instance UserTid ClaimType\n"); - for(i=0; i < result->row_count; i++) - { - len += sprintf(buf+len, "%-3d", i); - len += sprintf(buf+len, "%#8x ", result->user[i].instance); - len += sprintf(buf+len, "%#7x ", result->user[i].user_tid); - len += sprintf(buf+len, "%#9x\n", result->user[i].claim_type); + for (i = 0; i < result->row_count; i++) { + seq_printf(seq, "%-3d", i); + seq_printf(seq, "%#8x ", result->user[i].instance); + seq_printf(seq, "%#7x ", result->user[i].user_tid); + seq_printf(seq, "%#9x\n", result->user[i].claim_type); } if (result->more_flag) - len += sprintf(buf+len, "There is more...\n"); -out: - spin_unlock(&i2o_proc_lock); + seq_printf(seq, "There is more...\n"); + out: kfree(result); - return len; + return 0; } /* Generic group F005h - Private message extensions (table) (optional) */ -int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_priv_msgs(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - typedef struct _i2o_private - { + typedef struct _i2o_private { u16 ext_instance; u16 organization_id; u16 x_function_code; } i2o_private; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; i2o_private extension[64]; } result; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF000, -1, - NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF005 Private Message Extensions (optional)"); + return 0; } - - len += sprintf(buf+len, "Instance# OrgId FunctionCode\n"); - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance); - len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id); - len += sprintf(buf+len, "%0#6x", result.extension[i].x_function_code); + seq_printf(seq, "Instance# OrgId FunctionCode\n"); - len += sprintf(buf+len, "\n"); - } + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%0#9x ", result.extension[i].ext_instance); + seq_printf(seq, "%0#6x ", result.extension[i].organization_id); + seq_printf(seq, "%0#6x", result.extension[i].x_function_code); - if(result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "\n"); + } - spin_unlock(&i2o_proc_lock); + if (result.more_flag) + seq_printf(seq, "There is more...\n"); - return len; + return 0; } - /* Generic group F006h - Authorized User Table (table) */ -int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_authorized_users(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; int i; - struct - { + struct { u16 result_count; u16 pad; u16 block_size; - u8 block_status; - u8 error_info_size; + u8 block_status; + u8 error_info_size; u16 row_count; u16 more_flag; u32 alternate_tid[64]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0xF006, -1, - NULL, 0, - &result, sizeof(result)); + token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF006, -1, NULL, 0, + &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF006 Autohorized User Table"); + return 0; } if (result.row_count) - len += sprintf(buf+len, "# AlternateTid\n"); + seq_printf(seq, "# AlternateTid\n"); - for(i=0; i < result.row_count; i++) - { - len += sprintf(buf+len, "%-2d", i); - len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]); + for (i = 0; i < result.row_count; i++) { + seq_printf(seq, "%-2d", i); + seq_printf(seq, "%#7x ", result.alternate_tid[i]); } if (result.more_flag) - len += sprintf(buf+len, "There is more...\n"); + seq_printf(seq, "There is more...\n"); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } - /* Generic group F100h - Device Identity (scalar) */ -int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_dev_identity(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number - // == (allow) 512d bytes (max) - static u16 *work16 = (u16*)work32; + struct i2o_device *d = (struct i2o_device *)seq->private; + static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number + // == (allow) 512d bytes (max) + static u16 *work16 = (u16 *) work32; int token; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF100, -1, - &work32, sizeof(work32)); + token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF100 Device Identity"); + return 0; } - - len += sprintf(buf, "Device Class : %s\n", i2o_get_class_name(work16[0])); - len += sprintf(buf+len, "Owner TID : %0#5x\n", work16[2]); - len += sprintf(buf+len, "Parent TID : %0#5x\n", work16[3]); - len += sprintf(buf+len, "Vendor info : %s\n", chtostr((u8 *)(work32+2), 16)); - len += sprintf(buf+len, "Product info : %s\n", chtostr((u8 *)(work32+6), 16)); - len += sprintf(buf+len, "Description : %s\n", chtostr((u8 *)(work32+10), 16)); - len += sprintf(buf+len, "Product rev. : %s\n", chtostr((u8 *)(work32+14), 8)); - - len += sprintf(buf+len, "Serial number : "); - len = print_serial_number(buf, len, - (u8*)(work32+16), - /* allow for SNLen plus - * possible trailing '\0' - */ - sizeof(work32)-(16*sizeof(u32))-2 - ); - len += sprintf(buf+len, "\n"); - - spin_unlock(&i2o_proc_lock); - - return len; -} + seq_printf(seq, "Device Class : %s\n", i2o_get_class_name(work16[0])); + seq_printf(seq, "Owner TID : %0#5x\n", work16[2]); + seq_printf(seq, "Parent TID : %0#5x\n", work16[3]); + seq_printf(seq, "Vendor info : %s\n", + chtostr((u8 *) (work32 + 2), 16)); + seq_printf(seq, "Product info : %s\n", + chtostr((u8 *) (work32 + 6), 16)); + seq_printf(seq, "Description : %s\n", + chtostr((u8 *) (work32 + 10), 16)); + seq_printf(seq, "Product rev. : %s\n", + chtostr((u8 *) (work32 + 14), 8)); + + seq_printf(seq, "Serial number : "); + print_serial_number(seq, (u8 *) (work32 + 16), + /* allow for SNLen plus + * possible trailing '\0' + */ + sizeof(work32) - (16 * sizeof(u32)) - 2); + seq_printf(seq, "\n"); -int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; + return 0; +} - if ( d->dev_name[0] == '\0' ) - return 0; +int i2o_seq_show_dev_name(struct seq_file *seq, void *v) +{ + struct i2o_device *d = (struct i2o_device *)seq->private; - len = sprintf(buf, "%s\n", d->dev_name); + seq_printf(seq, "%s\n", d->device.bus_id); - return len; + return 0; } - /* Generic group F101h - DDM Identity (scalar) */ -int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; - struct - { + struct { u16 ddm_tid; u8 module_name[24]; u8 module_rev[8]; u8 sn_format; u8 serial_number[12]; - u8 pad[256]; // allow up to 256 byte (max) serial number - } result; - - spin_lock(&i2o_proc_lock); - - len = 0; + u8 pad[256]; // allow up to 256 byte (max) serial number + } result; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF101, -1, - &result, sizeof(result)); + token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF101 DDM Identity"); + return 0; } - len += sprintf(buf, "Registering DDM TID : 0x%03x\n", result.ddm_tid); - len += sprintf(buf+len, "Module name : %s\n", chtostr(result.module_name, 24)); - len += sprintf(buf+len, "Module revision : %s\n", chtostr(result.module_rev, 8)); + seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid); + seq_printf(seq, "Module name : %s\n", + chtostr(result.module_name, 24)); + seq_printf(seq, "Module revision : %s\n", + chtostr(result.module_rev, 8)); - len += sprintf(buf+len, "Serial number : "); - len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36); - /* allow for SNLen plus possible trailing '\0' */ + seq_printf(seq, "Serial number : "); + print_serial_number(seq, result.serial_number, sizeof(result) - 36); + /* allow for SNLen plus possible trailing '\0' */ - len += sprintf(buf+len, "\n"); + seq_printf(seq, "\n"); - spin_unlock(&i2o_proc_lock); - - return len; + return 0; } /* Generic group F102h - User Information (scalar) */ -int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_uinfo(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; - struct - { + struct { u8 device_name[64]; u8 service_name[64]; u8 physical_location[64]; u8 instance_number[4]; } result; - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF102, -1, - &result, sizeof(result)); + token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF102 User Information"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, "0xF102 User Information"); + return 0; } - len += sprintf(buf, "Device name : %s\n", chtostr(result.device_name, 64)); - len += sprintf(buf+len, "Service name : %s\n", chtostr(result.service_name, 64)); - len += sprintf(buf+len, "Physical name : %s\n", chtostr(result.physical_location, 64)); - len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4)); + seq_printf(seq, "Device name : %s\n", + chtostr(result.device_name, 64)); + seq_printf(seq, "Service name : %s\n", + chtostr(result.service_name, 64)); + seq_printf(seq, "Physical name : %s\n", + chtostr(result.physical_location, 64)); + seq_printf(seq, "Instance number : %s\n", + chtostr(result.instance_number, 4)); - spin_unlock(&i2o_proc_lock); - return len; + return 0; } /* Generic group F103h - SGL Operating Limits (scalar) */ -int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_sgl_limits(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; static u32 work32[12]; - static u16 *work16 = (u16 *)work32; - static u8 *work8 = (u8 *)work32; + static u16 *work16 = (u16 *) work32; + static u8 *work8 = (u8 *) work32; int token; - spin_lock(&i2o_proc_lock); - - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF103, -1, - &work32, sizeof(work32)); + token = i2o_parm_field_get(d, 0xF103, -1, &work32, sizeof(work32)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF103 SGL Operating Limits"); + return 0; } - len += sprintf(buf, "SGL chain size : %d\n", work32[0]); - len += sprintf(buf+len, "Max SGL chain size : %d\n", work32[1]); - len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]); - len += sprintf(buf+len, "SGL frag count : %d\n", work16[6]); - len += sprintf(buf+len, "Max SGL frag count : %d\n", work16[7]); - len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]); + seq_printf(seq, "SGL chain size : %d\n", work32[0]); + seq_printf(seq, "Max SGL chain size : %d\n", work32[1]); + seq_printf(seq, "SGL chain size target : %d\n", work32[2]); + seq_printf(seq, "SGL frag count : %d\n", work16[6]); + seq_printf(seq, "Max SGL frag count : %d\n", work16[7]); + seq_printf(seq, "SGL frag count target : %d\n", work16[8]); +/* FIXME if (d->i2oversion == 0x02) { - len += sprintf(buf+len, "SGL data alignment : %d\n", work16[8]); - len += sprintf(buf+len, "SGL addr limit : %d\n", work8[20]); - len += sprintf(buf+len, "SGL addr sizes supported : "); - if (work8[21] & 0x01) - len += sprintf(buf+len, "32 bit "); - if (work8[21] & 0x02) - len += sprintf(buf+len, "64 bit "); - if (work8[21] & 0x04) - len += sprintf(buf+len, "96 bit "); - if (work8[21] & 0x08) - len += sprintf(buf+len, "128 bit "); - len += sprintf(buf+len, "\n"); +*/ + seq_printf(seq, "SGL data alignment : %d\n", work16[8]); + seq_printf(seq, "SGL addr limit : %d\n", work8[20]); + seq_printf(seq, "SGL addr sizes supported : "); + if (work8[21] & 0x01) + seq_printf(seq, "32 bit "); + if (work8[21] & 0x02) + seq_printf(seq, "64 bit "); + if (work8[21] & 0x04) + seq_printf(seq, "96 bit "); + if (work8[21] & 0x08) + seq_printf(seq, "128 bit "); + seq_printf(seq, "\n"); +/* } +*/ - spin_unlock(&i2o_proc_lock); - - return len; + return 0; } /* Generic group F200h - Sensors (scalar) */ -int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_seq_show_sensors(struct seq_file *seq, void *v) { - struct i2o_device *d = (struct i2o_device*)data; + struct i2o_device *d = (struct i2o_device *)seq->private; int token; - struct - { + struct { u16 sensor_instance; - u8 component; + u8 component; u16 component_instance; - u8 sensor_class; - u8 sensor_type; - u8 scaling_exponent; + u8 sensor_class; + u8 sensor_type; + u8 scaling_exponent; u32 actual_reading; u32 minimum_reading; u32 low2lowcat_treshold; @@ -1615,1795 +1455,663 @@ int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len, u32 hicat2high_treshold; u32 hi2hicat_treshold; u32 maximum_reading; - u8 sensor_state; + u8 sensor_state; u16 event_enable; } result; - - spin_lock(&i2o_proc_lock); - len = 0; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0xF200, -1, - &result, sizeof(result)); + token = i2o_parm_field_get(d, 0xF200, -1, &result, sizeof(result)); if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)"); - spin_unlock(&i2o_proc_lock); - return len; + i2o_report_query_status(seq, token, + "0xF200 Sensors (optional)"); + return 0; } - - len += sprintf(buf+len, "Sensor instance : %d\n", result.sensor_instance); - len += sprintf(buf+len, "Component : %d = ", result.component); - switch (result.component) - { - case 0: len += sprintf(buf+len, "Other"); + seq_printf(seq, "Sensor instance : %d\n", result.sensor_instance); + + seq_printf(seq, "Component : %d = ", result.component); + switch (result.component) { + case 0: + seq_printf(seq, "Other"); break; - case 1: len += sprintf(buf+len, "Planar logic Board"); + case 1: + seq_printf(seq, "Planar logic Board"); break; - case 2: len += sprintf(buf+len, "CPU"); + case 2: + seq_printf(seq, "CPU"); break; - case 3: len += sprintf(buf+len, "Chassis"); + case 3: + seq_printf(seq, "Chassis"); break; - case 4: len += sprintf(buf+len, "Power Supply"); + case 4: + seq_printf(seq, "Power Supply"); break; - case 5: len += sprintf(buf+len, "Storage"); + case 5: + seq_printf(seq, "Storage"); break; - case 6: len += sprintf(buf+len, "External"); + case 6: + seq_printf(seq, "External"); break; - } - len += sprintf(buf+len,"\n"); + } + seq_printf(seq, "\n"); - len += sprintf(buf+len, "Component instance : %d\n", result.component_instance); - len += sprintf(buf+len, "Sensor class : %s\n", - result.sensor_class ? "Analog" : "Digital"); - - len += sprintf(buf+len, "Sensor type : %d = ",result.sensor_type); - switch (result.sensor_type) - { - case 0: len += sprintf(buf+len, "Other\n"); + seq_printf(seq, "Component instance : %d\n", + result.component_instance); + seq_printf(seq, "Sensor class : %s\n", + result.sensor_class ? "Analog" : "Digital"); + + seq_printf(seq, "Sensor type : %d = ", result.sensor_type); + switch (result.sensor_type) { + case 0: + seq_printf(seq, "Other\n"); break; - case 1: len += sprintf(buf+len, "Thermal\n"); + case 1: + seq_printf(seq, "Thermal\n"); break; - case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n"); + case 2: + seq_printf(seq, "DC voltage (DC volts)\n"); break; - case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n"); + case 3: + seq_printf(seq, "AC voltage (AC volts)\n"); break; - case 4: len += sprintf(buf+len, "DC current (DC amps)\n"); + case 4: + seq_printf(seq, "DC current (DC amps)\n"); break; - case 5: len += sprintf(buf+len, "AC current (AC volts)\n"); + case 5: + seq_printf(seq, "AC current (AC volts)\n"); break; - case 6: len += sprintf(buf+len, "Door open\n"); + case 6: + seq_printf(seq, "Door open\n"); break; - case 7: len += sprintf(buf+len, "Fan operational\n"); + case 7: + seq_printf(seq, "Fan operational\n"); break; - } + } - len += sprintf(buf+len, "Scaling exponent : %d\n", result.scaling_exponent); - len += sprintf(buf+len, "Actual reading : %d\n", result.actual_reading); - len += sprintf(buf+len, "Minimum reading : %d\n", result.minimum_reading); - len += sprintf(buf+len, "Low2LowCat treshold : %d\n", result.low2lowcat_treshold); - len += sprintf(buf+len, "LowCat2Low treshold : %d\n", result.lowcat2low_treshold); - len += sprintf(buf+len, "LowWarn2Low treshold : %d\n", result.lowwarn2low_treshold); - len += sprintf(buf+len, "Low2LowWarn treshold : %d\n", result.low2lowwarn_treshold); - len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold); - len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold); - len += sprintf(buf+len, "Nominal reading : %d\n", result.nominal_reading); - len += sprintf(buf+len, "HiWarn2Norm treshold : %d\n", result.hiwarn2norm_treshold); - len += sprintf(buf+len, "Norm2HiWarn treshold : %d\n", result.norm2hiwarn_treshold); - len += sprintf(buf+len, "High2HiWarn treshold : %d\n", result.high2hiwarn_treshold); - len += sprintf(buf+len, "HiWarn2High treshold : %d\n", result.hiwarn2high_treshold); - len += sprintf(buf+len, "HiCat2High treshold : %d\n", result.hicat2high_treshold); - len += sprintf(buf+len, "High2HiCat treshold : %d\n", result.hi2hicat_treshold); - len += sprintf(buf+len, "Maximum reading : %d\n", result.maximum_reading); + seq_printf(seq, "Scaling exponent : %d\n", + result.scaling_exponent); + seq_printf(seq, "Actual reading : %d\n", result.actual_reading); + seq_printf(seq, "Minimum reading : %d\n", result.minimum_reading); + seq_printf(seq, "Low2LowCat treshold : %d\n", + result.low2lowcat_treshold); + seq_printf(seq, "LowCat2Low treshold : %d\n", + result.lowcat2low_treshold); + seq_printf(seq, "LowWarn2Low treshold : %d\n", + result.lowwarn2low_treshold); + seq_printf(seq, "Low2LowWarn treshold : %d\n", + result.low2lowwarn_treshold); + seq_printf(seq, "Norm2LowWarn treshold : %d\n", + result.norm2lowwarn_treshold); + seq_printf(seq, "LowWarn2Norm treshold : %d\n", + result.lowwarn2norm_treshold); + seq_printf(seq, "Nominal reading : %d\n", result.nominal_reading); + seq_printf(seq, "HiWarn2Norm treshold : %d\n", + result.hiwarn2norm_treshold); + seq_printf(seq, "Norm2HiWarn treshold : %d\n", + result.norm2hiwarn_treshold); + seq_printf(seq, "High2HiWarn treshold : %d\n", + result.high2hiwarn_treshold); + seq_printf(seq, "HiWarn2High treshold : %d\n", + result.hiwarn2high_treshold); + seq_printf(seq, "HiCat2High treshold : %d\n", + result.hicat2high_treshold); + seq_printf(seq, "High2HiCat treshold : %d\n", + result.hi2hicat_treshold); + seq_printf(seq, "Maximum reading : %d\n", result.maximum_reading); - len += sprintf(buf+len, "Sensor state : %d = ", result.sensor_state); - switch (result.sensor_state) - { - case 0: len += sprintf(buf+len, "Normal\n"); - break; - case 1: len += sprintf(buf+len, "Abnormal\n"); - break; - case 2: len += sprintf(buf+len, "Unknown\n"); - break; - case 3: len += sprintf(buf+len, "Low Catastrophic (LoCat)\n"); - break; - case 4: len += sprintf(buf+len, "Low (Low)\n"); - break; - case 5: len += sprintf(buf+len, "Low Warning (LoWarn)\n"); - break; - case 6: len += sprintf(buf+len, "High Warning (HiWarn)\n"); - break; - case 7: len += sprintf(buf+len, "High (High)\n"); - break; - case 8: len += sprintf(buf+len, "High Catastrophic (HiCat)\n"); - break; - } - - len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable); - len += sprintf(buf+len, " [%s] Operational state change. \n", - (result.event_enable & 0x01) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low catastrophic. \n", - (result.event_enable & 0x02) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low reading. \n", - (result.event_enable & 0x04) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Low warning. \n", - (result.event_enable & 0x08) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] Change back to normal from out of range state. \n", - (result.event_enable & 0x10) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High warning. \n", - (result.event_enable & 0x20) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High reading. \n", - (result.event_enable & 0x40) ? "+" : "-" ); - len += sprintf(buf+len, " [%s] High catastrophic. \n", - (result.event_enable & 0x80) ? "+" : "-" ); - - spin_unlock(&i2o_proc_lock); - return len; + seq_printf(seq, "Sensor state : %d = ", result.sensor_state); + switch (result.sensor_state) { + case 0: + seq_printf(seq, "Normal\n"); + break; + case 1: + seq_printf(seq, "Abnormal\n"); + break; + case 2: + seq_printf(seq, "Unknown\n"); + break; + case 3: + seq_printf(seq, "Low Catastrophic (LoCat)\n"); + break; + case 4: + seq_printf(seq, "Low (Low)\n"); + break; + case 5: + seq_printf(seq, "Low Warning (LoWarn)\n"); + break; + case 6: + seq_printf(seq, "High Warning (HiWarn)\n"); + break; + case 7: + seq_printf(seq, "High (High)\n"); + break; + case 8: + seq_printf(seq, "High Catastrophic (HiCat)\n"); + break; + } + + seq_printf(seq, "Event_enable : 0x%02X\n", result.event_enable); + seq_printf(seq, " [%s] Operational state change. \n", + (result.event_enable & 0x01) ? "+" : "-"); + seq_printf(seq, " [%s] Low catastrophic. \n", + (result.event_enable & 0x02) ? "+" : "-"); + seq_printf(seq, " [%s] Low reading. \n", + (result.event_enable & 0x04) ? "+" : "-"); + seq_printf(seq, " [%s] Low warning. \n", + (result.event_enable & 0x08) ? "+" : "-"); + seq_printf(seq, + " [%s] Change back to normal from out of range state. \n", + (result.event_enable & 0x10) ? "+" : "-"); + seq_printf(seq, " [%s] High warning. \n", + (result.event_enable & 0x20) ? "+" : "-"); + seq_printf(seq, " [%s] High reading. \n", + (result.event_enable & 0x40) ? "+" : "-"); + seq_printf(seq, " [%s] High catastrophic. \n", + (result.event_enable & 0x80) ? "+" : "-"); + + return 0; } +static int i2o_seq_open_hrt(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_hrt, PDE(inode)->data); +}; -static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len) +static int i2o_seq_open_lct(struct inode *inode, struct file *file) { - int i; + return single_open(file, i2o_seq_show_lct, PDE(inode)->data); +}; - /* 19990419 -sralston - * The I2O v1.5 (and v2.0 so far) "official specification" - * got serial numbers WRONG! - * Apparently, and despite what Section 3.4.4 says and - * Figure 3-35 shows (pg 3-39 in the pdf doc), - * the convention / consensus seems to be: - * + First byte is SNFormat - * + Second byte is SNLen (but only if SNFormat==7 (?)) - * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format - */ - switch(serialno[0]) - { - case I2O_SNFORMAT_BINARY: /* Binary */ - pos += sprintf(buff+pos, "0x"); - for(i = 0; i < serialno[1]; i++) - { - pos += sprintf(buff+pos, "%02X", serialno[2+i]); - } - break; - - case I2O_SNFORMAT_ASCII: /* ASCII */ - if ( serialno[1] < ' ' ) /* printable or SNLen? */ - { - /* sanity */ - max_len = (max_len < serialno[1]) ? max_len : serialno[1]; - serialno[1+max_len] = '\0'; - - /* just print it */ - pos += sprintf(buff+pos, "%s", &serialno[2]); - } - else - { - /* print chars for specified length */ - for(i = 0; i < serialno[1]; i++) - { - pos += sprintf(buff+pos, "%c", serialno[2+i]); - } - } - break; +static int i2o_seq_open_status(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_status, PDE(inode)->data); +}; - case I2O_SNFORMAT_UNICODE: /* UNICODE */ - pos += sprintf(buff+pos, "UNICODE Format. Can't Display\n"); - break; +static int i2o_seq_open_hw(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_hw, PDE(inode)->data); +}; - case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ - pos += sprintf(buff+pos, - "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", - serialno[2], serialno[3], - serialno[4], serialno[5], - serialno[6], serialno[7]); - break; +static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_ddm_table, PDE(inode)->data); +}; - case I2O_SNFORMAT_WAN: /* WAN MAC Address */ - /* FIXME: Figure out what a WAN access address looks like?? */ - pos += sprintf(buff+pos, "WAN Access Address"); - break; +static int i2o_seq_open_driver_store(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_driver_store, PDE(inode)->data); +}; -/* plus new in v2.0 */ - case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ - /* FIXME: Figure out what a LAN-64 address really looks like?? */ - pos += sprintf(buff+pos, - "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", - serialno[8], serialno[9], - serialno[2], serialno[3], - serialno[4], serialno[5], - serialno[6], serialno[7]); - break; +static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_drivers_stored, PDE(inode)->data); +}; +static int i2o_seq_open_groups(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_groups, PDE(inode)->data); +}; - case I2O_SNFORMAT_DDM: /* I2O DDM */ - pos += sprintf(buff+pos, - "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", - *(u16*)&serialno[2], - *(u16*)&serialno[4], - *(u16*)&serialno[6]); - break; +static int i2o_seq_open_phys_device(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_phys_device, PDE(inode)->data); +}; - case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ - case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ - /* FIXME: Figure if this is even close?? */ - pos += sprintf(buff+pos, - "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", - *(u32*)&serialno[2], - *(u32*)&serialno[6], - *(u32*)&serialno[10], - *(u32*)&serialno[14]); - break; +static int i2o_seq_open_claimed(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_claimed, PDE(inode)->data); +}; +static int i2o_seq_open_users(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_users, PDE(inode)->data); +}; - case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ - case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ - default: - pos += sprintf(buff+pos, "Unknown data format (0x%02x)", - serialno[0]); - break; - } +static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_priv_msgs, PDE(inode)->data); +}; - return pos; -} +static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_authorized_users, + PDE(inode)->data); +}; -const char * i2o_get_connector_type(int conn) +static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file) { - int idx = 16; - static char *i2o_connector_type[] = { - "OTHER", - "UNKNOWN", - "AUI", - "UTP", - "BNC", - "RJ45", - "STP DB9", - "FIBER MIC", - "APPLE AUI", - "MII", - "DB9", - "HSSDC", - "DUPLEX SC FIBER", - "DUPLEX ST FIBER", - "TNC/BNC", - "HW DEFAULT" - }; + return single_open(file, i2o_seq_show_dev_identity, PDE(inode)->data); +}; - switch(conn) - { - case 0x00000000: - idx = 0; - break; - case 0x00000001: - idx = 1; - break; - case 0x00000002: - idx = 2; - break; - case 0x00000003: - idx = 3; - break; - case 0x00000004: - idx = 4; - break; - case 0x00000005: - idx = 5; - break; - case 0x00000006: - idx = 6; - break; - case 0x00000007: - idx = 7; - break; - case 0x00000008: - idx = 8; - break; - case 0x00000009: - idx = 9; - break; - case 0x0000000A: - idx = 10; - break; - case 0x0000000B: - idx = 11; - break; - case 0x0000000C: - idx = 12; - break; - case 0x0000000D: - idx = 13; - break; - case 0x0000000E: - idx = 14; - break; - case 0xFFFFFFFF: - idx = 15; - break; - } +static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_ddm_identity, PDE(inode)->data); +}; - return i2o_connector_type[idx]; -} +static int i2o_seq_open_uinfo(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_uinfo, PDE(inode)->data); +}; +static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file) +{ + return single_open(file, i2o_seq_show_sgl_limits, PDE(inode)->data); +}; -const char * i2o_get_connection_type(int conn) +static int i2o_seq_open_sensors(struct inode *inode, struct file *file) { - int idx = 0; - static char *i2o_connection_type[] = { - "Unknown", - "AUI", - "10BASE5", - "FIORL", - "10BASE2", - "10BROAD36", - "10BASE-T", - "10BASE-FP", - "10BASE-FB", - "10BASE-FL", - "100BASE-TX", - "100BASE-FX", - "100BASE-T4", - "1000BASE-SX", - "1000BASE-LX", - "1000BASE-CX", - "1000BASE-T", - "100VG-ETHERNET", - "100VG-TOKEN RING", - "4MBIT TOKEN RING", - "16 Mb Token Ring", - "125 MBAUD FDDI", - "Point-to-point", - "Arbitrated loop", - "Public loop", - "Fabric", - "Emulation", - "Other", - "HW default" - }; + return single_open(file, i2o_seq_show_sensors, PDE(inode)->data); +}; - switch(conn) - { - case I2O_LAN_UNKNOWN: - idx = 0; - break; - case I2O_LAN_AUI: - idx = 1; - break; - case I2O_LAN_10BASE5: - idx = 2; - break; - case I2O_LAN_FIORL: - idx = 3; - break; - case I2O_LAN_10BASE2: - idx = 4; - break; - case I2O_LAN_10BROAD36: - idx = 5; - break; - case I2O_LAN_10BASE_T: - idx = 6; - break; - case I2O_LAN_10BASE_FP: - idx = 7; - break; - case I2O_LAN_10BASE_FB: - idx = 8; - break; - case I2O_LAN_10BASE_FL: - idx = 9; - break; - case I2O_LAN_100BASE_TX: - idx = 10; - break; - case I2O_LAN_100BASE_FX: - idx = 11; - break; - case I2O_LAN_100BASE_T4: - idx = 12; - break; - case I2O_LAN_1000BASE_SX: - idx = 13; - break; - case I2O_LAN_1000BASE_LX: - idx = 14; - break; - case I2O_LAN_1000BASE_CX: - idx = 15; - break; - case I2O_LAN_1000BASE_T: - idx = 16; - break; - case I2O_LAN_100VG_ETHERNET: - idx = 17; - break; - case I2O_LAN_100VG_TR: - idx = 18; - break; - case I2O_LAN_4MBIT: - idx = 19; - break; - case I2O_LAN_16MBIT: - idx = 20; - break; - case I2O_LAN_125MBAUD: - idx = 21; - break; - case I2O_LAN_POINT_POINT: - idx = 22; - break; - case I2O_LAN_ARB_LOOP: - idx = 23; - break; - case I2O_LAN_PUBLIC_LOOP: - idx = 24; - break; - case I2O_LAN_FABRIC: - idx = 25; - break; - case I2O_LAN_EMULATION: - idx = 26; - break; - case I2O_LAN_OTHER: - idx = 27; - break; - case I2O_LAN_DEFAULT: - idx = 28; - break; - } - - return i2o_connection_type[idx]; -} - - -/* LAN group 0000h - Device info (scalar) */ -int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[56]; - static u8 *work8 = (u8*)work32; - static u16 *work16 = (u16*)work32; - static u64 *work64 = (u64*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0000, -1, &work32, 56*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "LAN Type : "); - switch (work16[0]) - { - case 0x0030: - len += sprintf(buf+len, "Ethernet, "); - break; - case 0x0040: - len += sprintf(buf+len, "100Base VG, "); - break; - case 0x0050: - len += sprintf(buf+len, "Token Ring, "); - break; - case 0x0060: - len += sprintf(buf+len, "FDDI, "); - break; - case 0x0070: - len += sprintf(buf+len, "Fibre Channel, "); - break; - default: - len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]); - break; - } - - if (work16[1]&0x00000001) - len += sprintf(buf+len, "emulated LAN, "); - else - len += sprintf(buf+len, "physical LAN port, "); - - if (work16[1]&0x00000002) - len += sprintf(buf+len, "full duplex\n"); - else - len += sprintf(buf+len, "simplex\n"); - - len += sprintf(buf+len, "Address format : "); - switch(work8[4]) { - case 0x00: - len += sprintf(buf+len, "IEEE 48bit\n"); - break; - case 0x01: - len += sprintf(buf+len, "FC IEEE\n"); - break; - default: - len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]); - break; - } - - len += sprintf(buf+len, "State : "); - switch(work8[5]) - { - case 0x00: - len += sprintf(buf+len, "Unknown\n"); - break; - case 0x01: - len += sprintf(buf+len, "Unclaimed\n"); - break; - case 0x02: - len += sprintf(buf+len, "Operational\n"); - break; - case 0x03: - len += sprintf(buf+len, "Suspended\n"); - break; - case 0x04: - len += sprintf(buf+len, "Resetting\n"); - break; - case 0x05: - len += sprintf(buf+len, "ERROR: "); - if(work16[3]&0x0001) - len += sprintf(buf+len, "TxCU inoperative "); - if(work16[3]&0x0002) - len += sprintf(buf+len, "RxCU inoperative "); - if(work16[3]&0x0004) - len += sprintf(buf+len, "Local mem alloc "); - len += sprintf(buf+len, "\n"); - break; - case 0x06: - len += sprintf(buf+len, "Operational no Rx\n"); - break; - case 0x07: - len += sprintf(buf+len, "Suspended no Rx\n"); - break; - default: - len += sprintf(buf+len, "Unspecified\n"); - break; - } - - len += sprintf(buf+len, "Min packet size : %d\n", work32[2]); - len += sprintf(buf+len, "Max packet size : %d\n", work32[3]); - len += sprintf(buf+len, "HW address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[16],work8[17],work8[18],work8[19], - work8[20],work8[21],work8[22],work8[23]); - - len += sprintf(buf+len, "Max Tx wire speed : %d bps\n", (int)work64[3]); - len += sprintf(buf+len, "Max Rx wire speed : %d bps\n", (int)work64[4]); - - len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]); - len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0001h - MAC address table (scalar) */ -int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[48]; - static u8 *work8 = (u8*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0001, -1, &work32, 48*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Active address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[0],work8[1],work8[2],work8[3], - work8[4],work8[5],work8[6],work8[7]); - len += sprintf(buf+len, "Current address : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[8],work8[9],work8[10],work8[11], - work8[12],work8[13],work8[14],work8[15]); - len += sprintf(buf+len, "Functional address mask : " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[16],work8[17],work8[18],work8[19], - work8[20],work8[21],work8[22],work8[23]); - - len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]); - len += sprintf(buf+len," [%s] Unicast packets supported\n", - (work32[7]&0x00000001)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous mode supported\n", - (work32[7]&0x00000002)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous multicast mode supported\n", - (work32[7]&0x00000004)?"+":"-"); - len += sprintf(buf+len," [%s] Broadcast reception disabling supported\n", - (work32[7]&0x00000100)?"+":"-"); - len += sprintf(buf+len," [%s] Multicast reception disabling supported\n", - (work32[7]&0x00000200)?"+":"-"); - len += sprintf(buf+len," [%s] Functional address disabling supported\n", - (work32[7]&0x00000400)?"+":"-"); - len += sprintf(buf+len," [%s] MAC reporting supported\n", - (work32[7]&0x00000800)?"+":"-"); - - len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]); - len += sprintf(buf+len," [%s] Unicast packets disable\n", - (work32[6]&0x00000001)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous mode enable\n", - (work32[6]&0x00000002)?"+":"-"); - len += sprintf(buf+len," [%s] Promiscuous multicast mode enable\n", - (work32[6]&0x00000004)?"+":"-"); - len += sprintf(buf+len," [%s] Broadcast packets disable\n", - (work32[6]&0x00000100)?"+":"-"); - len += sprintf(buf+len," [%s] Multicast packets disable\n", - (work32[6]&0x00000200)?"+":"-"); - len += sprintf(buf+len," [%s] Functional address disable\n", - (work32[6]&0x00000400)?"+":"-"); - - if (work32[7]&0x00000800) { - len += sprintf(buf+len, " MAC reporting mode : "); - if (work32[6]&0x00000800) - len += sprintf(buf+len, "Pass only priority MAC packets to user\n"); - else if (work32[6]&0x00001000) - len += sprintf(buf+len, "Pass all MAC packets to user\n"); - else if (work32[6]&0x00001800) - len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n"); - else - len += sprintf(buf+len, "Do not pass MAC packets to user\n"); - } - len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]); - len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n", - work32[9]); - len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n", - work32[10]); - - spin_unlock(&i2o_proc_lock); - - return len; -} - -/* LAN group 0002h - Multicast MAC address table (table) */ -int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 mc_addr[8]; - - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u8 mc_addr[256][8]; - } *result; - - result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) - return -ENOMEM; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, 0x0002, -1, - NULL, 0, result, sizeof(*result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address"); - goto out; - } - - for (i = 0; i < result->row_count; i++) - { - memcpy(mc_addr, result->mc_addr[i], 8); - - len += sprintf(buf+len, "MC MAC address[%d]: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - i, mc_addr[0], mc_addr[1], mc_addr[2], - mc_addr[3], mc_addr[4], mc_addr[5], - mc_addr[6], mc_addr[7]); - } -out: - spin_unlock(&i2o_proc_lock); - kfree(result); - return len; -} - -/* LAN group 0003h - Batch Control (scalar) */ -int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[9]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0003, -1, &work32, 9*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Batch mode "); - if (work32[0]&0x00000001) - len += sprintf(buf+len, "disabled"); - else - len += sprintf(buf+len, "enabled"); - if (work32[0]&0x00000002) - len += sprintf(buf+len, " (current setting)"); - if (work32[0]&0x00000004) - len += sprintf(buf+len, ", forced"); - else - len += sprintf(buf+len, ", toggle"); - len += sprintf(buf+len, "\n"); - - len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); - len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); - len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); - len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0004h - LAN Operation (scalar) */ -int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[5]; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0004, -1, &work32, 20); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]); - len += sprintf(buf+len, "Transmission error reporting : %s\n", - (work32[1]&1)?"on":"off"); - len += sprintf(buf+len, "Bad packet handling : %s\n", - (work32[1]&0x2)?"by host":"by DDM"); - len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); - - len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); - len += sprintf(buf+len, " [%s] HW CRC suppression\n", - (work32[3]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", - (work32[3]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW TCP checksum\n", - (work32[3]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW UDP checksum\n", - (work32[3]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW RSVP checksum\n", - (work32[3]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW ICMP checksum\n", - (work32[3]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback suppression enable\n", - (work32[3]&0x00002000) ? "+" : "-"); - - len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); - len += sprintf(buf+len, " [%s] FCS in payload\n", - (work32[4]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW IPv4 checksum validation\n", - (work32[4]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW TCP checksum validation\n", - (work32[4]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW UDP checksum validation\n", - (work32[4]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW RSVP checksum validation\n", - (work32[4]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] HW ICMP checksum validation\n", - (work32[4]&0x00001000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0005h - Media operation (scalar) */ -int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u32 connector_type; - u32 connection_type; - u64 current_tx_wire_speed; - u64 current_rx_wire_speed; - u8 duplex_mode; - u8 link_status; - u8 reserved; - u8 duplex_mode_target; - u32 connector_type_target; - u32 connection_type_target; - } result; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0005, -1, &result, sizeof(result)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Connector type : %s\n", - i2o_get_connector_type(result.connector_type)); - len += sprintf(buf+len, "Connection type : %s\n", - i2o_get_connection_type(result.connection_type)); - - len += sprintf(buf+len, "Current Tx wire speed : %d bps\n", (int)result.current_tx_wire_speed); - len += sprintf(buf+len, "Current Rx wire speed : %d bps\n", (int)result.current_rx_wire_speed); - len += sprintf(buf+len, "Duplex mode : %s duplex\n", - (result.duplex_mode)?"Full":"Half"); - - len += sprintf(buf+len, "Link status : "); - switch (result.link_status) - { - case 0x00: - len += sprintf(buf+len, "Unknown\n"); - break; - case 0x01: - len += sprintf(buf+len, "Normal\n"); - break; - case 0x02: - len += sprintf(buf+len, "Failure\n"); - break; - case 0x03: - len += sprintf(buf+len, "Reset\n"); - break; - default: - len += sprintf(buf+len, "Unspecified\n"); - } - - len += sprintf(buf+len, "Duplex mode target : "); - switch (result.duplex_mode_target){ - case 0: - len += sprintf(buf+len, "Half duplex\n"); - break; - case 1: - len += sprintf(buf+len, "Full duplex\n"); - break; - default: - len += sprintf(buf+len, "\n"); - } - - len += sprintf(buf+len, "Connector type target : %s\n", - i2o_get_connector_type(result.connector_type_target)); - len += sprintf(buf+len, "Connection type target : %s\n", - i2o_get_connection_type(result.connection_type_target)); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0006h - Alternate address (table) (optional) */ -int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int i2o_seq_open_dev_name(struct inode *inode, struct file *file) { - struct i2o_device *d = (struct i2o_device*)data; - int token; - int i; - u8 alt_addr[8]; - struct - { - u16 result_count; - u16 pad; - u16 block_size; - u8 block_status; - u8 error_info_size; - u16 row_count; - u16 more_flag; - u8 alt_addr[256][8]; - } *result; - - result = kmalloc(sizeof(*result), GFP_KERNEL); - if(!result) - return -ENOMEM; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data.tid, - 0x0006, -1, NULL, 0, result, sizeof(*result)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)"); - goto out; - } - - for (i=0; i < result->row_count; i++) - { - memcpy(alt_addr,result->alt_addr[i],8); - len += sprintf(buf+len, "Alternate address[%d]: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - i, alt_addr[0], alt_addr[1], alt_addr[2], - alt_addr[3], alt_addr[4], alt_addr[5], - alt_addr[6], alt_addr[7]); - } -out: - spin_unlock(&i2o_proc_lock); - kfree(result); - return len; -} + return single_open(file, i2o_seq_show_dev_name, PDE(inode)->data); +}; +static struct file_operations i2o_seq_fops_lct = { + .open = i2o_seq_open_lct, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; -/* LAN group 0007h - Transmit info (scalar) */ -int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[8]; - int token; +static struct file_operations i2o_seq_fops_hrt = { + .open = i2o_seq_open_hrt, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - spin_lock(&i2o_proc_lock); - len = 0; +static struct file_operations i2o_seq_fops_status = { + .open = i2o_seq_open_status, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0007, -1, &work32, 8*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_hw = { + .open = i2o_seq_open_hw, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += sprintf(buf, "Tx Max SG elements per packet : %d\n", work32[0]); - len += sprintf(buf+len, "Tx Max SG elements per chain : %d\n", work32[1]); - len += sprintf(buf+len, "Tx Max outstanding packets : %d\n", work32[2]); - len += sprintf(buf+len, "Tx Max packets per request : %d\n", work32[3]); - - len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]); - len += sprintf(buf+len, " [%s] No DA in SGL\n", - (work32[4]&0x00000002) ? "+" : "-"); - len += sprintf(buf+len, " [%s] CRC suppression\n", - (work32[4]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] MAC insertion\n", - (work32[4]&0x00000010) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RIF insertion\n", - (work32[4]&0x00000020) ? "+" : "-"); - len += sprintf(buf+len, " [%s] IPv4 checksum generation\n", - (work32[4]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] TCP checksum generation\n", - (work32[4]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] UDP checksum generation\n", - (work32[4]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RSVP checksum generation\n", - (work32[4]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] ICMP checksum generation\n", - (work32[4]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback enabled\n", - (work32[4]&0x00010000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback suppression enabled\n", - (work32[4]&0x00020000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} +static struct file_operations i2o_seq_fops_ddm_table = { + .open = i2o_seq_open_ddm_table, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; -/* LAN group 0008h - Receive info (scalar) */ -int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[8]; - int token; +static struct file_operations i2o_seq_fops_driver_store = { + .open = i2o_seq_open_driver_store, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - spin_lock(&i2o_proc_lock); - len = 0; +static struct file_operations i2o_seq_fops_drivers_stored = { + .open = i2o_seq_open_drivers_stored, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0008, -1, &work32, 8*4); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_groups = { + .open = i2o_seq_open_groups, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += sprintf(buf ,"Rx Max size of chain element : %d\n", work32[0]); - len += sprintf(buf+len, "Rx Max Buckets : %d\n", work32[1]); - len += sprintf(buf+len, "Rx Max Buckets in Reply : %d\n", work32[3]); - len += sprintf(buf+len, "Rx Max Packets in Bucket : %d\n", work32[4]); - len += sprintf(buf+len, "Rx Max Buckets in Post : %d\n", work32[5]); - - len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]); - len += sprintf(buf+len, " [%s] FCS reception\n", - (work32[2]&0x00000004) ? "+" : "-"); - len += sprintf(buf+len, " [%s] IPv4 checksum validation \n", - (work32[2]&0x00000100) ? "+" : "-"); - len += sprintf(buf+len, " [%s] TCP checksum validation \n", - (work32[2]&0x00000200) ? "+" : "-"); - len += sprintf(buf+len, " [%s] UDP checksum validation \n", - (work32[2]&0x00000400) ? "+" : "-"); - len += sprintf(buf+len, " [%s] RSVP checksum validation \n", - (work32[2]&0x00000800) ? "+" : "-"); - len += sprintf(buf+len, " [%s] ICMP checksum validation \n", - (work32[2]&0x00001000) ? "+" : "-"); - - spin_unlock(&i2o_proc_lock); - return len; -} +static struct file_operations i2o_seq_fops_phys_device = { + .open = i2o_seq_open_phys_device, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; -static int i2o_report_opt_field(char *buf, char *field_name, - int field_nbr, int supp_fields, u64 *value) -{ - if (supp_fields & (1 << field_nbr)) - return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value)); - else - return sprintf(buf, "%-24s : Not supported\n", field_name); -} +static struct file_operations i2o_seq_fops_claimed = { + .open = i2o_seq_open_claimed, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; -/* LAN group 0100h - LAN Historical statistics (scalar) */ -/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */ -/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */ -/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */ +static struct file_operations i2o_seq_fops_users = { + .open = i2o_seq_open_users, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; -int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - int token; +static struct file_operations i2o_seq_fops_priv_msgs = { + .open = i2o_seq_open_priv_msgs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - struct - { - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets; - u64 rx_bytes; - u64 tx_errors; - u64 rx_errors; - u64 rx_dropped; - u64 adapter_resets; - u64 adapter_suspends; - } stats; // 0x0100 - - static u64 supp_groups[4]; // 0x0180 - - struct - { - u64 tx_retries; - u64 tx_directed_bytes; - u64 tx_directed_packets; - u64 tx_multicast_bytes; - u64 tx_multicast_packets; - u64 tx_broadcast_bytes; - u64 tx_broadcast_packets; - u64 tx_group_addr_packets; - u64 tx_short_packets; - } tx_stats; // 0x0182 - - struct - { - u64 rx_crc_errors; - u64 rx_directed_bytes; - u64 rx_directed_packets; - u64 rx_multicast_bytes; - u64 rx_multicast_packets; - u64 rx_broadcast_bytes; - u64 rx_broadcast_packets; - u64 rx_group_addr_packets; - u64 rx_short_packets; - u64 rx_long_packets; - u64 rx_runt_packets; - } rx_stats; // 0x0183 - - struct - { - u64 ipv4_generate; - u64 ipv4_validate_success; - u64 ipv4_validate_errors; - u64 tcp_generate; - u64 tcp_validate_success; - u64 tcp_validate_errors; - u64 udp_generate; - u64 udp_validate_success; - u64 udp_validate_errors; - u64 rsvp_generate; - u64 rsvp_validate_success; - u64 rsvp_validate_errors; - u64 icmp_generate; - u64 icmp_validate_success; - u64 icmp_validate_errors; - } chksum_stats; // 0x0184 - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0100, -1, &stats, sizeof(stats)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_authorized_users = { + .open = i2o_seq_open_authorized_users, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += sprintf(buf+len, "Tx packets : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_packets)); - len += sprintf(buf+len, "Tx bytes : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_bytes)); - len += sprintf(buf+len, "Rx packets : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_packets)); - len += sprintf(buf+len, "Rx bytes : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_bytes)); - len += sprintf(buf+len, "Tx errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_errors)); - len += sprintf(buf+len, "Rx errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_errors)); - len += sprintf(buf+len, "Rx dropped : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_dropped)); - len += sprintf(buf+len, "Adapter resets : " FMT_U64_HEX "\n", - U64_VAL(&stats.adapter_resets)); - len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n", - U64_VAL(&stats.adapter_suspends)); - - /* Optional statistics follows */ - /* Get 0x0180 to see which optional groups/fields are supported */ - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0180, -1, &supp_groups, sizeof(supp_groups)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_dev_name = { + .open = i2o_seq_open_dev_name, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (supp_groups[1]) /* 0x0182 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0182, -1, &tx_stats, sizeof(tx_stats)); +static struct file_operations i2o_seq_fops_dev_identity = { + .open = i2o_seq_open_dev_identity, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_ddm_identity = { + .open = i2o_seq_open_ddm_identity, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n"); - - len += i2o_report_opt_field(buf+len, "Tx RetryCount", - 0, supp_groups[1], &tx_stats.tx_retries); - len += i2o_report_opt_field(buf+len, "Tx DirectedBytes", - 1, supp_groups[1], &tx_stats.tx_directed_bytes); - len += i2o_report_opt_field(buf+len, "Tx DirectedPackets", - 2, supp_groups[1], &tx_stats.tx_directed_packets); - len += i2o_report_opt_field(buf+len, "Tx MulticastBytes", - 3, supp_groups[1], &tx_stats.tx_multicast_bytes); - len += i2o_report_opt_field(buf+len, "Tx MulticastPackets", - 4, supp_groups[1], &tx_stats.tx_multicast_packets); - len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes", - 5, supp_groups[1], &tx_stats.tx_broadcast_bytes); - len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets", - 6, supp_groups[1], &tx_stats.tx_broadcast_packets); - len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets", - 7, supp_groups[1], &tx_stats.tx_group_addr_packets); - len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort", - 8, supp_groups[1], &tx_stats.tx_short_packets); - } +static struct file_operations i2o_seq_fops_uinfo = { + .open = i2o_seq_open_uinfo, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (supp_groups[2]) /* 0x0183 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0183, -1, &rx_stats, sizeof(rx_stats)); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats"); - spin_unlock(&i2o_proc_lock); - return len; - } +static struct file_operations i2o_seq_fops_sgl_limits = { + .open = i2o_seq_open_sgl_limits, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n"); - - len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount", - 0, supp_groups[2], &rx_stats.rx_crc_errors); - len += i2o_report_opt_field(buf+len, "Rx DirectedBytes", - 1, supp_groups[2], &rx_stats.rx_directed_bytes); - len += i2o_report_opt_field(buf+len, "Rx DirectedPackets", - 2, supp_groups[2], &rx_stats.rx_directed_packets); - len += i2o_report_opt_field(buf+len, "Rx MulticastBytes", - 3, supp_groups[2], &rx_stats.rx_multicast_bytes); - len += i2o_report_opt_field(buf+len, "Rx MulticastPackets", - 4, supp_groups[2], &rx_stats.rx_multicast_packets); - len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes", - 5, supp_groups[2], &rx_stats.rx_broadcast_bytes); - len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets", - 6, supp_groups[2], &rx_stats.rx_broadcast_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets", - 7, supp_groups[2], &rx_stats.rx_group_addr_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort", - 8, supp_groups[2], &rx_stats.rx_short_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong", - 9, supp_groups[2], &rx_stats.rx_long_packets); - len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt", - 10, supp_groups[2], &rx_stats.rx_runt_packets); - } - - if (supp_groups[3]) /* 0x0184 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0184, -1, &chksum_stats, sizeof(chksum_stats)); +static struct file_operations i2o_seq_fops_sensors = { + .open = i2o_seq_open_sensors, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats"); - spin_unlock(&i2o_proc_lock); - return len; - } +/* + * IOP specific entries...write field just in case someone + * ever wants one. + */ +static i2o_proc_entry i2o_proc_generic_iop_entries[] = { + {"hrt", S_IFREG | S_IRUGO, &i2o_seq_fops_hrt}, + {"lct", S_IFREG | S_IRUGO, &i2o_seq_fops_lct}, + {"status", S_IFREG | S_IRUGO, &i2o_seq_fops_status}, + {"hw", S_IFREG | S_IRUGO, &i2o_seq_fops_hw}, + {"ddm_table", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_table}, + {"driver_store", S_IFREG | S_IRUGO, &i2o_seq_fops_driver_store}, + {"drivers_stored", S_IFREG | S_IRUGO, &i2o_seq_fops_drivers_stored}, + {NULL, 0, NULL} +}; - len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n"); - - len += i2o_report_opt_field(buf+len, "IPv4 Generate", - 0, supp_groups[3], &chksum_stats.ipv4_generate); - len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess", - 1, supp_groups[3], &chksum_stats.ipv4_validate_success); - len += i2o_report_opt_field(buf+len, "IPv4 ValidateError", - 2, supp_groups[3], &chksum_stats.ipv4_validate_errors); - len += i2o_report_opt_field(buf+len, "TCP Generate", - 3, supp_groups[3], &chksum_stats.tcp_generate); - len += i2o_report_opt_field(buf+len, "TCP ValidateSuccess", - 4, supp_groups[3], &chksum_stats.tcp_validate_success); - len += i2o_report_opt_field(buf+len, "TCP ValidateError", - 5, supp_groups[3], &chksum_stats.tcp_validate_errors); - len += i2o_report_opt_field(buf+len, "UDP Generate", - 6, supp_groups[3], &chksum_stats.udp_generate); - len += i2o_report_opt_field(buf+len, "UDP ValidateSuccess", - 7, supp_groups[3], &chksum_stats.udp_validate_success); - len += i2o_report_opt_field(buf+len, "UDP ValidateError", - 8, supp_groups[3], &chksum_stats.udp_validate_errors); - len += i2o_report_opt_field(buf+len, "RSVP Generate", - 9, supp_groups[3], &chksum_stats.rsvp_generate); - len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess", - 10, supp_groups[3], &chksum_stats.rsvp_validate_success); - len += i2o_report_opt_field(buf+len, "RSVP ValidateError", - 11, supp_groups[3], &chksum_stats.rsvp_validate_errors); - len += i2o_report_opt_field(buf+len, "ICMP Generate", - 12, supp_groups[3], &chksum_stats.icmp_generate); - len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess", - 13, supp_groups[3], &chksum_stats.icmp_validate_success); - len += i2o_report_opt_field(buf+len, "ICMP ValidateError", - 14, supp_groups[3], &chksum_stats.icmp_validate_errors); - } +/* + * Device specific entries + */ +static i2o_proc_entry generic_dev_entries[] = { + {"groups", S_IFREG | S_IRUGO, &i2o_seq_fops_groups}, + {"phys_dev", S_IFREG | S_IRUGO, &i2o_seq_fops_phys_device}, + {"claimed", S_IFREG | S_IRUGO, &i2o_seq_fops_claimed}, + {"users", S_IFREG | S_IRUGO, &i2o_seq_fops_users}, + {"priv_msgs", S_IFREG | S_IRUGO, &i2o_seq_fops_priv_msgs}, + {"authorized_users", S_IFREG | S_IRUGO, &i2o_seq_fops_authorized_users}, + {"dev_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_identity}, + {"ddm_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_identity}, + {"user_info", S_IFREG | S_IRUGO, &i2o_seq_fops_uinfo}, + {"sgl_limits", S_IFREG | S_IRUGO, &i2o_seq_fops_sgl_limits}, + {"sensors", S_IFREG | S_IRUGO, &i2o_seq_fops_sensors}, + {NULL, 0, NULL} +}; - spin_unlock(&i2o_proc_lock); - return len; -} +/* + * Storage unit specific entries (SCSI Periph, BS) with device names + */ +static i2o_proc_entry rbs_dev_entries[] = { + {"dev_name", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_name}, + {NULL, 0, NULL} +}; -/* LAN group 0200h - Required Ethernet Statistics (scalar) */ -/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */ -/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */ -int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +/** + * i2o_proc_create_entries - Creates proc dir entries + * @dir: proc dir entry under which the entries should be placed + * @i2o_pe: pointer to the entries which should be added + * @data: pointer to I2O controller or device + * + * Create proc dir entries for a I2O controller or I2O device. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_proc_create_entries(struct proc_dir_entry *dir, + i2o_proc_entry * i2o_pe, void *data) { - struct i2o_device *d = (struct i2o_device*)data; - int token; - - struct - { - u64 rx_align_errors; - u64 tx_one_collisions; - u64 tx_multiple_collisions; - u64 tx_deferred; - u64 tx_late_collisions; - u64 tx_max_collisions; - u64 tx_carrier_lost; - u64 tx_excessive_deferrals; - } stats; - - static u64 supp_fields; - struct - { - u64 rx_overrun; - u64 tx_underrun; - u64 tx_heartbeat_failure; - } hist_stats; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0200, -1, &stats, sizeof(stats)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf+len, "Rx alignment errors : " FMT_U64_HEX "\n", - U64_VAL(&stats.rx_align_errors)); - len += sprintf(buf+len, "Tx one collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_one_collisions)); - len += sprintf(buf+len, "Tx multicollisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_multiple_collisions)); - len += sprintf(buf+len, "Tx deferred : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_deferred)); - len += sprintf(buf+len, "Tx late collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_late_collisions)); - len += sprintf(buf+len, "Tx max collisions : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_max_collisions)); - len += sprintf(buf+len, "Tx carrier lost : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_carrier_lost)); - len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n", - U64_VAL(&stats.tx_excessive_deferrals)); - - /* Optional Ethernet statistics follows */ - /* Get 0x0280 to see which optional fields are supported */ - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0280, -1, &supp_fields, sizeof(supp_fields)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } + struct proc_dir_entry *tmp; - if (supp_fields) /* 0x0281 */ - { - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0281, -1, &stats, sizeof(stats)); + while (i2o_pe->name) { + tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir); + if (!tmp) + return -1; - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics"); - spin_unlock(&i2o_proc_lock); - return len; - } + tmp->data = data; + tmp->proc_fops = i2o_pe->fops; - len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n"); - - len += i2o_report_opt_field(buf+len, "Rx Overrun", - 0, supp_fields, &hist_stats.rx_overrun); - len += i2o_report_opt_field(buf+len, "Tx Underrun", - 1, supp_fields, &hist_stats.tx_underrun); - len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure", - 2, supp_fields, &hist_stats.tx_heartbeat_failure); + i2o_pe++; } - spin_unlock(&i2o_proc_lock); - return len; + return 0; } -/* LAN group 0300h - Required Token Ring Statistics (scalar) */ -/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */ -int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +/** + * i2o_proc_subdir_remove - Remove child entries from a proc entry + * @dir: proc dir entry from which the childs should be removed + * + * Iterate over each i2o proc entry under dir and remove it. If the child + * also has entries, remove them too. + */ +static void i2o_proc_subdir_remove(struct proc_dir_entry *dir) { - struct i2o_device *d = (struct i2o_device*)data; - static u64 work64[13]; - int token; - - static char *ring_status[] = - { - "", - "", - "", - "", - "", - "Ring Recovery", - "Single Station", - "Counter Overflow", - "Remove Received", - "", - "Auto-Removal Error 1", - "Lobe Wire Fault", - "Transmit Beacon", - "Soft Error", - "Hard Error", - "Signal Loss" - }; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0300, -1, &work64, sizeof(work64)); - - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics"); - spin_unlock(&i2o_proc_lock); - return len; + struct proc_dir_entry *pe, *tmp; + pe = dir->subdir; + while (pe) { + tmp = pe->next; + i2o_proc_subdir_remove(pe); + remove_proc_entry(pe->name, dir); + pe = tmp; } +}; - len += sprintf(buf, "LineErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[0])); - len += sprintf(buf+len, "LostFrames : " FMT_U64_HEX "\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "ACError : " FMT_U64_HEX "\n", - U64_VAL(&work64[2])); - len += sprintf(buf+len, "TxAbortDelimiter : " FMT_U64_HEX "\n", - U64_VAL(&work64[3])); - len += sprintf(buf+len, "BursErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[4])); - len += sprintf(buf+len, "FrameCopiedErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[5])); - len += sprintf(buf+len, "FrequencyErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[6])); - len += sprintf(buf+len, "InternalErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[7])); - len += sprintf(buf+len, "LastRingStatus : %s\n", ring_status[work64[8]]); - len += sprintf(buf+len, "TokenError : " FMT_U64_HEX "\n", - U64_VAL(&work64[9])); - len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n", - U64_VAL(&work64[10])); - len += sprintf(buf+len, "LastRingID : " FMT_U64_HEX "\n", - U64_VAL(&work64[11])); - len += sprintf(buf+len, "LastBeaconType : " FMT_U64_HEX "\n", - U64_VAL(&work64[12])); - - spin_unlock(&i2o_proc_lock); - return len; -} - -/* LAN group 0400h - Required FDDI Statistics (scalar) */ -/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */ -int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset, - int len, int *eof, void *data) +/** + * i2o_proc_device_add - Add an I2O device to the proc dir + * @dir: proc dir entry to which the device should be added + * @dev: I2O device which should be added + * + * Add an I2O device to the proc dir entry dir and create the entries for + * the device depending on the class of the I2O device. + */ +static void i2o_proc_device_add(struct proc_dir_entry *dir, + struct i2o_device *dev) { - struct i2o_device *d = (struct i2o_device*)data; - static u64 work64[11]; - int token; - - static char *conf_state[] = - { - "Isolated", - "Local a", - "Local b", - "Local ab", - "Local s", - "Wrap a", - "Wrap b", - "Wrap ab", - "Wrap s", - "C-Wrap a", - "C-Wrap b", - "C-Wrap s", - "Through", - }; - - static char *ring_state[] = - { - "Isolated", - "Non-op", - "Rind-op", - "Detect", - "Non-op-Dup", - "Ring-op-Dup", - "Directed", - "Trace" - }; - - static char *link_state[] = - { - "Off", - "Break", - "Trace", - "Connect", - "Next", - "Signal", - "Join", - "Verify", - "Active", - "Maintenance" - }; + char buff[10]; + struct proc_dir_entry *devdir; + i2o_proc_entry *i2o_pe = NULL; - spin_lock(&i2o_proc_lock); - len = 0; + sprintf(buff, "%03x", dev->lct_data.tid); - token = i2o_query_scalar(d->controller, d->lct_data.tid, - 0x0400, -1, &work64, sizeof(work64)); + pr_debug("Adding device /proc/i2o/iop%d/%s\n", dev->iop->unit, buff); - if (token < 0) { - len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics"); - spin_unlock(&i2o_proc_lock); - return len; + devdir = proc_mkdir(buff, dir); + if (!devdir) { + printk(KERN_WARNING "i2o: Could not allocate procdir!\n"); + return; } - len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]); - len += sprintf(buf+len, "UpstreamNode : " FMT_U64_HEX "\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "DownStreamNode : " FMT_U64_HEX "\n", - U64_VAL(&work64[2])); - len += sprintf(buf+len, "FrameErrors : " FMT_U64_HEX "\n", - U64_VAL(&work64[3])); - len += sprintf(buf+len, "FramesLost : " FMT_U64_HEX "\n", - U64_VAL(&work64[4])); - len += sprintf(buf+len, "RingMgmtState : %s\n", ring_state[work64[5]]); - len += sprintf(buf+len, "LCTFailures : " FMT_U64_HEX "\n", - U64_VAL(&work64[6])); - len += sprintf(buf+len, "LEMRejects : " FMT_U64_HEX "\n", - U64_VAL(&work64[7])); - len += sprintf(buf+len, "LEMCount : " FMT_U64_HEX "\n", - U64_VAL(&work64[8])); - len += sprintf(buf+len, "LConnectionState : %s\n", - link_state[work64[9]]); - - spin_unlock(&i2o_proc_lock); - return len; -} + devdir->data = dev; -static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry, - struct proc_dir_entry *parent) -{ - struct proc_dir_entry *ent; - - while(pentry->name != NULL) - { - ent = create_proc_entry(pentry->name, pentry->mode, parent); - if(!ent) return -1; + i2o_proc_create_entries(devdir, generic_dev_entries, dev); - ent->data = data; - ent->read_proc = pentry->read_proc; - ent->write_proc = pentry->write_proc; - if(pentry->fops_proc) - ent->proc_fops = pentry->fops_proc; - - ent->nlink = 1; - - pentry++; - } - - return 0; -} - -static void i2o_proc_remove_entries(i2o_proc_entry *pentry, - struct proc_dir_entry *parent) -{ - while(pentry->name != NULL) - { - remove_proc_entry(pentry->name, parent); - pentry++; + /* Inform core that we want updates about this device's status */ + switch (dev->lct_data.class_id) { + case I2O_CLASS_SCSI_PERIPHERAL: + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + i2o_pe = rbs_dev_entries; + break; + default: + break; } + if (i2o_pe) + i2o_proc_create_entries(devdir, i2o_pe, dev); } -static int i2o_proc_add_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *root ) +/** + * i2o_proc_iop_add - Add an I2O controller to the i2o proc tree + * @dir: parent proc dir entry + * @c: I2O controller which should be added + * + * Add the entries to the parent proc dir entry. Also each device is added + * to the controllers proc dir entry. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_proc_iop_add(struct proc_dir_entry *dir, + struct i2o_controller *c) { - struct proc_dir_entry *dir, *dir1; + struct proc_dir_entry *iopdir; struct i2o_device *dev; char buff[10]; - sprintf(buff, "iop%d", pctrl->unit); + snprintf(buff, 10, "iop%d", c->unit); - dir = proc_mkdir(buff, root); - if(!dir) - return -1; - - pctrl->proc_entry = dir; + pr_debug("Adding IOP /proc/i2o/%s\n", buff); - i2o_proc_create_entries(pctrl, generic_iop_entries, dir); - - for(dev = pctrl->devices; dev; dev = dev->next) - { - sprintf(buff, "%0#5x", dev->lct_data.tid); + iopdir = proc_mkdir(buff, dir); + if (!iopdir) + return -1; - dir1 = proc_mkdir(buff, dir); - dev->proc_entry = dir1; + iopdir->data = c; - if(!dir1) - printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n"); + i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c); - i2o_proc_add_device(dev, dir1); - } + list_for_each_entry(dev, &c->devices, list) + i2o_proc_device_add(iopdir, dev); return 0; } -void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d) -{ - char buff[10]; - -#ifdef DRIVERDEBUG - printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit); -#endif - sprintf(buff, "%0#5x", d->lct_data.tid); - - d->proc_entry = proc_mkdir(buff, c->proc_entry); - - if(!d->proc_entry) - { - printk(KERN_WARNING "i2o: Could not allocate procdir!\n"); - return; - } - - i2o_proc_add_device(d, d->proc_entry); -} - -void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir) -{ - i2o_proc_create_entries(dev, generic_dev_entries, dir); - - /* Inform core that we want updates about this device's status */ - i2o_device_notify_on(dev, &i2o_proc_handler); - switch(dev->lct_data.class_id) - { - case I2O_CLASS_SCSI_PERIPHERAL: - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_create_entries(dev, rbs_dev_entries, dir); - break; - case I2O_CLASS_LAN: - i2o_proc_create_entries(dev, lan_entries, dir); - switch(dev->lct_data.sub_class) - { - case I2O_LAN_ETHERNET: - i2o_proc_create_entries(dev, lan_eth_entries, dir); - break; - case I2O_LAN_FDDI: - i2o_proc_create_entries(dev, lan_fddi_entries, dir); - break; - case I2O_LAN_TR: - i2o_proc_create_entries(dev, lan_tr_entries, dir); - break; - default: - break; - } - break; - default: - break; - } -} - -static void i2o_proc_remove_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *parent) -{ - char buff[10]; - struct i2o_device *dev; - - /* Remove unused device entries */ - for(dev=pctrl->devices; dev; dev=dev->next) - i2o_proc_remove_device(dev); - - if(!atomic_read(&pctrl->proc_entry->count)) - { - sprintf(buff, "iop%d", pctrl->unit); - - i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); - remove_proc_entry(buff, parent); - pctrl->proc_entry = NULL; - } -} - -void i2o_proc_remove_device(struct i2o_device *dev) +/** + * i2o_proc_iop_remove - Removes an I2O controller from the i2o proc tree + * @dir: parent proc dir entry + * @c: I2O controller which should be removed + * + * Iterate over each i2o proc entry and search controller c. If it is found + * remove it from the tree. + */ +static void i2o_proc_iop_remove(struct proc_dir_entry *dir, + struct i2o_controller *c) { - struct proc_dir_entry *de=dev->proc_entry; - char dev_id[10]; - - sprintf(dev_id, "%0#5x", dev->lct_data.tid); - - i2o_device_notify_off(dev, &i2o_proc_handler); - /* Would it be safe to remove _files_ even if they are in use? */ - if((de) && (!atomic_read(&de->count))) - { - i2o_proc_remove_entries(generic_dev_entries, de); - switch(dev->lct_data.class_id) - { - case I2O_CLASS_SCSI_PERIPHERAL: - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_remove_entries(rbs_dev_entries, de); - break; - case I2O_CLASS_LAN: - { - i2o_proc_remove_entries(lan_entries, de); - switch(dev->lct_data.sub_class) - { - case I2O_LAN_ETHERNET: - i2o_proc_remove_entries(lan_eth_entries, de); - break; - case I2O_LAN_FDDI: - i2o_proc_remove_entries(lan_fddi_entries, de); - break; - case I2O_LAN_TR: - i2o_proc_remove_entries(lan_tr_entries, de); - break; - } - } + struct proc_dir_entry *pe, *tmp; + + pe = dir->subdir; + while (pe) { + tmp = pe->next; + if (pe->data == c) { + i2o_proc_subdir_remove(pe); + remove_proc_entry(pe->name, dir); } - remove_proc_entry(dev_id, dev->controller->proc_entry); + pr_debug("Removing IOP /proc/i2o/iop%d\n", c->unit); + pe = tmp; } } - -void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d) -{ -#ifdef DRIVERDEBUG - printk(KERN_INFO "Deleting device %d from iop%d\n", - d->lct_data.tid, c->unit); -#endif - - i2o_proc_remove_device(d); -} -static int create_i2o_procfs(void) +/** + * i2o_proc_fs_create - Create the i2o proc fs. + * + * Iterate over each I2O controller and create the entries for it. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_proc_fs_create(void) { - struct i2o_controller *pctrl = NULL; - int i; + struct i2o_controller *c; i2o_proc_dir_root = proc_mkdir("i2o", NULL); - if(!i2o_proc_dir_root) + if (!i2o_proc_dir_root) return -1; + i2o_proc_dir_root->owner = THIS_MODULE; - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - pctrl = i2o_find_controller(i); - if(pctrl) - { - i2o_proc_add_controller(pctrl, i2o_proc_dir_root); - i2o_unlock_controller(pctrl); - } - }; + list_for_each_entry(c, &i2o_controllers, list) + i2o_proc_iop_add(i2o_proc_dir_root, c); return 0; -} +}; -static int __exit destroy_i2o_procfs(void) +/** + * i2o_proc_fs_destroy - Cleanup the all i2o proc entries + * + * Iterate over each I2O controller and remove the entries for it. + * + * Returns 0 on success or negative error code on failure. + */ +static int __exit i2o_proc_fs_destroy(void) { - struct i2o_controller *pctrl = NULL; - int i; + struct i2o_controller *c; - for(i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - pctrl = i2o_find_controller(i); - if(pctrl) - { - i2o_proc_remove_controller(pctrl, i2o_proc_dir_root); - i2o_unlock_controller(pctrl); - } - } + list_for_each_entry(c, &i2o_controllers, list) + i2o_proc_iop_remove(i2o_proc_dir_root, c); - if(!atomic_read(&i2o_proc_dir_root->count)) - remove_proc_entry("i2o", NULL); - else - return -1; + remove_proc_entry("i2o", NULL); return 0; -} +}; -int __init i2o_proc_init(void) +/** + * i2o_proc_init - Init function for procfs + * + * Registers Proc OSM and creates procfs entries. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_proc_init(void) { - if (i2o_install_handler(&i2o_proc_handler) < 0) - { - printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); - return 0; - } + int rc; + + rc = i2o_driver_register(&i2o_proc_driver); + if (rc) + return rc; - if(create_i2o_procfs()) - return -EBUSY; + rc = i2o_proc_fs_create(); + if (rc) { + i2o_driver_unregister(&i2o_proc_driver); + return rc; + } return 0; -} +}; + +/** + * i2o_proc_exit - Exit function for procfs + * + * Unregisters Proc OSM and removes procfs entries. + */ +static void __exit i2o_proc_exit(void) +{ + i2o_driver_unregister(&i2o_proc_driver); + i2o_proc_fs_destroy(); +}; MODULE_AUTHOR("Deepak Saxena"); MODULE_DESCRIPTION("I2O procfs Handler"); MODULE_LICENSE("GPL"); -static void __exit i2o_proc_exit(void) -{ - destroy_i2o_procfs(); - i2o_remove_handler(&i2o_proc_handler); -} - -#ifdef MODULE module_init(i2o_proc_init); -#endif module_exit(i2o_proc_exit); - diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index ba121fc85..9be68f380 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -19,13 +19,13 @@ * * o Each (bus,lun) is a logical device in I2O. We keep a map * table. We spoof failed selection for unmapped units - * o Request sense buffers can come back for free. + * o Request sense buffers can come back for free. * o Scatter gather is a bit dynamic. We have to investigate at * setup time. * o Some of our resources are dynamically shared. The i2o core * needs a message reservation protocol to avoid swap v net * deadlocking. We need to back off queue requests. - * + * * In general the firmware wants to help. Where its help isn't performance * useful we just ignore the aid. Its not worth the code in truth. * @@ -40,7 +40,6 @@ * Fix the resource management problems. */ - #include #include #include @@ -53,79 +52,229 @@ #include #include #include +#include +#include + #include #include #include #include -#include -#include #include -#include -#include #include - +#include +#include #define VERSION_STRING "Version 0.1.2" -//#define DRIVERDEBUG +static struct i2o_driver i2o_scsi_driver; -#ifdef DRIVERDEBUG -#define dprintk(s, args...) printk(s, ## args) -#else -#define dprintk(s, args...) -#endif +static int i2o_scsi_max_id = 16; +static int i2o_scsi_max_lun = 8; + +struct i2o_scsi_host { + struct Scsi_Host *scsi_host; /* pointer to the SCSI host */ + struct i2o_controller *iop; /* pointer to the I2O controller */ + struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */ +}; + +static struct scsi_host_template i2o_scsi_host_template; #define I2O_SCSI_CAN_QUEUE 4 -#define MAXHOSTS 32 -struct i2o_scsi_host -{ - struct i2o_controller *controller; - s16 task[16][8]; /* Allow 16 devices for now */ - unsigned long tagclock[16][8]; /* Tag clock for queueing */ - s16 bus_task; /* The adapter TID */ +/* SCSI OSM class handling definition */ +static struct i2o_class_id i2o_scsi_class_id[] = { + {I2O_CLASS_SCSI_PERIPHERAL}, + {I2O_CLASS_END} }; -static int scsi_context; -static int lun_done; -static int i2o_scsi_hosts; +static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c) +{ + struct i2o_scsi_host *i2o_shost; + struct i2o_device *i2o_dev; + struct Scsi_Host *scsi_host; + int max_channel = 0; + u8 type; + int i; + size_t size; + i2o_status_block *sb; -static u32 *retry[32]; -static struct i2o_controller *retry_ctrl[32]; -static struct timer_list retry_timer; -static spinlock_t retry_lock = SPIN_LOCK_UNLOCKED; -static int retry_ct = 0; + list_for_each_entry(i2o_dev, &c->devices, list) + if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) { + if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* SCSI bus */ + max_channel++; + } -static atomic_t queue_depth; + if (!max_channel) { + printk(KERN_WARNING "scsi-osm: no channels found on %s\n", + c->name); + return ERR_PTR(-EFAULT); + } -/* - * SG Chain buffer support... + size = max_channel * sizeof(struct i2o_device *) + + sizeof(struct i2o_scsi_host); + + scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size); + if (!scsi_host) { + printk(KERN_WARNING "scsi-osm: Could not allocate SCSI host\n"); + return ERR_PTR(-ENOMEM); + } + + scsi_host->max_channel = max_channel - 1; + scsi_host->max_id = i2o_scsi_max_id; + scsi_host->max_lun = i2o_scsi_max_lun; + scsi_host->this_id = c->unit; + + sb = c->status_block.virt; + + scsi_host->sg_tablesize = (sb->inbound_frame_size - + sizeof(struct i2o_message) / 4 - 6) / 2; + + i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata; + i2o_shost->scsi_host = scsi_host; + i2o_shost->iop = c; + + i = 0; + list_for_each_entry(i2o_dev, &c->devices, list) + if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) { + if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* only SCSI bus */ + i2o_shost->channel[i++] = i2o_dev; + + if (i >= max_channel) + break; + } + + return i2o_shost; +}; + +/** + * i2o_scsi_get_host - Get an I2O SCSI host + * @c: I2O controller to for which to get the SCSI host + * + * If the I2O controller already exists as SCSI host, the SCSI host + * is returned, otherwise the I2O controller is added to the SCSI + * core. + * + * Returns pointer to the I2O SCSI host on success or NULL on failure. + */ +static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c) +{ + return c->driver_data[i2o_scsi_driver.context]; +}; + +/** + * i2o_scsi_remove - Remove I2O device from SCSI core + * @dev: device which should be removed + * + * Removes the I2O device from the SCSI core again. + * + * Returns 0 on success. */ +static int i2o_scsi_remove(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_controller *c = i2o_dev->iop; + struct i2o_scsi_host *i2o_shost; + struct scsi_device *scsi_dev; + + i2o_shost = i2o_scsi_get_host(c); + + shost_for_each_device(scsi_dev, i2o_shost->scsi_host) + if (scsi_dev->hostdata == i2o_dev) { + scsi_remove_device(scsi_dev); + scsi_device_put(scsi_dev); + break; + } -#define SG_MAX_FRAGS 64 + return 0; +}; -/* - * FIXME: we should allocate one of these per bus we find as we - * locate them not in a lump at boot. +/** + * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it + * @dev: device to verify if it is a I2O SCSI device + * + * Retrieve channel, id and lun for I2O device. If everthing goes well + * register the I2O device as SCSI device on the I2O SCSI controller. + * + * Returns 0 on success or negative error code on failure. */ - -typedef struct _chain_buf +static int i2o_scsi_probe(struct device *dev) { - u32 sg_flags_cnt[SG_MAX_FRAGS]; - u32 sg_buf[SG_MAX_FRAGS]; -} chain_buf; + struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_controller *c = i2o_dev->iop; + struct i2o_scsi_host *i2o_shost; + struct Scsi_Host *scsi_host; + struct i2o_device *parent; + struct scsi_device *scsi_dev; + u32 id; + u64 lun; + int channel = -1; + int i; + + i2o_shost = i2o_scsi_get_host(c); + if (!i2o_shost) + return -EFAULT; + + scsi_host = i2o_shost->scsi_host; -#define SG_CHAIN_BUF_SZ sizeof(chain_buf) + if (i2o_parm_field_get(i2o_dev, 0, 3, &id, 4) < 0) + return -EFAULT; + + if (id >= scsi_host->max_id) { + printk(KERN_WARNING "scsi-osm: SCSI device id (%d) >= max_id " + "of I2O host (%d)", id, scsi_host->max_id); + return -EFAULT; + } + + if (i2o_parm_field_get(i2o_dev, 0, 4, &lun, 8) < 0) + return -EFAULT; + if (lun >= scsi_host->max_lun) { + printk(KERN_WARNING "scsi-osm: SCSI device id (%d) >= max_lun " + "of I2O host (%d)", (unsigned int)lun, + scsi_host->max_lun); + return -EFAULT; + } + + parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid); + if (!parent) { + printk(KERN_WARNING "scsi-osm: can not find parent of device " + "%03x\n", i2o_dev->lct_data.tid); + return -EFAULT; + } -#define SG_MAX_BUFS (i2o_num_controllers * I2O_SCSI_CAN_QUEUE) -#define SG_CHAIN_POOL_SZ (SG_MAX_BUFS * SG_CHAIN_BUF_SZ) + for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++) + if (i2o_shost->channel[i] == parent) + channel = i; + + if (channel == -1) { + printk(KERN_WARNING "scsi-osm: can not find channel of device " + "%03x\n", i2o_dev->lct_data.tid); + return -EFAULT; + } + + scsi_dev = + __scsi_add_device(i2o_shost->scsi_host, channel, id, lun, i2o_dev); + + if (!scsi_dev) { + printk(KERN_WARNING "scsi-osm: can not add SCSI device " + "%03x\n", i2o_dev->lct_data.tid); + return -EFAULT; + } + + pr_debug("Added new SCSI device %03x (cannel: %d, id: %d, lun: %d)\n", + i2o_dev->lct_data.tid, channel, id, (unsigned int)lun); + + return 0; +}; -static int max_sg_len = 0; -static chain_buf *sg_chain_pool = NULL; -static int sg_chain_tag = 0; -static int sg_max_frags = SG_MAX_FRAGS; +static const char *i2o_scsi_info(struct Scsi_Host *SChost) +{ + struct i2o_scsi_host *hostdata; + hostdata = (struct i2o_scsi_host *)SChost->hostdata; + return hostdata->iop->name; +} +#if 0 /** * i2o_retry_run - retry on timeout * @f: unused @@ -136,16 +285,16 @@ static int sg_max_frags = SG_MAX_FRAGS; * and its default handler should be this in the core, and this * call a 2nd "I give up" handler in the OSM ? */ - + static void i2o_retry_run(unsigned long f) { int i; unsigned long flags; - + spin_lock_irqsave(&retry_lock, flags); - for(i=0;i 0 + * on success and if the reply should be flushed. Returns negative error + * code on failure and if the reply should be flushed. */ - -static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +static int i2o_scsi_reply(struct i2o_controller *c, u32 m, + struct i2o_message *msg) { - struct scsi_cmnd *current_command; - spinlock_t *lock; - u32 *m = (u32 *)msg; - u8 as,ds,st; - unsigned long flags; + struct scsi_cmnd *cmd; + struct device *dev; + u8 as, ds, st; + + cmd = i2o_cntxt_list_get(c, readl(&msg->u.s.tcntxt)); + + if (msg->u.head[0] & (1 << 13)) { + struct i2o_message *pmsg; /* preserved message */ + u32 pm; + + pm = readl(&msg->body[3]); + + pmsg = c->in_queue.virt + pm; - if(m[0] & (1<<13)) - { printk("IOP fail.\n"); printk("From %d To %d Cmd %d.\n", - (m[1]>>12)&0xFFF, - m[1]&0xFFF, - m[1]>>24); - printk("Failure Code %d.\n", m[4]>>24); - if(m[4]&(1<<16)) + (msg->u.head[1] >> 12) & 0xFFF, + msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24); + printk("Failure Code %d.\n", msg->body[0] >> 24); + if (msg->body[0] & (1 << 16)) printk("Format error.\n"); - if(m[4]&(1<<17)) + if (msg->body[0] & (1 << 17)) printk("Path error.\n"); - if(m[4]&(1<<18)) + if (msg->body[0] & (1 << 18)) printk("Path State.\n"); - if(m[4]&(1<<18)) + if (msg->body[0] & (1 << 18)) printk("Congestion.\n"); - - m=(u32 *)bus_to_virt(m[7]); - printk("Failing message is %p.\n", m); - - /* This isnt a fast path .. */ - spin_lock_irqsave(&retry_lock, flags); - - if((m[4]&(1<<18)) && retry_ct < 32) - { - retry_ctrl[retry_ct]=c; - retry[retry_ct]=m; - if(!retry_ct++) - { - retry_timer.expires=jiffies+1; - add_timer(&retry_timer); - } - spin_unlock_irqrestore(&retry_lock, flags); - } - else - { - spin_unlock_irqrestore(&retry_lock, flags); - /* Create a scsi error for this */ - current_command = (struct scsi_cmnd *)i2o_context_list_get(m[3], c); - if(!current_command) - return; - - lock = current_command->device->host->host_lock; - printk("Aborted %ld\n", current_command->serial_number); - - spin_lock_irqsave(lock, flags); - current_command->result = DID_ERROR << 16; - current_command->scsi_done(current_command); - spin_unlock_irqrestore(lock, flags); - - /* Now flush the message by making it a NOP */ - m[0]&=0x00FFFFFF; - m[0]|=(I2O_CMD_UTIL_NOP)<<24; - i2o_post_message(c,virt_to_bus(m)); - } - return; + + printk("Failing message is %p.\n", pmsg); + + cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt)); + if (!cmd) + return 1; + + printk("Aborted %ld\n", cmd->serial_number); + cmd->result = DID_ERROR << 16; + cmd->scsi_done(cmd); + + /* Now flush the message by making it a NOP */ + i2o_msg_nop(c, pm); + + return 1; } - - prefetchw(&queue_depth); - - + /* - * Low byte is device status, next is adapter status, - * (then one byte reserved), then request status. + * Low byte is device status, next is adapter status, + * (then one byte reserved), then request status. */ - ds=(u8)le32_to_cpu(m[4]); - as=(u8)le32_to_cpu(m[4]>>8); - st=(u8)le32_to_cpu(m[4]>>24); - - dprintk(KERN_INFO "i2o got a scsi reply %08X: ", m[0]); - dprintk(KERN_INFO "m[2]=%08X: ", m[2]); - dprintk(KERN_INFO "m[4]=%08X\n", m[4]); - - if(m[2]&0x80000000) - { - if(m[2]&0x40000000) - { - dprintk(KERN_INFO "Event.\n"); - lun_done=1; - return; - } - printk(KERN_INFO "i2o_scsi: bus reset completed.\n"); - return; - } + ds = (u8) readl(&msg->body[0]); + as = (u8) (readl(&msg->body[0]) >> 8); + st = (u8) (readl(&msg->body[0]) >> 24); - current_command = (struct scsi_cmnd *)i2o_context_list_get(m[3], c); - /* - * Is this a control request coming back - eg an abort ? + * Is this a control request coming back - eg an abort ? */ - - atomic_dec(&queue_depth); - - if(current_command==NULL) - { - if(st) - dprintk(KERN_WARNING "SCSI abort: %08X", m[4]); - dprintk(KERN_INFO "SCSI abort completed.\n"); - return; - } - - dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number); - - if(st == 0x06) - { - if(le32_to_cpu(m[5]) < current_command->underflow) - { - int i; - printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", - le32_to_cpu(m[5]), current_command->underflow); - printk("Cmd: "); - for(i=0;i<15;i++) - printk("%02X ", current_command->cmnd[i]); - printk(".\n"); - } - else st=0; - } - - if(st) - { - /* An error has occurred */ - dprintk(KERN_WARNING "SCSI error %08X", m[4]); - - if (as == 0x0E) - /* SCSI Reset */ - current_command->result = DID_RESET << 16; - else if (as == 0x0F) - current_command->result = DID_PARITY << 16; - else - current_command->result = DID_ERROR << 16; - } - else - /* - * It worked maybe ? - */ - current_command->result = DID_OK << 16 | ds; - - if (current_command->use_sg) { - pci_unmap_sg(c->pdev, - (struct scatterlist *)current_command->buffer, - current_command->use_sg, - current_command->sc_data_direction); - } else if (current_command->request_bufflen) { - pci_unmap_single(c->pdev, - (dma_addr_t)((long)current_command->SCp.ptr), - current_command->request_bufflen, - current_command->sc_data_direction); + if (!cmd) { + if (st) + printk(KERN_WARNING "SCSI abort: %08X", + readl(&msg->body[0])); + printk(KERN_INFO "SCSI abort completed.\n"); + return -EFAULT; } - lock = current_command->device->host->host_lock; - spin_lock_irqsave(lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(lock, flags); - return; -} + pr_debug("Completed %ld\n", cmd->serial_number); -struct i2o_handler i2o_scsi_handler = { - .reply = i2o_scsi_reply, - .name = "I2O SCSI OSM", - .class = I2O_CLASS_SCSI_PERIPHERAL, -}; + if (st) { + u32 count, error; + /* An error has occurred */ -/** - * i2o_find_lun - report the lun of an i2o device - * @c: i2o controller owning the device - * @d: i2o disk device - * @target: filled in with target id - * @lun: filled in with target lun - * - * Query an I2O device to find out its SCSI lun and target numbering. We - * don't currently handle some of the fancy SCSI-3 stuff although our - * querying is sufficient to do so. - */ - -static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) -{ - u8 reply[8]; - - if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0) - return -1; - - *target=reply[0]; - - if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0) - return -1; - - *lun=reply[1]; - - dprintk(KERN_INFO "SCSI (%d,%d)\n", *target, *lun); - return 0; -} + switch (st) { + case 0x06: + count = readl(&msg->body[1]); + if (count < cmd->underflow) { + int i; + printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X" + "\n", count, cmd->underflow); + printk("Cmd: "); + for (i = 0; i < 15; i++) + printk("%02X ", cmd->cmnd[i]); + printk(".\n"); + cmd->result = (DID_ERROR << 16); + } + break; -/** - * i2o_scsi_init - initialize an i2o device for scsi - * @c: i2o controller owning the device - * @d: scsi controller - * @shpnt: scsi device we wish it to become - * - * Enumerate the scsi peripheral/fibre channel peripheral class - * devices that are children of the controller. From that we build - * a translation map for the command queue code. Since I2O works on - * its own tid's we effectively have to think backwards to get what - * the midlayer wants - */ - -static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) -{ - struct i2o_device *unit; - struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; - int lun; - int target; - - h->controller=c; - h->bus_task=d->lct_data.tid; - - for(target=0;target<16;target++) - for(lun=0;lun<8;lun++) - h->task[target][lun] = -1; - - for(unit=c->devices;unit!=NULL;unit=unit->next) - { - dprintk(KERN_INFO "Class %03X, parent %d, want %d.\n", - unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid); - - /* Only look at scsi and fc devices */ - if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) - && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) - ) - continue; - - /* On our bus ? */ - dprintk(KERN_INFO "Found a disk (%d).\n", unit->lct_data.tid); - if ((unit->lct_data.parent_tid == d->lct_data.tid) - || (unit->lct_data.parent_tid == d->lct_data.parent_tid) - ) - { - u16 limit; - dprintk(KERN_INFO "Its ours.\n"); - if(i2o_find_lun(c, unit, &target, &lun)==-1) - { - printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); - continue; + default: + error = readl(&msg->body[0]); + + printk(KERN_ERR "scsi-osm: SCSI error %08x\n", error); + + if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) { + int i; + u32 len = sizeof(cmd->sense_buffer); + len = (len > 40) ? 40 : len; + // Copy over the sense data + memcpy(cmd->sense_buffer, (void *)&msg->body[3], + len); + for (i = 0; i <= len; i++) + printk(KERN_INFO "%02x\n", + cmd->sense_buffer[i]); + if (cmd->sense_buffer[0] == 0x70 + && cmd->sense_buffer[2] == DATA_PROTECT) { + /* This is to handle an array failed */ + cmd->result = (DID_TIME_OUT << 16); + printk(KERN_WARNING "%s: SCSI Data " + "Protect-Device (%d,%d,%d) " + "hba_status=0x%x, dev_status=" + "0x%x, cmd=0x%x\n", c->name, + (u32) cmd->device->channel, + (u32) cmd->device->id, + (u32) cmd->device->lun, + (error >> 8) & 0xff, + error & 0xff, cmd->cmnd[0]); + } else + cmd->result = (DID_ERROR << 16); + + break; } - dprintk(KERN_INFO "Found disk %d %d.\n", target, lun); - h->task[target][lun]=unit->lct_data.tid; - h->tagclock[target][lun]=jiffies; - - /* Get the max fragments/request */ - i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2); - - /* sanity */ - if ( limit == 0 ) - { - printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n"); - limit = 1; + + switch (as) { + case 0x0E: + /* SCSI Reset */ + cmd->result = DID_RESET << 16; + break; + + case 0x0F: + cmd->result = DID_PARITY << 16; + break; + + default: + cmd->result = DID_ERROR << 16; + break; } - - shpnt->sg_tablesize = limit; - dprintk(KERN_INFO "i2o_scsi: set scatter-gather to %d.\n", - shpnt->sg_tablesize); + break; } - } -} + + cmd->scsi_done(cmd); + return 1; + } + + cmd->result = DID_OK << 16 | ds; + + cmd->scsi_done(cmd); + + dev = &c->pdev->dev; + if (cmd->use_sg) + dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer, + cmd->use_sg, cmd->sc_data_direction); + else if (cmd->request_bufflen) + dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr), + cmd->request_bufflen, cmd->sc_data_direction); + + return 1; +}; /** - * i2o_scsi_detect - probe for I2O scsi devices - * @tpnt: scsi layer template + * i2o_scsi_notify_controller_add - Retrieve notifications of added + * controllers + * @c: the controller which was added * - * I2O is a little odd here. The I2O core already knows what the - * devices are. It also knows them by disk and tape as well as - * by controller. We register each I2O scsi class object as a - * scsi controller and then let the enumeration fake up the rest + * If a I2O controller is added, we catch the notification to add a + * corresponding Scsi_Host. */ - -static int i2o_scsi_detect(struct scsi_host_template * tpnt) +void i2o_scsi_notify_controller_add(struct i2o_controller *c) { - struct Scsi_Host *shpnt = NULL; - int i; - int count; + struct i2o_scsi_host *i2o_shost; + int rc; - printk(KERN_INFO "i2o_scsi.c: %s\n", VERSION_STRING); - - if(i2o_install_handler(&i2o_scsi_handler)<0) - { - printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); - return 0; - } - scsi_context = i2o_scsi_handler.context; - - if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) - { - printk(KERN_INFO "i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); - printk(KERN_INFO "i2o_scsi: SG chaining DISABLED!\n"); - sg_max_frags = 11; - } - else - { - printk(KERN_INFO " chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); - printk(KERN_INFO " (%d byte buffers X %d can_queue X %d i2o controllers)\n", - SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); - sg_max_frags = SG_MAX_FRAGS; // 64 - } - - init_timer(&retry_timer); - retry_timer.data = 0UL; - retry_timer.function = i2o_retry_run; - -// printk("SCSI OSM at %d.\n", scsi_context); - - for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) - { - struct i2o_controller *c=i2o_find_controller(i); - struct i2o_device *d; - /* - * This controller doesn't exist. - */ - - if(c==NULL) - continue; - - /* - * Fixme - we need some altered device locking. This - * is racing with device addition in theory. Easy to fix. - */ - - for(d=c->devices;d!=NULL;d=d->next) - { - /* - * bus_adapter, SCSI (obsolete), or FibreChannel busses only - */ - if( (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter -// && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT - ) - continue; - - shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); - if(shpnt==NULL) - continue; - shpnt->unique_id = (u32)d; - shpnt->io_port = 0; - shpnt->n_io_port = 0; - shpnt->irq = 0; - shpnt->this_id = /* Good question */15; - i2o_scsi_init(c, d, shpnt); - count++; - } - } - i2o_scsi_hosts = count; - - if(count==0) - { - if(sg_chain_pool!=NULL) - { - kfree(sg_chain_pool); - sg_chain_pool = NULL; - } - flush_pending(); - del_timer(&retry_timer); - i2o_remove_handler(&i2o_scsi_handler); + i2o_shost = i2o_scsi_host_alloc(c); + if (IS_ERR(i2o_shost)) { + printk(KERN_ERR "scsi-osm: Could not initialize" + " SCSI host\n"); + return; } - - return count; -} -static int i2o_scsi_release(struct Scsi_Host *host) -{ - if(--i2o_scsi_hosts==0) - { - if(sg_chain_pool!=NULL) - { - kfree(sg_chain_pool); - sg_chain_pool = NULL; - } - flush_pending(); - del_timer(&retry_timer); - i2o_remove_handler(&i2o_scsi_handler); + rc = scsi_add_host(i2o_shost->scsi_host, &c->device); + if (rc) { + printk(KERN_ERR "scsi-osm: Could not add SCSI " + "host\n"); + scsi_host_put(i2o_shost->scsi_host); + return; } - scsi_unregister(host); - - return 0; -} + c->driver_data[i2o_scsi_driver.context] = i2o_shost; + pr_debug("new I2O SCSI host added\n"); +}; -static const char *i2o_scsi_info(struct Scsi_Host *SChost) +/** + * i2o_scsi_notify_controller_remove - Retrieve notifications of removed + * controllers + * @c: the controller which was removed + * + * If a I2O controller is removed, we catch the notification to remove the + * corresponding Scsi_Host. + */ +void i2o_scsi_notify_controller_remove(struct i2o_controller *c) { - struct i2o_scsi_host *hostdata; - hostdata = (struct i2o_scsi_host *)SChost->hostdata; - return(&hostdata->controller->name[0]); -} + struct i2o_scsi_host *i2o_shost; + i2o_shost = i2o_scsi_get_host(c); + if (!i2o_shost) + return; + + c->driver_data[i2o_scsi_driver.context] = NULL; + + scsi_remove_host(i2o_shost->scsi_host); + scsi_host_put(i2o_shost->scsi_host); + pr_debug("I2O SCSI host removed\n"); +}; + +/* SCSI OSM driver struct */ +static struct i2o_driver i2o_scsi_driver = { + .name = "scsi-osm", + .reply = i2o_scsi_reply, + .classes = i2o_scsi_class_id, + .notify_controller_add = i2o_scsi_notify_controller_add, + .notify_controller_remove = i2o_scsi_notify_controller_remove, + .driver = { + .probe = i2o_scsi_probe, + .remove = i2o_scsi_remove, + }, +}; /** - * i2o_scsi_queuecommand - queue a SCSI command + * i2o_scsi_queuecommand - queue a SCSI command * @SCpnt: scsi command pointer * @done: callback for completion * - * Issue a scsi comamnd asynchronously. Return 0 on success or 1 if - * we hit an error (normally message queue congestion). The only + * Issue a scsi command asynchronously. Return 0 on success or 1 if + * we hit an error (normally message queue congestion). The only * minor complication here is that I2O deals with the device addressing * so we have to map the bus/dev/lun back to an I2O handle as well - * as faking absent devices ourself. + * as faking absent devices ourself. * * Locks: takes the controller lock on error path only */ - + static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, void (*done) (struct scsi_cmnd *)) { - int i; - int tid; struct i2o_controller *c; - struct scsi_cmnd *current_command; struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 *msg, *mptr; + struct i2o_device *i2o_dev; + struct device *dev; + int tid; + struct i2o_message *msg; u32 m; - u32 *lenptr; - int direction; - int scsidir; - u32 len; - u32 reqlen; - u32 tag; - unsigned long flags; - - static int max_qd = 1; - + u32 scsi_flags, sg_flags; + u32 *mptr, *lenptr; + u32 len, reqlen; + int i; + /* - * Do the incoming paperwork + * Do the incoming paperwork */ - + + i2o_dev = SCpnt->device->hostdata; host = SCpnt->device->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - - c = hostdata->controller; - prefetch(c); - prefetchw(&queue_depth); + c = i2o_dev->iop; + dev = &c->pdev->dev; SCpnt->scsi_done = done; - - if(SCpnt->device->id > 15) - { - printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->device->id); - return -1; - } - - tid = hostdata->task[SCpnt->device->id][SCpnt->device->lun]; - - dprintk(KERN_INFO "qcmd: Tid = %d\n", tid); - - current_command = SCpnt; /* set current command */ - current_command->scsi_done = done; /* set ptr to done function */ - - /* We don't have such a device. Pretend we did the command - and that selection timed out */ - - if(tid == -1) - { + + if (unlikely(!i2o_dev)) { + printk(KERN_WARNING "scsi-osm: no I2O device in request\n"); SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } - - dprintk(KERN_INFO "Real scsi messages.\n"); + + tid = i2o_dev->lct_data.tid; + + pr_debug("qcmd: Tid = %03x\n", tid); + pr_debug("Real scsi messages.\n"); /* - * Obtain an I2O message. If there are none free then - * throw it back to the scsi layer - */ - - m = le32_to_cpu(I2O_POST_READ32(c)); - if(m==0xFFFFFFFF) - return 1; + * Obtain an I2O message. If there are none free then + * throw it back to the scsi layer + */ + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return SCSI_MLQUEUE_HOST_BUSY; - msg = (u32 *)(c->msg_virt + m); - /* - * Put together a scsi execscb message + * Put together a scsi execscb message */ - + len = SCpnt->request_bufflen; - direction = 0x00000000; // SGL IN (osm<--iop) - - if (SCpnt->sc_data_direction == DMA_NONE) { - scsidir = 0x00000000; // DATA NO XFER - } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { - direction = 0x04000000; // SGL OUT (osm-->iop) - scsidir = 0x80000000; // DATA OUT (iop-->dev) - } else if(SCpnt->sc_data_direction == DMA_FROM_DEVICE) { - scsidir = 0x40000000; // DATA IN (iop<--dev) - } else { + + switch (SCpnt->sc_data_direction) { + case PCI_DMA_NONE: + scsi_flags = 0x00000000; // DATA NO XFER + sg_flags = 0x00000000; + break; + + case PCI_DMA_TODEVICE: + scsi_flags = 0x80000000; // DATA OUT (iop-->dev) + sg_flags = 0x14000000; + break; + + case PCI_DMA_FROMDEVICE: + scsi_flags = 0x40000000; // DATA IN (iop<--dev) + sg_flags = 0x10000000; + break; + + default: /* Unknown - kill the command */ SCpnt->result = DID_NO_CONNECT << 16; - - /* We must lock the request queue while completing */ - spin_lock_irqsave(host->host_lock, flags); done(SCpnt); - spin_unlock_irqrestore(host->host_lock, flags); return 0; } - - i2o_raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]); - i2o_raw_writel(scsi_context, &msg[2]); /* So the I2O layer passes to us */ - i2o_raw_writel(i2o_context_list_add(SCpnt, c), &msg[3]); /* We want the SCSI control block back */ + writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[1]); + writel(i2o_scsi_driver.context, &msg->u.s.icntxt); + + /* We want the SCSI control block back */ + writel(i2o_cntxt_list_add(c, SCpnt), &msg->u.s.tcntxt); /* LSI_920_PCI_QUIRK * - * Intermittant observations of msg frame word data corruption - * observed on msg[4] after: - * WRITE, READ-MODIFY-WRITE - * operations. 19990606 -sralston + * Intermittant observations of msg frame word data corruption + * observed on msg[4] after: + * WRITE, READ-MODIFY-WRITE + * operations. 19990606 -sralston * - * (Hence we build this word via tag. Its good practice anyway - * we don't want fetches over PCI needlessly) + * (Hence we build this word via tag. Its good practice anyway + * we don't want fetches over PCI needlessly) */ - tag=0; - + /* Attach tags to the devices */ /* - * Attach tags to the devices - */ - if(SCpnt->device->tagged_supported) - { - /* - * Some drives are too stupid to handle fairness issues - * with tagged queueing. We throw in the odd ordered - * tag to stop them starving themselves. - */ - if((jiffies - hostdata->tagclock[SCpnt->device->id][SCpnt->device->lun]) > (5*HZ)) - { - tag=0x01800000; /* ORDERED! */ - hostdata->tagclock[SCpnt->device->id][SCpnt->device->lun]=jiffies; - } - else - { - /* Hmmm... I always see value of 0 here, - * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston - */ - if(SCpnt->tag == HEAD_OF_QUEUE_TAG) - tag=0x01000000; - else if(SCpnt->tag == ORDERED_QUEUE_TAG) - tag=0x01800000; - } - } + if(SCpnt->device->tagged_supported) { + if(SCpnt->tag == HEAD_OF_QUEUE_TAG) + scsi_flags |= 0x01000000; + else if(SCpnt->tag == ORDERED_QUEUE_TAG) + scsi_flags |= 0x01800000; + } + */ /* Direction, disconnect ok, tag, CDBLen */ - i2o_raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]); + writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]); - mptr=msg+5; + mptr = &msg->body[1]; - /* - * Write SCSI command into the message - always 16 byte block - */ - + /* Write SCSI command into the message - always 16 byte block */ memcpy_toio(mptr, SCpnt->cmnd, 16); - mptr+=4; - lenptr=mptr++; /* Remember me - fill in when we know */ - + mptr += 4; + lenptr = mptr++; /* Remember me - fill in when we know */ + reqlen = 12; // SINGLE SGE - - /* - * Now fill in the SGList and command - * - * FIXME: we need to set the sglist limits according to the - * message size of the I2O controller. We might only have room - * for 6 or so worst case - */ - - if(SCpnt->use_sg) - { - struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; + + /* Now fill in the SGList and command */ + if (SCpnt->use_sg) { + struct scatterlist *sg; int sg_count; - int chain = 0; - + + sg = SCpnt->request_buffer; len = 0; - sg_count = pci_map_sg(c->pdev, sg, SCpnt->use_sg, - SCpnt->sc_data_direction); - - /* FIXME: handle fail */ - if(!sg_count) - BUG(); - - if((sg_max_frags > 11) && (SCpnt->use_sg > 11)) - { - chain = 1; - /* - * Need to chain! - */ - i2o_raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++); - i2o_raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr); - mptr = (u32*)(sg_chain_pool + sg_chain_tag); - if (SCpnt->use_sg > max_sg_len) - { - max_sg_len = SCpnt->use_sg; - printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n", - SCpnt, SCpnt->use_sg, sg_chain_tag); - } - if ( ++sg_chain_tag == SG_MAX_BUFS ) - sg_chain_tag = 0; - for(i = 0 ; i < SCpnt->use_sg; i++) - { - *mptr++=cpu_to_le32(direction|0x10000000|sg_dma_len(sg)); - len+=sg_dma_len(sg); - *mptr++=cpu_to_le32(sg_dma_address(sg)); - sg++; - } - mptr[-2]=cpu_to_le32(direction|0xD0000000|sg_dma_len(sg-1)); - } - else - { - for(i = 0 ; i < SCpnt->use_sg; i++) - { - i2o_raw_writel(direction|0x10000000|sg_dma_len(sg), mptr++); - len+=sg->length; - i2o_raw_writel(sg_dma_address(sg), mptr++); - sg++; - } + sg_count = dma_map_sg(dev, sg, SCpnt->use_sg, + SCpnt->sc_data_direction); - /* Make this an end of list. Again evade the 920 bug and - unwanted PCI read traffic */ - - i2o_raw_writel(direction|0xD0000000|sg_dma_len(sg-1), &mptr[-2]); - } - - if(!chain) - reqlen = mptr - msg; - - i2o_raw_writel(len, lenptr); - - if(len != SCpnt->underflow) - printk("Cmd len %08X Cmd underflow %08X\n", - len, SCpnt->underflow); - } - else - { - dprintk(KERN_INFO "non sg for %p, %d\n", SCpnt->request_buffer, - SCpnt->request_bufflen); - i2o_raw_writel(len = SCpnt->request_bufflen, lenptr); - if(len == 0) - { - reqlen = 9; + if (unlikely(sg_count <= 0)) + return -ENOMEM; + + for (i = SCpnt->use_sg; i > 0; i--) { + if (i == 1) + sg_flags |= 0xC0000000; + writel(sg_flags | sg_dma_len(sg), mptr++); + writel(sg_dma_address(sg), mptr++); + len += sg_dma_len(sg); + sg++; } - else - { + + reqlen = mptr - &msg->u.head[0]; + writel(len, lenptr); + } else { + len = SCpnt->request_bufflen; + + writel(len, lenptr); + + if (len > 0) { dma_addr_t dma_addr; - dma_addr = pci_map_single(c->pdev, - SCpnt->request_buffer, - SCpnt->request_bufflen, - SCpnt->sc_data_direction); - if(dma_addr == 0) - BUG(); /* How to handle ?? */ - SCpnt->SCp.ptr = (char *)(unsigned long) dma_addr; - i2o_raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++); - i2o_raw_writel(dma_addr, mptr++); - } + + dma_addr = dma_map_single(dev, SCpnt->request_buffer, + SCpnt->request_bufflen, + SCpnt->sc_data_direction); + if (!dma_addr) + return -ENOMEM; + + SCpnt->SCp.ptr = (void *)(unsigned long)dma_addr; + sg_flags |= 0xC0000000; + writel(sg_flags | SCpnt->request_bufflen, mptr++); + writel(dma_addr, mptr++); + } else + reqlen = 9; } - - /* - * Stick the headers on - */ - i2o_raw_writel(reqlen<<16 | SGL_OFFSET_10, msg); - + /* Stick the headers on */ + writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]); + /* Queue the message */ - i2o_post_message(c,m); - - atomic_inc(&queue_depth); - - if(atomic_read(&queue_depth)> max_qd) - { - max_qd=atomic_read(&queue_depth); - printk("Queue depth now %d.\n", max_qd); - } - - mb(); - dprintk(KERN_INFO "Issued %ld\n", current_command->serial_number); - + i2o_msg_post(c, m); + + pr_debug("Issued %ld\n", SCpnt->serial_number); + return 0; -} +}; /** - * i2o_scsi_abort - abort a running command + * i2o_scsi_abort - abort a running command * @SCpnt: command to abort * * Ask the I2O controller to abort a command. This is an asynchrnous - * process and our callback handler will see the command complete - * with an aborted message if it succeeds. + * process and our callback handler will see the command complete with an + * aborted message if it succeeds. * - * Locks: no locks are held or needed + * Returns 0 if the command is successfully aborted or negative error code + * on failure. */ - -static int i2o_scsi_abort(struct scsi_cmnd * SCpnt) +int i2o_scsi_abort(struct scsi_cmnd *SCpnt) { + struct i2o_device *i2o_dev; struct i2o_controller *c; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 msg[5]; + struct i2o_message *msg; + u32 m; int tid; int status = FAILED; - - printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); - - host = SCpnt->device->host; - hostdata = (struct i2o_scsi_host *)host->hostdata; - tid = hostdata->task[SCpnt->device->id][SCpnt->device->lun]; - if(tid==-1) - { - printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n"); - return status; - } - c = hostdata->controller; - - spin_unlock_irq(host->host_lock); - - msg[0] = FIVE_WORD_MSG_SIZE; - msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid; - msg[2] = scsi_context; - msg[3] = 0; - msg[4] = i2o_context_list_remove(SCpnt, c); - if(i2o_post_wait(c, msg, sizeof(msg), 240)) - status = SUCCESS; - - spin_lock_irq(host->host_lock); - return status; -} - -/** - * i2o_scsi_bus_reset - Issue a SCSI reset - * @SCpnt: the command that caused the reset - * - * Perform a SCSI bus reset operation. In I2O this is just a message - * we pass. I2O can do clever multi-initiator and shared reset stuff - * but we don't support this. - * - * Locks: called with no lock held, requires no locks. - */ - -static int i2o_scsi_bus_reset(struct scsi_cmnd * SCpnt) -{ - int tid; - struct i2o_controller *c; - struct Scsi_Host *host; - struct i2o_scsi_host *hostdata; - u32 m; - void *msg; - unsigned long timeout; - - - /* - * Find the TID for the bus - */ - - host = SCpnt->device->host; + printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); - spin_unlock_irq(host->host_lock); + i2o_dev = SCpnt->device->hostdata; + c = i2o_dev->iop; + tid = i2o_dev->lct_data.tid; - printk(KERN_WARNING "i2o_scsi: Attempting to reset the bus.\n"); + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return SCSI_MLQUEUE_HOST_BUSY; - hostdata = (struct i2o_scsi_host *)host->hostdata; - tid = hostdata->bus_task; - c = hostdata->controller; + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid, + &msg->u.head[1]); + writel(i2o_cntxt_list_get_ptr(c, SCpnt), &msg->body[0]); - /* - * Now send a SCSI reset request. Any remaining commands - * will be aborted by the IOP. We need to catch the reply - * possibly ? - */ + if (i2o_msg_post_wait(c, m, I2O_TIMEOUT_SCSI_SCB_ABORT)) + status = SUCCESS; - timeout = jiffies+2*HZ; - do - { - m = le32_to_cpu(I2O_POST_READ32(c)); - if(m != 0xFFFFFFFF) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - mb(); - } - while(time_before(jiffies, timeout)); - - - msg = c->msg_virt + m; - i2o_raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, msg); - i2o_raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, msg+4); - i2o_raw_writel(scsi_context|0x80000000, msg+8); - /* We use the top bit to split controller and unit transactions */ - /* Now store unit,tid so we can tie the completion back to a specific device */ - __raw_writel(c->unit << 16 | tid, msg+12); - wmb(); - - /* We want the command to complete after we return */ - spin_lock_irq(host->host_lock); - i2o_post_message(c,m); - - /* Should we wait for the reset to complete ? */ - return SUCCESS; + return status; } /** * i2o_scsi_bios_param - Invent disk geometry - * @sdev: scsi device + * @sdev: scsi device * @dev: block layer device * @capacity: size in sectors * @ip: geometry array * - * This is anyones guess quite frankly. We use the same rules everyone + * This is anyones guess quite frankly. We use the same rules everyone * else appears to and hope. It seems to work. */ - -static int i2o_scsi_bios_param(struct scsi_device * sdev, - struct block_device *dev, sector_t capacity, int *ip) + +static int i2o_scsi_bios_param(struct scsi_device *sdev, + struct block_device *dev, sector_t capacity, + int *ip) { int size; @@ -1023,25 +819,64 @@ static int i2o_scsi_bios_param(struct scsi_device * sdev, return 0; } -MODULE_AUTHOR("Red Hat Software"); -MODULE_LICENSE("GPL"); +static struct scsi_host_template i2o_scsi_host_template = { + .proc_name = "SCSI-OSM", + .name = "I2O SCSI Peripheral OSM", + .info = i2o_scsi_info, + .queuecommand = i2o_scsi_queuecommand, + .eh_abort_handler = i2o_scsi_abort, + .bios_param = i2o_scsi_bios_param, + .can_queue = I2O_SCSI_CAN_QUEUE, + .sg_tablesize = 8, + .cmd_per_lun = 6, + .use_clustering = ENABLE_CLUSTERING, +}; +/* +int +i2o_scsi_queuecommand(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) +{ + printk(KERN_INFO "queuecommand\n"); + return SCSI_MLQUEUE_HOST_BUSY; +}; +*/ -static struct scsi_host_template driver_template = { - .proc_name = "i2o_scsi", - .name = "I2O SCSI Layer", - .detect = i2o_scsi_detect, - .release = i2o_scsi_release, - .info = i2o_scsi_info, - .queuecommand = i2o_scsi_queuecommand, - .eh_abort_handler = i2o_scsi_abort, - .eh_bus_reset_handler = i2o_scsi_bus_reset, - .bios_param = i2o_scsi_bios_param, - .can_queue = I2O_SCSI_CAN_QUEUE, - .this_id = 15, - .sg_tablesize = 8, - .cmd_per_lun = 6, - .use_clustering = ENABLE_CLUSTERING, +/** + * i2o_scsi_init - SCSI OSM initialization function + * + * Register SCSI OSM into I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_scsi_init(void) +{ + int rc; + + printk(KERN_INFO "I2O SCSI Peripheral OSM\n"); + + /* Register SCSI OSM into I2O core */ + rc = i2o_driver_register(&i2o_scsi_driver); + if (rc) { + printk(KERN_ERR "scsi-osm: Could not register SCSI driver\n"); + return rc; + } + + return 0; }; -#include "../../scsi/scsi_module.c" +/** + * i2o_scsi_exit - SCSI OSM exit function + * + * Unregisters SCSI OSM from I2O core. + */ +static void __exit i2o_scsi_exit(void) +{ + /* Unregister I2O SCSI OSM from I2O core */ + i2o_driver_unregister(&i2o_scsi_driver); +}; + +MODULE_AUTHOR("Red Hat Software"); +MODULE_LICENSE("GPL"); + +module_init(i2o_scsi_init); +module_exit(i2o_scsi_exit); diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c new file mode 100644 index 000000000..699723e3a --- /dev/null +++ b/drivers/message/i2o/iop.c @@ -0,0 +1,1258 @@ +/* + * Functions to handle I2O controllers and I2O message handling + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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. + * + * A lot of the I2O message side code from this is taken from the + * Red Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. + */ + +#include +#include + +/* global I2O controller list */ +LIST_HEAD(i2o_controllers); + +/* + * global I2O System Table. Contains information about all the IOPs in the + * system. Used to inform IOPs about each others existence. + */ +static struct i2o_dma i2o_systab; + +/* Module internal functions from other sources */ +extern struct i2o_driver i2o_exec_driver; +extern int i2o_exec_lct_get(struct i2o_controller *); +extern void i2o_device_remove(struct i2o_device *); + +extern int __init i2o_driver_init(void); +extern void __exit i2o_driver_exit(void); +extern int __init i2o_exec_init(void); +extern void __exit i2o_exec_exit(void); +extern int __init i2o_pci_init(void); +extern void __exit i2o_pci_exit(void); +extern int i2o_device_init(void); +extern void i2o_device_exit(void); + +/** + * i2o_msg_nop - Returns a message which is not used + * @c: I2O controller from which the message was created + * @m: message which should be returned + * + * If you fetch a message via i2o_msg_get, and can't use it, you must + * return the message with this function. Otherwise the message frame + * is lost. + */ +void i2o_msg_nop(struct i2o_controller *c, u32 m) +{ + struct i2o_message *msg = c->in_queue.virt + m; + + writel(THREE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(0, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + i2o_msg_post(c, m); +}; + +/** + * i2o_msg_get_wait - obtain an I2O message from the IOP + * @c: I2O controller + * @msg: pointer to a I2O message pointer + * @wait: how long to wait until timeout + * + * This function waits up to wait seconds for a message slot to be + * available. + * + * On a success the message is returned and the pointer to the message is + * set in msg. The returned message is the physical page frame offset + * address from the read port (see the i2o spec). If no message is + * available returns I2O_QUEUE_EMPTY and msg is leaved untouched. + */ +u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message **msg, + int wait) +{ + unsigned long timeout = jiffies + wait * HZ; + u32 m; + + while ((m = i2o_msg_get(c, msg)) == I2O_QUEUE_EMPTY) { + if (time_after(jiffies, timeout)) { + pr_debug("%s: Timeout waiting for message frame.\n", + c->name); + return I2O_QUEUE_EMPTY; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + return m; +}; + +#if BITS_PER_LONG == 64 +/** + * i2o_cntxt_list_add - Append a pointer to context list and return a id + * @c: controller to which the context list belong + * @ptr: pointer to add to the context list + * + * Because the context field in I2O is only 32-bit large, on 64-bit the + * pointer is to large to fit in the context field. The i2o_cntxt_list + * functions therefore map pointers to context fields. + * + * Returns context id > 0 on success or 0 on failure. + */ +u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr) +{ + struct i2o_context_list_element *entry; + unsigned long flags; + + if (!ptr) + printk(KERN_ERR "NULL pointer found!\n"); + + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + printk(KERN_ERR "i2o: Could not allocate memory for context " + "list element\n"); + return 0; + } + + entry->ptr = ptr; + entry->timestamp = jiffies; + INIT_LIST_HEAD(&entry->list); + + spin_lock_irqsave(&c->context_list_lock, flags); + + if (unlikely(atomic_inc_and_test(&c->context_list_counter))) + atomic_inc(&c->context_list_counter); + + entry->context = atomic_read(&c->context_list_counter); + + list_add(&entry->list, &c->context_list); + + spin_unlock_irqrestore(&c->context_list_lock, flags); + + pr_debug("Add context to list %p -> %d\n", ptr, context); + + return entry->context; +}; + +/** + * i2o_cntxt_list_remove - Remove a pointer from the context list + * @c: controller to which the context list belong + * @ptr: pointer which should be removed from the context list + * + * Removes a previously added pointer from the context list and returns + * the matching context id. + * + * Returns context id on succes or 0 on failure. + */ +u32 i2o_cntxt_list_remove(struct i2o_controller *c, void *ptr) +{ + struct i2o_context_list_element *entry; + u32 context = 0; + unsigned long flags; + + spin_lock_irqsave(&c->context_list_lock, flags); + list_for_each_entry(entry, &c->context_list, list) + if (entry->ptr == ptr) { + list_del(&entry->list); + context = entry->context; + kfree(entry); + break; + } + spin_unlock_irqrestore(&c->context_list_lock, flags); + + if (!context) + printk(KERN_WARNING "i2o: Could not remove nonexistent ptr " + "%p\n", ptr); + + pr_debug("remove ptr from context list %d -> %p\n", context, ptr); + + return context; +}; + +/** + * i2o_cntxt_list_get - Get a pointer from the context list and remove it + * @c: controller to which the context list belong + * @context: context id to which the pointer belong + * + * Returns pointer to the matching context id on success or NULL on + * failure. + */ +void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context) +{ + struct i2o_context_list_element *entry; + unsigned long flags; + void *ptr = NULL; + + spin_lock_irqsave(&c->context_list_lock, flags); + list_for_each_entry(entry, &c->context_list, list) + if (entry->context == context) { + list_del(&entry->list); + ptr = entry->ptr; + kfree(entry); + break; + } + spin_unlock_irqrestore(&c->context_list_lock, flags); + + if (!ptr) + printk(KERN_WARNING "i2o: context id %d not found\n", context); + + pr_debug("get ptr from context list %d -> %p\n", context, ptr); + + return ptr; +}; + +/** + * i2o_cntxt_list_get_ptr - Get a context id from the context list + * @c: controller to which the context list belong + * @ptr: pointer to which the context id should be fetched + * + * Returns context id which matches to the pointer on succes or 0 on + * failure. + */ +u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr) +{ + struct i2o_context_list_element *entry; + u32 context = 0; + unsigned long flags; + + spin_lock_irqsave(&c->context_list_lock, flags); + list_for_each_entry(entry, &c->context_list, list) + if (entry->ptr == ptr) { + context = entry->context; + break; + } + spin_unlock_irqrestore(&c->context_list_lock, flags); + + if (!context) + printk(KERN_WARNING "i2o: Could not find nonexistent ptr " + "%p\n", ptr); + + pr_debug("get context id from context list %p -> %d\n", ptr, context); + + return context; +}; +#endif + +/** + * i2o_iop_find - Find an I2O controller by id + * @unit: unit number of the I2O controller to search for + * + * Lookup the I2O controller on the controller list. + * + * Returns pointer to the I2O controller on success or NULL if not found. + */ +struct i2o_controller *i2o_find_iop(int unit) +{ + struct i2o_controller *c; + + list_for_each_entry(c, &i2o_controllers, list) { + if (c->unit == unit) + return c; + } + + return NULL; +}; + +/** + * i2o_iop_find_device - Find a I2O device on an I2O controller + * @c: I2O controller where the I2O device hangs on + * @tid: TID of the I2O device to search for + * + * Searches the devices of the I2O controller for a device with TID tid and + * returns it. + * + * Returns a pointer to the I2O device if found, otherwise NULL. + */ +struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid) +{ + struct i2o_device *dev; + + list_for_each_entry(dev, &c->devices, list) + if (dev->lct_data.tid == tid) + return dev; + + return NULL; +}; + +/** + * i2o_quiesce_controller - quiesce controller + * @c: controller + * + * Quiesce an IOP. Causes IOP to make external operation quiescent + * (i2o 'READY' state). Internal operation of the IOP continues normally. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_quiesce(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + i2o_status_block *sb = c->status_block.virt; + int rc; + + i2o_status_get(c); + + /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ + if ((sb->iop_state != ADAPTER_STATE_READY) && + (sb->iop_state != ADAPTER_STATE_OPERATIONAL)) + return 0; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + /* Long timeout needed for quiesce if lots of devices */ + if ((rc = i2o_msg_post_wait(c, m, 240))) + printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: Quiesced.\n", c->name); + + i2o_status_get(c); // Entered READY state + + return rc; +}; + +/** + * i2o_iop_enable - move controller from ready to OPERATIONAL + * @c: I2O controller + * + * Enable IOP. This allows the IOP to resume external operations and + * reverses the effect of a quiesce. Returns zero or an error code if + * an error occurs. + */ +static int i2o_iop_enable(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + i2o_status_block *sb = c->status_block.virt; + int rc; + + i2o_status_get(c); + + /* Enable only allowed on READY state */ + if (sb->iop_state != ADAPTER_STATE_READY) + return -EINVAL; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + /* How long of a timeout do we need? */ + if ((rc = i2o_msg_post_wait(c, m, 240))) + printk(KERN_ERR "%s: Could not enable (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: Enabled.\n", c->name); + + i2o_status_get(c); // entered OPERATIONAL state + + return rc; +}; + +/** + * i2o_iop_quiesce_all - Quiesce all I2O controllers on the system + * + * Quiesce all I2O controllers which are connected to the system. + */ +static inline void i2o_iop_quiesce_all(void) +{ + struct i2o_controller *c, *tmp; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) { + if (!c->no_quiesce) + i2o_iop_quiesce(c); + } +}; + +/** + * i2o_iop_enable_all - Enables all controllers on the system + * + * Enables all I2O controllers which are connected to the system. + */ +static inline void i2o_iop_enable_all(void) +{ + struct i2o_controller *c, *tmp; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) + i2o_iop_enable(c); +}; + +/** + * i2o_clear_controller - Bring I2O controller into HOLD state + * @c: controller + * + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. The IOP is not + * expected to rebuild its LCT. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_clear(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + int rc; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + /* Quiesce all IOPs first */ + i2o_iop_quiesce_all(); + + writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + if ((rc = i2o_msg_post_wait(c, m, 30))) + printk(KERN_INFO "%s: Unable to clear (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: Cleared.\n", c->name); + + /* Enable all IOPs */ + i2o_iop_enable_all(); + + i2o_status_get(c); + + return rc; +} + +/** + * i2o_iop_reset - reset an I2O controller + * @c: controller to reset + * + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment + * and all local DDMs. The IOP rebuilds its LCT. + */ +static int i2o_iop_reset(struct i2o_controller *c) +{ + u8 *status = c->status.virt; + struct i2o_message *msg; + u32 m; + unsigned long timeout; + i2o_status_block *sb = c->status_block.virt; + int rc = 0; + + pr_debug("Resetting controller\n"); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + memset(status, 0, 4); + + /* Quiesce all IOPs first */ + i2o_iop_quiesce_all(); + + writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0, &msg->u.s.tcntxt); //FIXME: use reasonable transaction context + writel(0, &msg->body[0]); + writel(0, &msg->body[1]); + writel(i2o_ptr_low((void *)c->status.phys), &msg->body[2]); + writel(i2o_ptr_high((void *)c->status.phys), &msg->body[3]); + + i2o_msg_post(c, m); + + /* Wait for a reply */ + timeout = jiffies + I2O_TIMEOUT_RESET * HZ; + while (!*status) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "IOP reset timeout.\n"); + rc = -ETIMEDOUT; + goto exit; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + rmb(); + } + + if (*status == I2O_CMD_IN_PROGRESS) { + /* + * Once the reset is sent, the IOP goes into the INIT state + * which is indeterminate. We need to wait until the IOP + * has rebooted before we can let the system talk to + * it. We read the inbound Free_List until a message is + * available. If we can't read one in the given ammount of + * time, we assume the IOP could not reboot properly. + */ + pr_debug("%s: Reset in progress, waiting for reboot...\n", + c->name); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); + while (m == I2O_QUEUE_EMPTY) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "IOP reset timeout.\n"); + rc = -ETIMEDOUT; + goto exit; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); + } + i2o_msg_nop(c, m); + } + + /* from here all quiesce commands are safe */ + c->no_quiesce = 0; + + /* If IopReset was rejected or didn't perform reset, try IopClear */ + i2o_status_get(c); + if (*status == I2O_CMD_REJECTED || sb->iop_state != ADAPTER_STATE_RESET) { + printk(KERN_WARNING "%s: Reset rejected, trying to clear\n", + c->name); + i2o_iop_clear(c); + } else + pr_debug("%s: Reset completed.\n", c->name); + + exit: + /* Enable all IOPs */ + i2o_iop_enable_all(); + + return rc; +}; + +/** + * i2o_iop_init_outbound_queue - setup the outbound message queue + * @c: I2O controller + * + * Clear and (re)initialize IOP's outbound queue and post the message + * frames to the IOP. + * + * Returns 0 on success or a negative errno code on failure. + */ +int i2o_iop_init_outbound_queue(struct i2o_controller *c) +{ + u8 *status = c->status.virt; + u32 m; + struct i2o_message *msg; + ulong timeout; + int i; + + pr_debug("%s: Initializing Outbound Queue...\n", c->name); + + memset(status, 0, 4); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0x0106, &msg->u.s.tcntxt); /* FIXME: why 0x0106, maybe in + Spec? */ + writel(PAGE_SIZE, &msg->body[0]); + writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]); /* Outbound msg frame + size in words and Initcode */ + writel(0xd0000004, &msg->body[2]); + writel(i2o_ptr_low((void *)c->status.phys), &msg->body[3]); + writel(i2o_ptr_high((void *)c->status.phys), &msg->body[4]); + + i2o_msg_post(c, m); + + timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ; + while (*status <= I2O_CMD_IN_PROGRESS) { + if (time_after(jiffies, timeout)) { + printk(KERN_WARNING "%s: Timeout Initializing\n", + c->name); + return -ETIMEDOUT; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + rmb(); + } + + m = c->out_queue.phys; + + /* Post frames */ + for (i = 0; i < NMBR_MSG_FRAMES; i++) { + i2o_flush_reply(c, m); + m += MSG_FRAME_SIZE * 4; + } + + return 0; +} + +/** + * i2o_iop_activate - Bring controller up to HOLD + * @c: controller + * + * This function brings an I2O controller into HOLD state. The adapter + * is reset if necessary and then the queues and resource table are read. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_activate(struct i2o_controller *c) +{ + i2o_status_block *sb = c->status_block.virt; + int rc; + /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ + /* In READY state, Get status */ + + rc = i2o_status_get(c); + if (rc) { + printk(KERN_INFO "Unable to obtain status of %s, " + "attempting a reset.\n", c->name); + if (i2o_iop_reset(c)) + return rc; + } + + if (sb->i2o_version > I2OVER15) { + printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O " + "Specification.\n", c->name); + return -ENODEV; + } + + switch (sb->iop_state) { + case ADAPTER_STATE_FAULTED: + printk(KERN_CRIT "%s: hardware fault\n", c->name); + return -ENODEV; + + case ADAPTER_STATE_READY: + case ADAPTER_STATE_OPERATIONAL: + case ADAPTER_STATE_HOLD: + case ADAPTER_STATE_FAILED: + pr_debug("already running, trying to reset...\n"); + if (i2o_iop_reset(c)) + return -ENODEV; + } + + rc = i2o_iop_init_outbound_queue(c); + if (rc) + return rc; + + /* In HOLD state */ + + rc = i2o_hrt_get(c); + if (rc) + return rc; + + return 0; +}; + +/** + * i2o_iop_systab_set - Set the I2O System Table of the specified IOP + * @c: I2O controller to which the system table should be send + * + * Before the systab could be set i2o_systab_build() must be called. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_iop_systab_set(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + i2o_status_block *sb = c->status_block.virt; + struct device *dev = &c->pdev->dev; + struct resource *root; + int rc; + + if (sb->current_mem_size < sb->desired_mem_size) { + struct resource *res = &c->mem_resource; + res->name = c->pdev->bus->name; + res->flags = IORESOURCE_MEM; + res->start = 0; + res->end = 0; + printk("%s: requires private memory resources.\n", c->name); + root = pci_find_parent_resource(c->pdev, res); + if (root == NULL) + printk("Can't find parent resource!\n"); + if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ + NULL, NULL) >= 0) { + c->mem_alloc = 1; + sb->current_mem_size = 1 + res->end - res->start; + sb->current_mem_base = res->start; + printk(KERN_INFO + "%s: allocated %ld bytes of PCI memory at 0x%08lX.\n", + c->name, 1 + res->end - res->start, res->start); + } + } + + if (sb->current_io_size < sb->desired_io_size) { + struct resource *res = &c->io_resource; + res->name = c->pdev->bus->name; + res->flags = IORESOURCE_IO; + res->start = 0; + res->end = 0; + printk("%s: requires private memory resources.\n", c->name); + root = pci_find_parent_resource(c->pdev, res); + if (root == NULL) + printk("Can't find parent resource!\n"); + if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ + NULL, NULL) >= 0) { + c->io_alloc = 1; + sb->current_io_size = 1 + res->end - res->start; + sb->current_mem_base = res->start; + printk(KERN_INFO + "%s: allocated %ld bytes of PCI I/O at 0x%08lX.\n", + c->name, 1 + res->end - res->start, res->start); + } + } + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len, + PCI_DMA_TODEVICE); + if (!i2o_systab.phys) { + i2o_msg_nop(c, m); + return -ENOMEM; + } + + writel(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6, &msg->u.head[0]); + writel(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + + /* + * Provide three SGL-elements: + * System table (SysTab), Private memory space declaration and + * Private i/o space declaration + * + * FIXME: is this still true? + * Nasty one here. We can't use dma_alloc_coherent to send the + * same table to everyone. We have to go remap it for them all + */ + + writel(c->unit + 2, &msg->body[0]); + writel(0, &msg->body[1]); + writel(0x54000000 | i2o_systab.phys, &msg->body[2]); + writel(i2o_systab.phys, &msg->body[3]); + writel(0x54000000 | sb->current_mem_size, &msg->body[4]); + writel(sb->current_mem_base, &msg->body[5]); + writel(0xd4000000 | sb->current_io_size, &msg->body[6]); + writel(sb->current_io_base, &msg->body[6]); + + rc = i2o_msg_post_wait(c, m, 120); + + dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len, + PCI_DMA_TODEVICE); + + if (rc < 0) + printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", + c->name, -rc); + else + pr_debug("%s: SysTab set.\n", c->name); + + i2o_status_get(c); // Entered READY state + + return rc; +} + +/** + * i2o_iop_online - Bring a controller online into OPERATIONAL state. + * @c: I2O controller + * + * Send the system table and enable the I2O controller. + * + * Returns 0 on success or negativer error code on failure. + */ +static int i2o_iop_online(struct i2o_controller *c) +{ + int rc; + + rc = i2o_iop_systab_set(c); + if (rc) + return rc; + + /* In READY state */ + pr_debug("%s: Attempting to enable...\n", c->name); + rc = i2o_iop_enable(c); + if (rc) + return rc; + + return 0; +}; + +/** + * i2o_iop_remove - Remove the I2O controller from the I2O core + * @c: I2O controller + * + * Remove the I2O controller from the I2O core. If devices are attached to + * the controller remove these also and finally reset the controller. + */ +void i2o_iop_remove(struct i2o_controller *c) +{ + struct i2o_device *dev, *tmp; + + pr_debug("Deleting controller %s\n", c->name); + + i2o_driver_notify_controller_remove_all(c); + + list_del(&c->list); + + list_for_each_entry_safe(dev, tmp, &c->devices, list) + i2o_device_remove(dev); + + /* Ask the IOP to switch to RESET state */ + i2o_iop_reset(c); +} + +/** + * i2o_systab_build - Build system table + * + * The system table contains information about all the IOPs in the system + * (duh) and is used by the Executives on the IOPs to establish peer2peer + * connections. We're not supporting peer2peer at the moment, but this + * will be needed down the road for things like lan2lan forwarding. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_systab_build(void) +{ + struct i2o_controller *c, *tmp; + int num_controllers = 0; + u32 change_ind = 0; + int count = 0; + struct i2o_sys_tbl *systab = i2o_systab.virt; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) + num_controllers++; + + if (systab) { + change_ind = systab->change_ind; + kfree(i2o_systab.virt); + } + + /* Header + IOPs */ + i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers * + sizeof(struct i2o_sys_tbl_entry); + + systab = i2o_systab.virt = kmalloc(i2o_systab.len, GFP_KERNEL); + if (!systab) { + printk(KERN_ERR "i2o: unable to allocate memory for System " + "Table\n"); + return -ENOMEM; + } + memset(systab, 0, i2o_systab.len); + + systab->version = I2OVERSION; + systab->change_ind = change_ind + 1; + + list_for_each_entry_safe(c, tmp, &i2o_controllers, list) { + i2o_status_block *sb; + + if (count >= num_controllers) { + printk(KERN_ERR "i2o: controller added while building " + "system table\n"); + break; + } + + sb = c->status_block.virt; + + /* + * Get updated IOP state so we have the latest information + * + * We should delete the controller at this point if it + * doesn't respond since if it's not on the system table + * it is techninically not part of the I2O subsystem... + */ + if (unlikely(i2o_status_get(c))) { + printk(KERN_ERR "%s: Deleting b/c could not get status" + " while attempting to build system table\n", + c->name); + i2o_iop_remove(c); + continue; // try the next one + } + + systab->iops[count].org_id = sb->org_id; + systab->iops[count].iop_id = c->unit + 2; + systab->iops[count].seg_num = 0; + systab->iops[count].i2o_version = sb->i2o_version; + systab->iops[count].iop_state = sb->iop_state; + systab->iops[count].msg_type = sb->msg_type; + systab->iops[count].frame_size = sb->inbound_frame_size; + systab->iops[count].last_changed = change_ind; + systab->iops[count].iop_capabilities = sb->iop_capabilities; + systab->iops[count].inbound_low = i2o_ptr_low(c->post_port); + systab->iops[count].inbound_high = i2o_ptr_high(c->post_port); + + count++; + } + + systab->num_entries = count; + + return 0; +}; + +/** + * i2o_parse_hrt - Parse the hardware resource table. + * @c: I2O controller + * + * We don't do anything with it except dumping it (in debug mode). + * + * Returns 0. + */ +static int i2o_parse_hrt(struct i2o_controller *c) +{ + i2o_dump_hrt(c); + return 0; +}; + +/** + * i2o_status_get - Get the status block from the I2O controller + * @c: I2O controller + * + * Issue a status query on the controller. This updates the attached + * status block. The status block could then be accessed through + * c->status_block. + * + * Returns 0 on sucess or negative error code on failure. + */ +int i2o_status_get(struct i2o_controller *c) +{ + struct i2o_message *msg; + u32 m; + u8 *status_block; + unsigned long timeout; + + status_block = (u8 *) c->status_block.virt; + memset(status_block, 0, sizeof(i2o_status_block)); + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(i2o_exec_driver.context, &msg->u.s.icntxt); + writel(0, &msg->u.s.tcntxt); // FIXME: use resonable transaction context + writel(0, &msg->body[0]); + writel(0, &msg->body[1]); + writel(i2o_ptr_low((void *)c->status_block.phys), &msg->body[2]); + writel(i2o_ptr_high((void *)c->status_block.phys), &msg->body[3]); + writel(sizeof(i2o_status_block), &msg->body[4]); /* always 88 bytes */ + + i2o_msg_post(c, m); + + /* Wait for a reply */ + timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ; + while (status_block[87] != 0xFF) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "%s: Get status timeout.\n", c->name); + return -ETIMEDOUT; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + rmb(); + } + +#ifdef DEBUG + i2o_debug_state(c); +#endif + + return 0; +} + +/* + * i2o_hrt_get - Get the Hardware Resource Table from the I2O controller + * @c: I2O controller from which the HRT should be fetched + * + * The HRT contains information about possible hidden devices but is + * mostly useless to us. + * + * Returns 0 on success or negativer error code on failure. + */ +int i2o_hrt_get(struct i2o_controller *c) +{ + int rc; + int i; + i2o_hrt *hrt = c->hrt.virt; + u32 size = sizeof(i2o_hrt); + struct device *dev = &c->pdev->dev; + + for (i = 0; i < I2O_HRT_GET_TRIES; i++) { + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(SIX_WORD_MSG_SIZE | SGL_OFFSET_4, &msg->u.head[0]); + writel(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 | ADAPTER_TID, + &msg->u.head[1]); + writel(0xd0000000 | c->hrt.len, &msg->body[0]); + writel(c->hrt.phys, &msg->body[1]); + + rc = i2o_msg_post_wait_mem(c, m, 20, &c->hrt); + + if (rc < 0) { + printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", + c->name, -rc); + return rc; + } + + size = hrt->num_entries * hrt->entry_len << 2; + if (size > c->hrt.len) { + if (i2o_dma_realloc(dev, &c->hrt, size, GFP_KERNEL)) + return -ENOMEM; + else + hrt = c->hrt.virt; + } else + return i2o_parse_hrt(c); + } + + printk(KERN_ERR "%s: Unable to get HRT after %d tries, giving up\n", + c->name, I2O_HRT_GET_TRIES); + + return -EBUSY; +} + +/** + * i2o_iop_alloc - Allocate and initialize a i2o_controller struct + * + * Allocate the necessary memory for a i2o_controller struct and + * initialize the lists. + * + * Returns a pointer to the I2O controller or a negative error code on + * failure. + */ +struct i2o_controller *i2o_iop_alloc(void) +{ + static int unit = 0; /* 0 and 1 are NULL IOP and Local Host */ + struct i2o_controller *c; + + c = kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) { + printk(KERN_ERR "i2o: Insufficient memory to allocate the " + "controller.\n"); + return ERR_PTR(-ENOMEM); + } + memset(c, 0, sizeof(*c)); + + INIT_LIST_HEAD(&c->devices); + c->lock = SPIN_LOCK_UNLOCKED; + init_MUTEX(&c->lct_lock); + c->unit = unit++; + sprintf(c->name, "iop%d", c->unit); + +#if BITS_PER_LONG == 64 + c->context_list_lock = SPIN_LOCK_UNLOCKED; + atomic_set(&c->context_list_counter, 0); + INIT_LIST_HEAD(&c->context_list); +#endif + + return c; +}; + +/** + * i2o_iop_free - Free the i2o_controller struct + * @c: I2O controller to free + */ +void i2o_iop_free(struct i2o_controller *c) +{ + kfree(c); +}; + +/** + * i2o_iop_add - Initialize the I2O controller and add him to the I2O core + * @c: controller + * + * Initialize the I2O controller and if no error occurs add him to the I2O + * core. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_iop_add(struct i2o_controller *c) +{ + int rc; + + printk(KERN_INFO "%s: Activating I2O controller...\n", c->name); + printk(KERN_INFO "%s: This may take a few minutes if there are many " + "devices\n", c->name); + + if ((rc = i2o_iop_activate(c))) { + printk(KERN_ERR "%s: controller could not activated\n", + c->name); + i2o_iop_reset(c); + return rc; + } + + pr_debug("building sys table %s...\n", c->name); + + if ((rc = i2o_systab_build())) { + i2o_iop_reset(c); + return rc; + } + + pr_debug("online controller %s...\n", c->name); + + if ((rc = i2o_iop_online(c))) { + i2o_iop_reset(c); + return rc; + } + + pr_debug("getting LCT %s...\n", c->name); + + if ((rc = i2o_exec_lct_get(c))) { + i2o_iop_reset(c); + return rc; + } + + list_add(&c->list, &i2o_controllers); + + i2o_driver_notify_controller_add_all(c); + + printk(KERN_INFO "%s: Controller added\n", c->name); + + return 0; +}; + +/** + * i2o_event_register - Turn on/off event notification for a I2O device + * @dev: I2O device which should receive the event registration request + * @drv: driver which want to get notified + * @tcntxt: transaction context to use with this notifier + * @evt_mask: mask of events + * + * Create and posts an event registration message to the task. No reply + * is waited for, or expected. If you do not want further notifications, + * call the i2o_event_register again with a evt_mask of 0. + * + * Returns 0 on success or -ETIMEDOUT if no message could be fetched for + * sending the request. + */ +int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv, + int tcntxt, u32 evt_mask) +{ + struct i2o_controller *c = dev->iop; + struct i2o_message *msg; + u32 m; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->lct_data. + tid, &msg->u.head[1]); + writel(drv->context, &msg->u.s.icntxt); + writel(tcntxt, &msg->u.s.tcntxt); + writel(evt_mask, &msg->body[0]); + + i2o_msg_post(c, m); + + return 0; +}; + +/** + * i2o_iop_init - I2O main initialization function + * + * Initialize the I2O drivers (OSM) functions, register the Executive OSM, + * initialize the I2O PCI part and finally initialize I2O device stuff. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_iop_init(void) +{ + int rc = 0; + + printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); + + rc = i2o_device_init(); + if (rc) + goto exit; + + rc = i2o_driver_init(); + if (rc) + goto device_exit; + + rc = i2o_exec_init(); + if (rc) + goto driver_exit; + + rc = i2o_pci_init(); + if (rc < 0) + goto exec_exit; + + return 0; + + exec_exit: + i2o_exec_exit(); + + driver_exit: + i2o_driver_exit(); + + device_exit: + i2o_device_exit(); + + exit: + return rc; +} + +/** + * i2o_iop_exit - I2O main exit function + * + * Removes I2O controllers from PCI subsystem and shut down OSMs. + */ +static void __exit i2o_iop_exit(void) +{ + i2o_pci_exit(); + i2o_exec_exit(); + i2o_driver_exit(); + i2o_device_exit(); +}; + +module_init(i2o_iop_init); +module_exit(i2o_iop_exit); + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Core"); +MODULE_LICENSE("GPL"); + +#if BITS_PER_LONG == 64 +EXPORT_SYMBOL(i2o_cntxt_list_add); +EXPORT_SYMBOL(i2o_cntxt_list_get); +EXPORT_SYMBOL(i2o_cntxt_list_remove); +EXPORT_SYMBOL(i2o_cntxt_list_get_ptr); +#endif +EXPORT_SYMBOL(i2o_msg_get_wait); +EXPORT_SYMBOL(i2o_msg_nop); +EXPORT_SYMBOL(i2o_find_iop); +EXPORT_SYMBOL(i2o_iop_find_device); +EXPORT_SYMBOL(i2o_event_register); +EXPORT_SYMBOL(i2o_status_get); +EXPORT_SYMBOL(i2o_hrt_get); +EXPORT_SYMBOL(i2o_controllers); diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c new file mode 100644 index 000000000..9ee58b6cf --- /dev/null +++ b/drivers/message/i2o/pci.c @@ -0,0 +1,528 @@ +/* + * PCI handling of I2O controller + * + * Copyright (C) 1999-2002 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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. + * + * A lot of the I2O message side code from this is taken from the Red + * Creek RCPCI45 adapter driver by Red Creek Communications + * + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. + * Markus Lidel : + * Support for sysfs included. + */ + +#include +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif // CONFIG_MTRR + +/* Module internal functions from other sources */ +extern struct i2o_controller *i2o_iop_alloc(void); +extern void i2o_iop_free(struct i2o_controller *); + +extern int i2o_iop_add(struct i2o_controller *); +extern void i2o_iop_remove(struct i2o_controller *); + +extern int i2o_driver_dispatch(struct i2o_controller *, u32, + struct i2o_message *); + +/* PCI device id table for all I2O controllers */ +static struct pci_device_id __devinitdata i2o_pci_ids[] = { + {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)}, + {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)}, + {0} +}; + +/** + * i2o_dma_realloc - Realloc DMA memory + * @dev: struct device pointer to the PCI device of the I2O controller + * @addr: pointer to a i2o_dma struct DMA buffer + * @len: new length of memory + * @gfp_mask: GFP mask + * + * If there was something allocated in the addr, free it first. If len > 0 + * than try to allocate it and write the addresses back to the addr + * structure. If len == 0 set the virtual address to NULL. + * + * Returns the 0 on success or negative error code on failure. + */ +int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len, + unsigned int gfp_mask) +{ + i2o_dma_free(dev, addr); + + if (len) + return i2o_dma_alloc(dev, addr, len, gfp_mask); + + return 0; +}; + +/** + * i2o_pci_free - Frees the DMA memory for the I2O controller + * @c: I2O controller to free + * + * Remove all allocated DMA memory and unmap memory IO regions. If MTRR + * is enabled, also remove it again. + */ +static void __devexit i2o_pci_free(struct i2o_controller *c) +{ + struct device *dev; + + dev = &c->pdev->dev; + + i2o_dma_free(dev, &c->out_queue); + i2o_dma_free(dev, &c->status_block); + if (c->lct) + kfree(c->lct); + i2o_dma_free(dev, &c->dlct); + i2o_dma_free(dev, &c->hrt); + i2o_dma_free(dev, &c->status); + +#ifdef CONFIG_MTRR + if (c->mtrr_reg0 >= 0) + mtrr_del(c->mtrr_reg0, 0, 0); + if (c->mtrr_reg1 >= 0) + mtrr_del(c->mtrr_reg1, 0, 0); +#endif + + if (c->raptor && c->in_queue.virt) + iounmap(c->in_queue.virt); + + if (c->base.virt) + iounmap(c->base.virt); +} + +/** + * i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller + * @c: I2O controller + * + * Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All + * IO mappings are also done here. If MTRR is enabled, also do add memory + * regions here. + * + * Returns 0 on success or negative error code on failure. + */ +static int __devinit i2o_pci_alloc(struct i2o_controller *c) +{ + struct pci_dev *pdev = c->pdev; + struct device *dev = &pdev->dev; + int i; + + for (i = 0; i < 6; i++) { + /* Skip I/O spaces */ + if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + if (!c->base.phys) { + c->base.phys = pci_resource_start(pdev, i); + c->base.len = pci_resource_len(pdev, i); + + /* + * If we know what card it is, set the size + * correctly. Code is taken from dpt_i2o.c + */ + if(pdev->device == 0xa501) { + if(pdev->subsystem_device >= 0xc032 && + pdev->subsystem_device <= 0xc03b) { + if(c->base.len > 0x400000) + c->base.len = 0x400000; + } else { + if(c->base.len > 0x100000) + c->base.len = 0x100000; + } + } + if (!c->raptor) + break; + } else { + c->in_queue.phys = pci_resource_start(pdev, i); + c->in_queue.len = pci_resource_len(pdev, i); + break; + } + } + } + + if (i == 6) { + printk(KERN_ERR "i2o: I2O controller has no memory regions" + " defined.\n"); + i2o_pci_free(c); + return -EINVAL; + } + + /* Map the I2O controller */ + if (c->raptor) { + printk(KERN_INFO "i2o: PCI I2O controller\n"); + printk(KERN_INFO " BAR0 at 0x%08lX size=%ld\n", + (unsigned long)c->base.phys, (unsigned long)c->base.len); + printk(KERN_INFO " BAR1 at 0x%08lX size=%ld\n", + (unsigned long)c->in_queue.phys, + (unsigned long)c->in_queue.len); + } else + printk(KERN_INFO "i2o: PCI I2O controller at %08lX size=%ld\n", + (unsigned long)c->base.phys, (unsigned long)c->base.len); + + c->base.virt = ioremap(c->base.phys, c->base.len); + if (!c->base.virt) { + printk(KERN_ERR "i2o: Unable to map controller.\n"); + return -ENOMEM; + } + + if (c->raptor) { + c->in_queue.virt = ioremap(c->in_queue.phys, c->in_queue.len); + if (!c->in_queue.virt) { + printk(KERN_ERR "i2o: Unable to map controller.\n"); + i2o_pci_free(c); + return -ENOMEM; + } + } else + c->in_queue = c->base; + + c->irq_mask = c->base.virt + 0x34; + c->post_port = c->base.virt + 0x40; + c->reply_port = c->base.virt + 0x44; + +#ifdef CONFIG_MTRR + /* Enable Write Combining MTRR for IOP's memory region */ + c->mtrr_reg0 = mtrr_add(c->in_queue.phys, c->in_queue.len, + MTRR_TYPE_WRCOMB, 1); + c->mtrr_reg1 = -1; + + if (c->mtrr_reg0 < 0) + printk(KERN_WARNING "i2o: could not enable write combining " + "MTRR\n"); + else + printk(KERN_INFO "i2o: using write combining MTRR\n"); + + /* + * If it is an INTEL i960 I/O processor then set the first 64K to + * Uncacheable since the region contains the messaging unit which + * shouldn't be cached. + */ + if ((pdev->vendor == PCI_VENDOR_ID_INTEL || + pdev->vendor == PCI_VENDOR_ID_DPT) && !c->raptor) { + printk(KERN_INFO "i2o: MTRR workaround for Intel i960 processor" + "\n"); + c->mtrr_reg1 = mtrr_add(c->base.phys, 0x10000, + MTRR_TYPE_UNCACHABLE, 1); + + if (c->mtrr_reg1 < 0) { + printk(KERN_WARNING "i2o_pci: Error in setting " + "MTRR_TYPE_UNCACHABLE\n"); + mtrr_del(c->mtrr_reg0, c->in_queue.phys, + c->in_queue.len); + c->mtrr_reg0 = -1; + } + } +#endif + + if (i2o_dma_alloc(dev, &c->status, 4, GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block), + GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + if (i2o_dma_alloc(dev, &c->out_queue, MSG_POOL_SIZE, GFP_KERNEL)) { + i2o_pci_free(c); + return -ENOMEM; + } + + pci_set_drvdata(pdev, c); + + return 0; +} + +/** + * i2o_pci_interrupt - Interrupt handler for I2O controller + * @irq: interrupt line + * @dev_id: pointer to the I2O controller + * @r: pointer to registers + * + * Handle an interrupt from a PCI based I2O controller. This turns out + * to be rather simple. We keep the controller pointer in the cookie. + */ +static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) +{ + struct i2o_controller *c = dev_id; + struct device *dev = &c->pdev->dev; + struct i2o_message *m; + u32 mv; + u32 *msg; + + /* + * Old 960 steppings had a bug in the I2O unit that caused + * the queue to appear empty when it wasn't. + */ + mv = I2O_REPLY_READ32(c); + if (mv == I2O_QUEUE_EMPTY) { + mv = I2O_REPLY_READ32(c); + if (unlikely(mv == I2O_QUEUE_EMPTY)) { + return IRQ_NONE; + } else + pr_debug("960 bug detected\n"); + } + + while (mv != I2O_QUEUE_EMPTY) { + /* + * Map the message from the page frame map to kernel virtual. + * Because bus_to_virt is deprecated, we have calculate the + * location by ourself! + */ + m = (struct i2o_message *)(mv - + (unsigned long)c->out_queue.phys + + (unsigned long)c->out_queue.virt); + + msg = (u32 *) m; + + /* + * Ensure this message is seen coherently but cachably by + * the processor + */ + dma_sync_single_for_cpu(dev, c->out_queue.phys, MSG_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + + /* dispatch it */ + if (i2o_driver_dispatch(c, mv, m)) + /* flush it if result != 0 */ + i2o_flush_reply(c, mv); + + /* + * That 960 bug again... + */ + mv = I2O_REPLY_READ32(c); + if (mv == I2O_QUEUE_EMPTY) + mv = I2O_REPLY_READ32(c); + } + return IRQ_HANDLED; +} + +/** + * i2o_pci_irq_enable - Allocate interrupt for I2O controller + * + * Allocate an interrupt for the I2O controller, and activate interrupts + * on the I2O controller. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_pci_irq_enable(struct i2o_controller *c) +{ + struct pci_dev *pdev = c->pdev; + int rc; + + I2O_IRQ_WRITE32(c, 0xffffffff); + + if (pdev->irq) { + rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ, + c->name, c); + if (rc < 0) { + printk(KERN_ERR "%s: unable to allocate interrupt %d." + "\n", c->name, pdev->irq); + return rc; + } + } + + I2O_IRQ_WRITE32(c, 0x00000000); + + printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq); + + return 0; +} + +/** + * i2o_pci_irq_disable - Free interrupt for I2O controller + * @c: I2O controller + * + * Disable interrupts in I2O controller and then free interrupt. + */ +static void i2o_pci_irq_disable(struct i2o_controller *c) +{ + I2O_IRQ_WRITE32(c, 0xffffffff); + + if (c->pdev->irq > 0) + free_irq(c->pdev->irq, c); +} + +/** + * i2o_pci_probe - Probe the PCI device for an I2O controller + * @dev: PCI device to test + * @id: id which matched with the PCI device id table + * + * Probe the PCI device for any device which is a memory of the + * Intelligent, I2O class or an Adaptec Zero Channel Controller. We + * attempt to set up each such device and register it with the core. + * + * Returns 0 on success or negative error code on failure. + */ +static int __devinit i2o_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct i2o_controller *c; + int rc; + + printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); + + if ((pdev->class & 0xff) > 1) { + printk(KERN_WARNING "i2o: I2O controller found but does not " + "support I2O 1.5 (skipping).\n"); + return -ENODEV; + } + + if ((rc = pci_enable_device(pdev))) { + printk(KERN_WARNING "i2o: I2O controller found but could not be" + " enabled.\n"); + return rc; + } + + printk(KERN_INFO "i2o: I2O controller found on bus %d at %d.\n", + pdev->bus->number, pdev->devfn); + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_WARNING "i2o: I2O controller on bus %d at %d: No " + "suitable DMA available!\n", pdev->bus->number, + pdev->devfn); + rc = -ENODEV; + goto disable; + } + + pci_set_master(pdev); + + c = i2o_iop_alloc(); + if (IS_ERR(c)) { + printk(KERN_ERR "i2o: memory for I2O controller could not be " + "allocated\n"); + rc = PTR_ERR(c); + goto disable; + } + + c->pdev = pdev; + c->device = pdev->dev; + + /* Cards that fall apart if you hit them with large I/O loads... */ + if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) { + c->short_req = 1; + printk(KERN_INFO "i2o: Symbios FC920 workarounds activated.\n"); + } + + if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) { + c->promise = 1; + printk(KERN_INFO "i2o: Promise workarounds activated.\n"); + } + + /* Cards that go bananas if you quiesce them before you reset them. */ + if (pdev->vendor == PCI_VENDOR_ID_DPT) { + c->no_quiesce = 1; + if (pdev->device == 0xa511) + c->raptor = 1; + } + + if ((rc = i2o_pci_alloc(c))) { + printk(KERN_ERR "i2o: DMA / IO allocation for I2O controller " + " failed\n"); + goto free_controller; + } + + if (i2o_pci_irq_enable(c)) { + printk(KERN_ERR "i2o: unable to enable interrupts for I2O " + "controller\n"); + goto free_pci; + } + + if ((rc = i2o_iop_add(c))) + goto uninstall; + + return 0; + + uninstall: + i2o_pci_irq_disable(c); + + free_pci: + i2o_pci_free(c); + + free_controller: + i2o_iop_free(c); + + disable: + pci_disable_device(pdev); + + return rc; +} + +/** + * i2o_pci_remove - Removes a I2O controller from the system + * pdev: I2O controller which should be removed + * + * Reset the I2O controller, disable interrupts and remove all allocated + * resources. + */ +static void __devexit i2o_pci_remove(struct pci_dev *pdev) +{ + struct i2o_controller *c; + c = pci_get_drvdata(pdev); + + i2o_iop_remove(c); + i2o_pci_irq_disable(c); + i2o_pci_free(c); + + printk(KERN_INFO "%s: Controller removed.\n", c->name); + + i2o_iop_free(c); + pci_disable_device(pdev); +}; + +/* PCI driver for I2O controller */ +static struct pci_driver i2o_pci_driver = { + .name = "I2O controller", + .id_table = i2o_pci_ids, + .probe = i2o_pci_probe, + .remove = __devexit_p(i2o_pci_remove), +}; + +/** + * i2o_pci_init - registers I2O PCI driver in PCI subsystem + * + * Returns > 0 on success or negative error code on failure. + */ +int __init i2o_pci_init(void) +{ + return pci_register_driver(&i2o_pci_driver); +}; + +/** + * i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem + */ +void __exit i2o_pci_exit(void) +{ + pci_unregister_driver(&i2o_pci_driver); +}; + +EXPORT_SYMBOL(i2o_dma_realloc); diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index ee29ced87..9dcf33c2a 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/mmc/Kconfig b/drivers/mmc/Kconfig new file mode 100644 index 000000000..6b1b5177d --- /dev/null +++ b/drivers/mmc/Kconfig @@ -0,0 +1,52 @@ +# +# MMC subsystem configuration +# + +menu "MMC/SD Card support" + +config MMC + tristate "MMC support" + help + MMC is the "multi-media card" bus protocol. + + If you want MMC support, you should say Y here and also + to the specific driver for your MMC interface. + +config MMC_DEBUG + bool "MMC debugging" + depends on MMC != n + help + This is an option for use by developers; most people should + say N here. This enables MMC core and driver debugging. + +config MMC_BLOCK + tristate "MMC block device driver" + depends on MMC + default y + help + Say Y here to enable the MMC block device driver support. + This provides a block device driver, which you can use to + mount the filesystem. Almost everyone wishing MMC support + should say Y or M here. + +config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA && MMC + help + This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card + Interface (PL180 and PL181) support. If you have an ARM(R) + platform with a Multimedia Card slot, say Y or M here. + + If unsure, say N. + +config MMC_PXA + tristate "Intel PXA255 Multimedia Card Interface support" + depends on ARCH_PXA && MMC + help + This selects the Intel(R) PXA(R) Multimedia card Interface. + If you have a PXA(R) platform with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + +endmenu diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile new file mode 100644 index 000000000..def01111d --- /dev/null +++ b/drivers/mmc/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the kernel mmc device drivers. +# + +# +# Core +# +obj-$(CONFIG_MMC) += mmc_core.o + +# +# Media drivers +# +obj-$(CONFIG_MMC_BLOCK) += mmc_block.o + +# +# Host drivers +# +obj-$(CONFIG_MMC_ARMMMCI) += mmci.o +obj-$(CONFIG_MMC_PXA) += pxamci.o + +mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c new file mode 100644 index 000000000..5c3d84894 --- /dev/null +++ b/drivers/mmc/mmc.c @@ -0,0 +1,913 @@ +/* + * linux/drivers/mmc/mmc.c + * + * Copyright (C) 2003-2004 Russell King, 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 version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mmc.h" + +#ifdef CONFIG_MMC_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) do { } while (0) +#endif + +#define CMD_RETRIES 3 + +/* + * OCR Bit positions to 10s of Vdd mV. + */ +static const unsigned short mmc_ocr_bit_to_vdd[] = { + 150, 155, 160, 165, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, + 290, 300, 310, 320, 330, 340, 350, 360 +}; + +static const unsigned int tran_exp[] = { + 10000, 100000, 1000000, 10000000, + 0, 0, 0, 0 +}; + +static const unsigned char tran_mant[] = { + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + +static const unsigned int tacc_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, +}; + +static const unsigned int tacc_mant[] = { + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + + +/** + * mmc_request_done - finish processing an MMC command + * @host: MMC host which completed command + * @mrq: MMC request which completed + * + * MMC drivers should call this function when they have completed + * their processing of a command. This should be called before the + * data part of the command has completed. + */ +void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + int err = mrq->cmd->error; + DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode, + err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + + if (err && cmd->retries) { + cmd->retries--; + cmd->error = 0; + host->ops->request(host, mrq); + } else if (mrq->done) { + mrq->done(mrq); + } +} + +EXPORT_SYMBOL(mmc_request_done); + +/** + * mmc_start_request - start a command on a host + * @host: MMC host to start command on + * @mrq: MMC request to start + * + * Queue a command on the specified host. We expect the + * caller to be holding the host lock with interrupts disabled. + */ +void +mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) +{ + DBG("MMC: starting cmd %02x arg %08x flags %08x\n", + mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); + + WARN_ON(host->card_busy == NULL); + + mrq->cmd->error = 0; + mrq->cmd->mrq = mrq; + if (mrq->data) { + mrq->cmd->data = mrq->data; + mrq->data->error = 0; + mrq->data->mrq = mrq; + if (mrq->stop) { + mrq->data->stop = mrq->stop; + mrq->stop->error = 0; + mrq->stop->mrq = mrq; + } + } + host->ops->request(host, mrq); +} + +EXPORT_SYMBOL(mmc_start_request); + +static void mmc_wait_done(struct mmc_request *mrq) +{ + complete(mrq->done_data); +} + +int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) +{ + DECLARE_COMPLETION(complete); + + mrq->done_data = &complete; + mrq->done = mmc_wait_done; + + mmc_start_request(host, mrq); + + wait_for_completion(&complete); + + return 0; +} + +EXPORT_SYMBOL(mmc_wait_for_req); + +/** + * mmc_wait_for_cmd - start a command and wait for completion + * @host: MMC host to start command + * @cmd: MMC command to start + * @retries: maximum number of retries + * + * Start a new MMC command for a host, and wait for the command + * to complete. Return any error that occurred while the command + * was executing. Do not attempt to parse the response. + */ +int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) +{ + struct mmc_request mrq; + + BUG_ON(host->card_busy == NULL); + + memset(&mrq, 0, sizeof(struct mmc_request)); + + memset(cmd->resp, 0, sizeof(cmd->resp)); + cmd->retries = retries; + + mrq.cmd = cmd; + cmd->data = NULL; + + mmc_wait_for_req(host, &mrq); + + return cmd->error; +} + +EXPORT_SYMBOL(mmc_wait_for_cmd); + + + +/** + * __mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * @card: mmc card to claim host for + * + * Claim a host for a set of operations. If a valid card + * is passed and this wasn't the last card selected, select + * the card before returning. + * + * Note: you should use mmc_card_claim_host or mmc_claim_host. + */ +int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int err = 0; + + add_wait_queue(&host->wq, &wait); + spin_lock_irqsave(&host->lock, flags); + while (1) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (host->card_busy == NULL) + break; + spin_unlock_irqrestore(&host->lock, flags); + schedule(); + spin_lock_irqsave(&host->lock, flags); + } + set_current_state(TASK_RUNNING); + host->card_busy = card; + spin_unlock_irqrestore(&host->lock, flags); + remove_wait_queue(&host->wq, &wait); + + if (card != (void *)-1 && host->card_selected != card) { + struct mmc_command cmd; + + host->card_selected = card; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + } + + return err; +} + +EXPORT_SYMBOL(__mmc_claim_host); + +/** + * mmc_release_host - release a host + * @host: mmc host to release + * + * Release a MMC host, allowing others to claim the host + * for their operations. + */ +void mmc_release_host(struct mmc_host *host) +{ + unsigned long flags; + + BUG_ON(host->card_busy == NULL); + + spin_lock_irqsave(&host->lock, flags); + host->card_busy = NULL; + spin_unlock_irqrestore(&host->lock, flags); + + wake_up(&host->wq); +} + +EXPORT_SYMBOL(mmc_release_host); + +/* + * Ensure that no card is selected. + */ +static void mmc_deselect_cards(struct mmc_host *host) +{ + struct mmc_command cmd; + + if (host->card_selected) { + host->card_selected = NULL; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE; + + mmc_wait_for_cmd(host, &cmd, 0); + } +} + + +static inline void mmc_delay(unsigned int ms) +{ + if (ms < HZ / 1000) { + yield(); + mdelay(ms); + } else { + msleep_interruptible (ms); + } +} + +/* + * Mask off any voltages we don't support and select + * the lowest voltage + */ +static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) +{ + int bit; + + ocr &= host->ocr_avail; + + bit = ffs(ocr); + if (bit) { + bit -= 1; + + ocr = 3 << bit; + + host->ios.vdd = bit; + host->ops->set_ios(host, &host->ios); + } else { + ocr = 0; + } + + return ocr; +} + +#define UNSTUFF_BITS(resp,start,size) \ + ({ \ + const u32 __mask = (1 << (size)) - 1; \ + const int __off = 3 - ((start) / 32); \ + const int __shft = (start) & 31; \ + u32 __res; \ + \ + __res = resp[__off] >> __shft; \ + if ((size) + __shft >= 32) \ + __res |= resp[__off-1] << (32 - __shft); \ + __res & __mask; \ + }) + +/* + * Given the decoded CSD structure, decode the raw CID to our CID structure. + */ +static void mmc_decode_cid(struct mmc_card *card) +{ + u32 *resp = card->raw_cid; + + memset(&card->cid, 0, sizeof(struct mmc_cid)); + + /* + * The selection of the format here is guesswork based upon + * information people have sent to date. + */ + switch (card->csd.mmca_vsn) { + case 0: /* MMC v1.? */ + case 1: /* MMC v1.4 */ + card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); + card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); + card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); + card->cid.serial = UNSTUFF_BITS(resp, 16, 24); + card->cid.month = UNSTUFF_BITS(resp, 12, 4); + card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + break; + + case 2: /* MMC v2.x ? */ + case 3: /* MMC v3.x ? */ + card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); + card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.serial = UNSTUFF_BITS(resp, 16, 32); + card->cid.month = UNSTUFF_BITS(resp, 12, 4); + card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + break; + + default: + printk("%s: card has unknown MMCA version %d\n", + card->host->host_name, card->csd.mmca_vsn); + mmc_card_set_bad(card); + break; + } +} + +/* + * Given a 128-bit response, decode to our card CSD structure. + */ +static void mmc_decode_csd(struct mmc_card *card) +{ + struct mmc_csd *csd = &card->csd; + unsigned int e, m, csd_struct; + u32 *resp = card->raw_csd; + + /* + * We only understand CSD structure v1.1 and v2. + * v2 has extra information in bits 15, 11 and 10. + */ + csd_struct = UNSTUFF_BITS(resp, 126, 2); + if (csd_struct != 1 && csd_struct != 2) { + printk("%s: unrecognised CSD structure version %d\n", + card->host->host_name, csd_struct); + mmc_card_set_bad(card); + return; + } + + csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); +} + +/* + * Locate a MMC card on this MMC host given a raw CID. + */ +static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid) +{ + struct mmc_card *card; + + list_for_each_entry(card, &host->cards, node) { + if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0) + return card; + } + return NULL; +} + +/* + * Allocate a new MMC card, and assign a unique RCA. + */ +static struct mmc_card * +mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca) +{ + struct mmc_card *card, *c; + unsigned int rca = *frca; + + card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + mmc_init_card(card, host); + memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid)); + + again: + list_for_each_entry(c, &host->cards, node) + if (c->rca == rca) { + rca++; + goto again; + } + + card->rca = rca; + + *frca = rca; + + return card; +} + +/* + * Tell attached cards to go to IDLE state + */ +static void mmc_idle_cards(struct mmc_host *host) +{ + struct mmc_command cmd; + + cmd.opcode = MMC_GO_IDLE_STATE; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE; + + mmc_wait_for_cmd(host, &cmd, 0); + + mmc_delay(1); +} + +/* + * Apply power to the MMC stack. + */ +static void mmc_power_up(struct mmc_host *host) +{ + int bit = fls(host->ocr_avail) - 1; + + host->ios.vdd = bit; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.power_mode = MMC_POWER_UP; + host->ops->set_ios(host, &host->ios); + + mmc_delay(1); + + host->ios.clock = host->f_min; + host->ios.power_mode = MMC_POWER_ON; + host->ops->set_ios(host, &host->ios); + + mmc_delay(2); +} + +static void mmc_power_off(struct mmc_host *host) +{ + host->ios.clock = 0; + host->ios.vdd = 0; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.power_mode = MMC_POWER_OFF; + host->ops->set_ios(host, &host->ios); +} + +static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + cmd.opcode = MMC_SEND_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R3; + + for (i = 100; i; i--) { + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err != MMC_ERR_NONE) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = MMC_ERR_TIMEOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + +/* + * Discover cards by requesting their CID. If this command + * times out, it is not an error; there are no further cards + * to be discovered. Add new cards to the list. + * + * Create a mmc_card entry for each discovered card, assigning + * it an RCA, and save the raw CID for decoding later. + */ +static void mmc_discover_cards(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int first_rca = 1, err; + + while (1) { + struct mmc_command cmd; + + cmd.opcode = MMC_ALL_SEND_CID; + cmd.arg = 0; + cmd.flags = MMC_RSP_R2; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err == MMC_ERR_TIMEOUT) { + err = MMC_ERR_NONE; + break; + } + if (err != MMC_ERR_NONE) { + printk(KERN_ERR "%s: error requesting CID: %d\n", + host->host_name, err); + break; + } + + card = mmc_find_card(host, cmd.resp); + if (!card) { + card = mmc_alloc_card(host, cmd.resp, &first_rca); + if (IS_ERR(card)) { + err = PTR_ERR(card); + break; + } + list_add(&card->node, &host->cards); + } + + card->state &= ~MMC_STATE_DEAD; + + cmd.opcode = MMC_SET_RELATIVE_ADDR; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + mmc_card_set_dead(card); + } +} + +static void mmc_read_csds(struct mmc_host *host) +{ + struct mmc_card *card; + + list_for_each_entry(card, &host->cards, node) { + struct mmc_command cmd; + int err; + + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + + cmd.opcode = MMC_SEND_CSD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R2; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd)); + + mmc_decode_csd(card); + mmc_decode_cid(card); + } +} + +static unsigned int mmc_calculate_clock(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int max_dtr = host->f_max; + + list_for_each_entry(card, &host->cards, node) + if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) + max_dtr = card->csd.max_dtr; + + DBG("MMC: selected %d.%03dMHz transfer rate\n", + max_dtr / 1000000, (max_dtr / 1000) % 1000); + + return max_dtr; +} + +/* + * Check whether cards we already know about are still present. + * We do this by requesting status, and checking whether a card + * responds. + * + * A request for status does not cause a state change in data + * transfer mode. + */ +static void mmc_check_cards(struct mmc_host *host) +{ + struct list_head *l, *n; + + mmc_deselect_cards(host); + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + struct mmc_command cmd; + int err; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err == MMC_ERR_NONE) + continue; + + mmc_card_set_dead(card); + } +} + +static void mmc_setup(struct mmc_host *host) +{ + if (host->ios.power_mode != MMC_POWER_ON) { + int err; + u32 ocr; + + mmc_power_up(host); + mmc_idle_cards(host); + + err = mmc_send_op_cond(host, 0, &ocr); + if (err != MMC_ERR_NONE) + return; + + host->ocr = mmc_select_voltage(host, ocr); + + /* + * Since we're changing the OCR value, we seem to + * need to tell some cards to go back to the idle + * state. We wait 1ms to give cards time to + * respond. + */ + if (host->ocr) + mmc_idle_cards(host); + } else { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.clock = host->f_min; + host->ops->set_ios(host, &host->ios); + + /* + * We should remember the OCR mask from the existing + * cards, and detect the new cards OCR mask, combine + * the two and re-select the VDD. However, if we do + * change VDD, we should do an idle, and then do a + * full re-initialisation. We would need to notify + * drivers so that they can re-setup the cards as + * well, while keeping their queues at bay. + * + * For the moment, we take the easy way out - if the + * new cards don't like our currently selected VDD, + * they drop off the bus. + */ + } + + if (host->ocr == 0) + return; + + /* + * Send the selected OCR multiple times... until the cards + * all get the idea that they should be ready for CMD2. + * (My SanDisk card seems to need this.) + */ + mmc_send_op_cond(host, host->ocr, NULL); + + mmc_discover_cards(host); + + /* + * Ok, now switch to push-pull mode. + */ + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ops->set_ios(host, &host->ios); + + mmc_read_csds(host); +} + + +/** + * mmc_detect_change - process change of state on a MMC socket + * @host: host which changed state. + * + * All we know is that card(s) have been inserted or removed + * from the socket(s). We don't know which socket or cards. + */ +void mmc_detect_change(struct mmc_host *host) +{ + schedule_work(&host->detect); +} + +EXPORT_SYMBOL(mmc_detect_change); + + +static void mmc_rescan(void *data) +{ + struct mmc_host *host = data; + struct list_head *l, *n; + + mmc_claim_host(host); + + if (host->ios.power_mode == MMC_POWER_ON) + mmc_check_cards(host); + + mmc_setup(host); + + if (!list_empty(&host->cards)) { + /* + * (Re-)calculate the fastest clock rate which the + * attached cards and the host support. + */ + host->ios.clock = mmc_calculate_clock(host); + host->ops->set_ios(host, &host->ios); + } + + mmc_release_host(host); + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + /* + * If this is a new and good card, register it. + */ + if (!mmc_card_present(card) && !mmc_card_dead(card)) { + if (mmc_register_card(card)) + mmc_card_set_dead(card); + else + mmc_card_set_present(card); + } + + /* + * If this card is dead, destroy it. + */ + if (mmc_card_dead(card)) { + list_del(&card->node); + mmc_remove_card(card); + } + } + + /* + * If we discover that there are no cards on the + * bus, turn off the clock and power down. + */ + if (list_empty(&host->cards)) + mmc_power_off(host); +} + + +/** + * mmc_alloc_host - initialise the per-host structure. + * @extra: sizeof private data structure + * @dev: pointer to host device model structure + * + * Initialise the per-host structure. + */ +struct mmc_host *mmc_alloc_host(int extra, struct device *dev) +{ + struct mmc_host *host; + + host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + if (host) { + memset(host, 0, sizeof(struct mmc_host) + extra); + + spin_lock_init(&host->lock); + init_waitqueue_head(&host->wq); + INIT_LIST_HEAD(&host->cards); + INIT_WORK(&host->detect, mmc_rescan, host); + + host->dev = dev; + + /* + * By default, hosts do not support SGIO or large requests. + * They have to set these according to their abilities. + */ + host->max_hw_segs = 1; + host->max_phys_segs = 1; + host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); + host->max_seg_size = PAGE_CACHE_SIZE; + } + + return host; +} + +EXPORT_SYMBOL(mmc_alloc_host); + +/** + * mmc_add_host - initialise host hardware + * @host: mmc host + */ +int mmc_add_host(struct mmc_host *host) +{ + static unsigned int host_num; + + snprintf(host->host_name, sizeof(host->host_name), + "mmc%d", host_num++); + + mmc_power_off(host); + mmc_detect_change(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_add_host); + +/** + * mmc_remove_host - remove host hardware + * @host: mmc host + * + * Unregister and remove all cards associated with this host, + * and power down the MMC bus. + */ +void mmc_remove_host(struct mmc_host *host) +{ + struct list_head *l, *n; + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + mmc_remove_card(card); + } + + mmc_power_off(host); +} + +EXPORT_SYMBOL(mmc_remove_host); + +/** + * mmc_free_host - free the host structure + * @host: mmc host + * + * Free the host once all references to it have been dropped. + */ +void mmc_free_host(struct mmc_host *host) +{ + flush_scheduled_work(); + kfree(host); +} + +EXPORT_SYMBOL(mmc_free_host); + +#ifdef CONFIG_PM + +/** + * mmc_suspend_host - suspend a host + * @host: mmc host + * @state: suspend mode (PM_SUSPEND_xxx) + */ +int mmc_suspend_host(struct mmc_host *host, u32 state) +{ + mmc_claim_host(host); + mmc_deselect_cards(host); + mmc_power_off(host); + mmc_release_host(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_suspend_host); + +/** + * mmc_resume_host - resume a previously suspended host + * @host: mmc host + */ +int mmc_resume_host(struct mmc_host *host) +{ + mmc_detect_change(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_resume_host); + +#endif + +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h new file mode 100644 index 000000000..b498dffe0 --- /dev/null +++ b/drivers/mmc/mmc.h @@ -0,0 +1,16 @@ +/* + * linux/drivers/mmc/mmc.h + * + * Copyright (C) 2003 Russell King, 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 version 2 as + * published by the Free Software Foundation. + */ +#ifndef _MMC_H +#define _MMC_H +/* core-internal functions */ +void mmc_init_card(struct mmc_card *card, struct mmc_host *host); +int mmc_register_card(struct mmc_card *card); +void mmc_remove_card(struct mmc_card *card); +#endif diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c new file mode 100644 index 000000000..f76673a47 --- /dev/null +++ b/drivers/mmc/mmc_block.c @@ -0,0 +1,495 @@ +/* + * Block driver for media (i.e., flash cards) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Author: Andrew Christian + * 28 May 2002 + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "mmc_queue.h" + +/* + * max 8 partitions per card + */ +#define MMC_SHIFT 3 + +static int major; + +/* + * There is one mmc_blk_data per slot. + */ +struct mmc_blk_data { + spinlock_t lock; + struct gendisk *disk; + struct mmc_queue queue; + + unsigned int usage; + unsigned int block_bits; +}; + +static DECLARE_MUTEX(open_lock); + +static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) +{ + struct mmc_blk_data *md; + + down(&open_lock); + md = disk->private_data; + if (md && md->usage == 0) + md = NULL; + if (md) + md->usage++; + up(&open_lock); + + return md; +} + +static void mmc_blk_put(struct mmc_blk_data *md) +{ + down(&open_lock); + md->usage--; + if (md->usage == 0) { + put_disk(md->disk); + mmc_cleanup_queue(&md->queue); + kfree(md); + } + up(&open_lock); +} + +static int mmc_blk_open(struct inode *inode, struct file *filp) +{ + struct mmc_blk_data *md; + int ret = -ENXIO; + + md = mmc_blk_get(inode->i_bdev->bd_disk); + if (md) { + if (md->usage == 2) + check_disk_change(inode->i_bdev); + ret = 0; + } + + return ret; +} + +static int mmc_blk_release(struct inode *inode, struct file *filp) +{ + struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data; + + mmc_blk_put(md); + return 0; +} + +static int +mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct block_device *bdev = inode->i_bdev; + + if (cmd == HDIO_GETGEO) { + struct hd_geometry geo; + + memset(&geo, 0, sizeof(struct hd_geometry)); + + geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16); + geo.heads = 4; + geo.sectors = 16; + geo.start = get_start_sect(bdev); + + return copy_to_user((void __user *)arg, &geo, sizeof(geo)) + ? -EFAULT : 0; + } + + return -ENOTTY; +} + +static struct block_device_operations mmc_bdops = { + .open = mmc_blk_open, + .release = mmc_blk_release, + .ioctl = mmc_blk_ioctl, + .owner = THIS_MODULE, +}; + +struct mmc_blk_request { + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; +}; + +static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req) +{ + struct mmc_blk_data *md = mq->data; + int stat = BLKPREP_OK; + + /* + * If we have no device, we haven't finished initialising. + */ + if (!md || !mq->card) { + printk(KERN_ERR "%s: killing request - no device/host\n", + req->rq_disk->disk_name); + stat = BLKPREP_KILL; + } + + return stat; +} + +static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) +{ + struct mmc_blk_data *md = mq->data; + struct mmc_card *card = md->queue.card; + int ret; + + if (mmc_card_claim_host(card)) + goto cmd_err; + + do { + struct mmc_blk_request brq; + struct mmc_command cmd; + + memset(&brq, 0, sizeof(struct mmc_blk_request)); + brq.mrq.cmd = &brq.cmd; + brq.mrq.data = &brq.data; + + brq.cmd.arg = req->sector << 9; + brq.cmd.flags = MMC_RSP_R1; + brq.data.req = req; + brq.data.timeout_ns = card->csd.tacc_ns * 10; + brq.data.timeout_clks = card->csd.tacc_clks * 10; + brq.data.blksz_bits = md->block_bits; + brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); + brq.stop.opcode = MMC_STOP_TRANSMISSION; + brq.stop.arg = 0; + brq.stop.flags = MMC_RSP_R1B; + + if (rq_data_dir(req) == READ) { + brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; + brq.data.flags |= MMC_DATA_READ; + } else { + brq.cmd.opcode = MMC_WRITE_BLOCK; + brq.cmd.flags = MMC_RSP_R1B; + brq.data.flags |= MMC_DATA_WRITE; + brq.data.blocks = 1; + } + brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL; + + mmc_wait_for_req(card->host, &brq.mrq); + if (brq.cmd.error) { + printk(KERN_ERR "%s: error %d sending read/write command\n", + req->rq_disk->disk_name, brq.cmd.error); + goto cmd_err; + } + + if (brq.data.error) { + printk(KERN_ERR "%s: error %d transferring data\n", + req->rq_disk->disk_name, brq.data.error); + goto cmd_err; + } + + if (brq.stop.error) { + printk(KERN_ERR "%s: error %d sending stop command\n", + req->rq_disk->disk_name, brq.stop.error); + goto cmd_err; + } + + do { + int err; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1; + err = mmc_wait_for_cmd(card->host, &cmd, 5); + if (err) { + printk(KERN_ERR "%s: error %d requesting status\n", + req->rq_disk->disk_name, err); + goto cmd_err; + } + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + +#if 0 + if (cmd.resp[0] & ~0x00000900) + printk(KERN_ERR "%s: status = %08x\n", + req->rq_disk->disk_name, cmd.resp[0]); + if (mmc_decode_status(cmd.resp)) + goto cmd_err; +#endif + + /* + * A block was successfully transferred. + */ + spin_lock_irq(&md->lock); + ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); + if (!ret) { + /* + * The whole request completed successfully. + */ + add_disk_randomness(req->rq_disk); + blkdev_dequeue_request(req); + end_that_request_last(req); + } + spin_unlock_irq(&md->lock); + } while (ret); + + mmc_card_release_host(card); + + return 1; + + cmd_err: + mmc_card_release_host(card); + + /* + * This is a little draconian, but until we get proper + * error handling sorted out here, its the best we can + * do - especially as some hosts have no idea how much + * data was transferred before the error occurred. + */ + spin_lock_irq(&md->lock); + do { + ret = end_that_request_chunk(req, 0, + req->current_nr_sectors << 9); + } while (ret); + + add_disk_randomness(req->rq_disk); + blkdev_dequeue_request(req); + end_that_request_last(req); + spin_unlock_irq(&md->lock); + + return 0; +} + +#define MMC_NUM_MINORS (256 >> MMC_SHIFT) + +static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; + +static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) +{ + struct mmc_blk_data *md; + int devidx, ret; + + devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); + if (devidx >= MMC_NUM_MINORS) + return ERR_PTR(-ENOSPC); + __set_bit(devidx, dev_use); + + md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); + if (md) { + memset(md, 0, sizeof(struct mmc_blk_data)); + + md->disk = alloc_disk(1 << MMC_SHIFT); + if (md->disk == NULL) { + kfree(md); + md = ERR_PTR(-ENOMEM); + goto out; + } + + spin_lock_init(&md->lock); + md->usage = 1; + + ret = mmc_init_queue(&md->queue, card, &md->lock); + if (ret) { + put_disk(md->disk); + kfree(md); + md = ERR_PTR(ret); + goto out; + } + md->queue.prep_fn = mmc_blk_prep_rq; + md->queue.issue_fn = mmc_blk_issue_rq; + md->queue.data = md; + + md->disk->major = major; + md->disk->first_minor = devidx << MMC_SHIFT; + md->disk->fops = &mmc_bdops; + md->disk->private_data = md; + md->disk->queue = md->queue.queue; + md->disk->driverfs_dev = &card->dev; + + sprintf(md->disk->disk_name, "mmcblk%d", devidx); + sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); + + md->block_bits = card->csd.read_blkbits; + + blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); + set_capacity(md->disk, card->csd.capacity); + } + out: + return md; +} + +static int +mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) +{ + struct mmc_command cmd; + int err; + + mmc_card_claim_host(card); + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = 1 << card->csd.read_blkbits; + cmd.flags = MMC_RSP_R1; + err = mmc_wait_for_cmd(card->host, &cmd, 5); + mmc_card_release_host(card); + + if (err) { + printk(KERN_ERR "%s: unable to set block size to %d: %d\n", + md->disk->disk_name, cmd.arg, err); + return -EINVAL; + } + + return 0; +} + +static int mmc_blk_probe(struct mmc_card *card) +{ + struct mmc_blk_data *md; + int err; + + if (card->csd.cmdclass & ~0x1ff) + return -ENODEV; + + if (card->csd.read_blkbits < 9) { + printk(KERN_WARNING "%s: read blocksize too small (%u)\n", + mmc_card_id(card), 1 << card->csd.read_blkbits); + return -ENODEV; + } + + md = mmc_blk_alloc(card); + if (IS_ERR(md)) + return PTR_ERR(md); + + err = mmc_blk_set_blksize(md, card); + if (err) + goto out; + + printk(KERN_INFO "%s: %s %s %dKiB\n", + md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), + (card->csd.capacity << card->csd.read_blkbits) / 1024); + + mmc_set_drvdata(card, md); + add_disk(md->disk); + return 0; + + out: + mmc_blk_put(md); + + return err; +} + +static void mmc_blk_remove(struct mmc_card *card) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (md) { + int devidx; + + del_gendisk(md->disk); + + /* + * I think this is needed. + */ + md->disk->queue = NULL; + + devidx = md->disk->first_minor >> MMC_SHIFT; + __clear_bit(devidx, dev_use); + + mmc_blk_put(md); + } + mmc_set_drvdata(card, NULL); +} + +#ifdef CONFIG_PM +static int mmc_blk_suspend(struct mmc_card *card, u32 state) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (md) { + mmc_queue_suspend(&md->queue); + } + return 0; +} + +static int mmc_blk_resume(struct mmc_card *card) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (md) { + mmc_blk_set_blksize(md, card); + mmc_queue_resume(&md->queue); + } + return 0; +} +#else +#define mmc_blk_suspend NULL +#define mmc_blk_resume NULL +#endif + +static struct mmc_driver mmc_driver = { + .drv = { + .name = "mmcblk", + }, + .probe = mmc_blk_probe, + .remove = mmc_blk_remove, + .suspend = mmc_blk_suspend, + .resume = mmc_blk_resume, +}; + +static int __init mmc_blk_init(void) +{ + int res = -ENOMEM; + + res = register_blkdev(major, "mmc"); + if (res < 0) { + printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n", + major, res); + goto out; + } + if (major == 0) + major = res; + + devfs_mk_dir("mmc"); + return mmc_register_driver(&mmc_driver); + + out: + return res; +} + +static void __exit mmc_blk_exit(void) +{ + mmc_unregister_driver(&mmc_driver); + devfs_remove("mmc"); + unregister_blkdev(major, "mmc"); +} + +module_init(mmc_blk_init); +module_exit(mmc_blk_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver"); + +module_param(major, int, 0444); +MODULE_PARM_DESC(major, "specify the major device number for MMC block driver"); diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c new file mode 100644 index 000000000..e818b9233 --- /dev/null +++ b/drivers/mmc/mmc_queue.c @@ -0,0 +1,222 @@ +/* + * linux/drivers/mmc/mmc_queue.c + * + * Copyright (C) 2003 Russell King, 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 version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include + +#include +#include +#include "mmc_queue.h" + +#define MMC_QUEUE_EXIT (1 << 0) +#define MMC_QUEUE_SUSPENDED (1 << 1) + +/* + * Prepare a MMC request. Essentially, this means passing the + * preparation off to the media driver. The media driver will + * create a mmc_io_request in req->special. + */ +static int mmc_prep_request(struct request_queue *q, struct request *req) +{ + struct mmc_queue *mq = q->queuedata; + int ret = BLKPREP_KILL; + + if (req->flags & REQ_SPECIAL) { + /* + * Special commands already have the command + * blocks already setup in req->special. + */ + BUG_ON(!req->special); + + ret = BLKPREP_OK; + } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + /* + * Block I/O requests need translating according + * to the protocol. + */ + ret = mq->prep_fn(mq, req); + } else { + /* + * Everything else is invalid. + */ + blk_dump_rq_flags(req, "MMC bad request"); + } + + if (ret == BLKPREP_OK) + req->flags |= REQ_DONTPREP; + + return ret; +} + +static int mmc_queue_thread(void *d) +{ + struct mmc_queue *mq = d; + struct request_queue *q = mq->queue; + DECLARE_WAITQUEUE(wait, current); + + /* + * Set iothread to ensure that we aren't put to sleep by + * the process freezing. We handle suspension ourselves. + */ + current->flags |= PF_MEMALLOC|PF_NOFREEZE; + + daemonize("mmcqd"); + + complete(&mq->thread_complete); + + down(&mq->thread_sem); + add_wait_queue(&mq->thread_wq, &wait); + do { + struct request *req = NULL; + + spin_lock_irq(q->queue_lock); + set_current_state(TASK_INTERRUPTIBLE); + if (!blk_queue_plugged(q)) + mq->req = req = elv_next_request(q); + spin_unlock(q->queue_lock); + + if (!req) { + if (mq->flags & MMC_QUEUE_EXIT) + break; + up(&mq->thread_sem); + schedule(); + down(&mq->thread_sem); + continue; + } + set_current_state(TASK_RUNNING); + + mq->issue_fn(mq, req); + } while (1); + remove_wait_queue(&mq->thread_wq, &wait); + up(&mq->thread_sem); + + complete_and_exit(&mq->thread_complete, 0); + return 0; +} + +/* + * Generic MMC request handler. This is called for any queue on a + * particular host. When the host is not busy, we look for a request + * on any queue on this host, and attempt to issue it. This may + * not be the queue we were asked to process. + */ +static void mmc_request(request_queue_t *q) +{ + struct mmc_queue *mq = q->queuedata; + + if (!mq->req) + wake_up(&mq->thread_wq); +} + +/** + * mmc_init_queue - initialise a queue structure. + * @mq: mmc queue + * @card: mmc card to attach this queue + * @lock: queue lock + * + * Initialise a MMC card request queue. + */ +int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) +{ + struct mmc_host *host = card->host; + u64 limit = BLK_BOUNCE_HIGH; + int ret; + + if (host->dev->dma_mask && *host->dev->dma_mask) + limit = *host->dev->dma_mask; + + mq->card = card; + mq->queue = blk_init_queue(mmc_request, lock); + if (!mq->queue) + return -ENOMEM; + + blk_queue_prep_rq(mq->queue, mmc_prep_request); + blk_queue_bounce_limit(mq->queue, limit); + blk_queue_max_sectors(mq->queue, host->max_sectors); + blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); + blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); + blk_queue_max_segment_size(mq->queue, host->max_seg_size); + + mq->queue->queuedata = mq; + mq->req = NULL; + + init_completion(&mq->thread_complete); + init_waitqueue_head(&mq->thread_wq); + init_MUTEX(&mq->thread_sem); + + ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); + if (ret < 0) { + blk_cleanup_queue(mq->queue); + } else { + wait_for_completion(&mq->thread_complete); + init_completion(&mq->thread_complete); + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(mmc_init_queue); + +void mmc_cleanup_queue(struct mmc_queue *mq) +{ + mq->flags |= MMC_QUEUE_EXIT; + wake_up(&mq->thread_wq); + wait_for_completion(&mq->thread_complete); + blk_cleanup_queue(mq->queue); + + mq->card = NULL; +} +EXPORT_SYMBOL(mmc_cleanup_queue); + +/** + * mmc_queue_suspend - suspend a MMC request queue + * @mq: MMC queue to suspend + * + * Stop the block request queue, and wait for our thread to + * complete any outstanding requests. This ensures that we + * won't suspend while a request is being processed. + */ +void mmc_queue_suspend(struct mmc_queue *mq) +{ + request_queue_t *q = mq->queue; + unsigned long flags; + + if (!(mq->flags & MMC_QUEUE_SUSPENDED)) { + mq->flags |= MMC_QUEUE_SUSPENDED; + + spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + + down(&mq->thread_sem); + } +} +EXPORT_SYMBOL(mmc_queue_suspend); + +/** + * mmc_queue_resume - resume a previously suspended MMC request queue + * @mq: MMC queue to resume + */ +void mmc_queue_resume(struct mmc_queue *mq) +{ + request_queue_t *q = mq->queue; + unsigned long flags; + + if (mq->flags & MMC_QUEUE_SUSPENDED) { + mq->flags &= ~MMC_QUEUE_SUSPENDED; + + up(&mq->thread_sem); + + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + } +} +EXPORT_SYMBOL(mmc_queue_resume); diff --git a/drivers/mmc/mmc_queue.h b/drivers/mmc/mmc_queue.h new file mode 100644 index 000000000..6bef90087 --- /dev/null +++ b/drivers/mmc/mmc_queue.h @@ -0,0 +1,32 @@ +#ifndef MMC_QUEUE_H +#define MMC_QUEUE_H + +struct request; +struct task_struct; + +struct mmc_queue { + struct mmc_card *card; + struct completion thread_complete; + wait_queue_head_t thread_wq; + struct semaphore thread_sem; + unsigned int flags; + struct request *req; + int (*prep_fn)(struct mmc_queue *, struct request *); + int (*issue_fn)(struct mmc_queue *, struct request *); + void *data; + struct request_queue *queue; +}; + +struct mmc_io_request { + struct request *rq; + int num; + struct mmc_command selcmd; /* mmc_queue private */ + struct mmc_command cmd[4]; /* max 4 commands */ +}; + +extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *); +extern void mmc_cleanup_queue(struct mmc_queue *); +extern void mmc_queue_suspend(struct mmc_queue *); +extern void mmc_queue_resume(struct mmc_queue *); + +#endif diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c new file mode 100644 index 000000000..2b7ebdac7 --- /dev/null +++ b/drivers/mmc/mmc_sysfs.c @@ -0,0 +1,241 @@ +/* + * linux/drivers/mmc/mmc_sysfs.c + * + * Copyright (C) 2003 Russell King, 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 version 2 as + * published by the Free Software Foundation. + * + * MMC sysfs/driver model support. + */ +#include +#include +#include + +#include +#include + +#include "mmc.h" + +#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) +#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) + +static void mmc_release_card(struct device *dev) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + + kfree(card); +} + +/* + * This currently matches any MMC driver to any MMC card - drivers + * themselves make the decision whether to drive this card in their + * probe method. However, we force "bad" cards to fail. + */ +static int mmc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + return !mmc_card_bad(card); +} + +static int +mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf, + int buf_size) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + char ccc[13]; + int i = 0; + +#define add_env(fmt,val) \ + ({ \ + int len, ret = -ENOMEM; \ + if (i < num_envp) { \ + envp[i++] = buf; \ + len = snprintf(buf, buf_size, fmt, val) + 1; \ + buf_size -= len; \ + buf += len; \ + if (buf_size >= 0) \ + ret = 0; \ + } \ + ret; \ + }) + + for (i = 0; i < 12; i++) + ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; + ccc[12] = '\0'; + + i = 0; + add_env("MMC_CCC=%s", ccc); + add_env("MMC_MANFID=%06x", card->cid.manfid); + add_env("MMC_NAME=%s", mmc_card_name(card)); + add_env("MMC_OEMID=%04x", card->cid.oemid); + + return 0; +} + +static int mmc_bus_suspend(struct device *dev, u32 state) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + int ret = 0; + + if (dev->driver && drv->suspend) + ret = drv->suspend(card, state); + return ret; +} + +static int mmc_bus_resume(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + int ret = 0; + + if (dev->driver && drv->resume) + ret = drv->resume(card); + return ret; +} + +static struct bus_type mmc_bus_type = { + .name = "mmc", + .match = mmc_bus_match, + .hotplug = mmc_bus_hotplug, + .suspend = mmc_bus_suspend, + .resume = mmc_bus_resume, +}; + + +static int mmc_drv_probe(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + + return drv->probe(card); +} + +static int mmc_drv_remove(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = dev_to_mmc_card(dev); + + drv->remove(card); + + return 0; +} + + +/** + * mmc_register_driver - register a media driver + * @drv: MMC media driver + */ +int mmc_register_driver(struct mmc_driver *drv) +{ + drv->drv.bus = &mmc_bus_type; + drv->drv.probe = mmc_drv_probe; + drv->drv.remove = mmc_drv_remove; + return driver_register(&drv->drv); +} + +EXPORT_SYMBOL(mmc_register_driver); + +/** + * mmc_unregister_driver - unregister a media driver + * @drv: MMC media driver + */ +void mmc_unregister_driver(struct mmc_driver *drv) +{ + drv->drv.bus = &mmc_bus_type; + driver_unregister(&drv->drv); +} + +EXPORT_SYMBOL(mmc_unregister_driver); + + +#define MMC_ATTR(name, fmt, args...) \ +static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \ +{ \ + struct mmc_card *card = dev_to_mmc_card(dev); \ + return sprintf(buf, fmt, args); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL) + +MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], + card->raw_cid[2], card->raw_cid[3]); +MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], + card->raw_csd[2], card->raw_csd[3]); +MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); +MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev); +MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid); +MMC_ATTR(name, "%s\n", card->cid.prod_name); +MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid); +MMC_ATTR(serial, "0x%08x\n", card->cid.serial); + +static struct device_attribute *mmc_dev_attributes[] = { + &dev_attr_cid, + &dev_attr_csd, + &dev_attr_date, + &dev_attr_fwrev, + &dev_attr_hwrev, + &dev_attr_manfid, + &dev_attr_name, + &dev_attr_oemid, + &dev_attr_serial, +}; + +/* + * Internal function. Initialise a MMC card structure. + */ +void mmc_init_card(struct mmc_card *card, struct mmc_host *host) +{ + memset(card, 0, sizeof(struct mmc_card)); + card->host = host; + device_initialize(&card->dev); + card->dev.parent = card->host->dev; + card->dev.bus = &mmc_bus_type; + card->dev.release = mmc_release_card; +} + +/* + * Internal function. Register a new MMC card with the driver model. + */ +int mmc_register_card(struct mmc_card *card) +{ + int ret, i; + + snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), + "%s:%04x", card->host->host_name, card->rca); + + ret = device_add(&card->dev); + if (ret == 0) + for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++) + device_create_file(&card->dev, mmc_dev_attributes[i]); + + return ret; +} + +/* + * Internal function. Unregister a new MMC card with the + * driver model, and (eventually) free it. + */ +void mmc_remove_card(struct mmc_card *card) +{ + if (mmc_card_present(card)) + device_del(&card->dev); + + put_device(&card->dev); +} + + +static int __init mmc_init(void) +{ + return bus_register(&mmc_bus_type); +} + +static void __exit mmc_exit(void) +{ + bus_unregister(&mmc_bus_type); +} + +module_init(mmc_init); +module_exit(mmc_exit); diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c new file mode 100644 index 000000000..47e1636de --- /dev/null +++ b/drivers/mmc/mmci.c @@ -0,0 +1,679 @@ +/* + * linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mmci.h" + +#define DRIVER_NAME "mmci-pl18x" + +#ifdef CONFIG_MMC_DEBUG +#define DBG(host,fmt,args...) \ + pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args) +#else +#define DBG(host,fmt,args...) do { } while (0) +#endif + +static unsigned int fmax = 515633; + +static void +mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) +{ + writel(0, host->base + MMCICOMMAND); + + host->mrq = NULL; + host->cmd = NULL; + + if (mrq->data) + mrq->data->bytes_xfered = host->data_xfered; + + /* + * Need to drop the host lock here; mmc_request_done may call + * back into the driver... + */ + spin_unlock(&host->lock); + mmc_request_done(host->mmc, mrq); + spin_lock(&host->lock); +} + +static void mmci_stop_data(struct mmci_host *host) +{ + writel(0, host->base + MMCIDATACTRL); + writel(0, host->base + MMCIMASK1); + host->data = NULL; +} + +static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) +{ + unsigned int datactrl, timeout, irqmask; + void *base; + + DBG(host, "blksz %04x blks %04x flags %08x\n", + 1 << data->blksz_bits, data->blocks, data->flags); + + host->data = data; + host->size = data->blocks << data->blksz_bits; + host->data_xfered = 0; + + mmci_init_sg(host, data); + + timeout = data->timeout_clks + + ((unsigned long long)data->timeout_ns * host->cclk) / + 1000000000ULL; + + base = host->base; + writel(timeout, base + MMCIDATATIMER); + writel(host->size, base + MMCIDATALENGTH); + + datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; + if (data->flags & MMC_DATA_READ) { + datactrl |= MCI_DPSM_DIRECTION; + irqmask = MCI_RXFIFOHALFFULLMASK; + } else { + /* + * We don't actually need to include "FIFO empty" here + * since its implicit in "FIFO half empty". + */ + irqmask = MCI_TXFIFOHALFEMPTYMASK; + } + + writel(datactrl, base + MMCIDATACTRL); + writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); + writel(irqmask, base + MMCIMASK1); +} + +static void +mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) +{ + void *base = host->base; + + DBG(host, "op %02x arg %08x flags %08x\n", + cmd->opcode, cmd->arg, cmd->flags); + + if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { + writel(0, base + MMCICOMMAND); + udelay(1); + } + + c |= cmd->opcode | MCI_CPSM_ENABLE; + switch (cmd->flags & MMC_RSP_MASK) { + case MMC_RSP_NONE: + default: + break; + case MMC_RSP_LONG: + c |= MCI_CPSM_LONGRSP; + case MMC_RSP_SHORT: + c |= MCI_CPSM_RESPONSE; + break; + } + if (/*interrupt*/0) + c |= MCI_CPSM_INTERRUPT; + + host->cmd = cmd; + + writel(cmd->arg, base + MMCIARGUMENT); + writel(c, base + MMCICOMMAND); +} + +static void +mmci_data_irq(struct mmci_host *host, struct mmc_data *data, + unsigned int status) +{ + if (status & MCI_DATABLOCKEND) { + host->data_xfered += 1 << data->blksz_bits; + } + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + if (status & MCI_DATACRCFAIL) + data->error = MMC_ERR_BADCRC; + else if (status & MCI_DATATIMEOUT) + data->error = MMC_ERR_TIMEOUT; + else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) + data->error = MMC_ERR_FIFO; + status |= MCI_DATAEND; + } + if (status & MCI_DATAEND) { + mmci_stop_data(host); + + if (!data->stop) { + mmci_request_end(host, data->mrq); + } else { + mmci_start_command(host, data->stop, 0); + } + } +} + +static void +mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + unsigned int status) +{ + void *base = host->base; + + host->cmd = NULL; + + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); + cmd->resp[2] = readl(base + MMCIRESPONSE2); + cmd->resp[3] = readl(base + MMCIRESPONSE3); + + if (status & MCI_CMDTIMEOUT) { + cmd->error = MMC_ERR_TIMEOUT; + } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { + cmd->error = MMC_ERR_BADCRC; + } + + if (!cmd->data || cmd->error != MMC_ERR_NONE) { + mmci_request_end(host, cmd->mrq); + } else if (!(cmd->data->flags & MMC_DATA_READ)) { + mmci_start_data(host, cmd->data); + } +} + +static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) +{ + void *base = host->base; + char *ptr = buffer; + u32 status; + + do { + int count = host->size - (readl(base + MMCIFIFOCNT) << 2); + + if (count > remain) + count = remain; + + if (count <= 0) + break; + + readsl(base + MMCIFIFO, ptr, count >> 2); + + ptr += count; + remain -= count; + + if (remain == 0) + break; + + status = readl(base + MMCISTATUS); + } while (status & MCI_RXDATAAVLBL); + + return ptr - buffer; +} + +static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) +{ + void *base = host->base; + char *ptr = buffer; + + do { + unsigned int count, maxcnt; + + maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; + count = min(remain, maxcnt); + + writesl(base + MMCIFIFO, ptr, count >> 2); + + ptr += count; + remain -= count; + + if (remain == 0) + break; + + status = readl(base + MMCISTATUS); + } while (status & MCI_TXFIFOHALFEMPTY); + + return ptr - buffer; +} + +/* + * PIO data transfer IRQ handler. + */ +static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmci_host *host = dev_id; + void *base = host->base; + u32 status; + + status = readl(base + MMCISTATUS); + + DBG(host, "irq1 %08x\n", status); + + do { + unsigned long flags; + unsigned int remain, len; + char *buffer; + + /* + * For write, we only need to test the half-empty flag + * here - if the FIFO is completely empty, then by + * definition it is more than half empty. + * + * For read, check for data available. + */ + if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) + break; + + /* + * Map the current scatter buffer. + */ + buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; + remain = host->sg_ptr->length - host->sg_off; + + len = 0; + if (status & MCI_RXACTIVE) + len = mmci_pio_read(host, buffer, remain); + if (status & MCI_TXACTIVE) + len = mmci_pio_write(host, buffer, remain, status); + + /* + * Unmap the buffer. + */ + mmci_kunmap_atomic(host, &flags); + + host->sg_off += len; + host->size -= len; + remain -= len; + + if (remain) + break; + + if (!mmci_next_sg(host)) + break; + + status = readl(base + MMCISTATUS); + } while (1); + + /* + * If we're nearing the end of the read, switch to + * "any data available" mode. + */ + if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) + writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + + /* + * If we run out of data, disable the data IRQs; this + * prevents a race where the FIFO becomes empty before + * the chip itself has disabled the data path, and + * stops us racing with our data end IRQ. + */ + if (host->size == 0) { + writel(0, base + MMCIMASK1); + writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); + } + + return IRQ_HANDLED; +} + +/* + * Handle completion of command and data transfers. + */ +static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmci_host *host = dev_id; + u32 status; + int ret = 0; + + spin_lock(&host->lock); + + do { + struct mmc_command *cmd; + struct mmc_data *data; + + status = readl(host->base + MMCISTATUS); + status &= readl(host->base + MMCIMASK0); + writel(status, host->base + MMCICLEAR); + + DBG(host, "irq0 %08x\n", status); + + data = host->data; + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| + MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) + mmci_data_irq(host, data, status); + + cmd = host->cmd; + if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) + mmci_cmd_irq(host, cmd, status); + + ret = 1; + } while (status); + + spin_unlock(&host->lock); + + return IRQ_RETVAL(ret); +} + +static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmci_host *host = mmc_priv(mmc); + + WARN_ON(host->mrq != NULL); + + spin_lock_irq(&host->lock); + + host->mrq = mrq; + + if (mrq->data && mrq->data->flags & MMC_DATA_READ) + mmci_start_data(host, mrq->data); + + mmci_start_command(host, mrq->cmd, 0); + + spin_unlock_irq(&host->lock); +} + +static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmci_host *host = mmc_priv(mmc); + u32 clk = 0, pwr = 0; + + DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", + ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); + + if (ios->clock) { + if (ios->clock >= host->mclk) { + clk = MCI_CLK_BYPASS; + host->cclk = host->mclk; + } else { + clk = host->mclk / (2 * ios->clock) - 1; + if (clk > 256) + clk = 255; + host->cclk = host->mclk / (2 * (clk + 1)); + } + clk |= MCI_CLK_ENABLE; + } + + if (host->plat->translate_vdd) + pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); + + switch (ios->power_mode) { + case MMC_POWER_OFF: + break; + case MMC_POWER_UP: + pwr |= MCI_PWR_UP; + break; + case MMC_POWER_ON: + pwr |= MCI_PWR_ON; + break; + } + + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) + pwr |= MCI_ROD; + + writel(clk, host->base + MMCICLOCK); + + if (host->pwr != pwr) { + host->pwr = pwr; + writel(pwr, host->base + MMCIPOWER); + } +} + +static struct mmc_host_ops mmci_ops = { + .request = mmci_request, + .set_ios = mmci_set_ios, +}; + +static void mmci_check_status(unsigned long data) +{ + struct mmci_host *host = (struct mmci_host *)data; + unsigned int status; + + status = host->plat->status(mmc_dev(host->mmc)); + if (status ^ host->oldstat) + mmc_detect_change(host->mmc); + + host->oldstat = status; + mod_timer(&host->timer, jiffies + HZ); +} + +static int mmci_probe(struct amba_device *dev, void *id) +{ + struct mmc_platform_data *plat = dev->dev.platform_data; + struct mmci_host *host; + struct mmc_host *mmc; + int ret; + + /* must have platform data */ + if (!plat) { + ret = -EINVAL; + goto out; + } + + ret = amba_request_regions(dev, DRIVER_NAME); + if (ret) + goto out; + + mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); + if (!mmc) { + ret = -ENOMEM; + goto rel_regions; + } + + host = mmc_priv(mmc); + host->clk = clk_get(&dev->dev, "MCLK"); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + host->clk = NULL; + goto host_free; + } + + ret = clk_use(host->clk); + if (ret) + goto clk_free; + + ret = clk_enable(host->clk); + if (ret) + goto clk_unuse; + + host->plat = plat; + host->mclk = clk_get_rate(host->clk); + host->mmc = mmc; + host->base = ioremap(dev->res.start, SZ_4K); + if (!host->base) { + ret = -ENOMEM; + goto clk_disable; + } + + mmc->ops = &mmci_ops; + mmc->f_min = (host->mclk + 511) / 512; + mmc->f_max = min(host->mclk, fmax); + mmc->ocr_avail = plat->ocr_mask; + + /* + * We can do SGIO + */ + mmc->max_hw_segs = 16; + mmc->max_phys_segs = 16; + + /* + * Since we only have a 16-bit data length register, we must + * ensure that we don't exceed 2^16-1 bytes in a single request. + * Choose 64 (512-byte) sectors as the limit. + */ + mmc->max_sectors = 64; + + /* + * Set the maximum segment size. Since we aren't doing DMA + * (yet) we are only limited by the data length register. + */ + mmc->max_seg_size = mmc->max_sectors << 9; + + spin_lock_init(&host->lock); + + writel(0, host->base + MMCIMASK0); + writel(0, host->base + MMCIMASK1); + writel(0xfff, host->base + MMCICLEAR); + + ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host); + if (ret) + goto unmap; + + ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host); + if (ret) + goto irq0_free; + + writel(MCI_IRQENABLE, host->base + MMCIMASK0); + + amba_set_drvdata(dev, mmc); + + mmc_add_host(mmc); + + printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n", + mmc->host_name, amba_rev(dev), amba_config(dev), + dev->res.start, dev->irq[0], dev->irq[1]); + + init_timer(&host->timer); + host->timer.data = (unsigned long)host; + host->timer.function = mmci_check_status; + host->timer.expires = jiffies + HZ; + add_timer(&host->timer); + + return 0; + + irq0_free: + free_irq(dev->irq[0], host); + unmap: + iounmap(host->base); + clk_disable: + clk_disable(host->clk); + clk_unuse: + clk_unuse(host->clk); + clk_free: + clk_put(host->clk); + host_free: + mmc_free_host(mmc); + rel_regions: + amba_release_regions(dev); + out: + return ret; +} + +static int mmci_remove(struct amba_device *dev) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + + del_timer_sync(&host->timer); + + mmc_remove_host(mmc); + + writel(0, host->base + MMCIMASK0); + writel(0, host->base + MMCIMASK1); + + writel(0, host->base + MMCICOMMAND); + writel(0, host->base + MMCIDATACTRL); + + free_irq(dev->irq[0], host); + free_irq(dev->irq[1], host); + + iounmap(host->base); + clk_disable(host->clk); + clk_unuse(host->clk); + clk_put(host->clk); + + mmc_free_host(mmc); + + amba_release_regions(dev); + } + + return 0; +} + +#ifdef CONFIG_PM +static int mmci_suspend(struct amba_device *dev, u32 state) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + int ret = 0; + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + + ret = mmc_suspend_host(mmc, state); + if (ret == 0) + writel(0, host->base + MMCIMASK0); + } + + return ret; +} + +static int mmci_resume(struct amba_device *dev) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + int ret = 0; + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + + writel(MCI_IRQENABLE, host->base + MMCIMASK0); + + ret = mmc_resume_host(mmc); + } + + return ret; +} +#else +#define mmci_suspend NULL +#define mmci_resume NULL +#endif + +static struct amba_id mmci_ids[] = { + { + .id = 0x00041180, + .mask = 0x000fffff, + }, + { + .id = 0x00041181, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver mmci_driver = { + .drv = { + .name = DRIVER_NAME, + }, + .probe = mmci_probe, + .remove = mmci_remove, + .suspend = mmci_suspend, + .resume = mmci_resume, + .id_table = mmci_ids, +}; + +static int __init mmci_init(void) +{ + return amba_driver_register(&mmci_driver); +} + +static void __exit mmci_exit(void) +{ + amba_driver_unregister(&mmci_driver); +} + +module_init(mmci_init); +module_exit(mmci_exit); +module_param(fmax, uint, 0444); + +MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h new file mode 100644 index 000000000..ce3a026d1 --- /dev/null +++ b/drivers/mmc/mmci.h @@ -0,0 +1,183 @@ +/* + * linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 version 2 as + * published by the Free Software Foundation. + */ +#define MMCIPOWER 0x000 +#define MCI_PWR_OFF 0x00 +#define MCI_PWR_UP 0x02 +#define MCI_PWR_ON 0x03 +#define MCI_OD (1 << 6) +#define MCI_ROD (1 << 7) + +#define MMCICLOCK 0x004 +#define MCI_CLK_ENABLE (1 << 8) +#define MCI_CLK_PWRSAVE (1 << 9) +#define MCI_CLK_BYPASS (1 << 10) + +#define MMCIARGUMENT 0x008 +#define MMCICOMMAND 0x00c +#define MCI_CPSM_RESPONSE (1 << 6) +#define MCI_CPSM_LONGRSP (1 << 7) +#define MCI_CPSM_INTERRUPT (1 << 8) +#define MCI_CPSM_PENDING (1 << 9) +#define MCI_CPSM_ENABLE (1 << 10) + +#define MMCIRESPCMD 0x010 +#define MMCIRESPONSE0 0x014 +#define MMCIRESPONSE1 0x018 +#define MMCIRESPONSE2 0x01c +#define MMCIRESPONSE3 0x020 +#define MMCIDATATIMER 0x024 +#define MMCIDATALENGTH 0x028 +#define MMCIDATACTRL 0x02c +#define MCI_DPSM_ENABLE (1 << 0) +#define MCI_DPSM_DIRECTION (1 << 1) +#define MCI_DPSM_MODE (1 << 2) +#define MCI_DPSM_DMAENABLE (1 << 3) + +#define MMCIDATACNT 0x030 +#define MMCISTATUS 0x034 +#define MCI_CMDCRCFAIL (1 << 0) +#define MCI_DATACRCFAIL (1 << 1) +#define MCI_CMDTIMEOUT (1 << 2) +#define MCI_DATATIMEOUT (1 << 3) +#define MCI_TXUNDERRUN (1 << 4) +#define MCI_RXOVERRUN (1 << 5) +#define MCI_CMDRESPEND (1 << 6) +#define MCI_CMDSENT (1 << 7) +#define MCI_DATAEND (1 << 8) +#define MCI_DATABLOCKEND (1 << 10) +#define MCI_CMDACTIVE (1 << 11) +#define MCI_TXACTIVE (1 << 12) +#define MCI_RXACTIVE (1 << 13) +#define MCI_TXFIFOHALFEMPTY (1 << 14) +#define MCI_RXFIFOHALFFULL (1 << 15) +#define MCI_TXFIFOFULL (1 << 16) +#define MCI_RXFIFOFULL (1 << 17) +#define MCI_TXFIFOEMPTY (1 << 18) +#define MCI_RXFIFOEMPTY (1 << 19) +#define MCI_TXDATAAVLBL (1 << 20) +#define MCI_RXDATAAVLBL (1 << 21) + +#define MMCICLEAR 0x038 +#define MCI_CMDCRCFAILCLR (1 << 0) +#define MCI_DATACRCFAILCLR (1 << 1) +#define MCI_CMDTIMEOUTCLR (1 << 2) +#define MCI_DATATIMEOUTCLR (1 << 3) +#define MCI_TXUNDERRUNCLR (1 << 4) +#define MCI_RXOVERRUNCLR (1 << 5) +#define MCI_CMDRESPENDCLR (1 << 6) +#define MCI_CMDSENTCLR (1 << 7) +#define MCI_DATAENDCLR (1 << 8) +#define MCI_DATABLOCKENDCLR (1 << 10) + +#define MMCIMASK0 0x03c +#define MCI_CMDCRCFAILMASK (1 << 0) +#define MCI_DATACRCFAILMASK (1 << 1) +#define MCI_CMDTIMEOUTMASK (1 << 2) +#define MCI_DATATIMEOUTMASK (1 << 3) +#define MCI_TXUNDERRUNMASK (1 << 4) +#define MCI_RXOVERRUNMASK (1 << 5) +#define MCI_CMDRESPENDMASK (1 << 6) +#define MCI_CMDSENTMASK (1 << 7) +#define MCI_DATAENDMASK (1 << 8) +#define MCI_DATABLOCKENDMASK (1 << 10) +#define MCI_CMDACTIVEMASK (1 << 11) +#define MCI_TXACTIVEMASK (1 << 12) +#define MCI_RXACTIVEMASK (1 << 13) +#define MCI_TXFIFOHALFEMPTYMASK (1 << 14) +#define MCI_RXFIFOHALFFULLMASK (1 << 15) +#define MCI_TXFIFOFULLMASK (1 << 16) +#define MCI_RXFIFOFULLMASK (1 << 17) +#define MCI_TXFIFOEMPTYMASK (1 << 18) +#define MCI_RXFIFOEMPTYMASK (1 << 19) +#define MCI_TXDATAAVLBLMASK (1 << 20) +#define MCI_RXDATAAVLBLMASK (1 << 21) + +#define MMCIMASK1 0x040 +#define MMCIFIFOCNT 0x048 +#define MMCIFIFO 0x080 /* to 0x0bc */ + +#define MCI_IRQENABLE \ + (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ + MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ + MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) + +/* + * The size of the FIFO in bytes. + */ +#define MCI_FIFOSIZE (16*4) + +#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) + +#define NR_SG 16 + +struct clk; + +struct mmci_host { + void *base; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + struct mmc_host *mmc; + struct clk *clk; + + unsigned int data_xfered; + + spinlock_t lock; + + unsigned int mclk; + unsigned int cclk; + u32 pwr; + struct mmc_platform_data *plat; + + struct timer_list timer; + unsigned int oldstat; + + struct scatterlist sg[NR_SG]; + unsigned int sg_len; + + /* pio stuff */ + struct scatterlist *sg_ptr; + unsigned int sg_off; + unsigned int size; +}; + +static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) +{ + struct scatterlist *sg = host->sg; + struct request *req = data->req; + + /* + * Ideally, we want the higher levels to pass us a scatter list. + */ + host->sg_len = blk_rq_map_sg(req->q, req, sg); + host->sg_ptr = sg; + host->sg_off = 0; +} + +static inline int mmci_next_sg(struct mmci_host *host) +{ + host->sg_ptr++; + host->sg_off = 0; + return --host->sg_len; +} + +static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags) +{ + struct scatterlist *sg = host->sg_ptr; + + local_irq_save(*flags); + return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; +} + +static inline void mmci_kunmap_atomic(struct mmci_host *host, unsigned long *flags) +{ + kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); + local_irq_restore(*flags); +} diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c new file mode 100644 index 000000000..23a509196 --- /dev/null +++ b/drivers/mmc/pxamci.c @@ -0,0 +1,604 @@ +/* + * linux/drivers/mmc/pxa.c - PXA MMCI driver + * + * Copyright (C) 2003 Russell King, 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 version 2 as + * published by the Free Software Foundation. + * + * This hardware is really sick: + * - No way to clear interrupts. + * - Have to turn off the clock whenever we touch the device. + * - Doesn't tell you how many data blocks were transferred. + * Yuck! + * + * 1 and 3 byte data transfers not supported + * max block length up to 1023 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "pxamci.h" + +#ifdef CONFIG_MMC_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) do { } while (0) +#endif + +struct pxamci_host { + struct mmc_host *mmc; + spinlock_t lock; + struct resource *res; + void *base; + int irq; + int dma; + unsigned int clkrt; + unsigned int cmdat; + unsigned int imask; + unsigned int power_mode; + struct pxamci_platform_data *pdata; + + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + + dma_addr_t sg_dma; + struct pxa_dma_desc *sg_cpu; + + dma_addr_t dma_buf; + unsigned int dma_size; + unsigned int dma_dir; +}; + +/* + * The base MMC clock rate + */ +#define CLOCKRATE 20000000 + +static inline unsigned int ns_to_clocks(unsigned int ns) +{ + return (ns * (CLOCKRATE / 1000000) + 999) / 1000; +} + +static void pxamci_stop_clock(struct pxamci_host *host) +{ + if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { + unsigned long timeout = 10000; + unsigned int v; + + writel(STOP_CLOCK, host->base + MMC_STRPCL); + + do { + v = readl(host->base + MMC_STAT); + if (!(v & STAT_CLK_EN)) + break; + udelay(1); + } while (timeout--); + + if (v & STAT_CLK_EN) + dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); + } +} + +static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->imask &= ~mask; + writel(host->imask, host->base + MMC_I_MASK); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->imask |= mask; + writel(host->imask, host->base + MMC_I_MASK); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) +{ + unsigned int nob = data->blocks; + unsigned int timeout, size; + dma_addr_t dma; + u32 dcmd; + int i; + + host->data = data; + + if (data->flags & MMC_DATA_STREAM) + nob = 0xffff; + + writel(nob, host->base + MMC_NOB); + writel(1 << data->blksz_bits, host->base + MMC_BLKLEN); + + timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks; + writel((timeout + 255) / 256, host->base + MMC_RDTO); + + if (data->flags & MMC_DATA_READ) { + host->dma_dir = DMA_FROM_DEVICE; + dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; + DRCMRTXMMC = 0; + DRCMRRXMMC = host->dma | DRCMR_MAPVLD; + } else { + host->dma_dir = DMA_TO_DEVICE; + dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; + DRCMRRXMMC = 0; + DRCMRTXMMC = host->dma | DRCMR_MAPVLD; + } + + dcmd |= DCMD_BURST32 | DCMD_WIDTH1; + + host->dma_size = data->blocks << data->blksz_bits; + host->dma_buf = dma_map_single(mmc_dev(host->mmc), data->req->buffer, + host->dma_size, host->dma_dir); + + for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) { + u32 len = size; + + if (len > DCMD_LENGTH) + len = 0x1000; + + if (data->flags & MMC_DATA_READ) { + host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; + host->sg_cpu[i].dtadr = dma; + } else { + host->sg_cpu[i].dsadr = dma; + host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; + } + host->sg_cpu[i].dcmd = dcmd | len; + + dma += len; + size -= len; + + if (size) { + host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * + sizeof(struct pxa_dma_desc); + } else { + host->sg_cpu[i].ddadr = DDADR_STOP; + } + } + wmb(); + + DDADR(host->dma) = host->sg_dma; + DCSR(host->dma) = DCSR_RUN; +} + +static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) +{ + WARN_ON(host->cmd != NULL); + host->cmd = cmd; + + if (cmd->flags & MMC_RSP_BUSY) + cmdat |= CMDAT_BUSY; + + switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) { + case MMC_RSP_SHORT | MMC_RSP_CRC: + cmdat |= CMDAT_RESP_SHORT; + break; + case MMC_RSP_SHORT: + cmdat |= CMDAT_RESP_R3; + break; + case MMC_RSP_LONG | MMC_RSP_CRC: + cmdat |= CMDAT_RESP_R2; + break; + default: + break; + } + + writel(cmd->opcode, host->base + MMC_CMD); + writel(cmd->arg >> 16, host->base + MMC_ARGH); + writel(cmd->arg & 0xffff, host->base + MMC_ARGL); + writel(cmdat, host->base + MMC_CMDAT); + writel(host->clkrt, host->base + MMC_CLKRT); + + writel(START_CLOCK, host->base + MMC_STRPCL); + + pxamci_enable_irq(host, END_CMD_RES); +} + +static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) +{ + DBG("PXAMCI: request done\n"); + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + mmc_request_done(host->mmc, mrq); +} + +static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) +{ + struct mmc_command *cmd = host->cmd; + int i; + u32 v; + + if (!cmd) + return 0; + + host->cmd = NULL; + + /* + * Did I mention this is Sick. We always need to + * discard the upper 8 bits of the first 16-bit word. + */ + v = readl(host->base + MMC_RES) & 0xffff; + for (i = 0; i < 4; i++) { + u32 w1 = readl(host->base + MMC_RES) & 0xffff; + u32 w2 = readl(host->base + MMC_RES) & 0xffff; + cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; + v = w2; + } + + if (stat & STAT_TIME_OUT_RESPONSE) { + cmd->error = MMC_ERR_TIMEOUT; + } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { + cmd->error = MMC_ERR_BADCRC; + } + + pxamci_disable_irq(host, END_CMD_RES); + if (host->data && cmd->error == MMC_ERR_NONE) { + pxamci_enable_irq(host, DATA_TRAN_DONE); + } else { + pxamci_finish_request(host, host->mrq); + } + + return 1; +} + +static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + + if (!data) + return 0; + + DCSR(host->dma) = 0; + dma_unmap_single(mmc_dev(host->mmc), host->dma_buf, host->dma_size, + host->dma_dir); + + if (stat & STAT_READ_TIME_OUT) + data->error = MMC_ERR_TIMEOUT; + else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) + data->error = MMC_ERR_BADCRC; + + /* + * There appears to be a hardware design bug here. There seems to + * be no way to find out how much data was transferred to the card. + * This means that if there was an error on any block, we mark all + * data blocks as being in error. + */ + if (data->error == MMC_ERR_NONE) + data->bytes_xfered = data->blocks << data->blksz_bits; + else + data->bytes_xfered = 0; + + pxamci_disable_irq(host, DATA_TRAN_DONE); + + host->data = NULL; + if (host->mrq->stop && data->error == MMC_ERR_NONE) { + pxamci_stop_clock(host); + pxamci_start_cmd(host, host->mrq->stop, 0); + } else { + pxamci_finish_request(host, host->mrq); + } + + return 1; +} + +static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct pxamci_host *host = devid; + unsigned int ireg; + int handled = 0; + + ireg = readl(host->base + MMC_I_REG); + + DBG("PXAMCI: irq %08x\n", ireg); + + if (ireg) { + unsigned stat = readl(host->base + MMC_STAT); + + DBG("PXAMCI: stat %08x\n", stat); + + if (ireg & END_CMD_RES) + handled |= pxamci_cmd_done(host, stat); + if (ireg & DATA_TRAN_DONE) + handled |= pxamci_data_done(host, stat); + } + + return IRQ_RETVAL(handled); +} + +static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct pxamci_host *host = mmc_priv(mmc); + unsigned int cmdat; + + WARN_ON(host->mrq != NULL); + + host->mrq = mrq; + + pxamci_stop_clock(host); + + cmdat = host->cmdat; + host->cmdat &= ~CMDAT_INIT; + + if (mrq->data) { + pxamci_setup_data(host, mrq->data); + + cmdat &= ~CMDAT_BUSY; + cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; + if (mrq->data->flags & MMC_DATA_WRITE) + cmdat |= CMDAT_WRITE; + + if (mrq->data->flags & MMC_DATA_STREAM) + cmdat |= CMDAT_STREAM; + } + + pxamci_start_cmd(host, mrq->cmd, cmdat); +} + +static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct pxamci_host *host = mmc_priv(mmc); + + DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", + ios->clock, ios->power_mode, ios->vdd / 100, + ios->vdd % 100); + + if (ios->clock) { + unsigned int clk = CLOCKRATE / ios->clock; + if (CLOCKRATE / clk > ios->clock) + clk <<= 1; + host->clkrt = fls(clk) - 1; + + /* + * we write clkrt on the next command + */ + } else if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { + /* + * Ensure that the clock is off. + */ + writel(STOP_CLOCK, host->base + MMC_STRPCL); + } + + if (host->power_mode != ios->power_mode) { + host->power_mode = ios->power_mode; + + if (host->pdata && host->pdata->setpower) + host->pdata->setpower(mmc->dev, ios->vdd); + + if (ios->power_mode == MMC_POWER_ON) + host->cmdat |= CMDAT_INIT; + } + + DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n", + host->clkrt, host->cmdat); +} + +static struct mmc_host_ops pxamci_ops = { + .request = pxamci_request, + .set_ios = pxamci_set_ios, +}; + +static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs) +{ + printk(KERN_ERR "DMA%d: IRQ???\n", dma); + DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; +} + +static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs) +{ + mmc_detect_change(devid); + return IRQ_HANDLED; +} + +static int pxamci_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mmc_host *mmc; + struct pxamci_host *host = NULL; + struct resource *r; + int ret, irq; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!r || irq == NO_IRQ) + return -ENXIO; + + r = request_mem_region(r->start, SZ_4K, "PXAMCI"); + if (!r) + return -EBUSY; + + mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + mmc->ops = &pxamci_ops; + mmc->f_min = 312500; + mmc->f_max = 20000000; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->dma = -1; + host->pdata = pdev->dev.platform_data; + mmc->ocr_avail = host->pdata ? + host->pdata->ocr_mask : + MMC_VDD_32_33|MMC_VDD_33_34; + + host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); + if (!host->sg_cpu) { + ret = -ENOMEM; + goto out; + } + + spin_lock_init(&host->lock); + host->res = r; + host->irq = irq; + host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| + END_CMD_RES|PRG_DONE|DATA_TRAN_DONE; + + host->base = ioremap(r->start, SZ_4K); + if (!host->base) { + ret = -ENOMEM; + goto out; + } + + /* + * Ensure that the host controller is shut down, and setup + * with our defaults. + */ + pxamci_stop_clock(host); + writel(0, host->base + MMC_SPI); + writel(64, host->base + MMC_RESTO); + writel(host->imask, host->base + MMC_I_MASK); + + pxa_gpio_mode(GPIO6_MMCCLK_MD); + pxa_gpio_mode(GPIO8_MMCCS0_MD); + pxa_set_cken(CKEN12_MMC, 1); + + host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host); + if (host->dma < 0) { + ret = -EBUSY; + goto out; + } + + ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host); + if (ret) + goto out; + + dev_set_drvdata(dev, mmc); + + if (host->pdata && host->pdata->init) + host->pdata->init(dev, pxamci_detect_irq, mmc); + + mmc_add_host(mmc); + + return 0; + + out: + if (host) { + if (host->dma >= 0) + pxa_free_dma(host->dma); + if (host->base) + iounmap(host->base); + if (host->sg_cpu) + dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + } + if (mmc) + mmc_free_host(mmc); + release_resource(r); + return ret; +} + +static int pxamci_remove(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + if (mmc) { + struct pxamci_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->exit) + host->pdata->exit(dev, mmc); + + mmc_remove_host(mmc); + + pxamci_stop_clock(host); + writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| + END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, + host->base + MMC_I_MASK); + + pxa_set_cken(CKEN12_MMC, 0); + + free_irq(host->irq, host); + pxa_free_dma(host->dma); + iounmap(host->base); + dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + + pxa_set_cken(CKEN12_MMC, 0); + + release_resource(host->res); + + mmc_free_host(mmc); + } + return 0; +} + +#ifdef CONFIG_PM +static int pxamci_suspend(struct device *dev, u32 state, u32 level) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + int ret = 0; + + if (mmc && level == SUSPEND_DISABLE) + ret = mmc_suspend_host(mmc, state); + + return ret; +} + +static int pxamci_resume(struct device *dev, u32 level) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + int ret = 0; + + if (mmc && level == RESUME_ENABLE) + ret = mmc_resume_host(mmc); + + return ret; +} +#else +#define pxamci_suspend NULL +#define pxamci_resume NULL +#endif + +static struct device_driver pxamci_driver = { + .name = "pxa2xx-mci", + .bus = &platform_bus_type, + .probe = pxamci_probe, + .remove = pxamci_remove, + .suspend = pxamci_suspend, + .resume = pxamci_resume, +}; + +static int __init pxamci_init(void) +{ + return driver_register(&pxamci_driver); +} + +static void __exit pxamci_exit(void) +{ + driver_unregister(&pxamci_driver); +} + +module_init(pxamci_init); +module_exit(pxamci_exit); + +MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/pxamci.h new file mode 100644 index 000000000..a80b24db9 --- /dev/null +++ b/drivers/mmc/pxamci.h @@ -0,0 +1,94 @@ +#undef MMC_STRPCL +#undef MMC_STAT +#undef MMC_CLKRT +#undef MMC_SPI +#undef MMC_CMDAT +#undef MMC_RESTO +#undef MMC_RDTO +#undef MMC_BLKLEN +#undef MMC_NOB +#undef MMC_PRTBUF +#undef MMC_I_MASK +#undef END_CMD_RES +#undef PRG_DONE +#undef DATA_TRAN_DONE +#undef MMC_I_REG +#undef MMC_CMD +#undef MMC_ARGH +#undef MMC_ARGL +#undef MMC_RES +#undef MMC_RXFIFO +#undef MMC_TXFIFO + +#define MMC_STRPCL 0x0000 +#define STOP_CLOCK (1 << 0) +#define START_CLOCK (2 << 0) + +#define MMC_STAT 0x0004 +#define STAT_END_CMD_RES (1 << 13) +#define STAT_PRG_DONE (1 << 12) +#define STAT_DATA_TRAN_DONE (1 << 11) +#define STAT_CLK_EN (1 << 8) +#define STAT_RECV_FIFO_FULL (1 << 7) +#define STAT_XMIT_FIFO_EMPTY (1 << 6) +#define STAT_RES_CRC_ERR (1 << 5) +#define STAT_SPI_READ_ERROR_TOKEN (1 << 4) +#define STAT_CRC_READ_ERROR (1 << 3) +#define STAT_CRC_WRITE_ERROR (1 << 2) +#define STAT_TIME_OUT_RESPONSE (1 << 1) +#define STAT_READ_TIME_OUT (1 << 0) + +#define MMC_CLKRT 0x0008 /* 3 bit */ + +#define MMC_SPI 0x000c +#define SPI_CS_ADDRESS (1 << 3) +#define SPI_CS_EN (1 << 2) +#define CRC_ON (1 << 1) +#define SPI_EN (1 << 0) + +#define MMC_CMDAT 0x0010 +#define CMDAT_DMAEN (1 << 7) +#define CMDAT_INIT (1 << 6) +#define CMDAT_BUSY (1 << 5) +#define CMDAT_STREAM (1 << 4) /* 1 = stream */ +#define CMDAT_WRITE (1 << 3) /* 1 = write */ +#define CMDAT_DATAEN (1 << 2) +#define CMDAT_RESP_NONE (0 << 0) +#define CMDAT_RESP_SHORT (1 << 0) +#define CMDAT_RESP_R2 (2 << 0) +#define CMDAT_RESP_R3 (3 << 0) + +#define MMC_RESTO 0x0014 /* 7 bit */ + +#define MMC_RDTO 0x0018 /* 16 bit */ + +#define MMC_BLKLEN 0x001c /* 10 bit */ + +#define MMC_NOB 0x0020 /* 16 bit */ + +#define MMC_PRTBUF 0x0024 +#define BUF_PART_FULL (1 << 0) + +#define MMC_I_MASK 0x0028 +#define TXFIFO_WR_REQ (1 << 6) +#define RXFIFO_RD_REQ (1 << 5) +#define CLK_IS_OFF (1 << 4) +#define STOP_CMD (1 << 3) +#define END_CMD_RES (1 << 2) +#define PRG_DONE (1 << 1) +#define DATA_TRAN_DONE (1 << 0) + +#define MMC_I_REG 0x002c +/* same as MMC_I_MASK */ + +#define MMC_CMD 0x0030 + +#define MMC_ARGH 0x0034 /* 16 bit */ + +#define MMC_ARGL 0x0038 /* 16 bit */ + +#define MMC_RES 0x003c /* 16 bit */ + +#define MMC_RXFIFO 0x0040 /* 8 bit */ + +#define MMC_TXFIFO 0x0044 /* 8 bit */ diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index e71624edb..c1e3536c2 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -603,6 +603,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad } spin_unlock(&shared->lock); } + } else { + spin_unlock(&shared->lock); } } @@ -1437,8 +1439,7 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, spin_unlock(chip->mutex); INVALIDATE_CACHED_RANGE(map, adr, len); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((chip->erase_time*HZ)/(2*1000)); + msleep(chip->erase_time / 2); spin_lock(chip->mutex); /* FIXME. Use a timer to check this, and return immediately. */ diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index daf554c00..8fb85f079 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 @@ -506,6 +511,17 @@ static const struct amd_flash_info jedec_table[] = { .regions = { 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, @@ -751,6 +767,17 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x02000,2), 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, @@ -1134,6 +1161,17 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x08000,1), 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, @@ -1209,7 +1247,7 @@ static const struct amd_flash_info jedec_table[] = { .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - regions: {ERASEINFO(0x01000,64), + .regions = {ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1221,7 +1259,7 @@ static const struct amd_flash_info jedec_table[] = { .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - regions: {ERASEINFO(0x01000,64), + .regions = {ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1570,7 +1608,7 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x02000, 2), ERASEINFO(0x04000, 1), } - } + } }; diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index cdc5bbd16..7458b68da 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -473,6 +473,15 @@ config MTD_IXP4XX IXDP425 and Coyote. If you have an IXP4xx based board and would like to use the flash chips on it, say 'Y'. +config MTD_IXP2000 + tristate "CFI Flash device mapped on Intel IXP2000 based systems" + depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 + help + This enables MTD access to flash devices on platforms based + on Intel's IXP2000 family of network processors such as the + IXDP2400 and IXDP2401. If you have an IXP2000 based board and + would like to use the flash chips on it, say 'Y'. + config MTD_EPXA10DB tristate "CFI Flash device mapped on Epxa10db" depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 505178f36..7fa2ae016 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -62,5 +62,6 @@ obj-$(CONFIG_MTD_SBC8240) += sbc8240.o obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o obj-$(CONFIG_MTD_MPC1211) += mpc1211.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o +obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 7f3ab3768..b43312731 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -26,7 +26,7 @@ struct amd76xrom_map_info { struct map_info map; struct mtd_info *mtd; - unsigned long window_addr; + void __iomem * window_addr; u32 window_start, window_size; struct pci_dev *pdev; struct resource window_rsrc; @@ -57,7 +57,7 @@ static void amd76xrom_cleanup(struct amd76xrom_map_info *info) del_mtd_device(info->mtd); map_destroy(info->mtd); info->mtd = NULL; - info->map.virt = 0; + info->map.virt = NULL; } if (info->rom_rsrc.parent) release_resource(&info->rom_rsrc); @@ -65,8 +65,8 @@ static void amd76xrom_cleanup(struct amd76xrom_map_info *info) release_resource(&info->window_rsrc); if (info->window_addr) { - iounmap((void *)(info->window_addr)); - info->window_addr = 0; + iounmap(info->window_addr); + info->window_addr = NULL; } } @@ -136,8 +136,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", window->size, window->start); /* For write accesses caches are useless */ - info->window_addr = - (unsigned long)ioremap_nocache(window->start, + info->window_addr = ioremap_nocache(window->start, window->size); if (!info->window_addr) { @@ -163,8 +162,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, } if (info->mtd) goto found_mtd; } - iounmap((void *)(info->window_addr)); - info->window_addr = 0; + iounmap(info->window_addr); + info->window_addr = NULL; /* Disable writes through the rom window */ pci_read_config_byte(pdev, 0x40, &byte); diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index 8475505f0..e34420bb1 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -103,7 +103,7 @@ struct clps_info { unsigned long base; unsigned long size; int width; - void *vbase; + void __iomem *vbase; struct map_info *map; struct mtd_info *mtd; struct resource *res; @@ -150,7 +150,7 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info break; } - clps[i].map->virt = (unsigned long)clps[i].vbase; + clps[i].map->virt = clps[i].vbase; clps[i].map->bankwidth = clps[i].width; clps[i].map->size = clps[i].size; diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 842f1b046..b7fd849dc 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 a05fc01b9..7d2b42436 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/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c new file mode 100644 index 000000000..104488c0b --- /dev/null +++ b/drivers/mtd/maps/ixp2000.c @@ -0,0 +1,281 @@ +/* + * $Id: ixp2000.c,v 1.1 2004/09/02 00:13:41 dsaxena Exp $ + * + * drivers/mtd/maps/ixp2000.c + * + * Mapping for the Intel XScale IXP2000 based systems + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Original Author: Naeem M Afzal + * Maintainer: Deepak Saxena + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct ixp2000_flash_info { + struct mtd_info *mtd; + struct map_info map; + struct mtd_partition *partitions; + struct resource *res; + int nr_banks; +}; + +static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) +{ + unsigned long (*set_bank)(unsigned long) = + (unsigned long(*)(unsigned long))map->map_priv_2; + + return (set_bank ? set_bank(ofs) : ofs); +} + +#ifdef __ARMEB__ +/* + * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which + * causes the lower address bits to be XORed with 0x11 on 8 bit accesses + * and XORed with 0x10 on 16 bit accesses. See the spec update, erratta 44. + */ +static int errata44_workaround = 0; + +static inline unsigned long address_fix8_write(unsigned long addr) +{ + if (errata44_workaround) { + return (addr ^ 3); + } + return addr; +} +#else + +#define address_fix8_write(x) (x) +#endif + +static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs) +{ + map_word val; + + val.x[0] = *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs))); + return val; +} + +/* + * We can't use the standard memcpy due to the broken SlowPort + * address translation on rev A0 and A1 silicon and the fact that + * we have banked flash. + */ +static void ixp2000_flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + from = flash_bank_setup(map, from); + while(len--) + *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); +} + +static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs) +{ + *(__u8 *) (address_fix8_write(map->map_priv_1 + + flash_bank_setup(map, ofs))) = d.x[0]; +} + +static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + to = flash_bank_setup(map, to); + while(len--) { + unsigned long tmp = address_fix8_write(map->map_priv_1 + to++); + *(__u8 *)(tmp) = *(__u8 *)(from++); + } +} + + +static int ixp2000_flash_remove(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + struct flash_platform_data *plat = dev->dev.platform_data; + struct ixp2000_flash_info *info = dev_get_drvdata(&dev->dev); + + dev_set_drvdata(&dev->dev, NULL); + + if(!info) + return 0; + + if (info->mtd) { + del_mtd_partitions(info->mtd); + map_destroy(info->mtd); + } + if (info->map.map_priv_1) + iounmap((void *) info->map.map_priv_1); + + if (info->partitions) + kfree(info->partitions); + + if (info->res) { + release_resource(info->res); + kfree(info->res); + } + + if (plat->exit) + plat->exit(); + + return 0; +} + + +static int ixp2000_flash_probe(struct device *_dev) +{ + static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + struct platform_device *dev = to_platform_device(_dev); + struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; + struct flash_platform_data *plat; + struct ixp2000_flash_info *info; + unsigned long window_size; + int err = -1; + + if (!ixp_data) + return -ENODEV; + + plat = ixp_data->platform_data; + if (!plat) + return -ENODEV; + + window_size = dev->resource->end - dev->resource->start + 1; + dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dM)\n", + ixp_data->nr_banks, ((u32)window_size >> 20)); + + if (plat->width != 1) { + dev_err(_dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n", + plat->width * 8); + return -EIO; + } + + info = kmalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL); + if(!info) { + err = -ENOMEM; + goto Error; + } + memzero(info, sizeof(struct ixp2000_flash_info)); + + dev_set_drvdata(&dev->dev, info); + + /* + * Tell the MTD layer we're not 1:1 mapped so that it does + * not attempt to do a direct access on us. + */ + info->map.phys = NO_XIP; + + info->nr_banks = ixp_data->nr_banks; + info->map.size = ixp_data->nr_banks * window_size; + info->map.bankwidth = 1; + + /* + * map_priv_2 is used to store a ptr to to the bank_setup routine + */ + info->map.map_priv_2 = (u32) ixp_data->bank_setup; + + info->map.name = dev->dev.bus_id; + info->map.read = ixp2000_flash_read8; + info->map.write = ixp2000_flash_write8; + info->map.copy_from = ixp2000_flash_copy_from; + info->map.copy_to = ixp2000_flash_copy_to; + + info->res = request_mem_region(dev->resource->start, + dev->resource->end - dev->resource->start + 1, + dev->dev.bus_id); + if (!info->res) { + dev_err(_dev, "Could not reserve memory region\n"); + err = -ENOMEM; + goto Error; + } + + info->map.map_priv_1 = + (unsigned long) ioremap(dev->resource->start, + dev->resource->end - dev->resource->start + 1); + if (!info->map.map_priv_1) { + dev_err(_dev, "Failed to ioremap flash region\n"); + err = -EIO; + goto Error; + } + + /* + * Setup read mode for FLASH + */ + *IXP2000_SLOWPORT_FRM = 1; + +#if defined(__ARMEB__) + /* + * Enable errata 44 workaround for NPUs with broken slowport + */ + + errata44_workaround = ixp2000_has_broken_slowport(); + dev_info(_dev, "Errata 44 workaround %s\n", + errata44_workaround ? "enabled" : "disabled"); +#endif + + info->mtd = do_map_probe(plat->map_name, &info->map); + if (!info->mtd) { + dev_err(_dev, "map_probe failed\n"); + err = -ENXIO; + goto Error; + } + info->mtd->owner = THIS_MODULE; + + err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->partitions, err); + if(err) + dev_err(_dev, "Could not parse partitions\n"); + } + + if (err) + goto Error; + + return 0; + +Error: + ixp2000_flash_remove(_dev); + return err; +} + +static struct device_driver ixp2000_flash_driver = { + .name = "IXP2000-Flash", + .bus = &platform_bus_type, + .probe = &ixp2000_flash_probe, + .remove = &ixp2000_flash_remove +}; + +static int __init ixp2000_flash_init(void) +{ + return driver_register(&ixp2000_flash_driver); +} + +static void __exit ixp2000_flash_exit(void) +{ + driver_unregister(&ixp2000_flash_driver); +} + +module_init(ixp2000_flash_init); +module_exit(ixp2000_flash_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena "); + diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 7ebc8cc5b..1770b1acc 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -1,5 +1,5 @@ /* - * $Id: ixp4xx.c,v 1.3 2004/07/12 22:38:29 dwmw2 Exp $ + * $Id: ixp4xx.c,v 1.6 2004/09/17 00:25:06 gleixner Exp $ * * drivers/mtd/maps/ixp4xx.c * @@ -69,9 +69,22 @@ static void ixp4xx_copy_from(struct map_info *map, void *to, dest[len - 1] = BYTE0(src[i]); } +/* + * Unaligned writes are ignored, causing the 8-bit + * probe to fail and proceed to the 16-bit probe (which succeeds). + */ +static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) +{ + if (!(adr & 1)) + *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; +} + +/* + * Fast write16 function without the probing check above + */ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) { - *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; + *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; } struct ixp4xx_flash_info { @@ -88,6 +101,7 @@ static int ixp4xx_flash_remove(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); struct flash_platform_data *plat = dev->dev.platform_data; struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); + map_word d; dev_set_drvdata(&dev->dev, NULL); @@ -97,7 +111,8 @@ static int ixp4xx_flash_remove(struct device *_dev) /* * This is required for a soft reboot to work. */ - ixp4xx_write16(&info->map, 0xff, 0x55 * 0x2); + d.x[0] = 0xff; + ixp4xx_write16(&info->map, d, 0x55 * 0x2); if (info->mtd) { del_mtd_partitions(info->mtd); @@ -169,7 +184,7 @@ static int ixp4xx_flash_probe(struct device *_dev) info->map.bankwidth = 2; info->map.name = dev->dev.bus_id; info->map.read = ixp4xx_read16, - info->map.write = ixp4xx_write16, + info->map.write = ixp4xx_probe_write16, info->map.copy_from = ixp4xx_copy_from, info->res = request_mem_region(dev->resource->start, @@ -182,7 +197,7 @@ static int ixp4xx_flash_probe(struct device *_dev) } info->map.map_priv_1 = - (unsigned long) ioremap(dev->resource->start, + (void __iomem *) ioremap(dev->resource->start, dev->resource->end - dev->resource->start + 1); if (!info->map.map_priv_1) { printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); @@ -198,6 +213,9 @@ static int ixp4xx_flash_probe(struct device *_dev) } info->mtd->owner = THIS_MODULE; + /* Use the fast version */ + info->map.write = ixp4xx_write16, + err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); if (err > 0) { err = add_mtd_partitions(info->mtd, info->partitions, err); diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c index 53e708b2e..881eab984 100644 --- a/drivers/mtd/maps/lubbock-flash.c +++ b/drivers/mtd/maps/lubbock-flash.c @@ -1,5 +1,5 @@ /* - * $Id: lubbock-flash.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: lubbock-flash.c,v 1.18 2004/09/28 18:54:40 nico Exp $ * * Map driver for the Lubbock developer platform. * @@ -15,11 +15,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include @@ -82,16 +84,14 @@ static int __init init_lubbock(void) lubbock_maps[flashboot].name = "Lubbock Boot ROM"; for (i = 0; i < 2; i++) { - lubbock_maps[i].virt = (unsigned long)ioremap(lubbock_maps[i].phys, WINDOW_SIZE); + lubbock_maps[i].virt = (void __iomem *)ioremap(lubbock_maps[i].phys, WINDOW_SIZE); if (!lubbock_maps[i].virt) { printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); if (!ret) ret = -ENOMEM; continue; } - lubbock_maps[i].cached = __ioremap(lubbock_maps[i].phys, - WINDOW_SIZE, - L_PTE_CACHEABLE, 1); + lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE); if (!lubbock_maps[i].cached) printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name); simple_map_init(&lubbock_maps[i]); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index e06b07351..38a81462f 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -180,7 +180,7 @@ int nettel_eraseconfig(void) if (mtd) { nettel_erase.mtd = mtd; nettel_erase.callback = nettel_erasecallback; - nettel_erase.callback = 0; + nettel_erase.callback = NULL; nettel_erase.addr = 0; nettel_erase.len = mtd->size; nettel_erase.priv = (u_long) &wait_q; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c42ca6f96..bb9c07780 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -885,7 +885,7 @@ struct sa_info { unsigned long base; unsigned long size; int width; - void *vbase; + void __iomem *vbase; void (*set_vpp)(struct map_info *, int); struct map_info *map; struct mtd_info *mtd; @@ -932,7 +932,7 @@ static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info * break; } - sa[i].map->virt = (unsigned long)sa[i].vbase; + sa[i].map->virt = sa[i].vbase; sa[i].map->phys = sa[i].base; sa[i].map->set_vpp = sa[i].set_vpp; sa[i].map->bankwidth = sa[i].width; diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 496c9857f..5a10fbaaa 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -50,7 +50,7 @@ static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; static struct map_info* map_banks[FLASH_BANK_MAX]; static struct mtd_part_def part_banks[FLASH_BANK_MAX]; static unsigned long num_banks; -static unsigned long start_scan_addr; +static void __iomem *start_scan_addr; /* * Here are partition information for all known TQM8xxL series devices. @@ -121,7 +121,7 @@ int __init init_tqm_mtd(void) flash_size = bd->bi_flashsize; //request maximum flash size address space - start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); + start_scan_addr = ioremap(flash_addr, flash_size); if (!start_scan_addr) { printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); return -EIO; @@ -231,7 +231,7 @@ error_mem: } } error: - iounmap((void *)start_scan_addr); + iounmap(start_scan_addr); return ret; } @@ -250,7 +250,7 @@ static void __exit cleanup_tqm_mtd(void) } if (start_scan_addr) { - iounmap((void *)start_scan_addr); + iounmap(start_scan_addr); start_scan_addr = 0; } } diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index c5cd70bdb..baff49bf7 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -69,10 +69,9 @@ int __init uclinux_mtd_init(void) printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", (int) mapp->map_priv_2, (int) mapp->size); - mapp->virt = (unsigned long) - ioremap_nocache(mapp->phys, mapp->size); + mapp->virt = ioremap_nocache(mapp->phys, mapp->size); - if (mapp->virt == 0) { + if (!mapp->virt) { printk("uclinux[mtd]: ioremap_nocache() failed\n"); return(-EIO); } @@ -82,7 +81,7 @@ int __init uclinux_mtd_init(void) mtd = do_map_probe("map_ram", mapp); if (!mtd) { printk("uclinux[mtd]: failed to find a mapping?\n"); - iounmap((void *) mapp->virt); + iounmap(mapp->virt); return(-ENXIO); } diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index a8a4e1ac8..eee7faa5c 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/3c507.c b/drivers/net/3c507.c index ca0d71d63..4866a09c0 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -294,6 +294,7 @@ static void el16_tx_timeout (struct net_device *dev); static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad); static void init_82586_mem(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static void init_rx_bufs(struct net_device *); static int io = 0x300; static int irq; @@ -612,7 +613,6 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if ((status & 0x0070) != 0x0040 && netif_running(dev)) { - static void init_rx_bufs(struct net_device *); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ if (net_debug) diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index c6f1995e0..a39c446c3 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -751,18 +751,15 @@ static int mc32_load_rx_ring(struct net_device *dev) rx_base=lp->rx_chain; - for(i=0; irx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); - skb_reserve(lp->rx_ring[i].skb, 18); - - if(lp->rx_ring[i].skb==NULL) - { - for(;i>=0;i--) + if (lp->rx_ring[i].skb==NULL) { + for (;i>=0;i--) kfree_skb(lp->rx_ring[i].skb); return -ENOBUFS; } - + skb_reserve(lp->rx_ring[i].skb, 18); + p=isa_bus_to_virt(lp->base+rx_base); p->control=0; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index ab2e61a9d..89faad1d2 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -695,7 +695,7 @@ enum Window2 { /* Window 2. */ Wn2_ResetOptions=12, }; enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, + Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; #define BFEXT(value, offset, bitcount) \ @@ -723,7 +723,8 @@ enum Win4_Media_bits { Media_LnkBeat = 0x0800, }; enum Window7 { /* Window 7: Bus Master control. */ - Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, + Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6, + Wn7_MasterStatus = 12, }; /* Boomerang bus master control registers. */ enum MasterCtrl { @@ -819,7 +820,8 @@ struct vortex_private { pm_state_valid:1, /* power_state[] has sane contents */ open:1, medialock:1, - must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ + must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ + large_frames:1; /* accept large frames */ int drv_flags; u16 status_enable; u16 intr_enable; @@ -900,10 +902,14 @@ static void dump_tx_ring(struct net_device *dev); static void update_stats(long ioaddr, struct net_device *dev); static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); +#ifdef CONFIG_PCI static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif static void vortex_tx_timeout(struct net_device *dev); static void acpi_set_WOL(struct net_device *dev); static struct ethtool_ops vortex_ethtool_ops; +static void set_8021q_mode(struct net_device *dev, int enable); + /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ @@ -1164,6 +1170,7 @@ static int __devinit vortex_probe1(struct device *gendev, dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; + vp->large_frames = mtu > 1500; vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; @@ -1290,6 +1297,13 @@ static int __devinit vortex_probe1(struct device *gendev, for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); } + /* Unfortunately an all zero eeprom passes the checksum and this + gets found in the wild in failure cases. Crypto is hard 8) */ + if (!is_valid_ether_addr(dev->dev_addr)) { + retval = -EINVAL; + printk(KERN_ERR "*** EEPROM MAC address is invalid.\n"); + goto free_ring; /* With every pack */ + } EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); @@ -1468,7 +1482,9 @@ static int __devinit vortex_probe1(struct device *gendev, dev->stop = vortex_close; dev->get_stats = vortex_get_stats; +#ifdef CONFIG_PCI dev->do_ioctl = vortex_ioctl; +#endif dev->ethtool_ops = &vortex_ethtool_ops; dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; @@ -1616,7 +1632,7 @@ vortex_up(struct net_device *dev) /* Set the full-duplex bit. */ outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0) | + (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -1700,6 +1716,8 @@ vortex_up(struct net_device *dev) } /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); + /* enable 802.1q tagged frames */ + set_8021q_mode(dev, 1); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ // issue_and_wait(dev, SetTxStart|0x07ff); @@ -1842,7 +1860,7 @@ vortex_timer(unsigned long data) /* Set the full-duplex bit. */ EL3WINDOW(3); outw( (vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0) | + (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) @@ -2068,6 +2086,8 @@ vortex_error(struct net_device *dev, int status) issue_and_wait(dev, RxReset|0x07); /* Set the Rx filter to the current state. */ set_rx_mode(dev); + /* enable 802.1q VLAN tagged frames */ + set_8021q_mode(dev, 1); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ outw(AckIntr | HostError, ioaddr + EL3_CMD); } @@ -2672,6 +2692,9 @@ vortex_down(struct net_device *dev, int final_down) outw(RxDisable, ioaddr + EL3_CMD); outw(TxDisable, ioaddr + EL3_CMD); + /* Disable receiving 802.1q tagged frames */ + set_8021q_mode(dev, 0); + if (dev->if_port == XCVR_10base2) /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); @@ -2868,6 +2891,7 @@ static struct ethtool_ops vortex_ethtool_ops = { .get_drvinfo = vortex_get_drvinfo, }; +#ifdef CONFIG_PCI static int vortex_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct vortex_private *vp = netdev_priv(dev); @@ -2925,6 +2949,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return err; } +#endif /* Pre-Cyclone chips have no documented multicast filter, so the only @@ -2947,6 +2972,61 @@ static void set_rx_mode(struct net_device *dev) outw(new_mode, ioaddr + EL3_CMD); } +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +/* Setup the card so that it can receive frames with an 802.1q VLAN tag. + Note that this must be done after each RxReset due to some backwards + compatibility logic in the Cyclone and Tornado ASICs */ + +/* The Ethernet Type used for 802.1q tagged frames */ +#define VLAN_ETHER_TYPE 0x8100 + +static void set_8021q_mode(struct net_device *dev, int enable) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + int old_window = inw(ioaddr + EL3_CMD); + int mac_ctrl; + + if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) { + /* cyclone and tornado chipsets can recognize 802.1q + * tagged frames and treat them correctly */ + + int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */ + if (enable) + max_pkt_size += 4; /* 802.1Q VLAN tag */ + + EL3WINDOW(3); + outw(max_pkt_size, ioaddr+Wn3_MaxPktSize); + + /* set VlanEtherType to let the hardware checksumming + treat tagged frames correctly */ + EL3WINDOW(7); + outw(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType); + } else { + /* on older cards we have to enable large frames */ + + vp->large_frames = dev->mtu > 1500 || enable; + + EL3WINDOW(3); + mac_ctrl = inw(ioaddr+Wn3_MAC_Ctrl); + if (vp->large_frames) + mac_ctrl |= 0x40; + else + mac_ctrl &= ~0x40; + outw(mac_ctrl, ioaddr+Wn3_MAC_Ctrl); + } + + EL3WINDOW(old_window); +} +#else + +static void set_8021q_mode(struct net_device *dev, int enable) +{ +} + + +#endif + /* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 62dd13951..1b18b3aca 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1698,7 +1698,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } /* Configure DMA attributes. */ - if ((sizeof(dma_addr_t) > 32) && + if ((sizeof(dma_addr_t) > 4) && !pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL) && !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { pci_using_dac = 1; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 58290c5bb..2a94719a4 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 "); @@ -613,7 +614,7 @@ static int rtl8139_open (struct net_device *dev); static int mdio_read (struct net_device *dev, int phy_id, int location); static void mdio_write (struct net_device *dev, int phy_id, int location, int val); -static inline void rtl8139_start_thread(struct net_device *dev); +static void rtl8139_start_thread(struct net_device *dev); static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, @@ -1643,7 +1644,7 @@ static int rtl8139_thread (void *data) complete_and_exit (&tp->thr_exited, 0); } -static inline void rtl8139_start_thread(struct net_device *dev) +static void rtl8139_start_thread(struct net_device *dev) { struct rtl8139_private *tp = dev->priv; @@ -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/8390.c b/drivers/net/8390.c index 22e7dfb47..04dcacda8 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -41,6 +41,8 @@ module by all drivers that require it. Alan Cox : Spinlocking work, added 'BUG_83C690' Paul Gortmaker : Separate out Tx timeout code from Tx path. + Paul Gortmaker : Remove old unused single Tx buffer code. + Hayato Fujiwara : Add m32r support. Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. @@ -218,6 +220,15 @@ void ei_tx_timeout(struct net_device *dev) int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; +#if defined(CONFIG_M32R) && defined(CONFIG_SMP) + unsigned long icucr; + + local_irq_save(flags); + icucr = inl(ICUCR1); + icucr |= M32R_ICUCR_ISMOD11; + outl(icucr, ICUCR1); + local_irq_restore(flags); +#endif ei_local->stat.tx_errors++; spin_lock_irqsave(&ei_local->page_lock, flags); @@ -289,8 +300,6 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) send_length = ETH_ZLEN < length ? length : ETH_ZLEN; -#ifdef EI_PINGPONG - /* * We have two Tx slots available for use. Find the first free * slot, and then perform some sanity checks. With two Tx bufs, @@ -309,7 +318,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) } else if (ei_local->tx2 == 0) { - output_page = ei_local->tx_start_page + TX_1X_PAGES; + output_page = ei_local->tx_start_page + TX_PAGES/2; ei_local->tx2 = send_length; if (ei_debug && ei_local->tx1 > 0) printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", @@ -366,28 +375,6 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) else netif_start_queue(dev); -#else /* EI_PINGPONG */ - - /* - * Only one Tx buffer in use. You need two Tx bufs to come close to - * back-to-back transmits. Expect a 20 -> 25% performance hit on - * reasonable hardware if you only use one Tx buffer. - */ - - if (length == send_length) - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); - else { - memset(scratch, 0, ETH_ZLEN); - memcpy(scratch, skb->data, skb->len); - ei_block_output(dev, ETH_ZLEN, scratch, ei_local->tx_start_page); - } - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - dev->trans_start = jiffies; - netif_stop_queue(dev); - -#endif /* EI_PINGPONG */ - /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -590,8 +577,6 @@ static void ei_tx_intr(struct net_device *dev) outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */ -#ifdef EI_PINGPONG - /* * There are two Tx buffers, see which one finished, and trigger * the send of another one if it exists. @@ -634,13 +619,6 @@ static void ei_tx_intr(struct net_device *dev) // else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n", // dev->name, ei_local->lasttx); -#else /* EI_PINGPONG */ - /* - * Single Tx buffer: mark it free so another packet can be loaded. - */ - ei_local->txing = 0; -#endif - /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) ei_local->stat.collisions++; diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 58fd65e03..948723b72 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -12,17 +12,7 @@ #include #include -#define TX_2X_PAGES 12 -#define TX_1X_PAGES 6 - -/* Should always use two Tx slots to get back-to-back transmits. */ -#define EI_PINGPONG - -#ifdef EI_PINGPONG -#define TX_PAGES TX_2X_PAGES -#else -#define TX_PAGES TX_1X_PAGES -#endif +#define TX_PAGES 12 /* Two Tx slots */ #define ETHER_ADDR_LEN 6 diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 882837793..967640710 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -200,7 +200,7 @@ source "drivers/net/arm/Kconfig" config MACE tristate "MACE (Power Mac ethernet) support" - depends on NET_ETHERNET && PPC_PMAC + depends on NET_ETHERNET && PPC_PMAC && PPC32 select CRC32 help Power Macintoshes and clones with Ethernet built-in on the @@ -223,7 +223,7 @@ config MACE_AAUI_PORT config BMAC tristate "BMAC (G3 ethernet) support" - depends on NET_ETHERNET && PPC_PMAC + depends on NET_ETHERNET && PPC_PMAC && PPC32 select CRC32 help Say Y for support of BMAC Ethernet interfaces. These are used on G3 @@ -817,7 +817,7 @@ config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6) + depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R) help This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it @@ -1075,7 +1075,7 @@ config ETH16I config NE2000 tristate "NE2000/NE1000 support" - depends on NET_ISA || (Q40 && m) + depends on NET_ISA || (Q40 && m) || M32R select CRC32 ---help--- If you have a network (Ethernet) card of this type, say Y and read @@ -1353,7 +1353,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on NET_PCI && ISA + depends on NET_PCI && (ISA || ARCH_IXDP2X01) ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -1746,12 +1746,13 @@ config VIA_VELOCITY tristate "VIA Velocity support" depends on NET_PCI && PCI select CRC32 + select CRC_CCITT select MII help 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)" @@ -2043,6 +2044,23 @@ config R8169 To compile this driver as a module, choose M here: the module will be called r8169. This is recommended. +config R8169_NAPI + bool "Use Rx and Tx Polling (NAPI) (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 for more + information. + + If in doubt, say N. + config SK98LIN tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support" depends on PCI @@ -2131,6 +2149,45 @@ config TIGON3 To compile this driver as a module, choose M here: the module will be called tg3. This is recommended. +config GIANFAR + tristate "Gianfar Ethernet" + depends on 85xx + help + This driver supports the Gigabit TSEC on the MPC85xx + family of chips, and the FEC on the 8540 + +config GFAR_NAPI + bool "NAPI Support" + depends on GIANFAR + +config MV643XX_ETH + tristate "MV-643XX Ethernet support" + depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX + help + This driver supports the gigabit Ethernet on the Marvell MV643XX + chipset which is used in the Momenco Ocelot C and Jaguar ATX. + +config MV643XX_ETH_0 + bool "MV-643XX Port 0" + depends on MV643XX_ETH + help + This enables support for Port 0 of the Marvell MV643XX Gigabit + Ethernet. + +config MV643XX_ETH_1 + bool "MV-643XX Port 1" + depends on MV643XX_ETH + help + This enables support for Port 1 of the Marvell MV643XX Gigabit + Ethernet. + +config MV643XX_ETH_2 + bool "MV-643XX Port 2" + depends on MV643XX_ETH + help + This enables support for Port 2 of the Marvell MV643XX Gigabit + Ethernet. + endmenu # diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 2ae71cf8b..3fc85500f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -10,6 +10,9 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_GIANFAR) += gianfar_driver.o + +gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o # # link order important here @@ -95,6 +98,8 @@ obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o +obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o + obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 90ed3329a..cc56ca3ac 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -425,13 +426,15 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; MODULE_AUTHOR("Jes Sorensen "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); -MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i"); + +static int num_params; +module_param_array(link, int, num_params, 0); +module_param_array(trace, int, num_params, 0); +module_param_array(tx_coal_tick, int, num_params, 0); +module_param_array(max_tx_desc, int, num_params, 0); +module_param_array(rx_coal_tick, int, num_params, 0); +module_param_array(max_rx_desc, int, num_params, 0); +module_param_array(tx_ratio, int, num_params, 0); MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state"); MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level"); MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives"); @@ -474,6 +477,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, ap = dev->priv; ap->pdev = pdev; + ap->name = pci_name(pdev); dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; #if ACENIC_DO_VLAN @@ -516,7 +520,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { printk(KERN_INFO "%s: Enabling PCI Memory Mapped " "access - was not enabled by BIOS/Firmware\n", - dev->name); + ap->name); ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); @@ -539,55 +543,40 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, if (!ap->regs) { printk(KERN_ERR "%s: Unable to map I/O register, " "AceNIC %i will be disabled.\n", - dev->name, boards_found); + ap->name, boards_found); goto fail_free_netdev; } switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { - strncpy(ap->name, "Farallon PN9100-T " - "Gigabit Ethernet", sizeof (ap->name)); printk(KERN_INFO "%s: Farallon PN9100-T ", - dev->name); + ap->name); } else { - strncpy(ap->name, "AceNIC Gigabit Ethernet", - sizeof (ap->name)); printk(KERN_INFO "%s: Alteon AceNIC ", - dev->name); + ap->name); } break; case PCI_VENDOR_ID_3COM: - strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); + printk(KERN_INFO "%s: 3Com 3C985 ", ap->name); break; case PCI_VENDOR_ID_NETGEAR: - strncpy(ap->name, "NetGear GA620 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: NetGear GA620 ", dev->name); + printk(KERN_INFO "%s: NetGear GA620 ", ap->name); break; case PCI_VENDOR_ID_DEC: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { - strncpy(ap->name, "Farallon PN9000-SX " - "Gigabit Ethernet", sizeof (ap->name)); printk(KERN_INFO "%s: Farallon PN9000-SX ", - dev->name); + ap->name); break; } case PCI_VENDOR_ID_SGI: - strncpy(ap->name, "SGI AceNIC Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: SGI AceNIC ", dev->name); + printk(KERN_INFO "%s: SGI AceNIC ", ap->name); break; default: - strncpy(ap->name, "Unknown AceNIC based Gigabit " - "Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); + printk(KERN_INFO "%s: Unknown AceNIC ", ap->name); break; } - ap->name [sizeof (ap->name) - 1] = '\0'; printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); #ifdef __sparc__ printk("irq %s\n", __irq_itoa(pdev->irq)); @@ -622,6 +611,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, printk(KERN_ERR "acenic: device registration failed\n"); goto fail_uninit; } + ap->name = dev->name; if (ap->pci_using_dac) dev->features |= NETIF_F_HIGHDMA; @@ -641,7 +631,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, static void __devexit acenic_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; short i; @@ -752,7 +742,7 @@ module_exit(acenic_exit); static void ace_free_descriptors(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); int size; if (ap->rx_std_ring != NULL) { @@ -802,7 +792,7 @@ static void ace_free_descriptors(struct net_device *dev) static int ace_allocate_descriptors(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); int size; size = (sizeof(struct rx_desc) * @@ -873,7 +863,7 @@ static void ace_init_cleanup(struct net_device *dev) { struct ace_private *ap; - ap = dev->priv; + ap = netdev_priv(dev); ace_free_descriptors(dev); @@ -921,7 +911,7 @@ static int __init ace_init(struct net_device *dev) short i; unsigned char cache_size; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; board_idx = ap->board_idx; @@ -1387,7 +1377,7 @@ static int __init ace_init(struct net_device *dev) if (board_idx == BOARD_IDX_OVERFLOW) { printk(KERN_WARNING "%s: more than %i NICs detected, " "ignoring module parameters!\n", - dev->name, ACE_MAX_MOD_PARMS); + ap->name, ACE_MAX_MOD_PARMS); } else if (board_idx >= 0) { if (tx_coal_tick[board_idx]) writel(tx_coal_tick[board_idx], @@ -1426,7 +1416,7 @@ static int __init ace_init(struct net_device *dev) if (option & 0x01) { printk(KERN_INFO "%s: Setting half duplex link\n", - dev->name); + ap->name); tmp &= ~LNK_FULL_DUPLEX; } if (option & 0x02) @@ -1439,7 +1429,7 @@ static int __init ace_init(struct net_device *dev) tmp |= LNK_1000MB; if ((option & 0x70) == 0) { printk(KERN_WARNING "%s: No media speed specified, " - "forcing auto negotiation\n", dev->name); + "forcing auto negotiation\n", ap->name); tmp |= LNK_NEGOTIATE | LNK_1000MB | LNK_100MB | LNK_10MB; } @@ -1447,12 +1437,12 @@ static int __init ace_init(struct net_device *dev) tmp |= LNK_NEG_FCTL; else printk(KERN_INFO "%s: Disabling flow control " - "negotiation\n", dev->name); + "negotiation\n", ap->name); if (option & 0x200) tmp |= LNK_RX_FLOW_CTL_Y; if ((option & 0x400) && (ap->version >= 2)) { printk(KERN_INFO "%s: Enabling TX flow control\n", - dev->name); + ap->name); tmp |= LNK_TX_FLOW_CTL_Y; } } @@ -1509,7 +1499,7 @@ static int __init ace_init(struct net_device *dev) cpu_relax(); if (!ap->fw_running) { - printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name); + printk(KERN_ERR "%s: Firmware NOT running!\n", ap->name); ace_dump_trace(ap); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); @@ -1542,13 +1532,13 @@ static int __init ace_init(struct net_device *dev) ace_load_std_rx_ring(ap, RX_RING_SIZE); else printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n", - dev->name); + ap->name); if (ap->version >= 2) { if (!test_and_set_bit(0, &ap->mini_refill_busy)) ace_load_mini_rx_ring(ap, RX_MINI_SIZE); else printk(KERN_ERR "%s: Someone is busy refilling " - "the RX mini ring\n", dev->name); + "the RX mini ring\n", ap->name); } return 0; @@ -1564,7 +1554,7 @@ static void ace_set_rxtx_parms(struct net_device *dev, int jumbo) struct ace_regs *regs; int board_idx; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; board_idx = ap->board_idx; @@ -1604,7 +1594,7 @@ static void ace_set_rxtx_parms(struct net_device *dev, int jumbo) static void ace_watchdog(struct net_device *data) { struct net_device *dev = data; - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; /* @@ -1878,13 +1868,13 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) { struct ace_private *ap; - ap = dev->priv; + ap = netdev_priv(dev); while (evtcsm != evtprd) { switch (ap->evt_ring[evtcsm].evt) { case E_FW_RUNNING: printk(KERN_INFO "%s: Firmware up and running\n", - dev->name); + ap->name); ap->fw_running = 1; wmb(); break; @@ -1899,7 +1889,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) u32 state = readl(&ap->regs->GigLnkState); printk(KERN_WARNING "%s: Optical link UP " "(%s Duplex, Flow Control: %s%s)\n", - dev->name, + ap->name, state & LNK_FULL_DUPLEX ? "Full":"Half", state & LNK_TX_FLOW_CTL_Y ? "TX " : "", state & LNK_RX_FLOW_CTL_Y ? "RX" : ""); @@ -1907,15 +1897,15 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) } case E_C_LINK_DOWN: printk(KERN_WARNING "%s: Optical link DOWN\n", - dev->name); + ap->name); break; case E_C_LINK_10_100: printk(KERN_WARNING "%s: 10/100BaseT link " - "UP\n", dev->name); + "UP\n", ap->name); break; default: printk(KERN_ERR "%s: Unknown optical link " - "state %02x\n", dev->name, code); + "state %02x\n", ap->name, code); } break; } @@ -1923,19 +1913,19 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) switch(ap->evt_ring[evtcsm].code) { case E_C_ERR_INVAL_CMD: printk(KERN_ERR "%s: invalid command error\n", - dev->name); + ap->name); break; case E_C_ERR_UNIMP_CMD: printk(KERN_ERR "%s: unimplemented command " - "error\n", dev->name); + "error\n", ap->name); break; case E_C_ERR_BAD_CFG: printk(KERN_ERR "%s: bad config error\n", - dev->name); + ap->name); break; default: printk(KERN_ERR "%s: unknown error %02x\n", - dev->name, ap->evt_ring[evtcsm].code); + ap->name, ap->evt_ring[evtcsm].code); } break; case E_RESET_JUMBO_RNG: @@ -1964,13 +1954,13 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) ap->jumbo = 0; ap->rx_jumbo_skbprd = 0; printk(KERN_INFO "%s: Jumbo ring flushed\n", - dev->name); + ap->name); clear_bit(0, &ap->jumbo_refill_busy); break; } default: printk(KERN_ERR "%s: Unhandled event 0x%02x\n", - dev->name, ap->evt_ring[evtcsm].evt); + ap->name, ap->evt_ring[evtcsm].evt); } evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES; } @@ -1981,7 +1971,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); u32 idx; int mini_count = 0, std_count = 0; @@ -2108,7 +2098,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) static inline void ace_tx_int(struct net_device *dev, u32 txcsm, u32 idx) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); do { struct sk_buff *skb; @@ -2181,7 +2171,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) u32 txcsm, rxretcsm, rxretprd; u32 evtcsm, evtprd; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; /* @@ -2304,7 +2294,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) #if ACENIC_DO_VLAN static void ace_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); unsigned long flags; local_irq_save(flags); @@ -2319,7 +2309,7 @@ static void ace_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); unsigned long flags; local_irq_save(flags); @@ -2340,7 +2330,7 @@ static int ace_open(struct net_device *dev) struct ace_regs *regs; struct cmd cmd; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; if (!(ap->fw_running)) { @@ -2407,7 +2397,7 @@ static int ace_close(struct net_device *dev) */ netif_stop_queue(dev); - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; if (ap->promisc) { @@ -2522,7 +2512,7 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr, static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; struct tx_desc *desc; u32 idx, flagsize; @@ -2661,7 +2651,7 @@ overflow: static int ace_change_mtu(struct net_device *dev, int new_mtu) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; if (new_mtu > ACE_JUMBO_MTU) @@ -2698,7 +2688,7 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu) static int ace_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; u32 link; @@ -2751,7 +2741,7 @@ static int ace_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; u32 link, speed; @@ -2814,7 +2804,7 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static void ace_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); strlcpy(info->driver, "acenic", sizeof(info->driver)); snprintf(info->version, sizeof(info->version), "%i.%i.%i", @@ -2844,7 +2834,7 @@ static int ace_set_mac_addr(struct net_device *dev, void *p) da = (u8 *)dev->dev_addr; - regs = ((struct ace_private *)dev->priv)->regs; + regs = ((struct ace_private *)netdev_priv(dev))->regs; writel(da[0] << 8 | da[1], ®s->MacAddrHi); writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5], ®s->MacAddrLo); @@ -2860,7 +2850,7 @@ static int ace_set_mac_addr(struct net_device *dev, void *p) static void ace_set_multicast_list(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_regs *regs = ap->regs; struct cmd cmd; @@ -2914,7 +2904,7 @@ static void ace_set_multicast_list(struct net_device *dev) static struct net_device_stats *ace_get_stats(struct net_device *dev) { - struct ace_private *ap = dev->priv; + struct ace_private *ap = netdev_priv(dev); struct ace_mac_stats *mac_stats = (struct ace_mac_stats *)ap->regs->Stats; @@ -2997,12 +2987,12 @@ int __init ace_load_firmware(struct net_device *dev) struct ace_private *ap; struct ace_regs *regs; - ap = dev->priv; + ap = netdev_priv(dev); regs = ap->regs; if (!(readl(®s->CpuCtrl) & CPU_HALTED)) { printk(KERN_ERR "%s: trying to download firmware while the " - "CPU is running!\n", dev->name); + "CPU is running!\n", ap->name); return -EFAULT; } @@ -3178,6 +3168,7 @@ static void __init eeprom_stop(struct ace_regs *regs) static int __init read_eeprom_byte(struct net_device *dev, unsigned long offset) { + struct ace_private *ap; struct ace_regs *regs; unsigned long flags; u32 local; @@ -3187,10 +3178,11 @@ static int __init read_eeprom_byte(struct net_device *dev, if (!dev) { printk(KERN_ERR "No device!\n"); result = -ENODEV; - goto eeprom_read_error; + goto out; } - regs = ((struct ace_private *)dev->priv)->regs; + ap = netdev_priv(dev); + regs = ap->regs; /* * Don't take interrupts on this CPU will bit banging @@ -3203,7 +3195,7 @@ static int __init read_eeprom_byte(struct net_device *dev, eeprom_prep(regs, EEPROM_WRITE_SELECT); if (eeprom_check_ack(regs)) { local_irq_restore(flags); - printk(KERN_ERR "%s: Unable to sync eeprom\n", dev->name); + printk(KERN_ERR "%s: Unable to sync eeprom\n", ap->name); result = -EIO; goto eeprom_read_error; } @@ -3212,7 +3204,7 @@ static int __init read_eeprom_byte(struct net_device *dev, if (eeprom_check_ack(regs)) { local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set address byte 0\n", - dev->name); + ap->name); result = -EIO; goto eeprom_read_error; } @@ -3221,7 +3213,7 @@ static int __init read_eeprom_byte(struct net_device *dev, if (eeprom_check_ack(regs)) { local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set address byte 1\n", - dev->name); + ap->name); result = -EIO; goto eeprom_read_error; } @@ -3231,7 +3223,7 @@ static int __init read_eeprom_byte(struct net_device *dev, if (eeprom_check_ack(regs)) { local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set READ_SELECT\n", - dev->name); + ap->name); result = -EIO; goto eeprom_read_error; } @@ -3288,7 +3280,7 @@ static int __init read_eeprom_byte(struct net_device *dev, eeprom_read_error: printk(KERN_ERR "%s: Unable to read eeprom byte 0x%02lx\n", - dev->name, offset); + ap->name, offset); goto out; } diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index c4624b85d..6eb134e7b 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -693,7 +693,7 @@ struct ace_private int board_idx; u16 pci_command; u8 pci_latency; - char name[48]; + const char *name; #ifdef INDEX_DEBUG spinlock_t debug_lock __attribute__ ((aligned (SMP_CACHE_BYTES))); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index ca57a7a53..91fa987dc 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -719,7 +719,7 @@ static int amd8111e_tx(struct net_device *dev) return 0; } -#if CONFIG_AMD8111E_NAPI +#ifdef CONFIG_AMD8111E_NAPI /* This function handles the driver receive operation in polling mode */ static int amd8111e_rx_poll(struct net_device *dev, int * budget) { diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 77ff7df32..edcc38761 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -231,7 +231,7 @@ err_free_irq: static int arcrimi_reset(struct net_device *dev, int really_reset) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); @@ -252,7 +252,7 @@ static int arcrimi_reset(struct net_device *dev, int really_reset) static void arcrimi_setmask(struct net_device *dev, int mask) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; AINTMASK(mask); } @@ -260,7 +260,7 @@ static void arcrimi_setmask(struct net_device *dev, int mask) static int arcrimi_status(struct net_device *dev) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; return ASTATUS(); } @@ -268,7 +268,7 @@ static int arcrimi_status(struct net_device *dev) static void arcrimi_command(struct net_device *dev, int cmd) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; + void __iomem *ioaddr = lp->mem_start + 0x800; ACOMMAND(cmd); } @@ -277,7 +277,7 @@ static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -286,7 +286,7 @@ static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offse void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 5912a24a3..5d304676f 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -401,7 +401,8 @@ static int arcnet_open(struct net_device *dev) lp->rfc1201.sequence = 1; /* bring up the hardware driver */ - lp->hw.open(dev); + if (lp->hw.open) + lp->hw.open(dev); if (dev->dev_addr[0] == 0) BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 05a832a2f..ba0f8a2eb 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -566,7 +566,7 @@ static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -575,7 +575,7 @@ static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offse void *buf, int count) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *memaddr = lp->mem_start + bufnum * 512 + offset; + void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } diff --git a/drivers/net/b44.c b/drivers/net/b44.c index ba1d4fc9a..02d58a237 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -98,13 +98,24 @@ static void b44_halt(struct b44 *); static void b44_init_rings(struct b44 *); static void b44_init_hw(struct b44 *); +static inline unsigned long br32(const struct b44 *bp, unsigned long reg) +{ + return readl(bp->regs + reg); +} + +static inline void bw32(const struct b44 *bp, + unsigned long reg, unsigned long val) +{ + writel(val, bp->regs + reg); +} + static int b44_wait_bit(struct b44 *bp, unsigned long reg, u32 bit, unsigned long timeout, const int clear) { unsigned long i; for (i = 0; i < timeout; i++) { - u32 val = br32(reg); + u32 val = br32(bp, reg); if (clear && !(val & bit)) break; @@ -168,7 +179,7 @@ static u32 ssb_get_addr(struct b44 *bp, u32 id, u32 instance) static u32 ssb_get_core_rev(struct b44 *bp) { - return (br32(B44_SBIDHIGH) & SBIDHIGH_RC_MASK); + return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); } static u32 ssb_pci_setup(struct b44 *bp, u32 cores) @@ -180,13 +191,13 @@ static u32 ssb_pci_setup(struct b44 *bp, u32 cores) ssb_get_addr(bp, SBID_REG_PCI, 0)); pci_rev = ssb_get_core_rev(bp); - val = br32(B44_SBINTVEC); + val = br32(bp, B44_SBINTVEC); val |= cores; - bw32(B44_SBINTVEC, val); + bw32(bp, B44_SBINTVEC, val); - val = br32(SSB_PCI_TRANS_2); + val = br32(bp, SSB_PCI_TRANS_2); val |= SSB_PCI_PREF | SSB_PCI_BURST; - bw32(SSB_PCI_TRANS_2, val); + bw32(bp, SSB_PCI_TRANS_2, val); pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig); @@ -195,18 +206,18 @@ static u32 ssb_pci_setup(struct b44 *bp, u32 cores) static void ssb_core_disable(struct b44 *bp) { - if (br32(B44_SBTMSLOW) & SBTMSLOW_RESET) + if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) return; - bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); - bw32(B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(B44_SBTMSLOW); + br32(bp, B44_SBTMSLOW); udelay(1); - bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); + br32(bp, B44_SBTMSLOW); udelay(1); } @@ -215,31 +226,31 @@ static void ssb_core_reset(struct b44 *bp) u32 val; ssb_core_disable(bp); - bw32(B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); + br32(bp, B44_SBTMSLOW); udelay(1); /* Clear SERR if set, this is a hw bug workaround. */ - if (br32(B44_SBTMSHIGH) & SBTMSHIGH_SERR) - bw32(B44_SBTMSHIGH, 0); + if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) + bw32(bp, B44_SBTMSHIGH, 0); - val = br32(B44_SBIMSTATE); + val = br32(bp, B44_SBIMSTATE); if (val & (SBIMSTATE_IBE | SBIMSTATE_TO)) - bw32(B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); + bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); - bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); + br32(bp, B44_SBTMSLOW); udelay(1); - bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK)); - br32(B44_SBTMSLOW); + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); + br32(bp, B44_SBTMSLOW); udelay(1); } static int ssb_core_unit(struct b44 *bp) { #if 0 - u32 val = br32(B44_SBADMATCH0); + u32 val = br32(bp, B44_SBADMATCH0); u32 base; type = val & SBADMATCH0_TYPE_MASK; @@ -263,7 +274,7 @@ static int ssb_core_unit(struct b44 *bp) static int ssb_is_core_up(struct b44 *bp) { - return ((br32(B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) + return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) == SBTMSLOW_CLOCK); } @@ -275,19 +286,19 @@ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) val |= ((u32) data[3]) << 16; val |= ((u32) data[4]) << 8; val |= ((u32) data[5]) << 0; - bw32(B44_CAM_DATA_LO, val); + bw32(bp, B44_CAM_DATA_LO, val); val = (CAM_DATA_HI_VALID | (((u32) data[0]) << 8) | (((u32) data[1]) << 0)); - bw32(B44_CAM_DATA_HI, val); - bw32(B44_CAM_CTRL, (CAM_CTRL_WRITE | + bw32(bp, B44_CAM_DATA_HI, val); + bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT))); b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); } static inline void __b44_disable_ints(struct b44 *bp) { - bw32(B44_IMASK, 0); + bw32(bp, B44_IMASK, 0); } static void b44_disable_ints(struct b44 *bp) @@ -295,34 +306,34 @@ static void b44_disable_ints(struct b44 *bp) __b44_disable_ints(bp); /* Flush posted writes. */ - br32(B44_IMASK); + br32(bp, B44_IMASK); } static void b44_enable_ints(struct b44 *bp) { - bw32(B44_IMASK, bp->imask); + bw32(bp, B44_IMASK, bp->imask); } static int b44_readphy(struct b44 *bp, int reg, u32 *val) { int err; - bw32(B44_EMAC_ISTAT, EMAC_INT_MII); - bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START | + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); - *val = br32(B44_MDIO_DATA) & MDIO_DATA_DATA; + *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA; return err; } static int b44_writephy(struct b44 *bp, int reg, u32 val) { - bw32(B44_EMAC_ISTAT, EMAC_INT_MII); - bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START | + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | @@ -382,20 +393,20 @@ static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE); bp->flags |= pause_flags; - val = br32(B44_RXCONFIG); + val = br32(bp, B44_RXCONFIG); if (pause_flags & B44_FLAG_RX_PAUSE) val |= RXCONFIG_FLOW; else val &= ~RXCONFIG_FLOW; - bw32(B44_RXCONFIG, val); + bw32(bp, B44_RXCONFIG, val); - val = br32(B44_MAC_FLOW); + val = br32(bp, B44_MAC_FLOW); if (pause_flags & B44_FLAG_TX_PAUSE) val |= (MAC_FLOW_PAUSE_ENAB | (0xc0 & MAC_FLOW_RX_HI_WATER)); else val &= ~MAC_FLOW_PAUSE_ENAB; - bw32(B44_MAC_FLOW, val); + bw32(bp, B44_MAC_FLOW, val); } static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) @@ -491,11 +502,11 @@ static void b44_stats_update(struct b44 *bp) val = &bp->hw_stats.tx_good_octets; for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) { - *val++ += br32(reg); + *val++ += br32(bp, reg); } val = &bp->hw_stats.rx_good_octets; for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) { - *val++ += br32(reg); + *val++ += br32(bp, reg); } } @@ -535,14 +546,14 @@ static void b44_check_phy(struct b44 *bp) if (!netif_carrier_ok(bp->dev) && (bmsr & BMSR_LSTATUS)) { - u32 val = br32(B44_TX_CTRL); + u32 val = br32(bp, B44_TX_CTRL); u32 local_adv, remote_adv; if (bp->flags & B44_FLAG_FULL_DUPLEX) val |= TX_CTRL_DUPLEX; else val &= ~TX_CTRL_DUPLEX; - bw32(B44_TX_CTRL, val); + bw32(bp, B44_TX_CTRL, val); if (!(bp->flags & B44_FLAG_FORCE_LINK) && !b44_readphy(bp, MII_ADVERTISE, &local_adv) && @@ -587,7 +598,7 @@ static void b44_tx(struct b44 *bp) { u32 cur, cons; - cur = br32(B44_DMATX_STAT) & DMATX_STAT_CDMASK; + cur = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK; cur /= sizeof(struct dma_desc); /* XXX needs updating when NETIF_F_SG is supported */ @@ -611,7 +622,7 @@ static void b44_tx(struct b44 *bp) TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH) netif_wake_queue(bp->dev); - bw32(B44_GPTIMER, 0); + bw32(bp, B44_GPTIMER, 0); } /* Works like this. This chip writes a 'struct rx_header" 30 bytes @@ -708,7 +719,7 @@ static int b44_rx(struct b44 *bp, int budget) u32 cons, prod; received = 0; - prod = br32(B44_DMARX_STAT) & DMARX_STAT_CDMASK; + prod = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK; prod /= sizeof(struct dma_desc); cons = bp->rx_cons; @@ -787,7 +798,7 @@ static int b44_rx(struct b44 *bp, int budget) } bp->rx_cons = cons; - bw32(B44_DMARX_PTR, cons * sizeof(struct dma_desc)); + bw32(bp, B44_DMARX_PTR, cons * sizeof(struct dma_desc)); return received; } @@ -851,8 +862,8 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_lock_irqsave(&bp->lock, flags); - istat = br32(B44_ISTAT); - imask = br32(B44_IMASK); + istat = br32(bp, B44_ISTAT); + imask = br32(bp, B44_IMASK); /* ??? What the fuck is the purpose of the interrupt mask * ??? register if we have to mask it out by hand anyways? @@ -872,8 +883,8 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev->name); } - bw32(B44_ISTAT, istat); - br32(B44_ISTAT); + bw32(bp, B44_ISTAT, istat); + br32(bp, B44_ISTAT); } spin_unlock_irqrestore(&bp->lock, flags); return IRQ_RETVAL(handled); @@ -937,11 +948,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) wmb(); - bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc)); + bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc)); if (bp->flags & B44_FLAG_BUGGY_TXPTR) - bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc)); + bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc)); if (bp->flags & B44_FLAG_REORDER_BUG) - br32(B44_DMATX_PTR); + br32(bp, B44_DMATX_PTR); if (TX_BUFFS_AVAIL(bp) < 1) netif_stop_queue(dev); @@ -1109,27 +1120,27 @@ static void b44_clear_stats(struct b44 *bp) { unsigned long reg; - bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); + bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) - br32(reg); + br32(bp, reg); for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) - br32(reg); + br32(bp, reg); } /* bp->lock is held. */ static void b44_chip_reset(struct b44 *bp) { if (ssb_is_core_up(bp)) { - bw32(B44_RCV_LAZY, 0); - bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE); + bw32(bp, B44_RCV_LAZY, 0); + bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1); - bw32(B44_DMATX_CTRL, 0); + bw32(bp, B44_DMATX_CTRL, 0); bp->tx_prod = bp->tx_cons = 0; - if (br32(B44_DMARX_STAT) & DMARX_STAT_EMASK) { + if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) { b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE, 100, 0); } - bw32(B44_DMARX_CTRL, 0); + bw32(bp, B44_DMARX_CTRL, 0); bp->rx_prod = bp->rx_cons = 0; } else { ssb_pci_setup(bp, (bp->core_unit == 0 ? @@ -1142,20 +1153,20 @@ static void b44_chip_reset(struct b44 *bp) b44_clear_stats(bp); /* Make PHY accessible. */ - bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | + bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); - br32(B44_MDIO_CTRL); + br32(bp, B44_MDIO_CTRL); - if (!(br32(B44_DEVCTRL) & DEVCTRL_IPP)) { - bw32(B44_ENET_CTRL, ENET_CTRL_EPSEL); - br32(B44_ENET_CTRL); + if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { + bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL); + br32(bp, B44_ENET_CTRL); bp->flags &= ~B44_FLAG_INTERNAL_PHY; } else { - u32 val = br32(B44_DEVCTRL); + u32 val = br32(bp, B44_DEVCTRL); if (val & DEVCTRL_EPR) { - bw32(B44_DEVCTRL, (val & ~DEVCTRL_EPR)); - br32(B44_DEVCTRL); + bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR)); + br32(bp, B44_DEVCTRL); udelay(100); } bp->flags |= B44_FLAG_INTERNAL_PHY; @@ -1172,13 +1183,13 @@ static void b44_halt(struct b44 *bp) /* bp->lock is held. */ static void __b44_set_mac_addr(struct b44 *bp) { - bw32(B44_CAM_CTRL, 0); + bw32(bp, B44_CAM_CTRL, 0); if (!(bp->dev->flags & IFF_PROMISC)) { u32 val; __b44_cam_write(bp, bp->dev->dev_addr, 0); - val = br32(B44_CAM_CTRL); - bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE); + val = br32(bp, B44_CAM_CTRL); + bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); } } @@ -1212,30 +1223,30 @@ static void b44_init_hw(struct b44 *bp) b44_setup_phy(bp); /* Enable CRC32, set proper LED modes and power on PHY */ - bw32(B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); - bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); + bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); + bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); /* This sets the MAC address too. */ __b44_set_rx_mode(bp->dev); /* MTU + eth header + possible VLAN tag + struct rx_header */ - bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); - bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); + bw32(bp, B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); + bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); - bw32(B44_TX_WMARK, 56); /* XXX magic */ - bw32(B44_DMATX_CTRL, DMATX_CTRL_ENABLE); - bw32(B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); - bw32(B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | + bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ + bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); + bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); + bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); - bw32(B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); + bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); - bw32(B44_DMARX_PTR, bp->rx_pending); + bw32(bp, B44_DMARX_PTR, bp->rx_pending); bp->rx_prod = bp->rx_pending; - bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); + bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); - val = br32(B44_ENET_CTRL); - bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); + val = br32(bp, B44_ENET_CTRL); + bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); } static int b44_open(struct net_device *dev) @@ -1372,11 +1383,11 @@ static void __b44_set_rx_mode(struct net_device *dev) int i=0; unsigned char zero[6] = {0,0,0,0,0,0}; - val = br32(B44_RXCONFIG); + val = br32(bp, B44_RXCONFIG); val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); if (dev->flags & IFF_PROMISC) { val |= RXCONFIG_PROMISC; - bw32(B44_RXCONFIG, val); + bw32(bp, B44_RXCONFIG, val); } else { __b44_set_mac_addr(bp); @@ -1388,9 +1399,9 @@ static void __b44_set_rx_mode(struct net_device *dev) for(;i<64;i++) { __b44_cam_write(bp, zero, i); } - bw32(B44_RXCONFIG, val); - val = br32(B44_CAM_CTRL); - bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE); + bw32(bp, B44_RXCONFIG, val); + val = br32(bp, B44_CAM_CTRL); + bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); } } @@ -1760,7 +1771,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, spin_lock_init(&bp->lock); - bp->regs = (unsigned long) ioremap(b44reg_base, b44reg_len); + bp->regs = ioremap(b44reg_base, b44reg_len); if (bp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -1826,7 +1837,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, return 0; err_out_iounmap: - iounmap((void *) bp->regs); + iounmap(bp->regs); err_out_free_dev: free_netdev(dev); @@ -1848,7 +1859,7 @@ static void __devexit b44_remove_one(struct pci_dev *pdev) struct b44 *bp = netdev_priv(dev); unregister_netdev(dev); - iounmap((void *) bp->regs); + iounmap(bp->regs); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 23bee93fe..22647be2c 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -395,9 +395,6 @@ #define SSB_PCI_MASK1 0xfc000000 #define SSB_PCI_MASK2 0xc0000000 -#define br32(REG) readl(bp->regs + (REG)) -#define bw32(REG,VAL) writel((VAL), bp->regs + (REG)) - /* 4400 PHY registers */ #define B44_MII_AUXCTRL 24 /* Auxiliary Control */ #define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */ @@ -530,7 +527,7 @@ struct b44 { struct net_device_stats stats; struct b44_hw_stats hw_stats; - unsigned long regs; + void __iomem *regs; struct pci_dev *pdev; struct net_device *dev; diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 49f5ceee5..a76519afa 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1285,7 +1285,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) int res = 1; skb->mac.raw = (unsigned char *)skb->data; - eth_data = (struct ethhdr *)skb->data; + eth_data = eth_hdr(skb); /* make sure that the curr_active_slave and the slaves list do * not change during tx diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index b04bf5e72..3ce3237b1 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -84,6 +84,9 @@ Oskar Schirmer : oskar@scara.com : HiCO.SH4 (superh) support added (irq#1, cs89x0_media=) + Deepak Saxena : dsaxena@plexity.net + : Intel IXDP2x01 (XScale ixp2x00 NPU) platform support + */ /* Always include 'config.h' first in case the user wants to turn on @@ -97,7 +100,11 @@ * Note that even if DMA is turned off we still support the 'dma' and 'use_dma' * module options so we don't break any startup scripts. */ +#ifndef CONFIG_ARCH_IXDP2X01 +#define ALLOW_DMA 0 +#else #define ALLOW_DMA 1 +#endif /* * Set this to zero to remove all the debug statements via @@ -162,6 +169,10 @@ static unsigned int cs8900_irq_map[] = {12,0,0,0}; static unsigned int netcard_portlist[] __initdata = { 0x0300, 0}; static unsigned int cs8900_irq_map[] = {1,0,0,0}; +#elif defined(CONFIG_ARCH_IXDP2X01) +#include +static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; +static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -454,11 +465,12 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) retval = -ENODEV; goto out2; } - ioaddr &= ~3; - outw(PP_ChipID, ioaddr + ADD_PORT); } printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); + ioaddr &= ~3; + outw(PP_ChipID, ioaddr + ADD_PORT); + if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { printk(KERN_ERR "%s: incorrect signature 0x%x\n", dev->name, inw(ioaddr + DATA_PORT)); @@ -665,6 +677,9 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); } else { i = lp->isa_config & INT_NO_MASK; if (lp->chip_type == CS8900) { +#ifdef CONFIG_ARCH_IXDP2X01 + i = cs8900_irq_map[0]; +#else /* Translate the IRQ using the IRQ mapping table. */ if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) printk("\ncs89x0: invalid ISA interrupt number %d\n", i); @@ -681,6 +696,7 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT) lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1] << 8); } +#endif } if (!dev->irq) dev->irq = i; @@ -884,8 +900,10 @@ skip_this_frame: void __init reset_chip(struct net_device *dev) { +#ifndef CONFIG_ARCH_IXDP2X01 struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; +#endif int reset_start_time; writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); @@ -894,6 +912,7 @@ void __init reset_chip(struct net_device *dev) current->state = TASK_INTERRUPTIBLE; schedule_timeout(30*HZ/1000); +#ifndef CONFIG_ARCH_IXDP2X01 if (lp->chip_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT); @@ -904,6 +923,8 @@ void __init reset_chip(struct net_device *dev) outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } +#endif /* IXDP2x01 */ + /* Wait until the chip is reset */ reset_start_time = jiffies; while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) @@ -1155,12 +1176,14 @@ net_open(struct net_device *dev) else #endif { +#ifndef CONFIG_ARCH_IXDP2X01 if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); ret = -EAGAIN; goto bad_out; } +#endif /* FIXME: Cirrus' release had this: */ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); /* And 2.3.47 had this: */ @@ -1575,7 +1598,9 @@ static void release_dma_buff(struct net_local *lp) static int net_close(struct net_device *dev) { +#if ALLOW_DMA struct net_local *lp = netdev_priv(dev); +#endif netif_stop_queue(dev); diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index f1507b549..b0ef7ad2b 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -16,6 +16,13 @@ #include +#ifdef CONFIG_ARCH_IXDP2X01 +/* IXDP2401/IXDP2801 uses dword-aligned register addressing */ +#define CS89x0_PORT(reg) ((reg) * 2) +#else +#define CS89x0_PORT(reg) (reg) +#endif + #define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ /* offset 2h -> Model/Product Number */ /* offset 3h -> Chip Revision Number */ @@ -324,16 +331,16 @@ #define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ #define PKT_START PP_TxFrame /* Start of packet RAM */ -#define RX_FRAME_PORT 0x0000 +#define RX_FRAME_PORT CS89x0_PORT(0x0000) #define TX_FRAME_PORT RX_FRAME_PORT -#define TX_CMD_PORT 0x0004 +#define TX_CMD_PORT CS89x0_PORT(0x0004) #define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ #define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ #define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ -#define TX_LEN_PORT 0x0006 -#define ISQ_PORT 0x0008 -#define ADD_PORT 0x000A -#define DATA_PORT 0x000C +#define TX_LEN_PORT CS89x0_PORT(0x0006) +#define ISQ_PORT CS89x0_PORT(0x0008) +#define ADD_PORT CS89x0_PORT(0x000A) +#define DATA_PORT CS89x0_PORT(0x000C) #define EEPROM_WRITE_EN 0x00F0 #define EEPROM_WRITE_DIS 0x0000 diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 9ef9f3944..85d1bb3a9 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -1814,16 +1814,18 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) /* Fill the bp->stats structure with driver-maintained counters */ - bp->stats.rx_packets = bp->rcv_total_frames; - bp->stats.tx_packets = bp->xmt_total_frames; - bp->stats.rx_bytes = bp->rcv_total_bytes; - bp->stats.tx_bytes = bp->xmt_total_bytes; - bp->stats.rx_errors = (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors); - bp->stats.tx_errors = bp->xmt_length_errors; - bp->stats.rx_dropped = bp->rcv_discards; - bp->stats.tx_dropped = bp->xmt_discards; - bp->stats.multicast = bp->rcv_multicast_frames; - bp->stats.transmit_collision = 0; /* always zero (0) for FDDI */ + bp->stats.gen.rx_packets = bp->rcv_total_frames; + bp->stats.gen.tx_packets = bp->xmt_total_frames; + bp->stats.gen.rx_bytes = bp->rcv_total_bytes; + bp->stats.gen.tx_bytes = bp->xmt_total_bytes; + bp->stats.gen.rx_errors = bp->rcv_crc_errors + + bp->rcv_frame_status_errors + + bp->rcv_length_errors; + bp->stats.gen.tx_errors = bp->xmt_length_errors; + bp->stats.gen.rx_dropped = bp->rcv_discards; + bp->stats.gen.tx_dropped = bp->xmt_discards; + bp->stats.gen.multicast = bp->rcv_multicast_frames; + bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ /* Get FDDI SMT MIB objects */ diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index 86302faf9..d46367392 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/e100.c b/drivers/net/e100.c index 8855b20e3..a39b58c81 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -87,9 +87,8 @@ * cb_to_use is the next CB to use for queuing a command; cb_to_clean * is the next CB to check for completion; cb_to_send is the first * CB to start on in case of a previous failure to resume. CB clean - * up happens in interrupt context in response to a CU interrupt, or - * in dev->poll in the case where NAPI is enabled. cbs_avail keeps - * track of number of free CB resources available. + * up happens in interrupt context in response to a CU interrupt. + * cbs_avail keeps track of number of free CB resources available. * * Hardware padding of short packets to minimum packet size is * enabled. 82557 pads with 7Eh, while the later controllers pad @@ -112,9 +111,8 @@ * replacement RFDs cannot be allocated, or the RU goes non-active, * the RU must be restarted. Frame arrival generates an interrupt, * and Rx indication and re-allocation happen in the same context, - * therefore no locking is required. If NAPI is enabled, this work - * happens in dev->poll. A software-generated interrupt is gen- - * erated from the watchdog to recover from a failed allocation + * therefore no locking is required. A software-generated interrupt + * is generated from the watchdog to recover from a failed allocation * senario where all Rx resources have been indicated and none re- * placed. * @@ -126,8 +124,6 @@ * supported. Tx Scatter/Gather is not supported. Jumbo Frames is * not supported (hardware limitation). * - * NAPI support is enabled with CONFIG_E100_NAPI. - * * MagicPacket(tm) WoL support is enabled/disabled via ethtool. * * Thanks to JC (jchapman@katalix.com) for helping with @@ -158,7 +154,8 @@ #define DRV_NAME "e100" -#define DRV_VERSION "3.0.18" +#define DRV_EXT "-NAPI" +#define DRV_VERSION "3.0.27-k2"DRV_EXT #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" #define PFX DRV_NAME ": " @@ -201,6 +198,8 @@ static struct pci_device_id e100_id_table[] = { INTEL_8255X_ETHERNET_DEVICE(0x1053, 5), INTEL_8255X_ETHERNET_DEVICE(0x1054, 5), INTEL_8255X_ETHERNET_DEVICE(0x1055, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1056, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1057, 5), INTEL_8255X_ETHERNET_DEVICE(0x1064, 6), INTEL_8255X_ETHERNET_DEVICE(0x1065, 6), INTEL_8255X_ETHERNET_DEVICE(0x1066, 6), @@ -242,6 +241,7 @@ enum phy { phy_nsc_tx = 0x5C002000, phy_82562_et = 0x033002A8, phy_82562_em = 0x032002A8, + phy_82562_ek = 0x031002A8, phy_82562_eh = 0x017002A8, phy_unknown = 0xFFFFFFFF, }; @@ -330,11 +330,16 @@ enum eeprom_op { }; enum eeprom_offsets { + eeprom_cnfg_mdix = 0x03, eeprom_id = 0x0A, eeprom_config_asf = 0x0D, eeprom_smbus_addr = 0x90, }; +enum eeprom_cnfg_mdix { + eeprom_mdix_enabled = 0x0080, +}; + enum eeprom_id { eeprom_id_wol = 0x0020, }; @@ -350,10 +355,12 @@ enum cb_status { }; enum cb_command { + cb_nop = 0x0000, cb_iaaddr = 0x0001, cb_config = 0x0002, cb_multi = 0x0003, cb_tx = 0x0004, + cb_ucode = 0x0005, cb_dump = 0x0006, cb_tx_sf = 0x0008, cb_cid = 0x1f00, @@ -428,12 +435,14 @@ struct multi { }; /* Important: keep total struct u32-aligned */ +#define UCODE_SIZE 134 struct cb { u16 status; u16 command; u32 link; union { u8 iaaddr[ETH_ALEN]; + u32 ucode[UCODE_SIZE]; struct config config; struct multi multi; struct { @@ -548,6 +557,7 @@ struct nic { u32 rx_fc_pause; u32 rx_fc_unsupported; u32 rx_tco_frames; + u32 rx_over_length_errors; u8 rev_id; u16 leds; @@ -980,6 +990,27 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); } +static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + int i; + static const u32 ucode[UCODE_SIZE] = { + /* NFS packets are misinterpreted as TCO packets and + * incorrectly routed to the BMC over SMBus. This + * microcode patch checks the fragmented IP bit in the + * NFS/UDP header to distinguish between NFS and TCO. */ + 0x0EF70E36, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, + 0x1FFF1FFF, 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, + 0x00906EFD, 0x00900EFD, 0x00E00EF8, + }; + + if(nic->mac == mac_82551_F || nic->mac == mac_82551_10) { + for(i = 0; i < UCODE_SIZE; i++) + cb->u.ucode[i] = cpu_to_le32(ucode[i]); + cb->command = cpu_to_le16(cb_ucode); + } else + cb->command = cpu_to_le16(cb_nop); +} + static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, struct sk_buff *skb) { @@ -1045,7 +1076,9 @@ static int e100_phy_init(struct nic *nic) mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); } - if(nic->mac >= mac_82550_D102) + if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && + (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && + (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) /* enable/disable MDI/MDI-X auto-switching */ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); @@ -1069,6 +1102,8 @@ static int e100_hw_init(struct nic *nic) return err; if((err = e100_exec_cmd(nic, ruc_load_base, 0))) return err; + if((err = e100_exec_cb(nic, NULL, e100_load_ucode))) + return err; if((err = e100_exec_cb(nic, NULL, e100_configure))) return err; if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr))) @@ -1143,9 +1178,11 @@ static void e100_update_stats(struct nic *nic) ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + le32_to_cpu(s->tx_lost_crs); ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); - ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors); + ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) + + nic->rx_over_length_errors; ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); + ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors); ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + le32_to_cpu(s->rx_alignment_errors) + @@ -1456,18 +1493,14 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, dev_kfree_skb_any(skb); } else if(actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) { /* Don't indicate oversized frames */ - nic->net_stats.rx_over_errors++; + nic->rx_over_length_errors++; nic->net_stats.rx_dropped++; dev_kfree_skb_any(skb); } else { nic->net_stats.rx_packets++; nic->net_stats.rx_bytes += actual_size; nic->netdev->last_rx = jiffies; -#ifdef CONFIG_E100_NAPI netif_receive_skb(skb); -#else - netif_rx(skb); -#endif if(work_done) (*work_done)++; } @@ -1562,20 +1595,12 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) if(stat_ack & stat_ack_rnr) nic->ru_running = 0; -#ifdef CONFIG_E100_NAPI e100_disable_irq(nic); netif_rx_schedule(netdev); -#else - if(stat_ack & stat_ack_rx) - e100_rx_clean(nic, NULL, 0); - if(stat_ack & stat_ack_tx) - e100_tx_clean(nic); -#endif return IRQ_HANDLED; } -#ifdef CONFIG_E100_NAPI static int e100_poll(struct net_device *netdev, int *budget) { struct nic *nic = netdev_priv(netdev); @@ -1598,7 +1623,6 @@ static int e100_poll(struct net_device *netdev, int *budget) return 1; } -#endif #ifdef CONFIG_NET_POLL_CONTROLLER static void e100_netpoll(struct net_device *netdev) @@ -1641,7 +1665,7 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu) static int e100_asf(struct nic *nic) { /* ASF can be enabled from eeprom */ - return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) && + return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) && (nic->eeprom[eeprom_config_asf] & eeprom_asf) && !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); @@ -1961,18 +1985,27 @@ static int e100_diag_test_count(struct net_device *netdev) static void e100_diag_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { + struct ethtool_cmd cmd; struct nic *nic = netdev_priv(netdev); - int i; + int i, err; memset(data, 0, E100_TEST_LEN * sizeof(u64)); data[0] = !mii_link_ok(&nic->mii); data[1] = e100_eeprom_load(nic); if(test->flags & ETH_TEST_FL_OFFLINE) { + + /* save speed, duplex & autoneg settings */ + err = mii_ethtool_gset(&nic->mii, &cmd); + if(netif_running(netdev)) e100_down(nic); data[2] = e100_self_test(nic); data[3] = e100_loopback_test(nic, lb_mac); data[4] = e100_loopback_test(nic, lb_phy); + + /* restore speed, duplex & autoneg settings */ + err = mii_ethtool_sset(&nic->mii, &cmd); + if(netif_running(netdev)) e100_up(nic); } @@ -2135,10 +2168,8 @@ static int __devinit e100_probe(struct pci_dev *pdev, SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; -#ifdef CONFIG_E100_NAPI netdev->poll = e100_poll; netdev->weight = E100_NAPI_WEIGHT; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e100_netpoll; #endif diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 067bb099e..108e33145 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include #include #include +#include #include #ifdef NETIF_F_TSO #include @@ -77,6 +79,8 @@ #define BAR_1 1 #define BAR_5 5 +#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} struct e1000_adapter; @@ -98,11 +102,12 @@ struct e1000_adapter; #define E1000_MAX_INTR 10 -/* How many descriptors for TX and RX ? */ +/* TX/RX descriptor defines */ #define E1000_DEFAULT_TXD 256 #define E1000_MAX_TXD 256 #define E1000_MIN_TXD 80 #define E1000_MAX_82544_TXD 4096 + #define E1000_DEFAULT_RXD 256 #define E1000_MAX_RXD 256 #define E1000_MIN_RXD 80 @@ -123,14 +128,11 @@ struct e1000_adapter; #define E1000_TX_HEAD_ADDR_SHIFT 7 #define E1000_PBA_TX_MASK 0xFFFF0000 -/* Flow Control High-Watermark: 5688 bytes below Rx FIFO size */ -#define E1000_FC_HIGH_DIFF 0x1638 - -/* Flow Control Low-Watermark: 5696 bytes below Rx FIFO size */ -#define E1000_FC_LOW_DIFF 0x1640 +/* Flow Control Watermarks */ +#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ +#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */ -/* Flow Control Pause Time: 858 usec */ -#define E1000_FC_PAUSE_TIME 0x0680 +#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 @@ -153,9 +155,9 @@ struct e1000_adapter; struct e1000_buffer { struct sk_buff *skb; uint64_t dma; - unsigned long length; unsigned long time_stamp; - unsigned int next_to_watch; + uint16_t length; + uint16_t next_to_watch; }; struct e1000_desc_ring { @@ -202,7 +204,7 @@ struct e1000_adapter { spinlock_t stats_lock; atomic_t irq_sem; struct work_struct tx_timeout_task; - uint8_t fc_autoneg; + uint8_t fc_autoneg; struct timer_list blink_timer; unsigned long led_status; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 9ca716eab..2e4544eca 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -88,9 +88,9 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, - { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, - { "rx_long_byte_count", E1000_STAT(stats.gorcl) } + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) @@ -170,7 +170,8 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->duplex = -1; } - ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) || + hw->autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; } @@ -192,6 +193,7 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if(netif_running(adapter->netdev)) { e1000_down(adapter); + e1000_reset(adapter); e1000_up(adapter); } else e1000_reset(adapter); @@ -199,12 +201,13 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) return 0; } -static void +static void e1000_get_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; + pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); @@ -218,9 +221,9 @@ e1000_get_pauseparam(struct net_device *netdev, } } -static int +static int e1000_set_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; @@ -271,7 +274,7 @@ e1000_set_rx_csum(struct net_device *netdev, uint32_t data) e1000_reset(adapter); return 0; } - + static uint32_t e1000_get_tx_csum(struct net_device *netdev) { @@ -337,7 +340,7 @@ e1000_get_regs_len(struct net_device *netdev) static void e1000_get_regs(struct net_device *netdev, - struct ethtool_regs *regs, void *p) + struct ethtool_regs *regs, void *p) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; @@ -418,6 +421,10 @@ e1000_get_regs(struct net_device *netdev, e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ + if(hw->mac_type >= e1000_82540 && + hw->media_type == e1000_media_type_copper) { + regs_buff[26] = E1000_READ_REG(hw, MANC); + } } static int @@ -438,7 +445,7 @@ e1000_get_eeprom(struct net_device *netdev, int ret_val = 0; uint16_t i; - if(eeprom->len == 0) + if(eeprom->len == 0) return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); @@ -446,9 +453,9 @@ e1000_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(uint16_t) * + eeprom_buff = kmalloc(sizeof(uint16_t) * (last_word - first_word + 1), GFP_KERNEL); - if (!eeprom_buff) + if(!eeprom_buff) return -ENOMEM; if(hw->eeprom.type == e1000_eeprom_spi) @@ -466,9 +473,8 @@ e1000_get_eeprom(struct net_device *netdev, for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); - - memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset%2), - eeprom->len); + memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset & 1), + eeprom->len); kfree(eeprom_buff); return ret_val; @@ -520,6 +526,7 @@ e1000_set_eeprom(struct net_device *netdev, le16_to_cpus(&eeprom_buff[i]); memcpy(ptr, bytes, eeprom->len); + for (i = 0; i < last_word - first_word + 1; i++) eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); @@ -575,17 +582,16 @@ static int e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - int err; struct e1000_adapter *adapter = netdev->priv; e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_desc_ring *txdr = &adapter->tx_ring; struct e1000_desc_ring *rxdr = &adapter->rx_ring; - struct e1000_desc_ring tx_old, tx_new; - struct e1000_desc_ring rx_old, rx_new; + struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new; + int err; tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; - + if(netif_running(adapter->netdev)) e1000_down(adapter); @@ -600,15 +606,15 @@ e1000_set_ringparam(struct net_device *netdev, E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); if(netif_running(adapter->netdev)) { - /* try to get new resources before deleting old */ + /* Try to get new resources before deleting old */ if((err = e1000_setup_rx_resources(adapter))) goto err_setup_rx; if((err = e1000_setup_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, - * then restore the new back again */ - + * then restore the new back again */ + rx_new = adapter->rx_ring; tx_new = adapter->tx_ring; adapter->rx_ring = rx_old; @@ -620,6 +626,7 @@ e1000_set_ringparam(struct net_device *netdev, if((err = e1000_up(adapter))) return err; } + return 0; err_setup_tx: e1000_free_rx_resources(adapter); @@ -766,13 +773,15 @@ static int e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) { struct net_device *netdev = adapter->netdev; - uint32_t icr, mask, i=0; + uint32_t icr, mask, i=0, shared_int = TRUE; + uint32_t irq = adapter->pdev->irq; *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, - netdev->name, netdev)) { + if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) { + shared_int = FALSE; + } else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){ *data = 1; return -1; } @@ -802,20 +811,22 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) /* Interrupt to test */ mask = 1 << i; - /* Disable the interrupt to be reported in - * the cause register and then force the same - * interrupt and see if one gets posted. If - * an interrupt was posted to the bus, the - * test failed. - */ - adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, mask); - E1000_WRITE_REG(&adapter->hw, ICS, mask); - msec_delay(10); - - if(adapter->test_icr & mask) { - *data = 3; - break; + if(!shared_int) { + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(adapter->test_icr & mask) { + *data = 3; + break; + } } /* Enable the interrupt to be reported in @@ -834,20 +845,22 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) break; } - /* Disable the other interrupts to be reported in - * the cause register and then force the other - * interrupts and see if any get posted. If - * an interrupt was posted to the bus, the - * test failed. - */ - adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, ~mask); - E1000_WRITE_REG(&adapter->hw, ICS, ~mask); - msec_delay(10); + if(!shared_int) { + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, ~mask); + E1000_WRITE_REG(&adapter->hw, ICS, ~mask); + msec_delay(10); - if(adapter->test_icr) { - *data = 5; - break; + if(adapter->test_icr) { + *data = 5; + break; + } } } @@ -856,7 +869,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) msec_delay(10); /* Unhook test interrupt handler */ - free_irq(adapter->pdev->irq, netdev); + free_irq(irq, netdev); return *data; } @@ -1021,7 +1034,7 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) return 0; - err_nomem: +err_nomem: e1000_free_desc_rings(adapter); return ret_val; } @@ -1312,15 +1325,15 @@ e1000_run_loopback_test(struct e1000_adapter *adapter) for(i = 0; i < 64; i++) { e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); - pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, - txdr->buffer_info[i].length, - PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); } E1000_WRITE_REG(&adapter->hw, TDT, i); msec_delay(200); - pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, + pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[0].dma, rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024); @@ -1357,7 +1370,7 @@ e1000_diag_test_count(struct net_device *netdev) } static void -e1000_diag_test(struct net_device *netdev, +e1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, uint64_t *data) { struct e1000_adapter *adapter = netdev->priv; @@ -1368,7 +1381,7 @@ e1000_diag_test(struct net_device *netdev, /* save speed, duplex, autoneg settings */ uint16_t autoneg_advertised = adapter->hw.autoneg_advertised; - uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; + uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; uint8_t autoneg = adapter->hw.autoneg; /* Link test performed before hardware reset so autoneg doesn't @@ -1396,10 +1409,11 @@ e1000_diag_test(struct net_device *netdev, if(e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; - /* restore Autoneg/speed/duplex settings */ + /* restore speed, duplex, autoneg settings */ adapter->hw.autoneg_advertised = autoneg_advertised; - adapter->hw.forced_speed_duplex = forced_speed_duplex; - adapter->hw.autoneg = autoneg; + adapter->hw.forced_speed_duplex = forced_speed_duplex; + adapter->hw.autoneg = autoneg; + e1000_reset(adapter); if(if_running) e1000_up(adapter); @@ -1427,6 +1441,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: wol->supported = 0; wol->wolopts = 0; return; @@ -1469,6 +1484,7 @@ e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: return wol->wolopts ? -EOPNOTSUPP : 0; case E1000_DEV_ID_82546EB_FIBER: @@ -1571,8 +1587,8 @@ e1000_get_ethtool_stats(struct net_device *netdev, e1000_update_stats(adapter); for(i = 0; i < E1000_STATS_LEN; i++) { char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; - data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) - ? *(uint64_t *)p : *(uint32_t *)p; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; } } diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 41c05e5c3..7c8cd3990 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -251,6 +251,7 @@ e1000_set_mac_type(struct e1000_hw *hw) break; case E1000_DEV_ID_82541ER: case E1000_DEV_ID_82541GI: + case E1000_DEV_ID_82541GI_LF: case E1000_DEV_ID_82541GI_MOBILE: hw->mac_type = e1000_82541_rev_2; break; @@ -920,7 +921,8 @@ e1000_setup_copper_link(struct e1000_hw *hw) if(ret_val) return ret_val; - if(hw->mac_type == e1000_82545_rev_3) { + if((hw->mac_type == e1000_82545_rev_3) || + (hw->mac_type == e1000_82546_rev_3)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); phy_data |= 0x00000008; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); @@ -3057,16 +3059,6 @@ e1000_init_eeprom_params(struct e1000_hw *hw) } break; default: - eeprom->type = e1000_eeprom_spi; - eeprom->opcode_bits = 8; - eeprom->delay_usec = 1; - if (eecd & E1000_EECD_ADDR_BITS) { - eeprom->page_size = 32; - eeprom->address_bits = 16; - } else { - eeprom->page_size = 8; - eeprom->address_bits = 8; - } break; } @@ -3453,7 +3445,6 @@ e1000_read_eeprom(struct e1000_hw *hw, uint32_t i = 0; DEBUGFUNC("e1000_read_eeprom"); - /* A check for invalid values: offset too large, too many words, and not * enough words. */ @@ -5224,3 +5215,4 @@ e1000_enable_mng_pass_thru(struct e1000_hw *hw) } return FALSE; } + diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index c9ee93a0d..9fb134ded 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -357,11 +357,11 @@ int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); #define E1000_DEV_ID_82547GI 0x1075 #define E1000_DEV_ID_82541GI 0x1076 #define E1000_DEV_ID_82541GI_MOBILE 0x1077 +#define E1000_DEV_ID_82541GI_LF 0x107C #define E1000_DEV_ID_82546GB_COPPER 0x1079 #define E1000_DEV_ID_82546GB_FIBER 0x107A #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82547EI 0x1019 - #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -1043,7 +1043,6 @@ struct e1000_hw { #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ #define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ - /* Register Bit Masks */ /* Device Control */ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4b9b77567..cac241e5a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -27,73 +27,69 @@ *******************************************************************************/ #include "e1000.h" -#include /* Change Log + * 5.3.12 6/7/04 + * - kcompat NETIF_MSG for older kernels (2.4.9) + * - if_mii support and associated kcompat for older kernels + * - More errlogging support from Jon Mason + * - Fix TSO issues on PPC64 machines -- Jon Mason * - * 5.2.51 5/14/04 - * o set default configuration to 'NAPI disabled'. NAPI enabled driver - * causes kernel panic when the interface is shutdown while data is being - * transferred. - * 5.2.47 5/04/04 - * o fixed ethtool -t implementation - * 5.2.45 4/29/04 - * o fixed ethtool -e implementation - * o Support for ethtool ops [Stephen Hemminger (shemminger@osdl.org)] - * 5.2.42 4/26/04 - * o Added support for the DPRINTK macro for enhanced error logging. Some - * parts of the patch were supplied by Jon Mason. - * o Move the register_netdevice() donw in the probe routine due to a - * loading/unloading test issue. - * o Added a long RX byte count the the extra ethtool data members for BER - * testing purposes. - * 5.2.39 3/12/04 + * 5.3.11 6/4/04 + * - ethtool register dump reads MANC register conditionally. + * + * 5.3.10 6/1/04 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.52-k4"; +#ifndef CONFIG_E1000_NAPI +#define DRIVERNAPI +#else +#define DRIVERNAPI "-NAPI" +#endif +char e1000_driver_version[] = "5.3.19-k2"DRIVERNAPI; char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * - * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, - * Class, Class Mask, private data (not used) } + * Macro expands to... + * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ static struct pci_device_id e1000_pci_tbl[] = { - {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + INTEL_E1000_ETHERNET_DEVICE(0x1000), + INTEL_E1000_ETHERNET_DEVICE(0x1001), + INTEL_E1000_ETHERNET_DEVICE(0x1004), + INTEL_E1000_ETHERNET_DEVICE(0x1008), + INTEL_E1000_ETHERNET_DEVICE(0x1009), + INTEL_E1000_ETHERNET_DEVICE(0x100C), + INTEL_E1000_ETHERNET_DEVICE(0x100D), + INTEL_E1000_ETHERNET_DEVICE(0x100E), + INTEL_E1000_ETHERNET_DEVICE(0x100F), + INTEL_E1000_ETHERNET_DEVICE(0x1010), + INTEL_E1000_ETHERNET_DEVICE(0x1011), + INTEL_E1000_ETHERNET_DEVICE(0x1012), + INTEL_E1000_ETHERNET_DEVICE(0x1013), + INTEL_E1000_ETHERNET_DEVICE(0x1015), + INTEL_E1000_ETHERNET_DEVICE(0x1016), + INTEL_E1000_ETHERNET_DEVICE(0x1017), + INTEL_E1000_ETHERNET_DEVICE(0x1018), + INTEL_E1000_ETHERNET_DEVICE(0x1019), + INTEL_E1000_ETHERNET_DEVICE(0x101D), + INTEL_E1000_ETHERNET_DEVICE(0x101E), + INTEL_E1000_ETHERNET_DEVICE(0x1026), + INTEL_E1000_ETHERNET_DEVICE(0x1027), + INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x1075), + INTEL_E1000_ETHERNET_DEVICE(0x1076), + INTEL_E1000_ETHERNET_DEVICE(0x1077), + INTEL_E1000_ETHERNET_DEVICE(0x1078), + INTEL_E1000_ETHERNET_DEVICE(0x1079), + INTEL_E1000_ETHERNET_DEVICE(0x107A), + INTEL_E1000_ETHERNET_DEVICE(0x107B), + INTEL_E1000_ETHERNET_DEVICE(0x107C), /* required last entry */ {0,} }; @@ -132,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 @@ -150,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); @@ -172,7 +168,7 @@ static int e1000_resume(struct pci_dev *pdev); #ifdef CONFIG_NET_POLL_CONTROLLER /* for netdump / net console */ -static void e1000_netpoll (struct net_device *dev); +static void e1000_netpoll (struct net_device *netdev); #endif struct notifier_block e1000_notifier_reboot = { @@ -185,7 +181,6 @@ struct notifier_block e1000_notifier_reboot = { extern void e1000_check_options(struct e1000_adapter *adapter); - static struct pci_driver e1000_driver = { .name = e1000_driver_name, .id_table = e1000_pci_tbl, @@ -202,7 +197,7 @@ MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); MODULE_LICENSE("GPL"); -static int debug = 3; +static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); @@ -256,6 +251,14 @@ e1000_up(struct e1000_adapter *adapter) /* hardware has been reset, we need to reload some things */ + /* Reset the PHY if it was previously powered down */ + if(adapter->hw.media_type == e1000_media_type_copper) { + uint16_t mii_reg; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + if(mii_reg & MII_CR_POWER_DOWN) + e1000_phy_reset(&adapter->hw); + } + e1000_set_multi(netdev); e1000_restore_vlan(adapter); @@ -294,6 +297,15 @@ e1000_down(struct e1000_adapter *adapter) e1000_reset(adapter); e1000_clean_tx_ring(adapter); e1000_clean_rx_ring(adapter); + + /* If WoL is not enabled + * Power down the PHY so no link is implied when interface is down */ + if(!adapter->wol && adapter->hw.media_type == e1000_media_type_copper) { + uint16_t mii_reg; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); + } } void @@ -323,10 +335,10 @@ e1000_reset(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, PBA, pba); /* flow control settings */ - adapter->hw.fc_high_water = - (pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_HIGH_DIFF; - adapter->hw.fc_low_water = - (pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_LOW_DIFF; + adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) - + E1000_FC_HIGH_DIFF; + adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) - + E1000_FC_LOW_DIFF; adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; @@ -334,7 +346,8 @@ e1000_reset(struct e1000_adapter *adapter) e1000_reset_hw(&adapter->hw); if(adapter->hw.mac_type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, WUC, 0); - e1000_init_hw(&adapter->hw); + if(e1000_init_hw(&adapter->hw)) + DPRINTK(PROBE, ERR, "Hardware Error\n"); /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); @@ -410,8 +423,8 @@ e1000_probe(struct pci_dev *pdev, adapter->msg_enable = (1 << debug) - 1; rtnl_lock(); - /* we need to set the name early since the DPRINTK macro needs it set */ - if (dev_alloc_name(netdev, netdev->name) < 0) + /* we need to set the name early for the DPRINTK macro */ + if(dev_alloc_name(netdev, netdev->name) < 0) goto err_free_unlock; mmio_start = pci_resource_start(pdev, BAR_0); @@ -476,7 +489,6 @@ e1000_probe(struct pci_dev *pdev, } #ifdef NETIF_F_TSO -#ifdef BROKEN_ON_NON_IA_ARCHS /* Disbaled for now until root-cause is found for * hangs reported against non-IA archs. TSO can be * enabled using ethtool -K eth tso on */ @@ -484,11 +496,12 @@ e1000_probe(struct pci_dev *pdev, (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; #endif -#endif - if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + /* hard_start_xmit is safe against parallel locking */ + netdev->features |= NETIF_F_LLTX; + adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); /* before reading the EEPROM, reset the controller to @@ -506,10 +519,12 @@ e1000_probe(struct pci_dev *pdev, /* copy the MAC address out of the EEPROM */ - e1000_read_mac_addr(&adapter->hw); + if (e1000_read_mac_addr(&adapter->hw)) + DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); if(!is_valid_ether_addr(netdev->dev_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; } @@ -569,10 +584,9 @@ e1000_probe(struct pci_dev *pdev, adapter->wol |= E1000_WUFC_MAG; /* reset the hardware with the new settings */ - e1000_reset(adapter); - /* since we are holding the rtnl lock already, call the no-lock version */ + /* We're already holding the rtnl lock; call the no-lock version */ if((err = register_netdevice(netdev))) goto err_register; @@ -663,7 +677,7 @@ e1000_sw_init(struct e1000_adapter *adapter) /* identify the MAC */ - if (e1000_set_mac_type(hw)) { + if(e1000_set_mac_type(hw)) { DPRINTK(PROBE, ERR, "Unknown MAC Type\n"); return -EIO; } @@ -672,19 +686,19 @@ e1000_sw_init(struct e1000_adapter *adapter) e1000_init_eeprom_params(hw); - if((hw->mac_type == e1000_82541) || - (hw->mac_type == e1000_82547) || - (hw->mac_type == e1000_82541_rev_2) || - (hw->mac_type == e1000_82547_rev_2)) + switch(hw->mac_type) { + default: + break; + case e1000_82541: + case e1000_82547: + case e1000_82541_rev_2: + case e1000_82547_rev_2: hw->phy_init_script = 1; + break; + } e1000_set_media_type(hw); - if(hw->mac_type < e1000_82543) - hw->report_tx_early = 0; - else - hw->report_tx_early = 1; - hw->wait_autoneg_complete = FALSE; hw->tbi_compatibility_en = TRUE; hw->adaptive_ifs = TRUE; @@ -736,7 +750,7 @@ e1000_open(struct net_device *netdev) if((err = e1000_up(adapter))) goto err_up; - return 0; + return E1000_SUCCESS; err_up: e1000_free_rx_resources(adapter); @@ -788,8 +802,10 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) int size; size = sizeof(struct e1000_buffer) * txdr->count; - txdr->buffer_info = kmalloc(size, GFP_KERNEL); + txdr->buffer_info = vmalloc(size); if(!txdr->buffer_info) { + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Transmit descriptor ring\n"); return -ENOMEM; } memset(txdr->buffer_info, 0, size); @@ -801,7 +817,9 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); if(!txdr->desc) { - kfree(txdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Transmit descriptor ring\n"); + vfree(txdr->buffer_info); return -ENOMEM; } memset(txdr->desc, 0, txdr->size); @@ -878,10 +896,10 @@ e1000_configure_tx(struct e1000_adapter *adapter) adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - if(adapter->hw.report_tx_early == 1) - adapter->txd_cmd |= E1000_TXD_CMD_RS; - else + if(adapter->hw.mac_type < e1000_82543) adapter->txd_cmd |= E1000_TXD_CMD_RPS; + else + adapter->txd_cmd |= E1000_TXD_CMD_RS; /* Cache if we're 82544 running in PCI-X because we'll * need this to apply a workaround later in the send path. */ @@ -905,8 +923,10 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) int size; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = kmalloc(size, GFP_KERNEL); + rxdr->buffer_info = vmalloc(size); if(!rxdr->buffer_info) { + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Recieve descriptor ring\n"); return -ENOMEM; } memset(rxdr->buffer_info, 0, size); @@ -919,7 +939,9 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); if(!rxdr->desc) { - kfree(rxdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unble to Allocate Memory for the Recieve descriptor ring\n"); + vfree(rxdr->buffer_info); return -ENOMEM; } memset(rxdr->desc, 0, rxdr->size); @@ -953,7 +975,9 @@ e1000_setup_rctl(struct e1000_adapter *adapter) else rctl &= ~E1000_RCTL_SBP; + /* Setup buffer sizes */ rctl &= ~(E1000_RCTL_SZ_4096); + rctl |= (E1000_RCTL_BSEX | E1000_RCTL_LPE); switch (adapter->rx_buffer_len) { case E1000_RXBUFFER_2048: default: @@ -961,13 +985,13 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE); break; case E1000_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_4096; break; case E1000_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_8192; break; case E1000_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_16384; break; } @@ -989,13 +1013,11 @@ e1000_configure_rx(struct e1000_adapter *adapter) uint32_t rctl; uint32_t rxcsum; - /* make sure receives are disabled while setting up the descriptors */ - + /* disable receives while setting up the descriptors */ rctl = E1000_READ_REG(&adapter->hw, RCTL); E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); if(adapter->hw.mac_type >= e1000_82540) { @@ -1006,7 +1028,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) } /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL)); E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); @@ -1025,7 +1046,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) } /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } @@ -1043,7 +1063,7 @@ e1000_free_tx_resources(struct e1000_adapter *adapter) e1000_clean_tx_ring(adapter); - kfree(adapter->tx_ring.buffer_info); + vfree(adapter->tx_ring.buffer_info); adapter->tx_ring.buffer_info = NULL; pci_free_consistent(pdev, adapter->tx_ring.size, @@ -1073,9 +1093,9 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter) if(buffer_info->skb) { pci_unmap_page(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_TODEVICE); + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); dev_kfree_skb(buffer_info->skb); @@ -1112,7 +1132,7 @@ e1000_free_rx_resources(struct e1000_adapter *adapter) e1000_clean_rx_ring(adapter); - kfree(rx_ring->buffer_info); + vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); @@ -1141,12 +1161,11 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) if(buffer_info->skb) { pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); dev_kfree_skb(buffer_info->skb); - buffer_info->skb = NULL; } } @@ -1259,9 +1278,12 @@ e1000_set_multi(struct net_device *netdev) uint32_t rctl; uint32_t hash_value; int i; + unsigned long flags; /* Check for Promiscuous and All Multicast modes */ + spin_lock_irqsave(&adapter->tx_lock, flags); + rctl = E1000_READ_REG(hw, RCTL); if(netdev->flags & IFF_PROMISC) { @@ -1310,9 +1332,12 @@ e1000_set_multi(struct net_device *netdev) if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); + + spin_unlock_irqrestore(&adapter->tx_lock, flags); } -/* need to wait a few seconds after link up to get diagnostic information from the phy */ +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ static void e1000_update_phy_info(unsigned long data) @@ -1420,7 +1445,7 @@ e1000_watchdog(unsigned long data) adapter->tpt_old = adapter->stats.tpt; adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old; adapter->colc_old = adapter->stats.colc; - + adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; adapter->gorcl_old = adapter->stats.gorcl; adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; @@ -1477,8 +1502,9 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; unsigned int i; - uint8_t ipcss, ipcso, tucss, tucso, hdr_len; + uint32_t cmd_length = 0; uint16_t ipcse, tucse, mss; + uint8_t ipcss, ipcso, tucss, tucso, hdr_len; if(skb_shinfo(skb)->tso_size) { hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); @@ -1497,6 +1523,10 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | + (skb->len - (hdr_len))); + i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); @@ -1508,10 +1538,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; - context_desc->cmd_and_length = cpu_to_le32( - E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | - E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | - (skb->len - (hdr_len))); + context_desc->cmd_and_length = cpu_to_le32(cmd_length); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; @@ -1528,22 +1555,21 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) { struct e1000_context_desc *context_desc; unsigned int i; - uint8_t css, cso; + uint8_t css; - if(skb->ip_summed == CHECKSUM_HW) { + if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; - cso = (skb->h.raw + skb->csum) - skb->data; i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = cso; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); - if(++i == adapter->tx_ring.count) i = 0; + if(unlikely(++i == adapter->tx_ring.count)) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; @@ -1567,7 +1593,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, unsigned int f; len -= skb->data_len; - i = tx_ring->next_to_use; while(len) { @@ -1576,14 +1601,14 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(mss && !nr_frags && size == len && size > 8) + if(unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. Avoid * terminating buffers within evenly-aligned dwords. */ - if(adapter->pcix_82544 && + if(unlikely(adapter->pcix_82544 && !((unsigned long)(skb->data + offset + size - 1) & 4) && - size > 4) + size > 4)) size -= 4; buffer_info->length = size; @@ -1597,7 +1622,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } for(f = 0; f < nr_frags; f++) { @@ -1613,15 +1638,15 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(mss && f == (nr_frags-1) && size == len && size > 8) + if(unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ - if(adapter->pcix_82544 && + if(unlikely(adapter->pcix_82544 && !((unsigned long)(frag->page+offset+size-1) & 4) && - size > 4) + size > 4)) size -= 4; buffer_info->length = size; @@ -1636,13 +1661,14 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } } + i = (i == 0) ? tx_ring->count - 1 : i - 1; tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - + return count; } @@ -1655,18 +1681,18 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; unsigned int i; - if(tx_flags & E1000_TX_FLAGS_TSO) { + if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; } - if(tx_flags & E1000_TX_FLAGS_CSUM) { + if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } - if(tx_flags & E1000_TX_FLAGS_VLAN) { + if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { txd_lower |= E1000_TXD_CMD_VLE; txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); } @@ -1680,7 +1706,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) tx_desc->lower.data = cpu_to_le32(txd_lower | buffer_info->length); tx_desc->upper.data = cpu_to_le32(txd_upper); - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); @@ -1733,7 +1759,7 @@ no_fifo_stall_required: return 0; } -#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { @@ -1741,22 +1767,23 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned long flags; unsigned int len = skb->len; - int count = 0; - unsigned int mss = 0; + unsigned long flags; unsigned int nr_frags = 0; + unsigned int mss = 0; + int count = 0; unsigned int f; nr_frags = skb_shinfo(skb)->nr_frags; len -= skb->data_len; - if(skb->len <= 0) { + + if(unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->tso_size; - /* The controller does a simple calculation to + /* The controller does a simple calculation to * make sure there is enough room in the FIFO before * initiating the DMA for each buffer. The calc is: * 4 = ceil(buffer len/mss). To make sure we don't @@ -1766,62 +1793,70 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) max_per_txd = min(mss << 2, max_per_txd); max_txd_pwr = fls(max_per_txd) - 1; } + if((mss) || (skb->ip_summed == CHECKSUM_HW)) count++; - count++; /*for sentinel desc*/ + count++; /* for sentinel desc */ #else if(skb->ip_summed == CHECKSUM_HW) count++; #endif - count += TXD_USE_COUNT(len, max_txd_pwr); + if(adapter->pcix_82544) count++; nr_frags = skb_shinfo(skb)->nr_frags; for(f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, - max_txd_pwr); + max_txd_pwr); if(adapter->pcix_82544) count += nr_frags; - - spin_lock_irqsave(&adapter->tx_lock, flags); - /* need: count + 2 desc gap to keep tail from touching + + local_irq_save(flags); + if (!spin_trylock(&adapter->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ - if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2 ) { + if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) { netif_stop_queue(netdev); spin_unlock_irqrestore(&adapter->tx_lock, flags); - return 1; + return NETDEV_TX_BUSY; } - spin_unlock_irqrestore(&adapter->tx_lock, flags); - if(adapter->hw.mac_type == e1000_82547) { - if(e1000_82547_fifo_workaround(adapter, skb)) { + if(unlikely(adapter->hw.mac_type == e1000_82547)) { + if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); - return 1; + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return NETDEV_TX_BUSY; } } - if(adapter->vlgrp && vlan_tx_tag_present(skb)) { + if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } first = adapter->tx_ring.next_to_use; - if(e1000_tso(adapter, skb)) + if(likely(e1000_tso(adapter, skb))) tx_flags |= E1000_TX_FLAGS_TSO; - else if(e1000_tx_csum(adapter, skb)) + else if(likely(e1000_tx_csum(adapter, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; - e1000_tx_queue(adapter, - e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), + e1000_tx_queue(adapter, + e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), tx_flags); netdev->trans_start = jiffies; - return 0; + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return NETDEV_TX_OK; } /** @@ -1843,10 +1878,8 @@ e1000_tx_timeout_task(struct net_device *netdev) { struct e1000_adapter *adapter = netdev->priv; - netif_device_detach(netdev); e1000_down(adapter); e1000_up(adapter); - netif_device_attach(netdev); } /** @@ -1905,7 +1938,6 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) } if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { - e1000_down(adapter); e1000_up(adapter); } @@ -1951,8 +1983,6 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); - /* the rest of the counters are only modified here */ - adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); adapter->stats.mpc += E1000_READ_REG(hw, MPC); adapter->stats.scc += E1000_READ_REG(hw, SCC); @@ -2059,7 +2089,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); @@ -2073,10 +2103,10 @@ e1000_irq_disable(struct e1000_adapter *adapter) * @adapter: board private structure **/ -static inline void +static void e1000_irq_enable(struct e1000_adapter *adapter) { - if(atomic_dec_and_test(&adapter->irq_sem)) { + if(likely(atomic_dec_and_test(&adapter->irq_sem))) { E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); E1000_WRITE_FLUSH(&adapter->hw); } @@ -2095,21 +2125,21 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; - uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); + uint32_t icr = E1000_READ_REG(hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; #endif - if(!icr) + if(unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ - if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + if(unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } #ifdef CONFIG_E1000_NAPI - if(netif_rx_schedule_prep(netdev)) { + if(likely(netif_rx_schedule_prep(netdev))) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. @@ -2121,8 +2151,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } #else for(i = 0; i < E1000_MAX_INTR; i++) - if(!e1000_clean_rx_irq(adapter) & - !e1000_clean_tx_irq(adapter)) + if(unlikely(!e1000_clean_rx_irq(adapter) & + !e1000_clean_tx_irq(adapter))) break; #endif @@ -2140,15 +2170,18 @@ e1000_clean(struct net_device *netdev, int *budget) { struct e1000_adapter *adapter = netdev->priv; int work_to_do = min(*budget, netdev->quota); + int tx_cleaned; int work_done = 0; - e1000_clean_tx_irq(adapter); + tx_cleaned = e1000_clean_tx_irq(adapter); e1000_clean_rx_irq(adapter, &work_done, work_to_do); *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do || !netif_running(netdev)) { + /* if no Rx and Tx cleanup work was done, exit the polling mode */ + if(!tx_cleaned || (work_done < work_to_do) || + !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); return 0; @@ -2156,8 +2189,8 @@ e1000_clean(struct net_device *netdev, int *budget) return (work_done >= work_to_do); } -#endif +#endif /** * e1000_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -2174,31 +2207,25 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) unsigned int i, eop; boolean_t cleaned = FALSE; - i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - for(cleaned = FALSE; !cleaned; ) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; - if(buffer_info->dma) { - + if(likely(buffer_info->dma)) { pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_TODEVICE); - buffer_info->dma = 0; } if(buffer_info->skb) { - dev_kfree_skb_any(buffer_info->skb); - buffer_info->skb = NULL; } @@ -2207,7 +2234,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) tx_desc->upper.data = 0; cleaned = (i == eop); - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } eop = tx_ring->buffer_info[i].next_to_watch; @@ -2218,7 +2245,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) spin_lock(&adapter->tx_lock); - if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) + if(unlikely(cleaned && netif_queue_stopped(netdev) && + netif_carrier_ok(netdev))) netif_wake_queue(netdev); spin_unlock(&adapter->tx_lock); @@ -2227,7 +2255,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) } /** - * e1000_clean_rx_irq - Send received data up the network stack, + * e1000_clean_rx_irq - Send received data up the network stack * @adapter: board private structure **/ @@ -2256,14 +2284,11 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) while(rx_desc->status & E1000_RXD_STAT_DD) { buffer_info = &rx_ring->buffer_info[i]; - #ifdef CONFIG_E1000_NAPI if(*work_done >= work_to_do) break; - (*work_done)++; #endif - cleaned = TRUE; pci_unmap_single(pdev, @@ -2274,49 +2299,28 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) skb = buffer_info->skb; length = le16_to_cpu(rx_desc->length); - if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { - + if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) { /* All receives must fit into a single buffer */ - - E1000_DBG("%s: Receive packet consumed multiple buffers\n", - netdev->name); - + E1000_DBG("%s: Receive packet consumed multiple" + " buffers\n", netdev->name); dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; + goto next_desc; } - if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { - + if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { last_byte = *(skb->data + length - 1); - if(TBI_ACCEPT(&adapter->hw, rx_desc->status, rx_desc->errors, length, last_byte)) { - spin_lock_irqsave(&adapter->stats_lock, flags); - e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, length, skb->data); - spin_unlock_irqrestore(&adapter->stats_lock, flags); length--; } else { - dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; + goto next_desc; } } @@ -2328,17 +2332,19 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + if(unlikely(adapter->vlgrp && + (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special & - E1000_RXD_SPC_VLAN_MASK)); + le16_to_cpu(rx_desc->special & + E1000_RXD_SPC_VLAN_MASK)); } else { netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + if(unlikely(adapter->vlgrp && + (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special & + le16_to_cpu(rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); } else { netif_rx(skb); @@ -2346,10 +2352,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +next_desc: rx_desc->status = 0; buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; + if(unlikely(++i == rx_ring->count)) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); } @@ -2381,11 +2387,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) buffer_info = &rx_ring->buffer_info[i]; while(!buffer_info->skb) { - rx_desc = E1000_RX_DESC(*rx_ring, i); skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); - - if(!skb) { + if(unlikely(!skb)) { /* Better luck next round */ break; } @@ -2400,15 +2404,15 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; - buffer_info->dma = - pci_map_single(pdev, - skb->data, - adapter->rx_buffer_len, - PCI_DMA_FROMDEVICE); + buffer_info->dma = pci_map_single(pdev, + skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); - if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) { + if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) { /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, @@ -2418,7 +2422,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, RDT, i); } - if(++i == rx_ring->count) i = 0; + if(unlikely(++i == rx_ring->count)) i = 0; buffer_info = &rx_ring->buffer_info[i]; } @@ -2537,22 +2541,24 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return -EFAULT; mii_reg = data->val_in; if (e1000_write_phy_reg(&adapter->hw, data->reg_num, - data->val_in)) + mii_reg)) return -EIO; if (adapter->hw.phy_type == e1000_phy_m88) { switch (data->reg_num) { case PHY_CTRL: - if(data->val_in & MII_CR_AUTO_NEG_EN) { + if(mii_reg & MII_CR_POWER_DOWN) + break; + if(mii_reg & MII_CR_AUTO_NEG_EN) { adapter->hw.autoneg = 1; adapter->hw.autoneg_advertised = 0x2F; } else { - if (data->val_in & 0x40) + if (mii_reg & 0x40) spddplx = SPEED_1000; - else if (data->val_in & 0x2000) + else if (mii_reg & 0x2000) spddplx = SPEED_100; else spddplx = SPEED_10; - spddplx += (data->val_in & 0x100) + spddplx += (mii_reg & 0x100) ? FULL_DUPLEX : HALF_DUPLEX; retval = e1000_set_spd_dplx(adapter, @@ -2572,6 +2578,18 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return -EIO; break; } + } else { + switch (data->reg_num) { + case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) + break; + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); + break; + } } break; default: @@ -2587,17 +2605,17 @@ 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) { /* 82543 or newer only */ - if((adapter->hw.mac_type < e1000_82543) || + if(unlikely((adapter->hw.mac_type < e1000_82543) || /* Ignore Checksum bit is set */ (rx_desc->status & E1000_RXD_STAT_IXSM) || /* TCP Checksum has not been calculated */ - (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { + (!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) { skb->ip_summed = CHECKSUM_NONE; return; } @@ -2609,7 +2627,7 @@ e1000_rx_checksum(struct e1000_adapter *adapter, skb->ip_summed = CHECKSUM_NONE; adapter->hw_csum_err++; } else { - /* TCP checksum is good */ + /* TCP checksum is good */ skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_good++; } @@ -2620,7 +2638,8 @@ e1000_pci_set_mwi(struct e1000_hw *hw) { struct e1000_adapter *adapter = hw->back; - pci_set_mwi(adapter->pdev); + int ret; + ret = pci_set_mwi(adapter->pdev); } void @@ -2670,26 +2689,22 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) if(grp) { /* enable VLAN tag insert/strip */ - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); /* enable VLAN receive filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } else { /* disable VLAN tag insert/strip */ - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl &= ~E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); /* disable VLAN filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~E1000_RCTL_VFE; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); @@ -2705,7 +2720,6 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) uint32_t vfta, index; /* add VID to filter table */ - index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); vfta |= (1 << (vid & 0x1F)); @@ -2725,8 +2739,7 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) e1000_irq_enable(adapter); - /* remove VID from filter table*/ - + /* remove VID from filter table */ index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); vfta &= ~(1 << (vid & 0x1F)); @@ -2772,6 +2785,8 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: + DPRINTK(PROBE, ERR, + "Unsupported Speed/Duplexity configuration\n"); return -EINVAL; } return 0; @@ -2865,6 +2880,8 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state) } } + pci_disable_device(pdev); + state = (state > 0) ? 3 : 0; pci_set_power_state(pdev, state); @@ -2879,6 +2896,7 @@ e1000_resume(struct pci_dev *pdev) struct e1000_adapter *adapter = netdev->priv; uint32_t manc; + pci_enable_device(pdev); pci_set_power_state(pdev, 0); pci_restore_state(pdev, adapter->pci_state); @@ -2910,12 +2928,12 @@ e1000_resume(struct pci_dev *pdev) * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */ - -static void e1000_netpoll (struct net_device *dev) +static void +e1000_netpoll (struct net_device *netdev) { - struct e1000_adapter *adapter = dev->priv; + struct e1000_adapter *adapter = netdev->priv; disable_irq(adapter->pdev->irq); - e1000_intr (adapter->pdev->irq, dev, NULL); + e1000_intr(adapter->pdev->irq, netdev, NULL); enable_irq(adapter->pdev->irq); } #endif diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 3e79a45de..555421366 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -212,7 +212,7 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); #define MAX_TXABSDELAY 0xFFFF #define MIN_TXABSDELAY 0 -#define DEFAULT_ITR 1 +#define DEFAULT_ITR 8000 #define MAX_ITR 100000 #define MIN_ITR 100 @@ -235,7 +235,7 @@ struct e1000_option { static int __devinit e1000_validate_option(int *value, struct e1000_option *opt, - struct e1000_adapter *adapter) + struct e1000_adapter *adapter) { if(*value == OPTION_UNSET) { *value = opt->def; @@ -256,7 +256,7 @@ e1000_validate_option(int *value, struct e1000_option *opt, case range_option: if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { DPRINTK(PROBE, INFO, - "%s set to %i\n", opt->name, *value); + "%s set to %i\n", opt->name, *value); return 0; } break; @@ -449,8 +449,7 @@ e1000_check_options(struct e1000_adapter *adapter) DPRINTK(PROBE, INFO, "%s turned off\n", opt.name); break; case 1: - DPRINTK(PROBE, INFO, - "%s set to dynamic mode\n", opt.name); + DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", opt.name); break; default: e1000_validate_option(&adapter->itr, &opt, adapter); @@ -493,8 +492,9 @@ e1000_check_fiber_options(struct e1000_adapter *adapter) "parameter ignored\n"); } if((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) { - DPRINTK(PROBE, INFO, "AutoNeg other than Full/1000 is " - "not valid for fiber adapters, parameter ignored\n"); + DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is " + "not valid for fiber adapters, " + "parameter ignored\n"); } } @@ -611,24 +611,24 @@ e1000_check_copper_options(struct e1000_adapter *adapter) break; case HALF_DUPLEX: DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at Half Duplex only\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "Half Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | ADVERTISE_100_HALF; break; case FULL_DUPLEX: DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at Full Duplex only\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_FULL | ADVERTISE_100_FULL | ADVERTISE_1000_FULL; break; case SPEED_10: - DPRINTK(PROBE, INFO, - "10 Mbps Speed specified without Duplex\n"); + DPRINTK(PROBE, INFO, "10 Mbps Speed specified " + "without Duplex\n"); DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | @@ -647,10 +647,10 @@ e1000_check_copper_options(struct e1000_adapter *adapter) adapter->hw.autoneg_advertised = 0; break; case SPEED_100: - DPRINTK(PROBE, INFO, - "100 Mbps Speed specified without Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 100 Mbps only\n"); + DPRINTK(PROBE, INFO, "100 Mbps Speed specified " + "without Duplex\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "100 Mbps only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_100_HALF | ADVERTISE_100_FULL; @@ -668,10 +668,11 @@ e1000_check_copper_options(struct e1000_adapter *adapter) adapter->hw.autoneg_advertised = 0; break; case SPEED_1000: + DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without " + "Duplex\n"); DPRINTK(PROBE, INFO, - "1000 Mbps Speed specified without Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + "Using Autonegotiation at 1000 Mbps " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -679,7 +680,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter) DPRINTK(PROBE, INFO, "Half Duplex is not supported at 1000 Mbps\n"); DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + "Using Autonegotiation at 1000 Mbps " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -696,8 +698,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter) /* Speed, AutoNeg and MDI/MDI-X must all play nice */ if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) { DPRINTK(PROBE, INFO, - "Speed, AutoNeg and MDI-X specifications are " - "incompatible. Setting MDI-X to a compatible value.\n"); + "Speed, AutoNeg and MDI-X specifications are " + "incompatible. Setting MDI-X to a compatible value.\n"); } } diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 36b5508f4..1132101ec 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -88,7 +88,6 @@ static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; #define PKT_BUF_SZ 1536 #include -#include #include #include @@ -2447,22 +2446,6 @@ static struct pci_driver eepro100_driver = { #endif /* CONFIG_PM */ }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48) -static int pci_module_init(struct pci_driver *pdev) -{ - int rc; - - rc = pci_register_driver(pdev); - if (rc <= 0) { - printk(KERN_INFO "%s: No cards found, driver not installed.\n", - pdev->name); - pci_unregister_driver(pdev); - return -ENODEV; - } - return 0; -} -#endif - static int __init eepro100_init_module(void) { #ifdef MODULE diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 771bfc672..ec327ad3a 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -80,8 +80,6 @@ These may be modified when a driver module is loaded.*/ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 32; /* Used to pass the full-duplex flag, etc. */ #define MAX_UNITS 8 /* More are supported, limit only on options */ @@ -99,9 +97,9 @@ static int rx_copybreak; Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 256 +#define TX_QUEUE_LEN 240 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 256 #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) @@ -152,12 +150,10 @@ MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)"); -MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt"); MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex"); MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)"); @@ -289,6 +285,12 @@ enum CommandBits { StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80, }; +#define EpicRemoved 0xffffffff /* Chip failed or removed (CardBus) */ + +#define EpicNapiEvent (TxEmpty | TxDone | \ + RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull) +#define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent) + static u16 media2miictl[16] = { 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -327,9 +329,12 @@ struct epic_private { /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ + spinlock_t napi_lock; + unsigned int reschedule_in_poll; unsigned int cur_tx, dirty_tx; unsigned int cur_rx, dirty_rx; + u32 irq_mask; unsigned int rx_buf_sz; /* Based on MTU+slack. */ struct pci_dev *pci_dev; /* PCI bus location. */ @@ -356,7 +361,8 @@ static void epic_timer(unsigned long data); static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int epic_rx(struct net_device *dev); +static int epic_rx(struct net_device *dev, int budget); +static int epic_poll(struct net_device *dev, int *budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; @@ -375,7 +381,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, int irq; struct net_device *dev; struct epic_private *ep; - int i, option = 0, duplex = 0; + int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; @@ -389,29 +395,33 @@ static int __devinit epic_init_one (struct pci_dev *pdev, card_idx++; - i = pci_enable_device(pdev); - if (i) - return i; + ret = pci_enable_device(pdev); + if (ret) + goto out; irq = pdev->irq; if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { printk (KERN_ERR "card %d: no PCI region space\n", card_idx); - return -ENODEV; + ret = -ENODEV; + goto err_out_disable; } pci_set_master(pdev); + ret = pci_request_regions(pdev, DRV_NAME); + if (ret < 0) + goto err_out_disable; + + ret = -ENOMEM; + dev = alloc_etherdev(sizeof (*ep)); if (!dev) { printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); - return -ENOMEM; + goto err_out_free_res; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - if (pci_request_regions(pdev, DRV_NAME)) - goto err_out_free_netdev; - #ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0); #else @@ -419,7 +429,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); - goto err_out_free_res; + goto err_out_free_netdev; } #endif @@ -456,7 +466,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = irq; - spin_lock_init (&ep->lock); + spin_lock_init(&ep->lock); + spin_lock_init(&ep->napi_lock); + ep->reschedule_in_poll = 0; /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); @@ -486,6 +498,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ep->pci_dev = pdev; ep->chip_id = chip_idx; ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; + ep->irq_mask = + (ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) + | CntFull | TxUnderrun | EpicNapiEvent; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but @@ -540,10 +555,12 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; + dev->poll = epic_poll; + dev->weight = 64; - i = register_netdev(dev); - if (i) - goto err_out_unmap_tx; + ret = register_netdev(dev); + if (ret < 0) + goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); @@ -551,19 +568,24 @@ static int __devinit epic_init_one (struct pci_dev *pdev, printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]); - return 0; +out: + return ret; +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); err_out_iounmap: #ifndef USE_IO_OPS iounmap(ioaddr); -err_out_free_res: -#endif - pci_release_regions(pdev); err_out_free_netdev: +#endif free_netdev(dev); - return -ENODEV; +err_out_free_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); + goto out; } /* Serial EEPROM section. */ @@ -589,6 +611,38 @@ err_out_free_netdev: #define EE_READ256_CMD (6 << 8) #define EE_ERASE_CMD (7 << 6) +static void epic_disable_int(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(0x00000000, ioaddr + INTMASK); +} + +static inline void __epic_pci_commit(long ioaddr) +{ +#ifndef USE_IO_OPS + inl(ioaddr + INTMASK); +#endif +} + +static inline void epic_napi_irq_off(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); + __epic_pci_commit(ioaddr); +} + +static inline void epic_napi_irq_on(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + /* No need to commit possible posted write */ + outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK); +} + static int __devinit read_eeprom(long ioaddr, int location) { int i; @@ -749,9 +803,8 @@ static int epic_open(struct net_device *dev) /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " @@ -792,7 +845,7 @@ static void epic_pause(struct net_device *dev) } /* Remove the packets on the Rx queue. */ - epic_rx(dev); + epic_rx(dev, RX_RING_SIZE); } static void epic_restart(struct net_device *dev) @@ -838,9 +891,9 @@ static void epic_restart(struct net_device *dev) /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); + printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), @@ -926,7 +979,6 @@ static void epic_init_ring(struct net_device *dev) int i; ep->tx_full = 0; - ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; ep->dirty_tx = ep->cur_tx = 0; ep->cur_rx = ep->dirty_rx = 0; ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); @@ -1026,6 +1078,76 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } +static void epic_tx_error(struct net_device *dev, struct epic_private *ep, + int status) +{ + struct net_device_stats *stats = &ep->stats; + +#ifndef final_version + /* There was an major error, log it. */ + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + stats->tx_errors++; + if (status & 0x1050) + stats->tx_aborted_errors++; + if (status & 0x0008) + stats->tx_carrier_errors++; + if (status & 0x0040) + stats->tx_window_errors++; + if (status & 0x0010) + stats->tx_fifo_errors++; +} + +static void epic_tx(struct net_device *dev, struct epic_private *ep) +{ + unsigned int dirty_tx, cur_tx; + + /* + * Note: if this lock becomes a problem we can narrow the locked + * region at the cost of occasionally grabbing the lock more times. + */ + cur_tx = ep->cur_tx; + for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) { + struct sk_buff *skb; + int entry = dirty_tx % TX_RING_SIZE; + int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + + if (txstatus & DescOwn) + break; /* It still hasn't been Txed */ + + if (likely(txstatus & 0x0001)) { + ep->stats.collisions += (txstatus >> 8) & 15; + ep->stats.tx_packets++; + ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; + } else + epic_tx_error(dev, ep, txstatus); + + /* Free the original skb. */ + skb = ep->tx_skbuff[entry]; + pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + ep->tx_skbuff[entry] = NULL; + } + +#ifndef final_version + if (cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_WARNING + "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, cur_tx, ep->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + ep->dirty_tx = dirty_tx; + if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, allow new TX entries. */ + ep->tx_full = 0; + netif_wake_queue(dev); + } +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) @@ -1033,135 +1155,71 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r struct net_device *dev = dev_instance; struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - int status, boguscnt = max_interrupt_work; unsigned int handled = 0; + int status; - do { - status = inl(ioaddr + INTSTAT); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status & 0x00007fff, ioaddr + INTSTAT); + status = inl(ioaddr + INTSTAT); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status & EpicNormalEvent, ioaddr + INTSTAT); - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " - "intstat=%#8.8x.\n", - dev->name, status, (int)inl(ioaddr + INTSTAT)); + if (debug > 4) { + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " + "intstat=%#8.8x.\n", dev->name, status, + (int)inl(ioaddr + INTSTAT)); + } - if ((status & IntrSummary) == 0) - break; - handled = 1; - - if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow)) - epic_rx(dev); - - if (status & (TxEmpty | TxDone)) { - unsigned int dirty_tx, cur_tx; - - /* Note: if this lock becomes a problem we can narrow the locked - region at the cost of occasionally grabbing the lock more - times. */ - spin_lock(&ep->lock); - cur_tx = ep->cur_tx; - dirty_tx = ep->dirty_tx; - for (; cur_tx - dirty_tx > 0; dirty_tx++) { - struct sk_buff *skb; - int entry = dirty_tx % TX_RING_SIZE; - int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); - - if (txstatus & DescOwn) - break; /* It still hasn't been Txed */ - - if ( ! (txstatus & 0x0001)) { - /* There was an major error, log it. */ -#ifndef final_version - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); -#endif - ep->stats.tx_errors++; - if (txstatus & 0x1050) ep->stats.tx_aborted_errors++; - if (txstatus & 0x0008) ep->stats.tx_carrier_errors++; - if (txstatus & 0x0040) ep->stats.tx_window_errors++; - if (txstatus & 0x0010) ep->stats.tx_fifo_errors++; - } else { - ep->stats.collisions += (txstatus >> 8) & 15; - ep->stats.tx_packets++; - ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; - } - - /* Free the original skb. */ - skb = ep->tx_skbuff[entry]; - pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - ep->tx_skbuff[entry] = NULL; - } + if ((status & IntrSummary) == 0) + goto out; -#ifndef final_version - if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, cur_tx, ep->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - ep->dirty_tx = dirty_tx; - if (ep->tx_full - && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, allow new TX entries. */ - ep->tx_full = 0; - spin_unlock(&ep->lock); - netif_wake_queue(dev); - } else - spin_unlock(&ep->lock); - } + handled = 1; - /* Check uncommon events all at once. */ - if (status & (CntFull | TxUnderrun | RxOverflow | RxFull | - PCIBusErr170 | PCIBusErr175)) { - if (status == 0xffffffff) /* Chip failed or removed (CardBus). */ - break; - /* Always update the error counts to avoid overhead later. */ - ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); - ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); - ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - - if (status & TxUnderrun) { /* Tx FIFO underflow. */ - ep->stats.tx_fifo_errors++; - outl(ep->tx_threshold += 128, ioaddr + TxThresh); - /* Restart the transmit process. */ - outl(RestartTx, ioaddr + COMMAND); - } - if (status & RxOverflow) { /* Missed a Rx frame. */ - ep->stats.rx_errors++; - } - if (status & (RxOverflow | RxFull)) - outw(RxQueued, ioaddr + COMMAND); - if (status & PCIBusErr170) { - printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n", - dev->name, status); - epic_pause(dev); - epic_restart(dev); - } - /* Clear all error sources. */ - outl(status & 0x7f18, ioaddr + INTSTAT); + if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { + spin_lock(&ep->napi_lock); + if (netif_rx_schedule_prep(dev)) { + epic_napi_irq_off(dev, ep); + __netif_rx_schedule(dev); + } else + ep->reschedule_in_poll++; + spin_unlock(&ep->napi_lock); + } + status &= ~EpicNapiEvent; + + /* Check uncommon events all at once. */ + if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) { + if (status == EpicRemoved) + goto out; + + /* Always update the error counts to avoid overhead later. */ + ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); + ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); + ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + + if (status & TxUnderrun) { /* Tx FIFO underflow. */ + ep->stats.tx_fifo_errors++; + outl(ep->tx_threshold += 128, ioaddr + TxThresh); + /* Restart the transmit process. */ + outl(RestartTx, ioaddr + COMMAND); } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, " - "IntrStatus=0x%8.8x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0x0001ffff, ioaddr + INTSTAT); - break; + if (status & PCIBusErr170) { + printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n", + dev->name, status); + epic_pause(dev); + epic_restart(dev); } - } while (1); + /* Clear all error sources. */ + outl(status & 0x7f18, ioaddr + INTSTAT); + } - if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, status); +out: + if (debug > 3) { + printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n", + dev->name, status); + } return IRQ_RETVAL(handled); } -static int epic_rx(struct net_device *dev) +static int epic_rx(struct net_device *dev, int budget) { struct epic_private *ep = dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; @@ -1171,6 +1229,10 @@ static int epic_rx(struct net_device *dev) if (debug > 4) printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); + + if (rx_work_limit > budget) + rx_work_limit = budget; + /* If we own the next entry, it's a new packet. Send it up. */ while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); @@ -1226,7 +1288,7 @@ static int epic_rx(struct net_device *dev) ep->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; ep->stats.rx_packets++; ep->stats.rx_bytes += pkt_len; @@ -1254,6 +1316,65 @@ static int epic_rx(struct net_device *dev) return work_done; } +static void epic_rx_err(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + int status; + + status = inl(ioaddr + INTSTAT); + + if (status == EpicRemoved) + return; + if (status & RxOverflow) /* Missed a Rx frame. */ + ep->stats.rx_errors++; + if (status & (RxOverflow | RxFull)) + outw(RxQueued, ioaddr + COMMAND); +} + +static int epic_poll(struct net_device *dev, int *budget) +{ + struct epic_private *ep = dev->priv; + int work_done, orig_budget; + long ioaddr = dev->base_addr; + + orig_budget = (*budget > dev->quota) ? dev->quota : *budget; + +rx_action: + + epic_tx(dev, ep); + + work_done = epic_rx(dev, *budget); + + epic_rx_err(dev, ep); + + *budget -= work_done; + dev->quota -= work_done; + + if (netif_running(dev) && (work_done < orig_budget)) { + unsigned long flags; + int more; + + /* A bit baroque but it avoids a (space hungry) spin_unlock */ + + spin_lock_irqsave(&ep->napi_lock, flags); + + more = ep->reschedule_in_poll; + if (!more) { + __netif_rx_complete(dev); + outl(EpicNapiEvent, ioaddr + INTSTAT); + epic_napi_irq_on(dev, ep); + } else + ep->reschedule_in_poll--; + + spin_unlock_irqrestore(&ep->napi_lock, flags); + + if (more) + goto rx_action; + } + + return (work_done >= orig_budget); +} + static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1268,9 +1389,13 @@ static int epic_close(struct net_device *dev) dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); - epic_pause(dev); + + epic_disable_int(dev, ep); + free_irq(dev->irq, dev); + epic_pause(dev); + /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { skb = ep->rx_skbuff[i]; @@ -1491,6 +1616,7 @@ static void __devexit epic_remove_one (struct pci_dev *pdev) #endif pci_release_regions(pdev); free_netdev(dev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); /* pci_power_off(pdev, -1); */ } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 0ead66f20..8d39ca77b 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -75,6 +75,7 @@ * added CK804/MCP04 device IDs, code fixes * for registers, link status and other minor fixes. * 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe + * 0.29: 31 Aug 2004: Add backup timer for link change notification. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -86,7 +87,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.28" +#define FORCEDETH_VERSION "0.29" #define DRV_NAME "forcedeth" #include @@ -120,10 +121,11 @@ * Hardware access: */ -#define DEV_NEED_LASTPACKET1 0x0001 -#define DEV_IRQMASK_1 0x0002 -#define DEV_IRQMASK_2 0x0004 -#define DEV_NEED_TIMERIRQ 0x0008 +#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */ +#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */ +#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */ +#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */ enum { NvRegIrqStatus = 0x000, @@ -367,6 +369,7 @@ struct ring_desc { #define OOM_REFILL (1+HZ/20) #define POLL_WAIT (1+HZ/100) +#define LINK_TIMEOUT (3*HZ) #define DESC_VER_1 0x0 #define DESC_VER_2 0x02100 @@ -446,6 +449,11 @@ struct fe_priv { struct timer_list oom_kick; struct timer_list nic_poll; + /* media detection workaround. + * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); + */ + int need_linktimer; + unsigned long link_timeout; /* * tx specific fields. */ @@ -1384,6 +1392,25 @@ set_speed: return retval; } +static void nv_linkchange(struct net_device *dev) +{ + if (nv_update_linkspeed(dev)) { + if (netif_carrier_ok(dev)) { + nv_stop_rx(dev); + } else { + netif_carrier_on(dev); + printk(KERN_INFO "%s: link up.\n", dev->name); + } + nv_start_rx(dev); + } else { + if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down.\n", dev->name); + nv_stop_rx(dev); + } + } +} + static void nv_link_irq(struct net_device *dev) { u8 *base = get_hwbase(dev); @@ -1391,25 +1418,10 @@ static void nv_link_irq(struct net_device *dev) miistat = readl(base + NvRegMIIStatus); writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); - dprintk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); + dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat); - if (miistat & (NVREG_MIISTAT_LINKCHANGE)) { - if (nv_update_linkspeed(dev)) { - if (netif_carrier_ok(dev)) { - nv_stop_rx(dev); - } else { - netif_carrier_on(dev); - printk(KERN_INFO "%s: link up.\n", dev->name); - } - nv_start_rx(dev); - } else { - if (netif_carrier_ok(dev)) { - netif_carrier_off(dev); - printk(KERN_INFO "%s: link down.\n", dev->name); - nv_stop_rx(dev); - } - } - } + if (miistat & (NVREG_MIISTAT_LINKCHANGE)) + nv_linkchange(dev); dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); } @@ -1452,6 +1464,12 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) nv_link_irq(dev); spin_unlock(&np->lock); } + if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } if (events & (NVREG_IRQ_TX_ERR)) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); @@ -1816,6 +1834,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->irqmask = NVREG_IRQMASK_WANTED_2; if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; + if (id->driver_data & DEV_NEED_LINKTIMER) { + dprintk(KERN_INFO "%s: link timer on.\n", pci_name(pci_dev)); + np->need_linktimer = 1; + np->link_timeout = jiffies + LINK_TIMEOUT; + } else { + dprintk(KERN_INFO "%s: link timer off.\n", pci_name(pci_dev)); + np->need_linktimer = 0; + } /* find a suitable phy */ for (i = 1; i < 32; i++) { @@ -1909,21 +1935,21 @@ static struct pci_device_id pci_tbl[] = { .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ, + .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 5005c1c94..a8ceee273 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -8,7 +8,7 @@ * Author: Andy Fleming * Maintainer: Kumar Gala (kumar.gala@freescale.com) * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright (c) 2002-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 @@ -96,20 +96,11 @@ #include "gianfar.h" #include "gianfar_phy.h" -#ifdef CONFIG_NET_FASTROUTE -#include -#include -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) -#define irqreturn_t void -#define IRQ_HANDLED -#endif #define TX_TIMEOUT (1*HZ) #define SKB_ALLOC_TIMEOUT 1000000 #undef BRIEF_GFAR_ERRORS -#define VERBOSE_GFAR_ERRORS +#undef VERBOSE_GFAR_ERRORS #ifdef CONFIG_GFAR_NAPI #define RECEIVE(x) netif_receive_skb(x) @@ -117,9 +108,8 @@ #define RECEIVE(x) netif_rx(x) #endif -#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.0, " -char gfar_driver_name[] = "Gianfar Ethernet"; -char gfar_driver_version[] = "1.0"; +const char gfar_driver_name[] = "Gianfar Ethernet"; +const char gfar_driver_version[] = "1.1"; int startup_gfar(struct net_device *dev); static int gfar_enet_open(struct net_device *dev); @@ -148,24 +138,11 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); #ifdef CONFIG_GFAR_NAPI static int gfar_poll(struct net_device *dev, int *budget); #endif -#ifdef CONFIG_NET_FASTROUTE -static int gfar_accept_fastpath(struct net_device *dev, struct dst_entry *dst); -#endif -static inline int try_fastroute(struct sk_buff *skb, struct net_device *dev, int length); -#ifdef CONFIG_GFAR_NAPI static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); -#else -static int gfar_clean_rx_ring(struct net_device *dev); -#endif static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); +static void gfar_phy_startup_timer(unsigned long data); extern struct ethtool_ops gfar_ethtool_ops; -extern void gfar_gstrings_normon(struct net_device *dev, u32 stringset, - u8 * buf); -extern void gfar_fill_stats_normon(struct net_device *dev, - struct ethtool_stats *dummy, u64 * buf); -extern int gfar_stats_count_normon(struct net_device *dev); - MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION("Gianfar Ethernet Driver"); @@ -183,7 +160,7 @@ static int gfar_probe(struct ocp_device *ocpdev) struct ocp_gfar_data *einfo; int idx; int err = 0; - struct ethtool_ops *dev_ethtool_ops; + int dev_ethtool_ops = 0; einfo = (struct ocp_gfar_data *) ocpdev->def->additions; @@ -197,7 +174,8 @@ static int gfar_probe(struct ocp_device *ocpdev) /* get a pointer to the register memory which can * configure the PHYs. If it's different from this set, * get the device which has those regs */ - if ((einfo->phyregidx >= 0) && (einfo->phyregidx != ocpdev->def->index)) { + if ((einfo->phyregidx >= 0) && + (einfo->phyregidx != ocpdev->def->index)) { mdiodev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_GFAR, einfo->phyregidx); @@ -222,7 +200,7 @@ static int gfar_probe(struct ocp_device *ocpdev) /* get a pointer to the register memory */ priv->regs = (struct gfar *) - ioremap(ocpdev->def->paddr, sizeof (struct gfar)); + ioremap(ocpdev->def->paddr, sizeof (struct gfar)); if (priv->regs == NULL) { err = -ENOMEM; @@ -238,6 +216,8 @@ static int gfar_probe(struct ocp_device *ocpdev) goto phy_regs_fail; } + spin_lock_init(&priv->lock); + ocp_set_drvdata(ocpdev, dev); /* Stop the DMA engine now, in case it was running before */ @@ -269,15 +249,13 @@ static int gfar_probe(struct ocp_device *ocpdev) gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS); /* Copy the station address into the dev structure, */ - /* and into the address registers MAC_STNADDR1,2. */ - /* Backwards, because little endian MACs are dumb. */ - /* Don't set the regs if the firmware already did */ memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN); /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long) (priv->regs); SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &ocpdev->dev); /* Fill in the dev structure */ dev->open = gfar_enet_open; @@ -293,37 +271,16 @@ static int gfar_probe(struct ocp_device *ocpdev) dev->change_mtu = gfar_change_mtu; dev->mtu = 1500; dev->set_multicast_list = gfar_set_multi; - dev->flags |= IFF_MULTICAST; - - dev_ethtool_ops = - (struct ethtool_ops *)kmalloc(sizeof(struct ethtool_ops), - GFP_KERNEL); - - if(dev_ethtool_ops == NULL) { - err = -ENOMEM; - goto ethtool_fail; - } - - memcpy(dev_ethtool_ops, &gfar_ethtool_ops, sizeof(gfar_ethtool_ops)); - - /* If there is no RMON support in this device, we don't - * want to expose non-existant statistics */ - if((priv->einfo->flags & GFAR_HAS_RMON) == 0) { - dev_ethtool_ops->get_strings = gfar_gstrings_normon; - dev_ethtool_ops->get_stats_count = gfar_stats_count_normon; - dev_ethtool_ops->get_ethtool_stats = gfar_fill_stats_normon; - } - if((priv->einfo->flags & GFAR_HAS_COALESCE) == 0) { - dev_ethtool_ops->set_coalesce = NULL; - dev_ethtool_ops->get_coalesce = NULL; - } + /* Index into the array of possible ethtool + * ops to catch all 4 possibilities */ + if((priv->einfo->flags & GFAR_HAS_RMON) == 0) + dev_ethtool_ops += 1; - dev->ethtool_ops = dev_ethtool_ops; + if((priv->einfo->flags & GFAR_HAS_COALESCE) == 0) + dev_ethtool_ops += 2; -#ifdef CONFIG_NET_FASTROUTE - dev->accept_fastpath = gfar_accept_fastpath; -#endif + dev->ethtool_ops = gfar_op_array[dev_ethtool_ops]; priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; #ifdef CONFIG_GFAR_BUFSTASH @@ -332,24 +289,23 @@ static int gfar_probe(struct ocp_device *ocpdev) priv->tx_ring_size = DEFAULT_TX_RING_SIZE; priv->rx_ring_size = DEFAULT_RX_RING_SIZE; - /* Initially, coalescing is disabled */ - priv->txcoalescing = 0; - priv->txcount = 0; - priv->txtime = 0; - priv->rxcoalescing = 0; - priv->rxcount = 0; - priv->rxtime = 0; + priv->txcoalescing = DEFAULT_TX_COALESCE; + priv->txcount = DEFAULT_TXCOUNT; + priv->txtime = DEFAULT_TXTIME; + priv->rxcoalescing = DEFAULT_RX_COALESCE; + priv->rxcount = DEFAULT_RXCOUNT; + priv->rxtime = DEFAULT_RXTIME; err = register_netdev(dev); if (err) { printk(KERN_ERR "%s: Cannot register net device, aborting.\n", - dev->name); + dev->name); goto register_fail; } /* Print out the device info */ - printk(DEVICE_NAME, dev->name); + printk(KERN_INFO DEVICE_NAME, dev->name); for (idx = 0; idx < 6; idx++) printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':'); printk("\n"); @@ -367,10 +323,7 @@ static int gfar_probe(struct ocp_device *ocpdev) return 0; - register_fail: - kfree(dev_ethtool_ops); -ethtool_fail: iounmap((void *) priv->phyregs); phy_regs_fail: iounmap((void *) priv->regs); @@ -386,7 +339,6 @@ static void gfar_remove(struct ocp_device *ocpdev) ocp_set_drvdata(ocpdev, NULL); - kfree(dev->ethtool_ops); iounmap((void *) priv->regs); iounmap((void *) priv->phyregs); free_netdev(dev); @@ -399,26 +351,90 @@ static int init_phy(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct phy_info *curphy; + unsigned int timeout = PHY_INIT_TIMEOUT; + struct gfar *phyregs = priv->phyregs; + struct gfar_mii_info *mii_info; + int err; - priv->link = 1; priv->oldlink = 0; priv->oldspeed = 0; - priv->olddplx = -1; + priv->oldduplex = -1; + + mii_info = kmalloc(sizeof(struct gfar_mii_info), + GFP_KERNEL); + + if(NULL == mii_info) { + printk(KERN_ERR "%s: Could not allocate mii_info\n", + dev->name); + return -ENOMEM; + } + + mii_info->speed = SPEED_1000; + mii_info->duplex = DUPLEX_FULL; + mii_info->pause = 0; + mii_info->link = 1; + + mii_info->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + mii_info->autoneg = 1; + + mii_info->mii_id = priv->einfo->phyid; + + mii_info->dev = dev; + + mii_info->mdio_read = &read_phy_reg; + mii_info->mdio_write = &write_phy_reg; + + priv->mii_info = mii_info; + + /* Reset the management interface */ + gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); + + /* Setup the MII Mgmt clock speed */ + gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); + + /* Wait until the bus is free */ + while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) && + timeout--) + cpu_relax(); + + if(timeout <= 0) { + printk(KERN_ERR "%s: The MII Bus is stuck!\n", + dev->name); + err = -1; + goto bus_fail; + } /* get info for this PHY */ - curphy = get_phy_info(dev); + curphy = get_phy_info(priv->mii_info); if (curphy == NULL) { printk(KERN_ERR "%s: No PHY found\n", dev->name); - return -1; + err = -1; + goto no_phy; } - priv->phyinfo = curphy; + mii_info->phyinfo = curphy; - /* Run the commands which configure the PHY */ - phy_run_commands(dev, curphy->config); + /* Run the commands which initialize the PHY */ + if(curphy->init) { + err = curphy->init(priv->mii_info); + + if (err) + goto phy_init_fail; + } return 0; + +phy_init_fail: +no_phy: +bus_fail: + kfree(mii_info); + + return err; } static void init_registers(struct net_device *dev) @@ -494,7 +510,7 @@ void stop_gfar(struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); /* Tell the kernel the link is down */ - priv->link = 0; + priv->mii_info->link = 0; adjust_link(dev); /* Mask all interrupts */ @@ -521,7 +537,12 @@ void stop_gfar(struct net_device *dev) gfar_write(®s->maccfg1, tempval); if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { - phy_run_commands(dev, priv->phyinfo->shutdown); + /* Clear any pending interrupts */ + mii_clear_phy_interrupt(priv->mii_info); + + /* Disable PHY Interrupts */ + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_DISABLED); } spin_unlock_irqrestore(&priv->lock, flags); @@ -543,15 +564,11 @@ void stop_gfar(struct net_device *dev) free_skb_resources(priv); - dma_unmap_single(NULL, gfar_read(®s->tbase), - sizeof(struct txbd)*priv->tx_ring_size, - DMA_BIDIRECTIONAL); - dma_unmap_single(NULL, gfar_read(®s->rbase), - sizeof(struct rxbd)*priv->rx_ring_size, - DMA_BIDIRECTIONAL); - - /* Free the buffer descriptors */ - kfree(priv->tx_bd_base); + dma_free_coherent(NULL, + sizeof(struct txbd8)*priv->tx_ring_size + + sizeof(struct rxbd8)*priv->rx_ring_size, + priv->tx_bd_base, + gfar_read(®s->tbase)); } /* If there are any tx skbs or rx skbs still around, free them. @@ -610,7 +627,8 @@ int startup_gfar(struct net_device *dev) { struct txbd8 *txbdp; struct rxbd8 *rxbdp; - unsigned long addr; + dma_addr_t addr; + unsigned long vaddr; int i; struct gfar_private *priv = netdev_priv(dev); struct gfar *regs = priv->regs; @@ -620,32 +638,27 @@ int startup_gfar(struct net_device *dev) gfar_write(®s->imask, IMASK_INIT_CLEAR); /* Allocate memory for the buffer descriptors */ - addr = - (unsigned int) kmalloc(sizeof (struct txbd8) * priv->tx_ring_size + - sizeof (struct rxbd8) * priv->rx_ring_size, - GFP_KERNEL); + vaddr = (unsigned long) dma_alloc_coherent(NULL, + sizeof (struct txbd8) * priv->tx_ring_size + + sizeof (struct rxbd8) * priv->rx_ring_size, + &addr, GFP_KERNEL); - if (addr == 0) { + if (vaddr == 0) { printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n", dev->name); return -ENOMEM; } - priv->tx_bd_base = (struct txbd8 *) addr; + priv->tx_bd_base = (struct txbd8 *) vaddr; /* enet DMA only understands physical addresses */ - gfar_write(®s->tbase, - dma_map_single(NULL, (void *)addr, - sizeof(struct txbd8) * priv->tx_ring_size, - DMA_BIDIRECTIONAL)); + gfar_write(®s->tbase, addr); /* Start the rx descriptor ring where the tx ring leaves off */ addr = addr + sizeof (struct txbd8) * priv->tx_ring_size; - priv->rx_bd_base = (struct rxbd8 *) addr; - gfar_write(®s->rbase, - dma_map_single(NULL, (void *)addr, - sizeof(struct rxbd8) * priv->rx_ring_size, - DMA_BIDIRECTIONAL)); + vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size; + priv->rx_bd_base = (struct rxbd8 *) vaddr; + gfar_write(®s->rbase, addr); /* Setup the skbuff rings */ priv->tx_skbuff = @@ -718,7 +731,7 @@ int startup_gfar(struct net_device *dev) /* Install our interrupt handlers for Error, * Transmit, and Receive */ if (request_irq(priv->einfo->interruptError, gfar_error, - SA_SHIRQ, "enet_error", dev) < 0) { + 0, "enet_error", dev) < 0) { printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->einfo->interruptError); @@ -727,7 +740,7 @@ int startup_gfar(struct net_device *dev) } if (request_irq(priv->einfo->interruptTransmit, gfar_transmit, - SA_SHIRQ, "enet_tx", dev) < 0) { + 0, "enet_tx", dev) < 0) { printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->einfo->interruptTransmit); @@ -737,7 +750,7 @@ int startup_gfar(struct net_device *dev) } if (request_irq(priv->einfo->interruptReceive, gfar_receive, - SA_SHIRQ, "enet_rx", dev) < 0) { + 0, "enet_rx", dev) < 0) { printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n", dev->name, priv->einfo->interruptReceive); @@ -746,7 +759,7 @@ int startup_gfar(struct net_device *dev) } } else { if (request_irq(priv->einfo->interruptTransmit, gfar_interrupt, - SA_SHIRQ, "gfar_interrupt", dev) < 0) { + 0, "gfar_interrupt", dev) < 0) { printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->einfo->interruptError); @@ -755,39 +768,13 @@ int startup_gfar(struct net_device *dev) } } - /* Grab the PHY interrupt */ - if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { - if (request_irq(priv->einfo->interruptPHY, phy_interrupt, - SA_SHIRQ, "phy_interrupt", dev) < 0) { - printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", - dev->name, priv->einfo->interruptPHY); - - err = -1; - - if (priv->einfo->flags & GFAR_HAS_MULTI_INTR) - goto phy_irq_fail; - else - goto tx_irq_fail; - } - } else { - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_timer; - priv->phy_info_timer.data = (unsigned long) dev; - mod_timer(&priv->phy_info_timer, jiffies + 2 * HZ); - } - - /* Set up the bottom half queue */ - INIT_WORK(&priv->tq, (void (*)(void *))gfar_phy_change, dev); - - /* Configure the PHY interrupt */ - phy_run_commands(dev, priv->phyinfo->startup); - - /* Tell the kernel the link is up, and determine the - * negotiated features (speed, duplex) */ - adjust_link(dev); + /* Set up the PHY change work queue */ + INIT_WORK(&priv->tq, gfar_phy_change, dev); - if (priv->link == 0) - printk(KERN_INFO "%s: No link detected\n", dev->name); + init_timer(&priv->phy_info_timer); + priv->phy_info_timer.function = &gfar_phy_startup_timer; + priv->phy_info_timer.data = (unsigned long) priv->mii_info; + mod_timer(&priv->phy_info_timer, jiffies + HZ); /* Configure the coalescing support */ if (priv->txcoalescing) @@ -827,8 +814,6 @@ int startup_gfar(struct net_device *dev) return 0; -phy_irq_fail: - free_irq(priv->einfo->interruptReceive, dev); rx_irq_fail: free_irq(priv->einfo->interruptTransmit, dev); tx_irq_fail: @@ -837,7 +822,17 @@ err_irq_fail: rx_skb_fail: free_skb_resources(priv); tx_skb_fail: - kfree(priv->tx_bd_base); + dma_free_coherent(NULL, + sizeof(struct txbd8)*priv->tx_ring_size + + sizeof(struct rxbd8)*priv->rx_ring_size, + priv->tx_bd_base, + gfar_read(®s->tbase)); + + if (priv->mii_info->phyinfo->close) + priv->mii_info->phyinfo->close(priv->mii_info); + + kfree(priv->mii_info); + return err; } @@ -854,7 +849,7 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); - if (err) + if(err) return err; err = startup_gfar(dev); @@ -934,8 +929,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Stops the kernel queue, and halts the controller */ static int gfar_close(struct net_device *dev) { + struct gfar_private *priv = netdev_priv(dev); stop_gfar(dev); + /* Shutdown the PHY */ + if (priv->mii_info->phyinfo->close) + priv->mii_info->phyinfo->close(priv->mii_info); + + kfree(priv->mii_info); + netif_stop_queue(dev); return 0; @@ -971,121 +973,6 @@ int gfar_set_mac_address(struct net_device *dev) return 0; } -/********************************************************************** - * gfar_accept_fastpath - * - * Used to authenticate to the kernel that a fast path entry can be - * added to device's routing table cache - * - * Input : pointer to ethernet interface network device structure and - * a pointer to the designated entry to be added to the cache. - * Output : zero upon success, negative upon failure - **********************************************************************/ -#ifdef CONFIG_NET_FASTROUTE -static int gfar_accept_fastpath(struct net_device *dev, struct dst_entry *dst) -{ - struct net_device *odev = dst->dev; - - if ((dst->ops->protocol != __constant_htons(ETH_P_IP)) - || (odev->type != ARPHRD_ETHER) - || (odev->accept_fastpath == NULL)) { - return -1; - } - - return 0; -} -#endif - -/* try_fastroute() -- Checks the fastroute cache to see if a given packet - * can be routed immediately to another device. If it can, we send it. - * If we used a fastroute, we return 1. Otherwise, we return 0. - * Returns 0 if CONFIG_NET_FASTROUTE is not on - */ -static inline int try_fastroute(struct sk_buff *skb, struct net_device *dev, int length) -{ -#ifdef CONFIG_NET_FASTROUTE - struct ethhdr *eth; - struct iphdr *iph; - unsigned int hash; - struct rtable *rt; - struct net_device *odev; - struct gfar_private *priv = netdev_priv(dev); - unsigned int CPU_ID = smp_processor_id(); - - eth = (struct ethhdr *) (skb->data); - - /* Only route ethernet IP packets */ - if (eth->h_proto == __constant_htons(ETH_P_IP)) { - iph = (struct iphdr *) (skb->data + ETH_HLEN); - - /* Generate the hash value */ - hash = ((*(u8 *) &iph->daddr) ^ (*(u8 *) & iph->saddr)) & NETDEV_FASTROUTE_HMASK; - - rt = (struct rtable *) (dev->fastpath[hash]); - if (rt != NULL - && ((*(u32 *) &iph->daddr) == (*(u32 *) &rt->key.dst)) - && ((*(u32 *) &iph->saddr) == (*(u32 *) &rt->key.src)) - && !(rt->u.dst.obsolete)) { - odev = rt->u.dst.dev; - netdev_rx_stat[CPU_ID].fastroute_hit++; - - /* Make sure the packet is: - * 1) IPv4 - * 2) without any options (header length of 5) - * 3) Not a multicast packet - * 4) going to a valid destination - * 5) Not out of time-to-live - */ - if (iph->version == 4 - && iph->ihl == 5 - && (!(eth->h_dest[0] & 0x01)) - && neigh_is_valid(rt->u.dst.neighbour) - && iph->ttl > 1) { - - /* Fast Route Path: Taken if the outgoing device is ready to transmit the packet now */ - if ((!netif_queue_stopped(odev)) - && (!spin_is_locked(odev->xmit_lock)) - && (skb->len <= (odev->mtu + ETH_HLEN + 2 + 4))) { - - skb->pkt_type = PACKET_FASTROUTE; - skb->protocol = __constant_htons(ETH_P_IP); - ip_decrease_ttl(iph); - memcpy(eth->h_source, odev->dev_addr, MAC_ADDR_LEN); - memcpy(eth->h_dest, rt->u.dst.neighbour->ha, MAC_ADDR_LEN); - skb->dev = odev; - - /* Prep the skb for the packet */ - skb_put(skb, length); - - if (odev->hard_start_xmit(skb, odev) != 0) { - panic("%s: FastRoute path corrupted", dev->name); - } - netdev_rx_stat[CPU_ID].fastroute_success++; - } - - /* Semi Fast Route Path: Mark the packet as needing fast routing, but let the - * stack handle getting it to the device */ - else { - skb->pkt_type = PACKET_FASTROUTE; - skb->nh.raw = skb->data + ETH_HLEN; - skb->protocol = __constant_htons(ETH_P_IP); - netdev_rx_stat[CPU_ID].fastroute_defer++; - - /* Prep the skb for the packet */ - skb_put(skb, length); - - if(RECEIVE(skb) == NET_RX_DROP) { - priv->extra_stats.kernel_dropped++; - } - } - - return 1; - } - } - } -#endif /* CONFIG_NET_FASTROUTE */ - return 0; -} static int gfar_change_mtu(struct net_device *dev, int new_mtu) { @@ -1148,8 +1035,7 @@ static void gfar_timeout(struct net_device *dev) startup_gfar(dev); } - if (!netif_queue_stopped(dev)) - netif_schedule(dev); + netif_schedule(dev); } /* Interrupt Handler for Transmit complete */ @@ -1315,7 +1201,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) #else spin_lock(&priv->lock); - gfar_clean_rx_ring(dev); + gfar_clean_rx_ring(dev, priv->rx_ring_size); /* If we are coalescing interrupts, update the timer */ /* Otherwise, clear it */ @@ -1336,7 +1222,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) /* gfar_process_frame() -- handle one incoming packet if skb - * isn't NULL. Try the fastroute before using the stack */ + * isn't NULL. */ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length) { @@ -1350,17 +1236,15 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, priv->stats.rx_dropped++; priv->extra_stats.rx_skbmissing++; } else { - if(try_fastroute(skb, dev, length) == 0) { - /* Prep the skb for the packet */ - skb_put(skb, length); + /* Prep the skb for the packet */ + skb_put(skb, length); - /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, dev); + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, dev); - /* Send the packet up the stack */ - if (RECEIVE(skb) == NET_RX_DROP) { - priv->extra_stats.kernel_dropped++; - } + /* Send the packet up the stack */ + if (RECEIVE(skb) == NET_RX_DROP) { + priv->extra_stats.kernel_dropped++; } } @@ -1368,14 +1252,10 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, } /* gfar_clean_rx_ring() -- Processes each frame in the rx ring - * until all are gone (or, in the case of NAPI, the budget/quota - * has been reached). Returns the number of frames handled + * until the budget/quota has been reached. Returns the number + * of frames handled */ -#ifdef CONFIG_GFAR_NAPI static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) -#else -static int gfar_clean_rx_ring(struct net_device *dev) -#endif { struct rxbd8 *bdp; struct sk_buff *skb; @@ -1386,12 +1266,7 @@ static int gfar_clean_rx_ring(struct net_device *dev) /* Get the first full descriptor */ bdp = priv->cur_rx; -#ifdef CONFIG_GFAR_NAPI -#define GFAR_RXDONE() ((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0)) -#else -#define GFAR_RXDONE() (bdp->status & RXBD_EMPTY) -#endif - while (!GFAR_RXDONE()) { + while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { skb = priv->rx_skbuff[priv->skb_currx]; if (!(bdp->status & @@ -1407,7 +1282,6 @@ static int gfar_clean_rx_ring(struct net_device *dev) gfar_process_frame(dev, skb, pkt_len); priv->stats.rx_bytes += pkt_len; - } else { count_errors(bdp->status, priv); @@ -1462,7 +1336,6 @@ static int gfar_poll(struct net_device *dev, int *budget) if (rx_work_limit > dev->quota) rx_work_limit = dev->quota; - spin_lock(&priv->lock); howmany = gfar_clean_rx_ring(dev, rx_work_limit); dev->quota -= howmany; @@ -1489,8 +1362,6 @@ static int gfar_poll(struct net_device *dev, int *budget) priv->rxclean = 1; } - spin_unlock(priv->lock); - return (rx_work_limit < 0) ? 1 : 0; } #endif @@ -1586,10 +1457,14 @@ static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); - /* Run the commands which acknowledge the interrupt */ - phy_run_commands(dev, priv->phyinfo->ack_int); + /* Clear the interrupt */ + mii_clear_phy_interrupt(priv->mii_info); + + /* Disable PHY interrupts */ + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_DISABLED); - /* Schedule the bottom half */ + /* Schedule the phy change */ schedule_work(&priv->tq); return IRQ_HANDLED; @@ -1600,18 +1475,24 @@ static void gfar_phy_change(void *data) { struct net_device *dev = (struct net_device *) data; struct gfar_private *priv = netdev_priv(dev); - int timeout = HZ / 1000 + 1; + int result = 0; /* Delay to give the PHY a chance to change the * register state */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); + msleep(1); - /* Run the commands which check the link state */ - phy_run_commands(dev, priv->phyinfo->handle_int); + /* Update the link, speed, duplex */ + result = priv->mii_info->phyinfo->read_status(priv->mii_info); - /* React to the change in state */ - adjust_link(dev); + /* Adjust the known status as long as the link + * isn't still coming up */ + if((0 == result) || (priv->mii_info->link == 0)) + adjust_link(dev); + + /* Reenable interrupts, if needed */ + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_ENABLED); } /* Called every so often on systems that don't interrupt @@ -1623,7 +1504,72 @@ static void gfar_phy_timer(unsigned long data) schedule_work(&priv->tq); - mod_timer(&priv->phy_info_timer, jiffies + 2 * HZ); + mod_timer(&priv->phy_info_timer, jiffies + + GFAR_PHY_CHANGE_TIME * HZ); +} + +/* Keep trying aneg for some time + * If, after GFAR_AN_TIMEOUT seconds, it has not + * finished, we switch to forced. + * Either way, once the process has completed, we either + * request the interrupt, or switch the timer over to + * using gfar_phy_timer to check status */ +static void gfar_phy_startup_timer(unsigned long data) +{ + int result; + static int secondary = GFAR_AN_TIMEOUT; + struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; + struct gfar_private *priv = netdev_priv(mii_info->dev); + + /* Configure the Auto-negotiation */ + result = mii_info->phyinfo->config_aneg(mii_info); + + /* If autonegotiation failed to start, and + * we haven't timed out, reset the timer, and return */ + if (result && secondary--) { + mod_timer(&priv->phy_info_timer, jiffies + HZ); + return; + } else if (result) { + /* Couldn't start autonegotiation. + * Try switching to forced */ + mii_info->autoneg = 0; + result = mii_info->phyinfo->config_aneg(mii_info); + + /* Forcing failed! Give up */ + if(result) { + printk(KERN_ERR "%s: Forcing failed!\n", + mii_info->dev->name); + return; + } + } + + /* Kill the timer so it can be restarted */ + del_timer_sync(&priv->phy_info_timer); + + /* Grab the PHY interrupt, if necessary/possible */ + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + if (request_irq(priv->einfo->interruptPHY, + phy_interrupt, + SA_SHIRQ, + "phy_interrupt", + mii_info->dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", + mii_info->dev->name, + priv->einfo->interruptPHY); + } else { + mii_configure_phy_interrupt(priv->mii_info, + MII_INTERRUPT_ENABLED); + return; + } + } + + /* Start the timer again, this time in order to + * handle a change in status */ + init_timer(&priv->phy_info_timer); + priv->phy_info_timer.function = &gfar_phy_timer; + priv->phy_info_timer.data = (unsigned long) mii_info->dev; + mod_timer(&priv->phy_info_timer, jiffies + + GFAR_PHY_CHANGE_TIME * HZ); } /* Called every time the controller might need to be made @@ -1637,12 +1583,13 @@ static void adjust_link(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); struct gfar *regs = priv->regs; u32 tempval; + struct gfar_mii_info *mii_info = priv->mii_info; - if (priv->link) { + if (mii_info->link) { /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ - if (priv->duplexity != priv->olddplx) { - if (!(priv->duplexity)) { + if (mii_info->duplex != priv->oldduplex) { + if (!(mii_info->duplex)) { tempval = gfar_read(®s->maccfg2); tempval &= ~(MACCFG2_FULL_DUPLEX); gfar_write(®s->maccfg2, tempval); @@ -1658,11 +1605,11 @@ static void adjust_link(struct net_device *dev) dev->name); } - priv->olddplx = priv->duplexity; + priv->oldduplex = mii_info->duplex; } - if (priv->speed != priv->oldspeed) { - switch (priv->speed) { + if (mii_info->speed != priv->oldspeed) { + switch (mii_info->speed) { case 1000: tempval = gfar_read(®s->maccfg2); tempval = @@ -1679,14 +1626,14 @@ static void adjust_link(struct net_device *dev) default: printk(KERN_WARNING "%s: Ack! Speed (%d) is not 10/100/1000!\n", - dev->name, priv->speed); + dev->name, mii_info->speed); break; } printk(KERN_INFO "%s: Speed %dBT\n", dev->name, - priv->speed); + mii_info->speed); - priv->oldspeed = priv->speed; + priv->oldspeed = mii_info->speed; } if (!priv->oldlink) { @@ -1700,15 +1647,10 @@ static void adjust_link(struct net_device *dev) printk(KERN_INFO "%s: Link is down\n", dev->name); priv->oldlink = 0; priv->oldspeed = 0; - priv->olddplx = -1; + priv->oldduplex = -1; netif_carrier_off(dev); } } - -#ifdef VERBOSE_GFAR_ERRORS - printk(KERN_INFO "%s: Link now %s; %dBT %s-duplex\n", - dev->name, priv->link ? "up" : "down", priv->speed, priv->duplexity ? "full" : "half"); -#endif } @@ -1905,11 +1847,7 @@ static int __init gfar_init(void) int rc; rc = ocp_register_driver(&gfar_driver); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) if (rc != 0) { -#else - if (rc == 0) { -#endif ocp_unregister_driver(&gfar_driver); return -ENODEV; } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index f7af3465c..91eaab35d 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -8,7 +8,7 @@ * Author: Andy Fleming * Maintainer: Kumar Gala (kumar.gala@freescale.com) * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright (c) 2002-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 @@ -17,6 +17,8 @@ * * Still left to do: * -Add support for module parameters + * -Add support for ethtool -s + * -Add patch for ethtool phys id */ #ifndef __GIANFAR_H #define __GIANFAR_H @@ -42,15 +44,7 @@ #include #include #include - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) #include -#else -#include -#define work_struct tq_struct -#define schedule_work schedule_task -#endif - #include #include #include @@ -70,8 +64,13 @@ #define MAC_ADDR_LEN 6 -extern char gfar_driver_name[]; -extern char gfar_driver_version[]; +#define PHY_INIT_TIMEOUT 100000 +#define GFAR_PHY_CHANGE_TIME 2 + +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, " +#define DRV_NAME "gfar-enet" +extern const char gfar_driver_name[]; +extern const char gfar_driver_version[]; /* These need to be powers of 2 for this driver */ #ifdef CONFIG_GFAR_NAPI @@ -105,11 +104,13 @@ extern char gfar_driver_version[]; #define GFAR_100_TIME 2560 #define GFAR_10_TIME 25600 +#define DEFAULT_TX_COALESCE 1 #define DEFAULT_TXCOUNT 16 -#define DEFAULT_TXTIME 32768 +#define DEFAULT_TXTIME 400 +#define DEFAULT_RX_COALESCE 1 #define DEFAULT_RXCOUNT 16 -#define DEFAULT_RXTIME 32768 +#define DEFAULT_RXTIME 400 #define TBIPA_VALUE 0x1f #define MIIMCFG_INIT_VALUE 0x00000007 @@ -467,8 +468,7 @@ struct gfar { * empty and completely full conditions. The empty/ready indicator in * the buffer descriptor determines the actual condition. */ -struct gfar_private -{ +struct gfar_private { /* pointers to arrays of skbuffs for tx and rx */ struct sk_buff ** tx_skbuff; struct sk_buff ** rx_skbuff; @@ -496,7 +496,6 @@ struct gfar_private struct txbd8 *cur_tx; /* Next free ring entry */ struct txbd8 *dirty_tx; /* The Ring entry to be freed. */ struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ - struct phy_info *phyinfo; struct gfar *phyregs; struct work_struct tq; struct timer_list phy_info_timer; @@ -509,15 +508,14 @@ struct gfar_private unsigned int rx_ring_size; wait_queue_head_t rxcleanupq; unsigned int rxclean; - int link; /* current link state */ - int oldlink; - int duplexity; /* Indicates negotiated duplex state */ - int olddplx; - int speed; /* Indicates negotiated speed */ - int oldspeed; - + /* Info structure initialized by board setup code */ struct ocp_gfar_data *einfo; + + struct gfar_mii_info *mii_info; + int oldspeed; + int oldduplex; + int oldlink; }; extern inline u32 gfar_read(volatile unsigned *addr) @@ -532,6 +530,6 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val) out_be32(addr, val); } - +extern struct ethtool_ops *gfar_op_array[]; #endif /* __GIANFAR_H */ diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 4ccb5afd6..14ab0b217 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -1,18 +1,18 @@ /* - * drivers/net/gianfar_ethtool.c + * drivers/net/gianfar_ethtool.c * - * Gianfar Ethernet Driver - * Ethtool support for Gianfar Enet - * Based on e1000 ethtool support + * Gianfar Ethernet Driver + * Ethtool support for Gianfar Enet + * Based on e1000 ethtool support * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright (c) 2003,2004 Freescale Semiconductor, Inc. * - * This software may be used and distributed according to - * the terms of the GNU Public License, Version 2, incorporated herein - * by reference. + * This software may be used and distributed according to + * the terms of the GNU Public License, Version 2, incorporated herein + * by reference. */ #include @@ -58,64 +58,64 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals); void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo); static char stat_gstrings[][ETH_GSTRING_LEN] = { - "RX Dropped by Kernel", - "RX Large Frame Errors", - "RX Short Frame Errors", - "RX Non-Octet Errors", - "RX CRC Errors", - "RX Overrun Errors", - "RX Busy Errors", - "RX Babbling Errors", - "RX Truncated Frames", - "Ethernet Bus Error", - "TX Babbling Errors", - "TX Underrun Errors", - "RX SKB Missing Errors", - "TX Timeout Errors", - "tx&rx 64B frames", - "tx&rx 65-127B frames", - "tx&rx 128-255B frames", - "tx&rx 256-511B frames", - "tx&rx 512-1023B frames", - "tx&rx 1024-1518B frames", - "tx&rx 1519-1522B Good VLAN", - "RX bytes", - "RX Packets", - "RX FCS Errors", - "Receive Multicast Packet", - "Receive Broadcast Packet", - "RX Control Frame Packets", - "RX Pause Frame Packets", - "RX Unknown OP Code", - "RX Alignment Error", - "RX Frame Length Error", - "RX Code Error", - "RX Carrier Sense Error", - "RX Undersize Packets", - "RX Oversize Packets", - "RX Fragmented Frames", - "RX Jabber Frames", - "RX Dropped Frames", - "TX Byte Counter", - "TX Packets", - "TX Multicast Packets", - "TX Broadcast Packets", - "TX Pause Control Frames", - "TX Deferral Packets", - "TX Excessive Deferral Packets", - "TX Single Collision Packets", - "TX Multiple Collision Packets", - "TX Late Collision Packets", - "TX Excessive Collision Packets", - "TX Total Collision", - "RESERVED", - "TX Dropped Frames", - "TX Jabber Frames", - "TX FCS Errors", - "TX Control Frames", - "TX Oversize Frames", - "TX Undersize Frames", - "TX Fragmented Frames", + "rx-dropped-by-kernel", + "rx-large-frame-errors", + "rx-short-frame-errors", + "rx-non-octet-errors", + "rx-crc-errors", + "rx-overrun-errors", + "rx-busy-errors", + "rx-babbling-errors", + "rx-truncated-frames", + "ethernet-bus-error", + "tx-babbling-errors", + "tx-underrun-errors", + "rx-skb-missing-errors", + "tx-timeout-errors", + "tx-rx-64-frames", + "tx-rx-65-127-frames", + "tx-rx-128-255-frames", + "tx-rx-256-511-frames", + "tx-rx-512-1023-frames", + "tx-rx-1024-1518-frames", + "tx-rx-1519-1522-good-vlan", + "rx-bytes", + "rx-packets", + "rx-fcs-errors", + "receive-multicast-packet", + "receive-broadcast-packet", + "rx-control-frame-packets", + "rx-pause-frame-packets", + "rx-unknown-op-code", + "rx-alignment-error", + "rx-frame-length-error", + "rx-code-error", + "rx-carrier-sense-error", + "rx-undersize-packets", + "rx-oversize-packets", + "rx-fragmented-frames", + "rx-jabber-frames", + "rx-dropped-frames", + "tx-byte-counter", + "tx-packets", + "tx-multicast-packets", + "tx-broadcast-packets", + "tx-pause-control-frames", + "tx-deferral-packets", + "tx-excessive-deferral-packets", + "tx-single-collision-packets", + "tx-multiple-collision-packets", + "tx-late-collision-packets", + "tx-excessive-collision-packets", + "tx-total-collision", + "reserved", + "tx-dropped-frames", + "tx-jabber-frames", + "tx-fcs-errors", + "tx-control-frames", + "tx-oversize-frames", + "tx-undersize-frames", + "tx-fragmented-frames", }; /* Fill in an array of 64-bit statistics from various sources. @@ -125,7 +125,7 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = { void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf) { int i; - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); u32 *rmon = (u32 *) & priv->regs->rmon; u64 *extra = (u64 *) & priv->extra_stats; struct gfar_stats *stats = (struct gfar_stats *) buf; @@ -154,7 +154,7 @@ void gfar_fill_stats_normon(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf) { int i; - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); u64 *extra = (u64 *) & priv->extra_stats; for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) { @@ -171,7 +171,7 @@ int gfar_stats_count_normon(struct net_device *dev) void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { - strncpy(drvinfo->driver, gfar_driver_name, GFAR_INFOSTR_LEN); + strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN); strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN); strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN); strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN); @@ -184,7 +184,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct /* Return the current settings in the ethtool_cmd structure */ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); uint gigabit_support = priv->einfo->flags & GFAR_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; uint gigabit_advert = @@ -201,10 +201,10 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) | ADVERTISED_100baseT_Full | gigabit_advert | ADVERTISED_Autoneg); - cmd->speed = priv->speed; - cmd->duplex = priv->duplexity; + cmd->speed = priv->mii_info->speed; + cmd->duplex = priv->mii_info->duplex; cmd->port = PORT_MII; - cmd->phy_address = priv->einfo->phyid; + cmd->phy_address = priv->mii_info->mii_id; cmd->transceiver = XCVR_EXTERNAL; cmd->autoneg = AUTONEG_ENABLE; cmd->maxtxpkt = priv->txcount; @@ -223,7 +223,7 @@ int gfar_reglen(struct net_device *dev) void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) { int i; - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); u32 *theregs = (u32 *) priv->regs; u32 *buf = (u32 *) regbuf; @@ -231,13 +231,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb buf[i] = theregs[i]; } -/* Return the link state 1 is up, 0 is down */ -u32 gfar_get_link(struct net_device *dev) -{ - struct gfar_private *priv = (struct gfar_private *) dev->priv; - return (u32) priv->link; -} - /* Fill in a buffer with the strings which correspond to the * stats */ void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf) @@ -252,7 +245,7 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->speed) { + switch (priv->mii_info->speed) { case 1000: count = GFAR_GBIT_TIME; break; @@ -276,7 +269,7 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->speed) { + switch (priv->mii_info->speed) { case 1000: count = GFAR_GBIT_TIME; break; @@ -298,7 +291,7 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic * structure. */ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); cvals->rx_max_coalesced_frames = priv->rxcount; @@ -344,7 +337,7 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) */ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); /* Set up rx coalescing */ if ((cvals->rx_coalesce_usecs == 0) || @@ -386,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) * jumbo are ignored by the driver */ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE; rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE; @@ -409,7 +402,7 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals) int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { u32 tempval; - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); int err = 0; if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) @@ -473,7 +466,7 @@ struct ethtool_ops gfar_ethtool_ops = { .get_drvinfo = gfar_gdrvinfo, .get_regs_len = gfar_reglen, .get_regs = gfar_get_regs, - .get_link = gfar_get_link, + .get_link = ethtool_op_get_link, .get_coalesce = gfar_gcoalesce, .set_coalesce = gfar_scoalesce, .get_ringparam = gfar_gringparam, @@ -482,3 +475,51 @@ struct ethtool_ops gfar_ethtool_ops = { .get_stats_count = gfar_stats_count, .get_ethtool_stats = gfar_fill_stats, }; + +struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings_normon, + .get_stats_count = gfar_stats_count_normon, + .get_ethtool_stats = gfar_fill_stats_normon, +}; + +struct ethtool_ops gfar_nocoalesce_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings, + .get_stats_count = gfar_stats_count, + .get_ethtool_stats = gfar_fill_stats, +}; + +struct ethtool_ops gfar_normon_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = ethtool_op_get_link, + .get_coalesce = gfar_gcoalesce, + .set_coalesce = gfar_scoalesce, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings_normon, + .get_stats_count = gfar_stats_count_normon, + .get_ethtool_stats = gfar_fill_stats_normon, +}; + +struct ethtool_ops *gfar_op_array[] = { + &gfar_ethtool_ops, + &gfar_normon_ethtool_ops, + &gfar_nocoalesce_ethtool_ops, + &gfar_normon_nocoalesce_ethtool_ops +}; diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c index ea02e5da9..02b16abc8 100644 --- a/drivers/net/gianfar_phy.c +++ b/drivers/net/gianfar_phy.c @@ -8,7 +8,7 @@ * Author: Andy Fleming * Maintainer: Kumar Gala (kumar.gala@freescale.com) * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright (c) 2002-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 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -39,21 +38,31 @@ #include #include #include +#include #include "gianfar.h" #include "gianfar_phy.h" +static void config_genmii_advert(struct gfar_mii_info *mii_info); +static void genmii_setup_forced(struct gfar_mii_info *mii_info); +static void genmii_restart_aneg(struct gfar_mii_info *mii_info); +static int gbit_config_aneg(struct gfar_mii_info *mii_info); +static int genmii_config_aneg(struct gfar_mii_info *mii_info); +static int genmii_update_link(struct gfar_mii_info *mii_info); +static int genmii_read_status(struct gfar_mii_info *mii_info); +u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum); +void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val); + /* Write value to the PHY for this device to the register at regnum, */ /* waiting until the write is done before it returns. All PHY */ /* configuration has to be done through the TSEC1 MIIM regs */ -void write_phy_reg(struct net_device *dev, u16 regnum, u16 value) +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); struct gfar *regbase = priv->phyregs; - struct ocp_gfar_data *einfo = priv->einfo; /* Set the PHY address and the register address we want to write */ - gfar_write(®base->miimadd, ((einfo->phyid) << 8) | regnum); + gfar_write(®base->miimadd, (mii_id << 8) | regnum); /* Write out the value we want */ gfar_write(®base->miimcon, value); @@ -66,19 +75,18 @@ void write_phy_reg(struct net_device *dev, u16 regnum, u16 value) /* Reads from register regnum in the PHY for device dev, */ /* returning the value. Clears miimcom first. All PHY */ /* configuration has to be done through the TSEC1 MIIM regs */ -u16 read_phy_reg(struct net_device *dev, u16 regnum) +int read_phy_reg(struct net_device *dev, int mii_id, int regnum) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_private *priv = netdev_priv(dev); struct gfar *regbase = priv->phyregs; - struct ocp_gfar_data *einfo = priv->einfo; u16 value; /* Set the PHY address and the register address we want to read */ - gfar_write(®base->miimadd, ((einfo->phyid) << 8) | regnum); + gfar_write(®base->miimadd, (mii_id << 8) | regnum); /* Clear miimcom, and then initiate a read */ gfar_write(®base->miimcom, 0); - gfar_write(®base->miimcom, MIIM_READ_COMMAND); + gfar_write(®base->miimcom, MII_READ_COMMAND); /* Wait for the transaction to finish */ while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) @@ -90,444 +98,557 @@ u16 read_phy_reg(struct net_device *dev, u16 regnum) return value; } -/* returns which value to write to the control register. */ -/* For 10/100 the value is slightly different. */ -u16 mii_cr_init(u16 mii_reg, struct net_device * dev) +void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; - struct ocp_gfar_data *einfo = priv->einfo; + if(mii_info->phyinfo->ack_interrupt) + mii_info->phyinfo->ack_interrupt(mii_info); +} - if (einfo->flags & GFAR_HAS_GIGABIT) - return MIIM_CONTROL_INIT; - else - return MIIM_CR_INIT; + +void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts) +{ + mii_info->interrupts = interrupts; + if(mii_info->phyinfo->config_intr) + mii_info->phyinfo->config_intr(mii_info); } -#define BRIEF_GFAR_ERRORS -/* Wait for auto-negotiation to complete */ -u16 mii_parse_sr(u16 mii_reg, struct net_device * dev) + +/* Writes MII_ADVERTISE with the appropriate values, after + * sanitizing advertise to make sure only supported features + * are advertised + */ +static void config_genmii_advert(struct gfar_mii_info *mii_info) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + u32 advertise; + u16 adv; + + /* Only allow advertising what this PHY supports */ + mii_info->advertising &= mii_info->phyinfo->features; + advertise = mii_info->advertising; + + /* Setup standard advertisement */ + adv = phy_read(mii_info, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(mii_info, MII_ADVERTISE, adv); +} - unsigned int timeout = GFAR_AN_TIMEOUT; +static void genmii_setup_forced(struct gfar_mii_info *mii_info) +{ + u16 ctrl; + u32 features = mii_info->phyinfo->features; + + ctrl = phy_read(mii_info, MII_BMCR); + + ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE); + ctrl |= BMCR_RESET; + + switch(mii_info->speed) { + case SPEED_1000: + if(features & (SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full)) { + ctrl |= BMCR_SPEED1000; + break; + } + mii_info->speed = SPEED_100; + case SPEED_100: + if (features & (SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full)) { + ctrl |= BMCR_SPEED100; + break; + } + mii_info->speed = SPEED_10; + case SPEED_10: + if (features & (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full)) + break; + default: /* Unsupported speed! */ + printk(KERN_ERR "%s: Bad speed!\n", + mii_info->dev->name); + break; + } - if (mii_reg & MIIM_STATUS_LINK) - priv->link = 1; - else - priv->link = 0; + phy_write(mii_info, MII_BMCR, ctrl); +} - /* Only auto-negotiate if the link has just gone up */ - if (priv->link && !priv->oldlink) { - while ((!(mii_reg & MIIM_STATUS_AN_DONE)) && timeout--) - mii_reg = read_phy_reg(dev, MIIM_STATUS); -#if defined(BRIEF_GFAR_ERRORS) - if (mii_reg & MIIM_STATUS_AN_DONE) - printk(KERN_INFO "%s: Auto-negotiation done\n", - dev->name); - else - printk(KERN_INFO "%s: Auto-negotiation timed out\n", - dev->name); -#endif - } +/* Enable and Restart Autonegotiation */ +static void genmii_restart_aneg(struct gfar_mii_info *mii_info) +{ + u16 ctl; + + ctl = phy_read(mii_info, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(mii_info, MII_BMCR, ctl); +} + + +static int gbit_config_aneg(struct gfar_mii_info *mii_info) +{ + u16 adv; + u32 advertise; + + if(mii_info->autoneg) { + /* Configure the ADVERTISE register */ + config_genmii_advert(mii_info); + advertise = mii_info->advertising; + + adv = phy_read(mii_info, MII_1000BASETCONTROL); + adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | + MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; + phy_write(mii_info, MII_1000BASETCONTROL, adv); + + /* Start/Restart aneg */ + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); return 0; } -/* Determine the speed and duplex which was negotiated */ -u16 mii_parse_88E1011_psr(u16 mii_reg, struct net_device * dev) +static int marvell_config_aneg(struct gfar_mii_info *mii_info) +{ + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation */ + phy_write(mii_info, MII_BMCR, BMCR_RESET); + + phy_write(mii_info, 0x1d, 0x1f); + phy_write(mii_info, 0x1e, 0x200c); + phy_write(mii_info, 0x1d, 0x5); + phy_write(mii_info, 0x1e, 0); + phy_write(mii_info, 0x1e, 0x100); + + gbit_config_aneg(mii_info); + + return 0; +} +static int genmii_config_aneg(struct gfar_mii_info *mii_info) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; - unsigned int speed; + if (mii_info->autoneg) { + config_genmii_advert(mii_info); + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + + +static int genmii_update_link(struct gfar_mii_info *mii_info) +{ + u16 status; + + /* Do a fake read */ + phy_read(mii_info, MII_BMSR); + + /* Read link and autonegotiation status */ + status = phy_read(mii_info, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + mii_info->link = 0; + else + mii_info->link = 1; - if (priv->link) { - if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) - priv->duplexity = 1; + /* If we are autonegotiating, and not done, + * return an error */ + if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return -EAGAIN; + + return 0; +} + +static int genmii_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + if (mii_info->autoneg) { + status = phy_read(mii_info, MII_LPA); + + if (status & (LPA_10FULL | LPA_100FULL)) + mii_info->duplex = DUPLEX_FULL; else - priv->duplexity = 0; + mii_info->duplex = DUPLEX_HALF; + if (status & (LPA_100FULL | LPA_100HALF)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + mii_info->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ - speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); + return 0; +} +static int marvell_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); - switch (speed) { - case MIIM_88E1011_PHYSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_88E1011_PHYSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - break; +#if 0 + /* If speed and duplex aren't resolved, + * return an error. Isn't this handled + * by checking aneg? + */ + if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) + return -EAGAIN; +#endif + + /* Get the duplexity */ + if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + /* Get the speed */ + speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; + switch(speed) { + case MII_M1011_PHY_SPEC_STATUS_1000: + mii_info->speed = SPEED_1000; + break; + case MII_M1011_PHY_SPEC_STATUS_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; } - } else { - priv->speed = 0; - priv->duplexity = 0; + mii_info->pause = 0; } return 0; } -u16 mii_parse_cis8201(u16 mii_reg, struct net_device * dev) -{ - struct gfar_private *priv = (struct gfar_private *) dev->priv; - unsigned int speed; - if (priv->link) { - if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) - priv->duplexity = 1; +static int cis820x_read_status(struct gfar_mii_info *mii_info) +{ + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + + status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); + if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) + mii_info->duplex = DUPLEX_FULL; else - priv->duplexity = 0; + mii_info->duplex = DUPLEX_HALF; - speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; + speed = status & MII_CIS8201_AUXCONSTAT_SPEED; switch (speed) { - case MIIM_CIS8201_AUXCONSTAT_GBIT: - priv->speed = 1000; + case MII_CIS8201_AUXCONSTAT_GBIT: + mii_info->speed = SPEED_1000; break; - case MIIM_CIS8201_AUXCONSTAT_100: - priv->speed = 100; + case MII_CIS8201_AUXCONSTAT_100: + mii_info->speed = SPEED_100; break; default: - priv->speed = 10; + mii_info->speed = SPEED_10; break; } - } else { - priv->speed = 0; - priv->duplexity = 0; } return 0; } -u16 mii_parse_dm9161_scsr(u16 mii_reg, struct net_device * dev) +static int marvell_ack_interrupt(struct gfar_mii_info *mii_info) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + /* Clear the interrupts by reading the reg */ + phy_read(mii_info, MII_M1011_IEVENT); + + return 0; +} - if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) - priv->speed = 100; +static int marvell_config_intr(struct gfar_mii_info *mii_info) +{ + if(mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else - priv->speed = 10; + phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + + return 0; +} + +static int cis820x_init(struct gfar_mii_info *mii_info) +{ + phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, + MII_CIS8201_AUXCONSTAT_INIT); + phy_write(mii_info, MII_CIS8201_EXT_CON1, + MII_CIS8201_EXTCON1_INIT); + + return 0; +} - if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) - priv->duplexity = 1; +static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info) +{ + phy_read(mii_info, MII_CIS8201_ISTAT); + + return 0; +} + +static int cis820x_config_intr(struct gfar_mii_info *mii_info) +{ + if(mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); else - priv->duplexity = 0; + phy_write(mii_info, MII_CIS8201_IMASK, 0); return 0; } -u16 dm9161_wait(u16 mii_reg, struct net_device *dev) +#define DM9161_DELAY 10 + +static int dm9161_read_status(struct gfar_mii_info *mii_info) { - int timeout = HZ; - int secondary = 10; - u16 temp; + u16 status; + int err; + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + status = phy_read(mii_info, MII_DM9161_SCSR); + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + } - do { + return 0; +} - /* Davicom takes a bit to come up after a reset, - * so wait here for a bit */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - temp = read_phy_reg(dev, MIIM_STATUS); +static int dm9161_config_aneg(struct gfar_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; - secondary--; - } while ((!(temp & MIIM_STATUS_AN_DONE)) && secondary); + if(0 == priv->resetdone) + return -EAGAIN; return 0; } -/* - * consult the BCM54xx auxilliary status register to find the link settings - */ -u16 mii_parse_bcm54xx_sr(u16 mii_reg, struct net_device * dev) +static void dm9161_timer(unsigned long data) { - struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; + struct dm9161_private *priv = mii_info->priv; + u16 status = phy_read(mii_info, MII_BMSR); + + if (status & BMSR_ANEGCOMPLETE) { + priv->resetdone = 1; + } else + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); +} + +static int dm9161_init(struct gfar_mii_info *mii_info) +{ + struct dm9161_private *priv; + + /* Allocate the private data structure */ + priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); + + if (NULL == priv) + return -ENOMEM; - /* Link modes of the BCM5400 PHY */ - static const uint16_t link_table[8][3] = { - { 0, 0 }, /* No link */ - { 0, 10 }, /* 10BT Half Duplex */ - { 1, 10 }, /* 10BT Full Duplex */ - { 0, 100 }, /* 100BT Half Duplex */ - { 0, 100 }, /* 100BT Half Duplex */ - { 1, 100 }, /* 100BT Full Duplex*/ - { 1, 1000 }, /* 1000BT */ - { 1, 1000 }, /* 1000BT */ - }; + mii_info->priv = priv; - uint16_t link_mode; + /* Reset is not done yet */ + priv->resetdone = 0; - link_mode = mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK; - link_mode >>= MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT; + /* Isolate the PHY */ + phy_write(mii_info, MII_BMCR, BMCR_ISOLATE); - priv->duplexity = link_table[link_mode][0]; - priv->speed = link_table[link_mode][1]; + /* Do not bypass the scrambler/descrambler */ + phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + + /* Clear 10BTCSR to default */ + phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); + + /* Reconnect the PHY, and enable Autonegotiation */ + phy_write(mii_info, MII_BMCR, BMCR_ANENABLE); + + /* Start a timer for DM9161_DELAY seconds to wait + * for the PHY to be ready */ + init_timer(&priv->timer); + priv->timer.function = &dm9161_timer; + priv->timer.data = (unsigned long) mii_info; + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); return 0; } -static struct phy_info phy_info_M88E1011S = { - 0x01410c6, - "Marvell 88E1011S", - 4, - (const struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, mii_parse_88E1011_psr}, - /* Clear the IEVENT register */ - {MIIM_88E1011_IEVENT, miim_read, NULL}, - /* Set up the mask */ - {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_INIT, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* ack_int */ - /* Clear the interrupt */ - {MIIM_88E1011_IEVENT, miim_read, NULL}, - /* Disable interrupts */ - {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_CLEAR, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* handle_int */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Check the status */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - {MIIM_88E1011_PHY_STATUS, miim_read, mii_parse_88E1011_psr}, - /* Enable Interrupts */ - {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_INIT, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* shutdown */ - {MIIM_88E1011_IEVENT, miim_read, NULL}, - {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_CLEAR, NULL}, - {miim_end,} - }, -}; +static void dm9161_close(struct gfar_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + del_timer_sync(&priv->timer); + kfree(priv); +} + +#if 0 +static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info) +{ + phy_read(mii_info, MII_DM9161_INTR); -/* Cicada 8204 */ -static struct phy_info phy_info_cis8204 = { - 0x3f11, + return 0; +} +#endif + +/* Cicada 820x */ +static struct phy_info phy_info_cis820x = { + 0x000fc440, "Cicada Cis8204", - 6, - (const struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Set up the interface mode */ - {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, mii_parse_cis8201}, - /* Clear the status register */ - {MIIM_CIS8204_ISTAT, miim_read, NULL}, - /* Enable interrupts */ - {MIIM_CIS8204_IMASK, MIIM_CIS8204_IMASK_MASK, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* ack_int */ - /* Clear the status register */ - {MIIM_CIS8204_ISTAT, miim_read, NULL}, - /* Disable interrupts */ - {MIIM_CIS8204_IMASK, 0x0, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* handle_int */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, mii_parse_cis8201}, - /* Enable interrupts */ - {MIIM_CIS8204_IMASK, MIIM_CIS8204_IMASK_MASK, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* shutdown */ - /* Clear the status register */ - {MIIM_CIS8204_ISTAT, miim_read, NULL}, - /* Disable interrupts */ - {MIIM_CIS8204_IMASK, 0x0, NULL}, - {miim_end,} - }, + 0x000fffc0, + .features = MII_GBIT_FEATURES, + .init = &cis820x_init, + .config_aneg = &gbit_config_aneg, + .read_status = &cis820x_read_status, + .ack_interrupt = &cis820x_ack_interrupt, + .config_intr = &cis820x_config_intr, }; -/* Cicada 8201 */ -static struct phy_info phy_info_cis8201 = { - 0xfc41, - "CIS8201", - 4, - (const struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Set up the interface mode */ - {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, mii_parse_cis8201}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* ack_int */ - {miim_end,} - }, - (const struct phy_cmd[]) { /* handle_int */ - {miim_end,} - }, - (const struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, +static struct phy_info phy_info_dm9161 = { + .phy_id = 0x0181b880, + .name = "Davicom DM9161E", + .phy_id_mask = 0x0ffffff0, + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .close = dm9161_close, }; -static struct phy_info phy_info_dm9161 = { - 0x0181b88, - "Davicom DM9161E", - 4, - (const struct phy_cmd[]) { /* config */ - {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL}, - /* Do not bypass the scrambler/descrambler */ - {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL}, - /* Clear 10BTCSR to default */ - {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CR_INIT, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* startup */ - /* Restart Auto Negotiation */ - {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL}, - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, dm9161_wait}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - /* Read the status */ - {MIIM_DM9161_SCSR, miim_read, mii_parse_dm9161_scsr}, - /* Clear any pending interrupts */ - {MIIM_DM9161_INTR, miim_read, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* ack_int */ - {MIIM_DM9161_INTR, miim_read, NULL}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* handle_int */ - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, mii_parse_sr}, - {MIIM_DM9161_SCSR, miim_read, mii_parse_dm9161_scsr}, - {miim_end,} - }, - (const struct phy_cmd[]) { /* shutdown */ - {MIIM_DM9161_INTR, miim_read, NULL}, - {miim_end,} - }, +static struct phy_info phy_info_marvell = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E1101", + .features = MII_GBIT_FEATURES, + .config_aneg = &marvell_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, }; -/* Broadcom BCM5421S PHY */ -static struct phy_info phy_info_bcm5421s = { - .id = 0x2060E1, - .name = "Broadcom BCM5421S", - .shift = 0, - .config = (const struct phy_cmd[]) { - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CR_INIT, NULL}, -#if 0 /* 5421 only */ - miim_write(MII_BCM5400_AUXCONTROL, 0x1007), - miim_set_bits(MII_BCM5400_AUXCONTROL, 0x0400), - miim_write(MII_BCM5400_AUXCONTROL, 0x0007), - miim_set_bits(MII_BCM5400_AUXCONTROL, 0x0800), - miim_write(0x17, 0x000a), - miim_set_bits(MII_RERRCOUNTER, 0x0200), -#endif -#if 0 /* enable automatic low power */ - miim_write(MII_NCONFIG, 0x9002), - miim_write(MII_NCONFIG, 0xa821), - miim_write(MII_NCONFIG, 0x941d), -#endif - {miim_end,} - }, - .startup = (const struct phy_cmd[]) { - /* Restart Auto Negotiation */ - miim_set_bits(MIIM_CONTROL, BMCR_ANENABLE | BMCR_ANRESTART), -#if 0 - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, dm9161_wait}, -#endif - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, mii_parse_sr}, - - /* Read the link status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, mii_parse_bcm54xx_sr}, - - {miim_end,} - }, - .ack_int = (const struct phy_cmd[]) { - {miim_end,} - }, - .handle_int = (const struct phy_cmd[]) { - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, mii_parse_sr}, - {miim_end,} - }, - .shutdown = (const struct phy_cmd[]) { - {miim_end,} - }, +static struct phy_info phy_info_genmii= { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .features = MII_BASIC_FEATURES, + .config_aneg = genmii_config_aneg, + .read_status = genmii_read_status, }; static struct phy_info *phy_info[] = { - &phy_info_cis8201, - &phy_info_cis8204, - &phy_info_M88E1011S, + &phy_info_cis820x, + &phy_info_marvell, &phy_info_dm9161, - &phy_info_bcm5421s, + &phy_info_genmii, NULL }; +u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum) +{ + u16 retval; + unsigned long flags; + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); + + return retval; +} + +void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val) +{ + unsigned long flags; + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + mii_info->mdio_write(mii_info->dev, + mii_info->mii_id, + regnum, val); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); +} + /* Use the PHY ID registers to determine what type of PHY is attached * to device dev. return a struct phy_info structure describing that PHY */ -struct phy_info * get_phy_info(struct net_device *dev) +struct phy_info * get_phy_info(struct gfar_mii_info *mii_info) { u16 phy_reg; u32 phy_ID; int i; struct phy_info *theInfo = NULL; + struct net_device *dev = mii_info->dev; /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = read_phy_reg(dev, MIIM_PHYIR1); + phy_reg = phy_read(mii_info, MII_PHYSID1); phy_ID = (phy_reg & 0xffff) << 16; /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = read_phy_reg(dev, MIIM_PHYIR2); + phy_reg = phy_read(mii_info, MII_PHYSID2); phy_ID |= (phy_reg & 0xffff); /* loop through all the known PHY types, and find one that */ /* matches the ID we read from the PHY. */ for (i = 0; phy_info[i]; i++) - if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) + if (phy_info[i]->phy_id == + (phy_ID & phy_info[i]->phy_id_mask)) { theInfo = phy_info[i]; + break; + } + /* This shouldn't happen, as we have generic PHY support */ if (theInfo == NULL) { printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); return NULL; @@ -538,85 +659,3 @@ struct phy_info * get_phy_info(struct net_device *dev) return theInfo; } - -/* Take a list of struct phy_cmd, and, depending on the values, either */ -/* read or write, using a helper function if provided */ -/* It is assumed that all lists of struct phy_cmd will be terminated by */ -/* mii_end. */ -void phy_run_commands(struct net_device *dev, const struct phy_cmd *cmd) -{ - int i; - u16 result; - struct gfar_private *priv = (struct gfar_private *) dev->priv; - struct gfar *phyregs = priv->phyregs; - - /* Reset the management interface */ - gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); - - /* Setup the MII Mgmt clock speed */ - gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); - - /* Wait until the bus is free */ - while (gfar_read(&phyregs->miimind) & MIIMIND_BUSY) - cpu_relax(); - - for (i = 0; cmd->mii_reg != miim_end; i++) { - switch (cmd->mii_data >> 16) { - case 0x0000: - /* Otherwise, it's a write */ - /* If a function was supplied, it will provide - * the value to write */ - /* Otherwise, the value was supplied in cmd->mii_data */ - if (cmd->funct != NULL) - result = (*(cmd->funct)) (0, dev); - else - result = cmd->mii_data; - - write_phy_reg(dev, cmd->mii_reg, result); - break; - - case 0x0001: - /* Read the value of the PHY reg */ - result = read_phy_reg(dev, cmd->mii_reg); - - /* If a function was supplied, we need to let it process */ - /* the result. */ - if (cmd->funct != NULL) - (*(cmd->funct)) (result, dev); - break; - - case 0x0002: - /* read the value, clear some bits and write it back */ - BUG_ON(cmd->funct); - - result = read_phy_reg(dev, cmd->mii_reg); - result &= cmd->mii_data; - write_phy_reg(dev, cmd->mii_reg, result); - break; - - case 0x0003: - /* read the value, set some bits and write it back */ - BUG_ON(cmd->funct); - - result = read_phy_reg(dev, cmd->mii_reg); - result &= cmd->mii_data; - write_phy_reg(dev, cmd->mii_reg, result); - break; - - case 0x0004: - /* read the value, flip some bits and write it back */ - BUG_ON(cmd->funct); - - result = read_phy_reg(dev, cmd->mii_reg); - result &= cmd->mii_data; - write_phy_reg(dev, cmd->mii_reg, result); - break; - - default: - printk("GIANFAR: Unknown MII command %08x\n", - cmd->mii_data); - BUG(); - } - cmd++; - } -} diff --git a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h index df4c0ec9d..1e9b3abf1 100644 --- a/drivers/net/gianfar_phy.h +++ b/drivers/net/gianfar_phy.h @@ -8,7 +8,7 @@ * Author: Andy Fleming * Maintainer: Kumar Gala (kumar.gala@freescale.com) * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright (c) 2002-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 @@ -19,145 +19,144 @@ #ifndef __GIANFAR_PHY_H #define __GIANFAR_PHY_H -/* simple datum processing commands */ -#define miim_end (0xffff0000U) -#define miim_read (0x00010000U) -#define miim_clear_bits(reg,x) { reg, (0x00020000U | ~(u32)(x)), NULL } -#define miim_set_bits(reg,x) { reg, (0x00030000U | (u32)(x)), NULL } -#define miim_flip_bits(reg,x) { reg, (0x00040000U | (u32)(x)), NULL } -#define miim_write(reg, x) { reg, (0x0000ffffU & (u32)(x)), NULL } +#define MII_end ((u32)-2) +#define MII_read ((u32)-1) #define MIIMIND_BUSY 0x00000001 #define MIIMIND_NOTVALID 0x00000004 -#define MIIM_CONTROL 0x00 -#define MIIM_CONTROL_RESET 0x00008000 -#define MIIM_CONTROL_INIT 0x00001140 -#define MIIM_ANEN 0x00001000 - -#define MIIM_CR 0x00 -#define MIIM_CR_RST 0x00008000 -#define MIIM_CR_INIT 0x00001000 - -#define MIIM_STATUS 0x1 -#define MIIM_STATUS_AN_DONE 0x00000020 -#define MIIM_STATUS_LINK 0x0004 - -#define MIIM_PHYIR1 0x2 -#define MIIM_PHYIR2 0x3 - -#define GFAR_AN_TIMEOUT 0x000fffff - -#define MIIM_ANLPBPA 0x5 -#define MIIM_ANLPBPA_HALF 0x00000040 -#define MIIM_ANLPBPA_FULL 0x00000020 - -#define MIIM_ANEX 0x6 -#define MIIM_ANEX_NP 0x00000004 -#define MIIM_ANEX_PRX 0x00000002 +#define GFAR_AN_TIMEOUT 2000 +/* 1000BT control (Marvell & BCM54xx at least) */ +#define MII_1000BASETCONTROL 0x09 +#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 +#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 /* Cicada Extended Control Register 1 */ -#define MIIM_CIS8201_EXT_CON1 0x17 -#define MIIM_CIS8201_EXTCON1_INIT 0x0000 +#define MII_CIS8201_EXT_CON1 0x17 +#define MII_CIS8201_EXTCON1_INIT 0x0000 /* Cicada Interrupt Mask Register */ -#define MIIM_CIS8204_IMASK 0x19 -#define MIIM_CIS8204_IMASK_IEN 0x8000 -#define MIIM_CIS8204_IMASK_SPEED 0x4000 -#define MIIM_CIS8204_IMASK_LINK 0x2000 -#define MIIM_CIS8204_IMASK_DUPLEX 0x1000 -#define MIIM_CIS8204_IMASK_MASK 0xf000 +#define MII_CIS8201_IMASK 0x19 +#define MII_CIS8201_IMASK_IEN 0x8000 +#define MII_CIS8201_IMASK_SPEED 0x4000 +#define MII_CIS8201_IMASK_LINK 0x2000 +#define MII_CIS8201_IMASK_DUPLEX 0x1000 +#define MII_CIS8201_IMASK_MASK 0xf000 /* Cicada Interrupt Status Register */ -#define MIIM_CIS8204_ISTAT 0x1a -#define MIIM_CIS8204_ISTAT_STATUS 0x8000 -#define MIIM_CIS8204_ISTAT_SPEED 0x4000 -#define MIIM_CIS8204_ISTAT_LINK 0x2000 -#define MIIM_CIS8204_ISTAT_DUPLEX 0x1000 +#define MII_CIS8201_ISTAT 0x1a +#define MII_CIS8201_ISTAT_STATUS 0x8000 +#define MII_CIS8201_ISTAT_SPEED 0x4000 +#define MII_CIS8201_ISTAT_LINK 0x2000 +#define MII_CIS8201_ISTAT_DUPLEX 0x1000 /* Cicada Auxiliary Control/Status Register */ -#define MIIM_CIS8201_AUX_CONSTAT 0x1c -#define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004 -#define MIIM_CIS8201_AUXCONSTAT_DUPLEX 0x0020 -#define MIIM_CIS8201_AUXCONSTAT_SPEED 0x0018 -#define MIIM_CIS8201_AUXCONSTAT_GBIT 0x0010 -#define MIIM_CIS8201_AUXCONSTAT_100 0x0008 +#define MII_CIS8201_AUX_CONSTAT 0x1c +#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MII_CIS8201_AUXCONSTAT_100 0x0008 /* 88E1011 PHY Status Register */ -#define MIIM_88E1011_PHY_STATUS 0x11 -#define MIIM_88E1011_PHYSTAT_SPEED 0xc000 -#define MIIM_88E1011_PHYSTAT_GBIT 0x8000 -#define MIIM_88E1011_PHYSTAT_100 0x4000 -#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000 -#define MIIM_88E1011_PHYSTAT_LINK 0x0400 +#define MII_M1011_PHY_SPEC_STATUS 0x11 +#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 +#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 +#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 +#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 +#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 +#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 -#define MIIM_88E1011_IEVENT 0x13 -#define MIIM_88E1011_IEVENT_CLEAR 0x0000 +#define MII_M1011_IEVENT 0x13 +#define MII_M1011_IEVENT_CLEAR 0x0000 -#define MIIM_88E1011_IMASK 0x12 -#define MIIM_88E1011_IMASK_INIT 0x6400 -#define MIIM_88E1011_IMASK_CLEAR 0x0000 +#define MII_M1011_IMASK 0x12 +#define MII_M1011_IMASK_INIT 0x6400 +#define MII_M1011_IMASK_CLEAR 0x0000 -/* DM9161 Control register values */ -#define MIIM_DM9161_CR_STOP 0x0400 -#define MIIM_DM9161_CR_RSTAN 0x1200 - -#define MIIM_DM9161_SCR 0x10 -#define MIIM_DM9161_SCR_INIT 0x0610 +#define MII_DM9161_SCR 0x10 +#define MII_DM9161_SCR_INIT 0x0610 /* DM9161 Specified Configuration and Status Register */ -#define MIIM_DM9161_SCSR 0x11 -#define MIIM_DM9161_SCSR_100F 0x8000 -#define MIIM_DM9161_SCSR_100H 0x4000 -#define MIIM_DM9161_SCSR_10F 0x2000 -#define MIIM_DM9161_SCSR_10H 0x1000 +#define MII_DM9161_SCSR 0x11 +#define MII_DM9161_SCSR_100F 0x8000 +#define MII_DM9161_SCSR_100H 0x4000 +#define MII_DM9161_SCSR_10F 0x2000 +#define MII_DM9161_SCSR_10H 0x1000 /* DM9161 Interrupt Register */ -#define MIIM_DM9161_INTR 0x15 -#define MIIM_DM9161_INTR_PEND 0x8000 -#define MIIM_DM9161_INTR_DPLX_MASK 0x0800 -#define MIIM_DM9161_INTR_SPD_MASK 0x0400 -#define MIIM_DM9161_INTR_LINK_MASK 0x0200 -#define MIIM_DM9161_INTR_MASK 0x0100 -#define MIIM_DM9161_INTR_DPLX_CHANGE 0x0010 -#define MIIM_DM9161_INTR_SPD_CHANGE 0x0008 -#define MIIM_DM9161_INTR_LINK_CHANGE 0x0004 -#define MIIM_DM9161_INTR_INIT 0x0000 -#define MIIM_DM9161_INTR_STOP \ -(MIIM_DM9161_INTR_DPLX_MASK | MIIM_DM9161_INTR_SPD_MASK \ - | MIIM_DM9161_INTR_LINK_MASK | MIIM_DM9161_INTR_MASK) +#define MII_DM9161_INTR 0x15 +#define MII_DM9161_INTR_PEND 0x8000 +#define MII_DM9161_INTR_DPLX_MASK 0x0800 +#define MII_DM9161_INTR_SPD_MASK 0x0400 +#define MII_DM9161_INTR_LINK_MASK 0x0200 +#define MII_DM9161_INTR_MASK 0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MII_DM9161_INTR_SPD_CHANGE 0x0008 +#define MII_DM9161_INTR_LINK_CHANGE 0x0004 +#define MII_DM9161_INTR_INIT 0x0000 +#define MII_DM9161_INTR_STOP \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) /* DM9161 10BT Configuration/Status */ -#define MIIM_DM9161_10BTCSR 0x12 -#define MIIM_DM9161_10BTCSR_INIT 0x7800 - -/* BCM54xx regs */ -#define MIIM_BCM54xx_AUXCONTROL 0x18 -#define MIIM_BCM54xx_AUXSTATUS 0x19 -#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700 -#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8 - -#define MIIM_READ_COMMAND 0x00000001 - -/* - * struct phy_cmd: A command for reading or writing a PHY register - * - * mii_reg: The register to read or write - * - * mii_data: For writes, the value to put in the register. - * A value of -1 indicates this is a read. - * - * funct: A function pointer which is invoked for each command. - * For reads, this function will be passed the value read - * from the PHY, and process it. - * For writes, the result of this function will be written - * to the PHY register - */ -struct phy_cmd { - u32 mii_reg; - u32 mii_data; - u16 (*funct) (u16 mii_reg, struct net_device * dev); +#define MII_DM9161_10BTCSR 0x12 +#define MII_DM9161_10BTCSR_INIT 0x7800 + +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | \ + SUPPORTED_TP | \ + SUPPORTED_MII) + +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | \ + SUPPORTED_1000baseT_Full) + +#define MII_READ_COMMAND 0x00000001 + +#define MII_INTERRUPT_DISABLED 0x0 +#define MII_INTERRUPT_ENABLED 0x1 +/* Taken from mii_if_info and sungem_phy.h */ +struct gfar_mii_info { + /* Information about the PHY type */ + /* And management functions */ + struct phy_info *phyinfo; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + + /* The most recently read link state */ + int link; + + /* Enabled Interrupts */ + u32 interrupts; + + u32 advertising; + int autoneg; + int mii_id; + + /* private data pointer */ + /* For use by PHYs to maintain extra state */ + void *priv; + + /* Provided by host chip */ + struct net_device *dev; + + /* A lock to ensure that only one thing can read/write + * the MDIO bus at a time */ + spinlock_t mdio_lock; + + /* Provided by ethernet driver */ + int (*mdio_read) (struct net_device *dev, int mii_id, int reg); + void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); }; /* struct phy_info: a structure which defines attributes for a PHY @@ -165,38 +164,50 @@ struct phy_cmd { * id will contain a number which represents the PHY. During * startup, the driver will poll the PHY to find out what its * UID--as defined by registers 2 and 3--is. The 32-bit result - * gotten from the PHY will be shifted right by "shift" bits to + * gotten from the PHY will be ANDed with phy_id_mask to * discard any bits which may change based on revision numbers * unimportant to functionality * - * The struct phy_cmd entries represent pointers to an arrays of - * commands which tell the driver what to do to the PHY. + * There are 6 commands which take a gfar_mii_info structure. + * Each PHY must declare config_aneg, and read_status. */ struct phy_info { - u32 id; - char *name; - unsigned int shift; - /* Called to configure the PHY, and modify the controller - * based on the results */ - const struct phy_cmd *config; - - /* Called when starting up the controller. Usually sets - * up the interrupt for state changes */ - const struct phy_cmd *startup; - - /* Called inside the interrupt handler to acknowledge - * the interrupt */ - const struct phy_cmd *ack_int; - - /* Called in the bottom half to handle the interrupt */ - const struct phy_cmd *handle_int; - - /* Called when bringing down the controller. Usually stops - * the interrupts from being generated */ - const struct phy_cmd *shutdown; + u32 phy_id; + char *name; + unsigned int phy_id_mask; + u32 features; + + /* Called to initialize the PHY */ + int (*init)(struct gfar_mii_info *mii_info); + + /* Called to suspend the PHY for power */ + int (*suspend)(struct gfar_mii_info *mii_info); + + /* Reconfigures autonegotiation (or disables it) */ + int (*config_aneg)(struct gfar_mii_info *mii_info); + + /* Determines the negotiated speed and duplex */ + int (*read_status)(struct gfar_mii_info *mii_info); + + /* Clears any pending interrupts */ + int (*ack_interrupt)(struct gfar_mii_info *mii_info); + + /* Enables or disables interrupts */ + int (*config_intr)(struct gfar_mii_info *mii_info); + + /* Clears up any memory if needed */ + void (*close)(struct gfar_mii_info *mii_info); }; -struct phy_info *get_phy_info(struct net_device *dev); -void phy_run_commands(struct net_device *dev, const struct phy_cmd *cmd); +struct phy_info *get_phy_info(struct gfar_mii_info *mii_info); +int read_phy_reg(struct net_device *dev, int mii_id, int regnum); +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); +void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info); +void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts); + +struct dm9161_private { + struct timer_list timer; + int resetdone; +}; #endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h new file mode 100644 index 000000000..7e7af0d56 --- /dev/null +++ b/drivers/net/gt64240eth.h @@ -0,0 +1,402 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 Patton Electronics Company + * Copyright (C) 2002 Momentum Computer + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.com + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Ethernet driver definitions for the MIPS GT96100 Advanced + * Communication Controller. + * + * Modified for the Marvellous GT64240 Retarded Communication Controller. + */ +#ifndef _GT64240ETH_H +#define _GT64240ETH_H + +#include + +#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400 + +/* Translate those weanie names from Galileo/VxWorks header files: */ + +#define GT64240_MRR MAIN_ROUTING_REGISTER +#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER +#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL +#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER +#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER +#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW +#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH +#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER + +#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER +#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER +#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER +#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER +#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER +#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS +#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER +#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE +#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER +#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER +#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER +#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER +#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 +#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1 +#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 +#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 +#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER + +/* Turn on NAPI by default */ + +#define GT64240_NAPI 1 + +/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */ +/* (Board-specific to the DSL3224 Rev A board ONLY!) */ +#define D3224_MPP_CTRL0_SETTING 0x66669900 +#define D3224_MPP_CTRL1_SETTING 0x00000000 +#define D3224_MPP_CTRL2_SETTING 0x00887700 +#define D3224_MPP_CTRL3_SETTING 0x00000044 +#define D3224_GPP_IO_CTRL_SETTING 0x0000e800 +#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703 +#define D3224_GPP_VALUE_SETTING 0x00000000 + +/* Keep the ring sizes a power of two for efficiency. */ +//-#define TX_RING_SIZE 16 +#define TX_RING_SIZE 64 /* TESTING !!! */ +#define RX_RING_SIZE 32 +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + +#define RX_HASH_TABLE_SIZE 16384 +#define HASH_HOP_NUMBER 12 + +#define NUM_INTERFACES 3 + +#define GT64240ETH_TX_TIMEOUT HZ/4 + +#define MIPS_GT64240_BASE 0xf4000000 +#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG) +#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE) +#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE) + +#if defined(CONFIG_MIPS_DSL3224) +#define GT64240_ETHER0_IRQ 4 +#define GT64240_ETHER1_IRQ 4 +#else +#define GT64240_ETHER0_IRQ -1 +#define GT64240_ETHER1_IRQ -1 +#endif + +#define REV_GT64240 0x1 +#define REV_GT64240A 0x10 + +#define GT64240ETH_READ(gp, offset) \ + GT_READ((gp)->port_offset + (offset)) + +#define GT64240ETH_WRITE(gp, offset, data) \ + GT_WRITE((gp)->port_offset + (offset), (data)) + +#define GT64240ETH_SETBIT(gp, offset, bits) \ + GT64240ETH_WRITE((gp), (offset), \ + GT64240ETH_READ((gp), (offset)) | (bits)) + +#define GT64240ETH_CLRBIT(gp, offset, bits) \ + GT64240ETH_WRITE((gp), (offset), \ + GT64240ETH_READ((gp), (offset)) & ~(bits)) + +#define GT64240_READ(ofs) GT_READ(ofs) +#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data)) + +/* Bit definitions of the SMI Reg */ +enum { + smirDataMask = 0xffff, + smirPhyAdMask = 0x1f << 16, + smirPhyAdBit = 16, + smirRegAdMask = 0x1f << 21, + smirRegAdBit = 21, + smirOpCode = 1 << 26, + smirReadValid = 1 << 27, + smirBusy = 1 << 28 +}; + +/* Bit definitions of the Port Config Reg */ +enum pcr_bits { + pcrPM = 1 << 0, + pcrRBM = 1 << 1, + pcrPBF = 1 << 2, + pcrEN = 1 << 7, + pcrLPBKMask = 0x3 << 8, + pcrLPBKBit = 1 << 8, + pcrFC = 1 << 10, + pcrHS = 1 << 12, + pcrHM = 1 << 13, + pcrHDM = 1 << 14, + pcrHD = 1 << 15, + pcrISLMask = 0x7 << 28, + pcrISLBit = 28, + pcrACCS = 1 << 31 +}; + +/* Bit definitions of the Port Config Extend Reg */ +enum pcxr_bits { + pcxrIGMP = 1, + pcxrSPAN = 2, + pcxrPAR = 4, + pcxrPRIOtxMask = 0x7 << 3, + pcxrPRIOtxBit = 3, + pcxrPRIOrxMask = 0x3 << 6, + pcxrPRIOrxBit = 6, + pcxrPRIOrxOverride = 1 << 8, + pcxrDPLXen = 1 << 9, + pcxrFCTLen = 1 << 10, + pcxrFLP = 1 << 11, + pcxrFCTL = 1 << 12, + pcxrMFLMask = 0x3 << 14, + pcxrMFLBit = 14, + pcxrMIBclrMode = 1 << 16, + pcxrSpeed = 1 << 18, + pcxrSpeeden = 1 << 19, + pcxrRMIIen = 1 << 20, + pcxrDSCPen = 1 << 21 +}; + +/* Bit definitions of the Port Command Reg */ +enum pcmr_bits { + pcmrFJ = 1 << 15 +}; + + +/* Bit definitions of the Port Status Reg */ +enum psr_bits { + psrSpeed = 1, + psrDuplex = 2, + psrFctl = 4, + psrLink = 8, + psrPause = 1 << 4, + psrTxLow = 1 << 5, + psrTxHigh = 1 << 6, + psrTxInProg = 1 << 7 +}; + +/* Bit definitions of the SDMA Config Reg */ +enum sdcr_bits { + sdcrRCMask = 0xf << 2, + sdcrRCBit = 2, + sdcrBLMR = 1 << 6, + sdcrBLMT = 1 << 7, + sdcrPOVR = 1 << 8, + sdcrRIFB = 1 << 9, + sdcrBSZMask = 0x3 << 12, + sdcrBSZBit = 12 +}; + +/* Bit definitions of the SDMA Command Reg */ +enum sdcmr_bits { + sdcmrERD = 1 << 7, + sdcmrAR = 1 << 15, + sdcmrSTDH = 1 << 16, + sdcmrSTDL = 1 << 17, + sdcmrTXDH = 1 << 23, + sdcmrTXDL = 1 << 24, + sdcmrAT = 1 << 31 +}; + +/* Bit definitions of the Interrupt Cause Reg */ +enum icr_bits { + icrRxBuffer = 1, + icrTxBufferHigh = 1 << 2, + icrTxBufferLow = 1 << 3, + icrTxEndHigh = 1 << 6, + icrTxEndLow = 1 << 7, + icrRxError = 1 << 8, + icrTxErrorHigh = 1 << 10, + icrTxErrorLow = 1 << 11, + icrRxOVR = 1 << 12, + icrTxUdr = 1 << 13, + icrRxBufferQ0 = 1 << 16, + icrRxBufferQ1 = 1 << 17, + icrRxBufferQ2 = 1 << 18, + icrRxBufferQ3 = 1 << 19, + icrRxErrorQ0 = 1 << 20, + icrRxErrorQ1 = 1 << 21, + icrRxErrorQ2 = 1 << 22, + icrRxErrorQ3 = 1 << 23, + icrMIIPhySTC = 1 << 28, + icrSMIdone = 1 << 29, + icrEtherIntSum = 1 << 31 +}; + + +/* The Rx and Tx descriptor lists. */ +#ifdef __LITTLE_ENDIAN +typedef struct { + u32 cmdstat; + u16 reserved; //-prk21aug01 u32 reserved:16; + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u32 buff_ptr; + u32 next; +} gt64240_td_t; + +typedef struct { + u32 cmdstat; + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u16 buff_sz; //-prk21aug01 u32 buff_sz:16; + u32 buff_ptr; + u32 next; +} gt64240_rd_t; +#elif defined(__BIG_ENDIAN) +typedef struct { + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u16 reserved; //-prk21aug01 u32 reserved:16; + u32 cmdstat; + u32 next; + u32 buff_ptr; +} gt64240_td_t; + +typedef struct { + u16 buff_sz; //-prk21aug01 u32 buff_sz:16; + u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16; + u32 cmdstat; + u32 next; + u32 buff_ptr; +} gt64240_rd_t; +#else +#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined! +#endif + + +/* Values for the Tx command-status descriptor entry. */ +enum td_cmdstat { + txOwn = 1 << 31, + txAutoMode = 1 << 30, + txEI = 1 << 23, + txGenCRC = 1 << 22, + txPad = 1 << 18, + txFirst = 1 << 17, + txLast = 1 << 16, + txErrorSummary = 1 << 15, + txReTxCntMask = 0x0f << 10, + txReTxCntBit = 10, + txCollision = 1 << 9, + txReTxLimit = 1 << 8, + txUnderrun = 1 << 6, + txLateCollision = 1 << 5 +}; + + +/* Values for the Rx command-status descriptor entry. */ +enum rd_cmdstat { + rxOwn = 1 << 31, + rxAutoMode = 1 << 30, + rxEI = 1 << 23, + rxFirst = 1 << 17, + rxLast = 1 << 16, + rxErrorSummary = 1 << 15, + rxIGMP = 1 << 14, + rxHashExpired = 1 << 13, + rxMissedFrame = 1 << 12, + rxFrameType = 1 << 11, + rxShortFrame = 1 << 8, + rxMaxFrameLen = 1 << 7, + rxOverrun = 1 << 6, + rxCollision = 1 << 4, + rxCRCError = 1 +}; + +/* Bit fields of a Hash Table Entry */ +enum hash_table_entry { + hteValid = 1, + hteSkip = 2, + hteRD = 4 +}; + +// The MIB counters +typedef struct { + u32 byteReceived; + u32 byteSent; + u32 framesReceived; + u32 framesSent; + u32 totalByteReceived; + u32 totalFramesReceived; + u32 broadcastFramesReceived; + u32 multicastFramesReceived; + u32 cRCError; + u32 oversizeFrames; + u32 fragments; + u32 jabber; + u32 collision; + u32 lateCollision; + u32 frames64; + u32 frames65_127; + u32 frames128_255; + u32 frames256_511; + u32 frames512_1023; + u32 frames1024_MaxSize; + u32 macRxError; + u32 droppedFrames; + u32 outMulticastFrames; + u32 outBroadcastFrames; + u32 undersizeFrames; +} mib_counters_t; + + +struct gt64240_private { + gt64240_rd_t *rx_ring; + gt64240_td_t *tx_ring; + // The Rx and Tx rings must be 16-byte aligned + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + char *hash_table; + // The Hash Table must be 8-byte aligned + dma_addr_t hash_table_dma; + int hash_mode; + + // The Rx buffers must be 8-byte aligned + char *rx_buff; + dma_addr_t rx_buff_dma; + // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes + // of payload must be 8-byte aligned + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + int rx_next_out; /* The next free ring entry to receive */ + int tx_next_in; /* The next free ring entry to send */ + int tx_next_out; /* The last ring entry the ISR processed */ + int tx_count; /* current # of pkts waiting to be sent in Tx ring */ + int intr_work_done; /* number of Rx and Tx pkts processed in the isr */ + int tx_full; /* Tx ring is full */ + + mib_counters_t mib; + struct net_device_stats stats; + + int io_size; + int port_num; // 0 or 1 + u32 port_offset; + + int phy_addr; // PHY address + u32 last_psr; // last value of the port status register + + int options; /* User-settable misc. driver options. */ + int drv_flags; + spinlock_t lock; /* Serialise access to device */ + struct mii_if_info mii_if; + + u32 msg_enable; +}; + +#endif /* _GT64240ETH_H */ diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c index 0cbf1d143..a41ccc452 100644 --- a/drivers/net/gt96100eth.c +++ b/drivers/net/gt96100eth.c @@ -28,7 +28,6 @@ * gt96100_cleanup_module(), and other general code cleanups * . */ -#include #include #include #include @@ -66,10 +65,6 @@ static int gt96100_add_hash_entry(struct net_device *dev, static void read_mib_counters(struct gt96100_private *gp); static int read_MII(int phy_addr, u32 reg); static int write_MII(int phy_addr, u32 reg, u16 data); -#if 0 -static void dump_tx_ring(struct net_device *dev); -static void dump_rx_ring(struct net_device *dev); -#endif static int gt96100_init_module(void); static void gt96100_cleanup_module(void); static void dump_MII(int dbg_lvl, struct net_device *dev); @@ -84,7 +79,7 @@ static void abort(struct net_device *dev, u32 abort_bits); static void hard_stop(struct net_device *dev); static void enable_ether_irq(struct net_device *dev); static void disable_ether_irq(struct net_device *dev); -static int gt96100_probe1(int port_num); +static int gt96100_probe1(struct pci_dev *pci, int port_num); static void reset_tx(struct net_device *dev); static void reset_rx(struct net_device *dev); static int gt96100_check_tx_consistent(struct gt96100_private *gp); @@ -164,13 +159,11 @@ chip_name(int chip_rev) /* DMA memory allocation, derived from pci_alloc_consistent. */ -static void * -dmaalloc(size_t size, dma_addr_t *dma_handle) +static void * dmaalloc(size_t size, dma_addr_t *dma_handle) { void *ret; - ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, - get_order(size)); + ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(size)); if (ret != NULL) { dma_cache_inv((unsigned long)ret, size); @@ -184,17 +177,13 @@ dmaalloc(size_t size, dma_addr_t *dma_handle) return ret; } -static void -dmafree(size_t size, void *vaddr) +static void dmafree(size_t size, void *vaddr) { vaddr = (void*)KSEG0ADDR(vaddr); free_pages((unsigned long)vaddr, get_order(size)); } - - -static void -gt96100_delay(int ms) +static void gt96100_delay(int ms) { if (in_interrupt()) return; @@ -327,34 +316,6 @@ write_MII(int phy_addr, u32 reg, u16 data) return 0; } -#if 0 -// These routines work, just disabled to avoid compile warnings -static void -dump_tx_ring(struct net_device *dev) -{ - struct gt96100_private *gp = netdev_priv(dev); - int i; - - dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__, - gp->tx_next_out, gp->tx_next_in, gp->tx_count); - - for (i=0; irx_next_out); - - for (i=0; iirq < 0) { - printk(KERN_ERR "%s: irq unknown - probing not supported\n", __FUNCTION_); + printk(KERN_ERR "%s: irq unknown - probing not supported\n", + __FUNCTION__); return -ENODEV; } - pcibios_read_config_byte(0, 0, PCI_REVISION_ID, &chip_rev); + pci_read_config_byte(pci, PCI_REVISION_ID, &chip_rev); if (chip_rev >= REV_GT96100A_1) { phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); phy_addr = (phyAD >> (5*port_num)) & 0x1f; } else { /* - * not sure what's this about -- probably - * a gt bug + * not sure what's this about -- probably a gt bug */ phy_addr = port_num; phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); @@ -831,6 +784,7 @@ out1: free_netdev (dev); out: release_region(gtif->iobase, GT96100_ETH_IO_SIZE); + err("%s failed. Returns %d\n", __FUNCTION__, retval); return retval; } @@ -1102,6 +1056,7 @@ gt96100_close(struct net_device *dev) } free_irq(dev->irq, dev); + return 0; } @@ -1312,10 +1267,11 @@ gt96100_tx_complete(struct net_device *dev, u32 status) cmdstat, nextOut); if (cmdstat & (u32)txOwn) { - //dump_tx_ring(dev); - // DMA is not finished writing descriptor??? - // Leave and come back later to pick-up where - // we left off. + /* + * DMA is not finished writing descriptor??? + * Leave and come back later to pick-up where + * we left off. + */ break; } @@ -1342,7 +1298,8 @@ gt96100_tx_complete(struct net_device *dev, u32 status) gp->tx_full = 0; if (gp->last_psr & psrLink) { netif_wake_queue(dev); - dbg(2, "%s: Tx Ring was full, queue waked\n", __FUNCTION_); + dbg(2, "%s: Tx Ring was full, queue waked\n", + __FUNCTION__); } } @@ -1425,12 +1382,12 @@ gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((psr & psrLink) && !gp->tx_full && netif_queue_stopped(dev)) { - dbg(0, ": Link up, waking queue.\n", - __FUNCTION_); + dbg(0, "%s: Link up, waking queue.\n", + __FUNCTION__); netif_wake_queue(dev); } else if (!(psr & psrLink) && !netif_queue_stopped(dev)) { - dbg(0, "Link down, stopping queue.\n", + dbg(0, "%s: Link down, stopping queue.\n", __FUNCTION__); netif_stop_queue(dev); } @@ -1569,8 +1526,8 @@ static void gt96100_cleanup_module(void) for (i=0; idev != NULL) { - struct gt96100_private *gp = - (struct gt96100_private *)gtif->dev->priv; + struct gt96100_private *gp = (struct gt96100_private *) + netdev_priv(gtif->dev); unregister_netdev(gtif->dev); dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); @@ -1583,9 +1540,6 @@ static void gt96100_cleanup_module(void) } } - -#ifndef MODULE - static int __init gt96100_setup(char *options) { char *this_opt; @@ -1610,9 +1564,6 @@ static int __init gt96100_setup(char *options) __setup("gt96100eth=", gt96100_setup); -#endif /* !MODULE */ - - module_init(gt96100_init_module); module_exit(gt96100_cleanup_module); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index b5169e849..6b0cb2cab 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/bpqether.c b/drivers/net/hamradio/bpqether.c index 6b85ab3c9..803d5a137 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -193,7 +193,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty bpq = (struct bpqdev *)dev->priv; - eth = (struct ethhdr *)skb->mac.raw; + eth = eth_hdr(skb); if (!(bpq->acpt_addr[0] & 0x01) && memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 9f3dac7d2..4beb7ac2a 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/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index c7076aa0b..e2a28b562 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -602,8 +602,6 @@ static int ax25_open(struct tty_struct *tty) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); /* Restore default settings */ ax->dev->type = ARPHRD_AX25; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 78ae4b2ac..3c783a459 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2906,13 +2906,19 @@ static struct eisa_driver hp100_eisa_driver = { static int __devinit hp100_pci_probe (struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); - int ioaddr = pci_resource_start(pdev, 0); + struct net_device *dev; + int ioaddr; u_short pci_command; int err; - - if (!dev) - return -ENOMEM; + + if (pci_enable_device(pdev)) + return -ENODEV; + + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + err = -ENOMEM; + goto out0; + } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -2934,7 +2940,7 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev, pci_write_config_word(pdev, PCI_COMMAND, pci_command); } - + ioaddr = pci_resource_start(pdev, 0); err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); if (err) goto out1; @@ -2951,6 +2957,8 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev, release_region(dev->base_addr, HP100_REGION_SIZE); out1: free_netdev(dev); + out0: + pci_disable_device(pdev); return err; } @@ -2959,6 +2967,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/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h index 5310033ad..7436af605 100644 --- a/drivers/net/ibm_emac/ibm_emac.h +++ b/drivers/net/ibm_emac/ibm_emac.h @@ -228,6 +228,21 @@ typedef struct emac_regs { (desc & EMAC_BAD_RX_PACKET) #endif +/* SoC implementation specific EMAC register defaults */ +#if defined(CONFIG_440GP) +#define EMAC_RWMR_DEFAULT 0x80009000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0xf8640000 +#elif defined(CONFIG_440GX) +#define EMAC_RWMR_DEFAULT 0x1000a200 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 +#define EMAC_TMR1_DEFAULT 0xa00f0000 +#else +#define EMAC_RWMR_DEFAULT 0x0f002000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0x380f0000 +#endif /* CONFIG_440GP */ + /* Revision specific EMAC register defaults */ #ifdef CONFIG_IBM_EMAC4 #define EMAC_M1_DEFAULT (EMAC_M1_BASE | \ @@ -236,7 +251,7 @@ typedef struct emac_regs { #define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \ EMAC_RMR_RFAF_128_2048) #define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \ - EMAC_TMR0_TFAE_128_2048) + EMAC_TMR0_DEFAULT) #define EMAC_TRTR_DEFAULT EMAC_TRTR_1024 #else /* !CONFIG_IBM_EMAC4 */ #define EMAC_M1_DEFAULT EMAC_M1_BASE @@ -245,19 +260,4 @@ typedef struct emac_regs { #define EMAC_TRTR_DEFAULT EMAC_TRTR_1600 #endif /* CONFIG_IBM_EMAC4 */ -/* SoC implementation specific EMAC register defaults */ -#if defined(CONFIG_440GP) -#define EMAC_RWMR_DEFAULT 0x80009000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0xf8640000 -#elif defined(CONFIG_440GX) -#define EMAC_RWMR_DEFAULT 0x1000a200 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048 -#define EMAC_TMR1_DEFAULT 0x88810000 -#else -#define EMAC_RWMR_DEFAULT 0x0f002000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0x380f0000 -#endif /* CONFIG_440GP */ - #endif diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 2ca3de076..6b0328fbc 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -90,23 +90,24 @@ MODULE_PARM_DESC(skb_res, "Amount of data to reserve on skb buffs\n" #define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev)) -static unsigned int rgmii_enable[] = - { RGMII_RTBI, RGMII_RGMII, RGMII_TBI, RGMII_GMII }; +static unsigned int rgmii_enable[] = { + RGMII_RTBI, + RGMII_RGMII, + RGMII_TBI, + RGMII_GMII +}; -static unsigned int rgmii_speed_mask[] = { 0, - 0, +static unsigned int rgmii_speed_mask[] = { RGMII_MII2_SPDMASK, RGMII_MII3_SPDMASK }; -static unsigned int rgmii_speed100[] = { 0, - 0, +static unsigned int rgmii_speed100[] = { RGMII_MII2_100MB, RGMII_MII3_100MB }; -static unsigned int rgmii_speed1000[] = { 0, - 0, +static unsigned int rgmii_speed1000[] = { RGMII_MII2_1000MB, RGMII_MII3_1000MB }; @@ -122,11 +123,21 @@ static unsigned int zmii_enable[][4] = { ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)}, {ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)} }; -static unsigned int mdi_enable[] = - { ZMII_MDI0, ZMII_MDI1, ZMII_MDI2, ZMII_MDI3 }; + +static unsigned int mdi_enable[] = { + ZMII_MDI0, + ZMII_MDI1, + ZMII_MDI2, + ZMII_MDI3 +}; static unsigned int zmii_speed = 0x0; -static unsigned int zmii_speed100[] = { ZMII_MII0_100MB, ZMII_MII1_100MB }; +static unsigned int zmii_speed100[] = { + ZMII_MII0_100MB, + ZMII_MII1_100MB, + ZMII_MII2_100MB, + ZMII_MII3_100MB +}; /* Since multiple EMACs share MDIO lines in various ways, we need * to avoid re-using the same PHY ID in cases where the arch didn't @@ -367,6 +378,7 @@ static void emac_close_zmii(struct ocp_device *ocpdev) int emac_phy_read(struct net_device *dev, int mii_id, int reg) { + int count; uint32_t stacr; struct ocp_enet_private *fep = dev->priv; emac_t *emacp = fep->emacp; @@ -385,9 +397,13 @@ int emac_phy_read(struct net_device *dev, int mii_id, int reg) emacp = fep->emacp; } - udelay(MDIO_DELAY); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); - if ((in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) { + if ((stacr & EMAC_STACR_OC) == 0) { printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name); return -1; } @@ -398,8 +414,11 @@ int emac_phy_read(struct net_device *dev, int mii_id, int reg) out_be32(&emacp->em0stacr, stacr); - udelay(MDIO_DELAY); - stacr = in_be32(&emacp->em0stacr); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); if ((stacr & EMAC_STACR_OC) == 0) { printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name); @@ -419,6 +438,7 @@ int emac_phy_read(struct net_device *dev, int mii_id, int reg) void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) { + int count; uint32_t stacr; struct ocp_enet_private *fep = dev->priv; emac_t *emacp = fep->emacp; @@ -437,9 +457,13 @@ void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) emacp = fep->emacp; } - udelay(MDIO_DELAY); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); - if ((in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) { + if ((stacr & EMAC_STACR_OC) == 0) { printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); return; } @@ -451,9 +475,12 @@ void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) out_be32(&emacp->em0stacr, stacr); - udelay(MDIO_DELAY); + while (((stacr = in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) + && (count++ < 5000)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); - if ((in_be32(&emacp->em0stacr) & EMAC_STACR_OC) == 0) + if ((stacr & EMAC_STACR_OC) == 0) printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); /* Check for a write error */ @@ -1940,8 +1967,6 @@ static struct ocp_driver emac_driver = { static int __init emac_init(void) { - int rc; - printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n"); printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n"); @@ -1950,13 +1975,8 @@ static int __init emac_init(void) skb_res); skb_res = 2; } - rc = ocp_register_driver(&emac_driver); - if (rc < 0) { - ocp_unregister_driver(&emac_driver); - return -ENODEV; - } - return 0; + return ocp_register_driver(&emac_driver); } static void __exit emac_exit(void) diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h index 691ce4e5c..97e6e1ea8 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -67,7 +67,7 @@ #define TX_TIMEOUT (2*HZ) /* MDIO latency delay */ -#define MDIO_DELAY 50 +#define MDIO_DELAY 250 /* Power managment shift registers */ #define IBM_CPM_EMMII 0 /* Shift value for MII */ diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index 02d847cfa..6597791a7 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -55,8 +55,6 @@ int mal_register_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) write_unlock_irqrestore(&mal_list_lock, flags); - MOD_INC_USE_COUNT; - return 0; } @@ -73,8 +71,6 @@ int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) write_unlock_irqrestore(&mal_list_lock, flags); - MOD_DEC_USE_COUNT; - return 0; } diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5fa162f6c..be0729dfb 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -2,8 +2,8 @@ /* */ /* IBM eServer i/pSeries Virtual Ethernet Device Driver */ /* Copyright (C) 2003 IBM Corp. */ -/* Dave Larson (larson1@us.ibm.com) */ -/* Santiago Leon (santil@us.ibm.com) */ +/* Originally written by Dave Larson (larson1@us.ibm.com) */ +/* Maintained by Santiago Leon (santil@us.ibm.com) */ /* */ /* 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 */ @@ -104,11 +104,12 @@ static struct proc_dir_entry *ibmveth_proc_dir; static const char ibmveth_driver_name[] = "ibmveth"; static const char ibmveth_driver_string[] = "IBM i/pSeries Virtual Ethernet Driver"; -static const char ibmveth_driver_version[] = "1.0"; +#define ibmveth_driver_version "1.02" -MODULE_AUTHOR("Dave Larson "); +MODULE_AUTHOR("Santiago Leon "); MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ibmveth_driver_version); /* simple methods of getting data from the current rxq entry */ static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter) @@ -213,11 +214,12 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc free_index = pool->consumer_index++ % pool->size; index = pool->free_map[free_index]; - ibmveth_assert(index != 0xffff); + ibmveth_assert(index != IBM_VETH_INVALID_MAP); ibmveth_assert(pool->skbuff[index] == NULL); dma_addr = vio_map_single(adapter->vdev, skb->data, pool->buff_size, DMA_FROM_DEVICE); + pool->free_map[free_index] = IBM_VETH_INVALID_MAP; pool->dma_addr[index] = dma_addr; pool->skbuff[index] = skb; @@ -232,6 +234,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); if(lpar_rc != H_Success) { + pool->free_map[free_index] = IBM_VETH_INVALID_MAP; pool->skbuff[index] = NULL; pool->consumer_index--; vio_unmap_single(adapter->vdev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -239,7 +242,6 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc adapter->replenish_add_buff_failure++; break; } else { - pool->free_map[free_index] = 0xffff; buffers_added++; adapter->replenish_add_buff_success++; } @@ -269,7 +271,6 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); atomic_inc(&adapter->not_replenishing); - ibmveth_assert(atomic_read(&adapter->not_replenishing) == 1); } /* kick the replenish tasklet if we need replenishing and it isn't already running */ @@ -528,7 +529,7 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); do { rc = h_free_logical_lan(adapter->vdev->unit_address); - } while H_isLongBusy(rc); + } while (H_isLongBusy(rc) || (rc == H_Busy)); ibmveth_cleanup(adapter); return rc; @@ -560,7 +561,7 @@ static int ibmveth_close(struct net_device *netdev) do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); - } while H_isLongBusy(lpar_rc); + } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); if(lpar_rc != H_Success) { @@ -732,6 +733,8 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) if(ibmveth_rxq_pending_buffer(adapter)) { struct sk_buff *skb; + rmb(); + if(!ibmveth_rxq_buffer_valid(adapter)) { wmb(); /* suggested by larson1 */ adapter->rx_invalid_buffer++; @@ -882,13 +885,16 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0); if(!mac_addr_p) { - ibmveth_error_printk("Can't find VETH_MAC_ADDR attribute\n"); + printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR " + "attribute\n", __FILE__, __LINE__); return 0; } mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0); if(!mcastFilterSize_p) { - ibmveth_error_printk("Can't find VETH_MCAST_FILTER_SIZE attribute\n"); + printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find " + "VETH_MCAST_FILTER_SIZE attribute\n", + __FILE__, __LINE__); return 0; } diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 599d15b2f..51a470da9 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -77,6 +77,8 @@ #define IbmVethPool1DftCnt 256 #define IbmVethPool2DftCnt 256 +#define IBM_VETH_INVALID_MAP ((u16)0xffff) + struct ibmveth_buff_pool { u32 size; u32 index; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index a93cda669..e16f8b20a 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -506,7 +506,7 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev) static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) { - struct ethhdr *eh = skb->mac.ethernet; + struct ethhdr *eh = eth_hdr(skb); uint32_t csum, ehsum; unsigned int proto; struct iphdr *ih; @@ -1333,7 +1333,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) uint32_t csum, ehsum; uint16_t *eh; - /* The MAC header. skb->mac.ethernet seem the logic approach + /* The MAC header. skb->mac seem the logic approach to find the MAC header - except it's a NULL pointer ... */ eh = (uint16_t *) skb->data; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6ae10e514..62f985389 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -268,7 +268,6 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) speed_bulk_callback, self); urb->transfer_buffer_length = USB_IRDA_HEADER; urb->transfer_flags = URB_ASYNC_UNLINK; - urb->timeout = msecs_to_jiffies(100); /* Irq disabled -> GFP_ATOMIC */ if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { @@ -411,8 +410,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) * after each of our packets that is exact multiple of the frame size. * This is how the dongle will detect the end of packet - Jean II */ urb->transfer_flags |= URB_ZERO_PACKET; - /* Timeout need to be shorter than NET watchdog timer */ - urb->timeout = msecs_to_jiffies(200); /* Generate min turn time. FIXME: can we do better than this? */ /* Trying to a turnaround time at this level is trying to measure diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index b67441d0a..13b6e627a 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -509,13 +509,6 @@ static int irtty_open(struct tty_struct *tty) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); -/* from old irtty - but what is it good for? - * we _are_ the ldisc and we _don't_ implement flush_buffer! - * - * if (tty->ldisc.flush_buffer) - * tty->ldisc.flush_buffer(tty); - */ - /* apply mtt override */ sir_tty_drv.qos_mtt_bits = qos_mtt_bits; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index f28ab3346..26af3785d 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 @@ -1729,6 +1729,39 @@ static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter) return cleaned; } +/** + * 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 @@ -1955,39 +1988,6 @@ static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return 0; } -/** - * 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. * diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 4957de6d8..b315acb14 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1426,8 +1426,6 @@ static int i596_close(struct net_device *dev) free_irq(dev->irq, dev); remove_rx_bufs(dev); - MOD_DEC_USE_COUNT; - return 0; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 8ffa894c3..4bca692d6 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include /* For the statistics structure. */ @@ -183,6 +184,17 @@ static struct net_device_stats *get_stats(struct net_device *dev) return stats; } +u32 loopback_get_link(struct net_device *dev) +{ + return 1; +} + +static struct ethtool_ops loopback_ethtool_ops = { + .get_link = loopback_get_link, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, +}; + struct net_device loopback_dev = { .name = "lo", .mtu = (16 * 1024) + 20 + 20 + 12, @@ -199,6 +211,7 @@ struct net_device loopback_dev = { .features = NETIF_F_SG|NETIF_F_FRAGLIST |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA |NETIF_F_LLTX, + .ethtool_ops = &loopback_ethtool_ops, }; /* Setup and register the of the LOOPBACK device. */ diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c new file mode 100644 index 000000000..41d38b3b3 --- /dev/null +++ b/drivers/net/mv643xx_eth.c @@ -0,0 +1,2646 @@ +/* + * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports + * Copyright (C) 2002 Matthew Dharm + * + * Based on the 64360 driver from: + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * Copyright (C) 2003 PMC-Sierra, Inc., + * written by Manish Lachwani (lachwani@pmc-sierra.com) + * + * Copyright (C) 2003 Ralf Baechle + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "mv643xx_eth.h" + +/* + * The first part is the high level driver of the gigE ethernet ports. + */ + +/* Definition for configuring driver */ +#undef MV64340_RX_QUEUE_FILL_ON_TASK + +/* Constants */ +#define EXTRA_BYTES 32 +#define WRAP ETH_HLEN + 2 + 4 + 16 +#define BUFFER_MTU dev->mtu + WRAP +#define INT_CAUSE_UNMASK_ALL 0x0007ffff +#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff +#ifdef MV64340_RX_FILL_ON_TASK +#define INT_CAUSE_MASK_ALL 0x00000000 +#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL +#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT +#endif + +/* Static function declarations */ +static int mv64340_eth_real_open(struct net_device *); +static int mv64340_eth_real_stop(struct net_device *); +static int mv64340_eth_change_mtu(struct net_device *, int); +static struct net_device_stats *mv64340_eth_get_stats(struct net_device *); +static void eth_port_init_mac_tables(unsigned int eth_port_num); +#ifdef MV64340_NAPI +static int mv64340_poll(struct net_device *dev, int *budget); +#endif + +unsigned char prom_mac_addr_base[6]; +unsigned long mv64340_sram_base; + +/* + * Changes MTU (maximum transfer unit) of the gigabit ethenret port + * + * Input : pointer to ethernet interface network device structure + * new mtu size + * Output : 0 upon success, -EINVAL upon failure + */ +static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); + + if ((new_mtu > 9500) || (new_mtu < 64)) { + spin_unlock_irqrestore(&mp->lock, flags); + return -EINVAL; + } + + dev->mtu = new_mtu; + /* + * Stop then re-open the interface. This will allocate RX skb's with + * the new MTU. + * There is a possible danger that the open will not successed, due + * to memory is full, which might fail the open function. + */ + if (netif_running(dev)) { + if (mv64340_eth_real_stop(dev)) + printk(KERN_ERR + "%s: Fatal error on stopping device\n", + dev->name); + if (mv64340_eth_real_open(dev)) + printk(KERN_ERR + "%s: Fatal error on opening device\n", + dev->name); + } + + spin_unlock_irqrestore(&mp->lock, flags); + return 0; +} + +/* + * mv64340_eth_rx_task + * + * Fills / refills RX queue on a certain gigabit ethernet port + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_rx_task(void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct mv64340_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; + struct sk_buff *skb; + + if (test_and_set_bit(0, &mp->rx_task_busy)) + panic("%s: Error in test_set_bit / clear_bit", dev->name); + + while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) { + /* The +8 for buffer allignment and another 32 byte extra */ + + skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES); + if (!skb) + /* Better luck next time */ + break; + mp->rx_ring_skbs++; + pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; + pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES; + /* Allign buffer to 8 bytes */ + if (pkt_info.byte_cnt & ~0x7) { + pkt_info.byte_cnt &= ~0x7; + pkt_info.byte_cnt += 8; + } + pkt_info.buf_ptr = + pci_map_single(0, skb->data, + dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES, + PCI_DMA_FROMDEVICE); + pkt_info.return_info = skb; + if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { + printk(KERN_ERR + "%s: Error allocating RX Ring\n", dev->name); + break; + } + skb_reserve(skb, 2); + } + clear_bit(0, &mp->rx_task_busy); + /* + * If RX ring is empty of SKB, set a timer to try allocating + * again in a later time . + */ + if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) { + printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); + /* After 100mSec */ + mp->timeout.expires = jiffies + (HZ / 10); + add_timer(&mp->timeout); + mp->rx_timer_flag = 1; + } +#if MV64340_RX_QUEUE_FILL_ON_TASK + else { + /* Return interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num), + INT_CAUSE_UNMASK_ALL); + } +#endif +} + +/* + * mv64340_eth_rx_task_timer_wrapper + * + * Timer routine to wake up RX queue filling task. This function is + * used only in case the RX queue is empty, and all alloc_skb has + * failed (due to out of memory event). + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_rx_task_timer_wrapper(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct mv64340_private *mp = netdev_priv(dev); + + mp->rx_timer_flag = 0; + mv64340_eth_rx_task((void *) data); +} + + +/* + * mv64340_eth_update_mac_address + * + * Update the MAC address of the port in the address table + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_update_mac_address(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + + eth_port_init_mac_tables(port_num); + memcpy(mp->port_mac_addr, dev->dev_addr, 6); + eth_port_uc_addr_set(port_num, mp->port_mac_addr); +} + +/* + * mv64340_eth_set_rx_mode + * + * Change from promiscuos to regular rx mode + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_set_rx_mode(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + if (dev->flags & IFF_PROMISC) { + ethernet_set_config_reg + (mp->port_num, + ethernet_get_config_reg(mp->port_num) | + ETH_UNICAST_PROMISCUOUS_MODE); + } else { + ethernet_set_config_reg + (mp->port_num, + ethernet_get_config_reg(mp->port_num) & + ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE); + } +} + + +/* + * mv64340_eth_set_mac_address + * + * Change the interface's mac address. + * No special hardware thing should be done because interface is always + * put in promiscuous mode. + * + * Input : pointer to ethernet interface network device structure and + * a pointer to the designated entry to be added to the cache. + * Output : zero upon success, negative upon failure + */ +static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr) +{ + int i; + + for (i = 0; i < 6; i++) + /* +2 is for the offset of the HW addr type */ + dev->dev_addr[i] = ((unsigned char *) addr)[i + 2]; + mv64340_eth_update_mac_address(dev); + return 0; +} + +/* + * mv64340_eth_tx_timeout + * + * Called upon a timeout on transmitting a packet + * + * Input : pointer to ethernet interface network device structure. + * Output : N/A + */ +static void mv64340_eth_tx_timeout(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + printk(KERN_INFO "%s: TX timeout ", dev->name); + + /* Do the reset outside of interrupt context */ + schedule_work(&mp->tx_timeout_task); +} + +/* + * mv64340_eth_tx_timeout_task + * + * Actual routine to reset the adapter when a timeout on Tx has occurred + */ +static void mv64340_eth_tx_timeout_task(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + netif_device_detach(dev); + eth_port_reset(mp->port_num); + eth_port_start(mp); + netif_device_attach(dev); +} + +/* + * mv64340_eth_free_tx_queue + * + * Input : dev - a pointer to the required interface + * + * Output : 0 if was able to release skb , nonzero otherwise + */ +static int mv64340_eth_free_tx_queue(struct net_device *dev, + unsigned int eth_int_cause_ext) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + struct pkt_info pkt_info; + int released = 1; + + if (!(eth_int_cause_ext & (BIT0 | BIT8))) + return released; + + spin_lock(&mp->lock); + + /* Check only queue 0 */ + while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { + if (pkt_info.cmd_sts & BIT0) { + printk("%s: Error in TX\n", dev->name); + stats->tx_errors++; + } + + /* + * If return_info is different than 0, release the skb. + * The case where return_info is not 0 is only in case + * when transmitted a scatter/gather packet, where only + * last skb releases the whole chain. + */ + if (pkt_info.return_info) { + dev_kfree_skb_irq((struct sk_buff *) + pkt_info.return_info); + released = 0; + if (skb_shinfo(pkt_info.return_info)->nr_frags) + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, PCI_DMA_TODEVICE); + + if (mp->tx_ring_skbs != 1) + mp->tx_ring_skbs--; + } else + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, PCI_DMA_TODEVICE); + + /* + * Decrement the number of outstanding skbs counter on + * the TX queue. + */ + if (mp->tx_ring_skbs == 0) + panic("ERROR - TX outstanding SKBs counter is corrupted"); + + } + + spin_unlock(&mp->lock); + + return released; +} + +/* + * mv64340_eth_receive + * + * This function is forward packets that are received from the port's + * queues toward kernel core or FastRoute them to another interface. + * + * Input : dev - a pointer to the required interface + * max - maximum number to receive (0 means unlimted) + * + * Output : number of served packets + */ +#ifdef MV64340_NAPI +static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max, + int budget) +#else +static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max) +#endif +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + unsigned int received_packets = 0; + struct sk_buff *skb; + struct pkt_info pkt_info; + +#ifdef MV64340_NAPI + while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) { +#else + while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) { +#endif + mp->rx_ring_skbs--; + received_packets++; +#ifdef MV64340_NAPI + budget--; +#endif + /* Update statistics. Note byte count includes 4 byte CRC count */ + stats->rx_packets++; + stats->rx_bytes += pkt_info.byte_cnt; + skb = (struct sk_buff *) pkt_info.return_info; + /* + * In case received a packet without first / last bits on OR + * the error summary bit is on, the packets needs to be dropeed. + */ + if (((pkt_info.cmd_sts + & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) + || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { + stats->rx_dropped++; + if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC | + ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) { + if (net_ratelimit()) + printk(KERN_ERR + "%s: Received packet spread on multiple" + " descriptors\n", + dev->name); + } + if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY) + stats->rx_errors++; + + dev_kfree_skb_irq(skb); + } else { + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, pkt_info.byte_cnt - 4); + skb->dev = dev; + + if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->csum = htons((pkt_info.cmd_sts + & 0x0007fff8) >> 3); + } + skb->protocol = eth_type_trans(skb, dev); +#ifdef MV64340_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + + return received_packets; +} + +/* + * mv64340_eth_int_handler + * + * Main interrupt handler for the gigbit ethernet ports + * + * Input : irq - irq number (not used) + * dev_id - a pointer to the required interface's data structure + * regs - not used + * Output : N/A + */ + +static irqreturn_t mv64340_eth_int_handler(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mv64340_private *mp = netdev_priv(dev); + u32 eth_int_cause, eth_int_cause_ext = 0; + unsigned int port_num = mp->port_num; + + /* Read interrupt cause registers */ + eth_int_cause = MV_READ(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) & + INT_CAUSE_UNMASK_ALL; + + if (eth_int_cause & BIT1) + eth_int_cause_ext = + MV_READ(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & + INT_CAUSE_UNMASK_ALL_EXT; + +#ifdef MV64340_NAPI + if (!(eth_int_cause & 0x0007fffd)) { + /* Dont ack the Rx interrupt */ +#endif + /* + * Clear specific ethernet port intrerrupt registers by + * acknowleding relevant bits. + */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), + ~eth_int_cause); + if (eth_int_cause_ext != 0x0) + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), + ~eth_int_cause_ext); + + /* UDP change : We may need this */ + if ((eth_int_cause_ext & 0x0000ffff) && + (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && + (MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1)) + netif_wake_queue(dev); +#ifdef MV64340_NAPI + } else { + if (netif_rx_schedule_prep(dev)) { + /* Mask all the interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + __netif_rx_schedule(dev); + } +#else + { + if (eth_int_cause & (BIT2 | BIT11)) + mv64340_eth_receive_queue(dev, 0); + + /* + * After forwarded received packets to upper layer, add a task + * in an interrupts enabled context that refills the RX ring + * with skb's. + */ +#if MV64340_RX_QUEUE_FILL_ON_TASK + /* Unmask all interrupts on ethernet port */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_MASK_ALL); + queue_task(&mp->rx_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + mp->rx_task.func(dev); +#endif +#endif + } + /* PHY status changed */ + if (eth_int_cause_ext & (BIT16 | BIT20)) { + unsigned int phy_reg_data; + + /* Check Link status on ethernet port */ + eth_port_read_smi_reg(port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) { + netif_stop_queue(dev); + } else { + netif_wake_queue(dev); + + /* + * Start all TX queues on ethernet port. This is good in + * case of previous packets where not transmitted, due + * to link down and this command re-enables all TX + * queues. + * Note that it is possible to get a TX resource error + * interrupt after issuing this, since not all TX queues + * are enabled, or has anything to send. + */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1); + } + } + + /* + * If no real interrupt occured, exit. + * This can happen when using gigE interrupt coalescing mechanism. + */ + if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0)) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +#ifdef MV64340_COAL + +/* + * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path + * + * DESCRIPTION: + * This routine sets the RX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the tClk of the MV-643xx chip + * , and the required delay of the interrupt in usec. + * + * INPUT: + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in usec + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + */ +static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num, + unsigned int t_clk, unsigned int delay) +{ + unsigned int coal = ((t_clk / 1000000) * delay) / 64; + + /* Set RX Coalescing mechanism */ + MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), + ((coal & 0x3fff) << 8) | + (MV_READ(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num)) + & 0xffc000ff)); + + return coal; +} +#endif + +/* + * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path + * + * DESCRIPTION: + * This routine sets the TX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the t_cLK frequency of the + * MV-643xx chip and the required delay in the interrupt in uSec + * + * INPUT: + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in uSeconds + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + */ +static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num, + unsigned int t_clk, unsigned int delay) +{ + unsigned int coal; + coal = ((t_clk / 1000000) * delay) / 64; + /* Set TX Coalescing mechanism */ + MV_WRITE(MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num), + coal << 4); + return coal; +} + +/* + * mv64340_eth_open + * + * This function is called when openning the network device. The function + * should initialize all the hardware, initialize cyclic Rx/Tx + * descriptors chain and buffers and allocate an IRQ to the network + * device. + * + * Input : a pointer to the network device structure + * + * Output : zero of success , nonzero if fails. + */ + +static int mv64340_eth_open(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + int err = err; + + spin_lock_irq(&mp->lock); + + err = request_irq(dev->irq, mv64340_eth_int_handler, + SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev); + + if (err) { + printk(KERN_ERR "Can not assign IRQ number to MV64340_eth%d\n", + port_num); + err = -EAGAIN; + goto out; + } + + if (mv64340_eth_real_open(dev)) { + printk("%s: Error opening interface\n", dev->name); + err = -EBUSY; + goto out_free; + } + + spin_unlock_irq(&mp->lock); + + return 0; + +out_free: + free_irq(dev->irq, dev); + +out: + spin_unlock_irq(&mp->lock); + + return err; +} + +/* + * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Rx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * int rx_desc_num Number of Rx descriptors + * int rx_buff_size Size of Rx buffer + * unsigned int rx_desc_base_addr Rx descriptors memory area base addr. + * unsigned int rx_buff_base_addr Rx buffer memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Rx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + */ +static int ether_init_rx_desc_ring(struct mv64340_private * mp, + unsigned long rx_buff_base_addr) +{ + unsigned long buffer_addr = rx_buff_base_addr; + volatile struct eth_rx_desc *p_rx_desc; + int rx_desc_num = mp->rx_ring_size; + unsigned long rx_desc_base_addr = (unsigned long) mp->p_rx_desc_area; + int rx_buff_size = 1536; /* Dummy, will be replaced later */ + int i; + + p_rx_desc = (struct eth_rx_desc *) rx_desc_base_addr; + + /* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (rx_buff_base_addr & 0xf) + return 0; + + /* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes */ + if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE)) + return 0; + + /* Rx buffers must be 64-bit aligned. */ + if ((rx_buff_base_addr + rx_buff_size) & 0x7) + return 0; + + /* initialize the Rx descriptors ring */ + for (i = 0; i < rx_desc_num; i++) { + p_rx_desc[i].buf_size = rx_buff_size; + p_rx_desc[i].byte_cnt = 0x0000; + p_rx_desc[i].cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + p_rx_desc[i].next_desc_ptr = mp->rx_desc_dma + + ((i + 1) % rx_desc_num) * sizeof(struct eth_rx_desc); + p_rx_desc[i].buf_ptr = buffer_addr; + + mp->rx_skb[i] = NULL; + buffer_addr += rx_buff_size; + } + + /* Save Rx desc pointer to driver struct. */ + mp->rx_curr_desc_q = 0; + mp->rx_used_desc_q = 0; + + mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); + + mp->port_rx_queue_command |= 1; + + return 1; +} + +/* + * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Tx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * int tx_desc_num Number of Tx descriptors + * int tx_buff_size Size of Tx buffer + * unsigned int tx_desc_base_addr Tx descriptors memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Tx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + */ +static int ether_init_tx_desc_ring(struct mv64340_private *mp) +{ + unsigned long tx_desc_base_addr = (unsigned long) mp->p_tx_desc_area; + int tx_desc_num = mp->tx_ring_size; + struct eth_tx_desc *p_tx_desc; + int i; + + /* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (tx_desc_base_addr & 0xf) + return 0; + + /* save the first desc pointer to link with the last descriptor */ + p_tx_desc = (struct eth_tx_desc *) tx_desc_base_addr; + + /* Initialize the Tx descriptors ring */ + for (i = 0; i < tx_desc_num; i++) { + p_tx_desc[i].byte_cnt = 0x0000; + p_tx_desc[i].l4i_chk = 0x0000; + p_tx_desc[i].cmd_sts = 0x00000000; + p_tx_desc[i].next_desc_ptr = mp->tx_desc_dma + + ((i + 1) % tx_desc_num) * sizeof(struct eth_tx_desc); + p_tx_desc[i].buf_ptr = 0x00000000; + mp->tx_skb[i] = NULL; + } + + /* Set Tx desc pointer in driver struct. */ + mp->tx_curr_desc_q = 0; + mp->tx_used_desc_q = 0; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + mp->tx_first_desc_q = 0; +#endif + /* Init Tx ring base and size parameters */ + mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); + + /* Add the queue to the list of Tx queues of this port */ + mp->port_tx_queue_command |= 1; + + return 1; +} + +/* Helper function for mv64340_eth_open */ +static int mv64340_eth_real_open(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + u32 phy_reg_data; + unsigned int size; + + /* Stop RX Queues */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Clear the ethernet port interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + + /* Unmask RX buffer and TX end interrupt */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + + /* Unmask phy and link status changes interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + + /* Set the MAC Address */ + memcpy(mp->port_mac_addr, dev->dev_addr, 6); + + eth_port_init(mp); + + INIT_WORK(&mp->rx_task, (void (*)(void *)) mv64340_eth_rx_task, dev); + + memset(&mp->timeout, 0, sizeof(struct timer_list)); + mp->timeout.function = mv64340_eth_rx_task_timer_wrapper; + mp->timeout.data = (unsigned long) dev; + + mp->rx_task_busy = 0; + mp->rx_timer_flag = 0; + + /* Allocate TX ring */ + mp->tx_ring_skbs = 0; + mp->tx_ring_size = MV64340_TX_QUEUE_SIZE; + size = mp->tx_ring_size * sizeof(struct eth_tx_desc); + mp->tx_desc_area_size = size; + + /* Assumes allocated ring is 16 bytes alligned */ + mp->p_tx_desc_area = pci_alloc_consistent(NULL, size, &mp->tx_desc_dma); + if (!mp->p_tx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", + dev->name, size); + return -ENOMEM; + } + memset((void *) mp->p_tx_desc_area, 0, mp->tx_desc_area_size); + + /* Dummy will be replaced upon real tx */ + ether_init_tx_desc_ring(mp); + + /* Allocate RX ring */ + /* Meantime RX Ring are fixed - but must be configurable by user */ + mp->rx_ring_size = MV64340_RX_QUEUE_SIZE; + mp->rx_ring_skbs = 0; + size = mp->rx_ring_size * sizeof(struct eth_rx_desc); + mp->rx_desc_area_size = size; + + /* Assumes allocated ring is 16 bytes aligned */ + + mp->p_rx_desc_area = pci_alloc_consistent(NULL, size, &mp->rx_desc_dma); + + if (!mp->p_rx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n", + dev->name, size); + printk(KERN_ERR "%s: Freeing previously allocated TX queues...", + dev->name); + pci_free_consistent(0, mp->tx_desc_area_size, + (void *) mp->p_tx_desc_area, + mp->tx_desc_dma); + return -ENOMEM; + } + memset(mp->p_rx_desc_area, 0, size); + + if (!(ether_init_rx_desc_ring(mp, 0))) + panic("%s: Error initializing RX Ring", dev->name); + + mv64340_eth_rx_task(dev); /* Fill RX ring with skb's */ + + eth_port_start(mp); + + /* Interrupt Coalescing */ + +#ifdef MV64340_COAL + mp->rx_int_coal = + eth_port_set_rx_coal(port_num, 133000000, MV64340_RX_COAL); +#endif + + mp->tx_int_coal = + eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL); + + /* Increase the Rx side buffer size */ + + MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) | + (MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num)) + & 0xfff1ffff)); + + /* Check Link status on phy */ + eth_port_read_smi_reg(port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) + netif_stop_queue(dev); + else + netif_start_queue(dev); + + return 0; +} + +static void mv64340_eth_free_tx_rings(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + unsigned int curr; + + /* Stop Tx Queues */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Free TX rings */ + /* Free outstanding skb's on TX rings */ + for (curr = 0; + (mp->tx_ring_skbs) && (curr < MV64340_TX_QUEUE_SIZE); + curr++) { + if (mp->tx_skb[curr]) { + dev_kfree_skb(mp->tx_skb[curr]); + mp->tx_ring_skbs--; + } + } + if (mp->tx_ring_skbs != 0) + printk("%s: Error on Tx descriptor free - could not free %d" + " descriptors\n", dev->name, + mp->tx_ring_skbs); + pci_free_consistent(0, mp->tx_desc_area_size, + (void *) mp->p_tx_desc_area, mp->tx_desc_dma); +} + +static void mv64340_eth_free_rx_rings(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + int curr; + + /* Stop RX Queues */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Free RX rings */ + /* Free preallocated skb's on RX rings */ + for (curr = 0; + mp->rx_ring_skbs && (curr < MV64340_RX_QUEUE_SIZE); + curr++) { + if (mp->rx_skb[curr]) { + dev_kfree_skb(mp->rx_skb[curr]); + mp->rx_ring_skbs--; + } + } + + if (mp->rx_ring_skbs != 0) + printk(KERN_ERR + "%s: Error in freeing Rx Ring. %d skb's still" + " stuck in RX Ring - ignoring them\n", dev->name, + mp->rx_ring_skbs); + pci_free_consistent(0, mp->rx_desc_area_size, + (void *) mp->p_rx_desc_area, + mp->rx_desc_dma); +} + +/* + * mv64340_eth_stop + * + * This function is used when closing the network device. + * It updates the hardware, + * release all memory that holds buffers and descriptors and release the IRQ. + * Input : a pointer to the device structure + * Output : zero if success , nonzero if fails + */ + +/* Helper function for mv64340_eth_stop */ + +static int mv64340_eth_real_stop(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + + netif_stop_queue(dev); + + mv64340_eth_free_tx_rings(dev); + mv64340_eth_free_rx_rings(dev); + + eth_port_reset(mp->port_num); + + /* Disable ethernet port interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + + /* Mask RX buffer and TX end interrupt */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 0); + + /* Mask phy and link status changes interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + + return 0; +} + +static int mv64340_eth_stop(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + spin_lock_irq(&mp->lock); + + mv64340_eth_real_stop(dev); + + free_irq(dev->irq, dev); + spin_unlock_irq(&mp->lock); + + return 0; +} + +#ifdef MV64340_NAPI +static void mv64340_tx(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; + + while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { + if (pkt_info.return_info) { + dev_kfree_skb_irq((struct sk_buff *) + pkt_info.return_info); + if (skb_shinfo(pkt_info.return_info)->nr_frags) + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + PCI_DMA_TODEVICE); + + if (mp->tx_ring_skbs != 1) + mp->tx_ring_skbs--; + } else + pci_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt, + PCI_DMA_TODEVICE); + } + + if (netif_queue_stopped(dev) && + MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1) + netif_wake_queue(dev); +} + +/* + * mv64340_poll + * + * This function is used in case of NAPI + */ +static int mv64340_poll(struct net_device *dev, int *budget) +{ + struct mv64340_private *mp = netdev_priv(dev); + int done = 1, orig_budget, work_done; + unsigned int port_num = mp->port_num; + unsigned long flags; + +#ifdef MV64340_TX_FAST_REFILL + if (++mp->tx_clean_threshold > 5) { + spin_lock_irqsave(&mp->lock, flags); + mv64340_tx(dev); + mp->tx_clean_threshold = 0; + spin_unlock_irqrestore(&mp->lock, flags); + } +#endif + + if ((u32)(MV_READ(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) != (u32)mp->rx_used_desc_q) { + orig_budget = *budget; + if (orig_budget > dev->quota) + orig_budget = dev->quota; + work_done = mv64340_eth_receive_queue(dev, 0, orig_budget); + mp->rx_task.func(dev); + *budget -= work_done; + dev->quota -= work_done; + if (work_done >= orig_budget) + done = 0; + } + + if (done) { + spin_lock_irqsave(&mp->lock, flags); + __netif_rx_complete(dev); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + spin_unlock_irqrestore(&mp->lock, flags); + } + + return done ? 0 : 1; +} +#endif + +/* + * mv64340_eth_start_xmit + * + * This function is queues a packet in the Tx descriptor for + * required port. + * + * Input : skb - a pointer to socket buffer + * dev - a pointer to the required port + * + * Output : zero upon success + */ +static int mv64340_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + ETH_FUNC_RET_STATUS status; + unsigned long flags; + struct pkt_info pkt_info; + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR + "%s: Tried sending packet when interface is stopped\n", + dev->name); + return 1; + } + + /* This is a hard error, log it. */ + if ((MV64340_TX_QUEUE_SIZE - mp->tx_ring_skbs) <= + (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + printk(KERN_ERR + "%s: Bug in mv64340_eth - Trying to transmit when" + " queue full !\n", dev->name); + return 1; + } + + /* Paranoid check - this shouldn't happen */ + if (skb == NULL) { + stats->tx_dropped++; + return 1; + } + + spin_lock_irqsave(&mp->lock, flags); + + /* Update packet info data structure -- DMA owned, first last */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) { +#endif + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | + ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; + + pkt_info.byte_cnt = skb->len; + pkt_info.buf_ptr = pci_map_single(0, skb->data, skb->len, + PCI_DMA_TODEVICE); + + + pkt_info.return_info = skb; + status = eth_port_send(mp, &pkt_info); + if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) + printk(KERN_ERR "%s: Error on transmitting packet\n", + dev->name); + mp->tx_ring_skbs++; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + } else { + unsigned int frag; + u32 ipheader; + + /* first frag which is skb header */ + pkt_info.byte_cnt = skb_headlen(skb); + pkt_info.buf_ptr = pci_map_single(0, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + pkt_info.return_info = 0; + ipheader = skb->nh.iph->ihl << 11; + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + ipheader; + /* CPU already calculated pseudo header checksum. So, use it */ + pkt_info.l4i_chk = skb->h.th->check; + status = eth_port_send(mp, &pkt_info); + if (status != ETH_OK) { + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + if (status == ETH_QUEUE_FULL) + printk("Error on Queue Full \n"); + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); + } + + /* Check for the remaining frags */ + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + pkt_info.l4i_chk = 0x0000; + pkt_info.cmd_sts = 0x00000000; + + /* Last Frag enables interrupt and frees the skb */ + if (frag == (skb_shinfo(skb)->nr_frags - 1)) { + pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | + ETH_TX_LAST_DESC; + pkt_info.return_info = skb; + mp->tx_ring_skbs++; + } + else { + pkt_info.return_info = 0; + } + pkt_info.byte_cnt = this_frag->size; + if (this_frag->size < 8) + printk("%d : \n", skb_shinfo(skb)->nr_frags); + + pkt_info.buf_ptr = pci_map_page(NULL, this_frag->page, + this_frag->page_offset, + this_frag->size, PCI_DMA_TODEVICE); + + status = eth_port_send(mp, &pkt_info); + + if (status != ETH_OK) { + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); + + if (status == ETH_QUEUE_FULL) + printk("Queue is full \n"); + } + } + } +#endif + + /* Check if TX queue can handle another skb. If not, then + * signal higher layers to stop requesting TX + */ + if (MV64340_TX_QUEUE_SIZE <= (mp->tx_ring_skbs + 1)) + /* + * Stop getting skb's from upper layers. + * Getting skb's from upper layers will be enabled again after + * packets are released. + */ + netif_stop_queue(dev); + + /* Update statistics and start of transmittion time */ + stats->tx_bytes += skb->len; + stats->tx_packets++; + dev->trans_start = jiffies; + + spin_unlock_irqrestore(&mp->lock, flags); + + return 0; /* success */ +} + +/* + * mv64340_eth_get_stats + * + * Returns a pointer to the interface statistics. + * + * Input : dev - a pointer to the required interface + * + * Output : a pointer to the interface's statistics + */ + +static struct net_device_stats *mv64340_eth_get_stats(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + return &mp->stats; +} + +/*/ + * mv64340_eth_init + * + * First function called after registering the network device. + * It's purpose is to initialize the device as an ethernet device, + * fill the structure that was given in registration with pointers + * to functions, and setting the MAC address of the interface + * + * Input : number of port to initialize + * Output : -ENONMEM if failed , 0 if success + */ +static struct net_device *mv64340_eth_init(int port_num) +{ + struct mv64340_private *mp; + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct mv64340_private)); + if (!dev) + return NULL; + + mp = netdev_priv(dev); + + dev->irq = ETH_PORT0_IRQ_NUM + port_num; + + dev->open = mv64340_eth_open; + dev->stop = mv64340_eth_stop; + dev->hard_start_xmit = mv64340_eth_start_xmit; + dev->get_stats = mv64340_eth_get_stats; + dev->set_mac_address = mv64340_eth_set_mac_address; + dev->set_multicast_list = mv64340_eth_set_rx_mode; + + /* No need to Tx Timeout */ + dev->tx_timeout = mv64340_eth_tx_timeout; +#ifdef MV64340_NAPI + dev->poll = mv64340_poll; + dev->weight = 64; +#endif + + dev->watchdog_timeo = 2 * HZ; + dev->tx_queue_len = MV64340_TX_QUEUE_SIZE; + dev->base_addr = 0; + dev->change_mtu = mv64340_eth_change_mtu; + +#ifdef MV64340_CHECKSUM_OFFLOAD_TX +#ifdef MAX_SKB_FRAGS +#ifndef CONFIG_JAGUAR_DMALOW + /* + * Zero copy can only work if we use Discovery II memory. Else, we will + * have to map the buffers to ISA memory which is only 16 MB + */ + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM; +#endif +#endif +#endif + + mp->port_num = port_num; + + /* Configure the timeout task */ + INIT_WORK(&mp->tx_timeout_task, + (void (*)(void *))mv64340_eth_tx_timeout_task, dev); + + spin_lock_init(&mp->lock); + + /* set MAC addresses */ + memcpy(dev->dev_addr, prom_mac_addr_base, 6); + dev->dev_addr[5] += port_num; + + err = register_netdev(dev); + if (err) + goto out_free_dev; + + printk(KERN_NOTICE "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, port_num, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + if (dev->features & NETIF_F_SG) + printk("Scatter Gather Enabled "); + + if (dev->features & NETIF_F_IP_CSUM) + printk("TX TCP/IP Checksumming Supported \n"); + + printk("RX TCP/UDP Checksum Offload ON, \n"); + printk("TX and RX Interrupt Coalescing ON \n"); + +#ifdef MV64340_NAPI + printk("RX NAPI Enabled \n"); +#endif + + return dev; + +out_free_dev: + free_netdev(dev); + + return NULL; +} + +static void mv64340_eth_remove(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + unregister_netdev(dev); + flush_scheduled_work(); + free_netdev(dev); +} + +static struct net_device *mv64340_dev0; +static struct net_device *mv64340_dev1; +static struct net_device *mv64340_dev2; + +/* + * mv64340_init_module + * + * Registers the network drivers into the Linux kernel + * + * Input : N/A + * + * Output : N/A + */ +static int __init mv64340_init_module(void) +{ + printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); + +#ifdef CONFIG_MV643XX_ETH_0 + mv64340_dev0 = mv64340_eth_init(0); + if (!mv64340_dev0) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 0\n"); + } +#endif +#ifdef CONFIG_MV643XX_ETH_1 + mv64340_dev1 = mv64340_eth_init(1); + if (!mv64340_dev1) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 1\n"); + } +#endif +#ifdef CONFIG_MV643XX_ETH_2 + mv64340_dev2 = mv64340_eth_init(2); + if (!mv64340_dev2) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 2\n"); + } +#endif + return 0; +} + +/* + * mv64340_cleanup_module + * + * Registers the network drivers into the Linux kernel + * + * Input : N/A + * + * Output : N/A + */ +static void __exit mv64340_cleanup_module(void) +{ + if (mv64340_dev2) + mv64340_eth_remove(mv64340_dev2); + if (mv64340_dev1) + mv64340_eth_remove(mv64340_dev1); + if (mv64340_dev0) + mv64340_eth_remove(mv64340_dev0); +} + +module_init(mv64340_init_module); +module_exit(mv64340_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani"); +MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340"); + +/* + * The second part is the low level driver of the gigE ethernet ports. + */ + +/* + * Marvell's Gigabit Ethernet controller low level driver + * + * DESCRIPTION: + * This file introduce low level API to Marvell's Gigabit Ethernet + * controller. This Gigabit Ethernet Controller driver API controls + * 1) Operations (i.e. port init, start, reset etc'). + * 2) Data flow (i.e. port send, receive etc'). + * Each Gigabit Ethernet port is controlled via + * struct mv64340_private. + * This struct includes user configuration information as well as + * driver internal data needed for its operations. + * + * Supported Features: + * - This low level driver is OS independent. Allocating memory for + * the descriptor rings and buffers are not within the scope of + * this driver. + * - The user is free from Rx/Tx queue managing. + * - This low level driver introduce functionality API that enable + * the to operate Marvell's Gigabit Ethernet Controller in a + * convenient way. + * - Simple Gigabit Ethernet port operation API. + * - Simple Gigabit Ethernet port data flow API. + * - Data flow and operation API support per queue functionality. + * - Support cached descriptors for better performance. + * - Enable access to all four DRAM banks and internal SRAM memory + * spaces. + * - PHY access and control API. + * - Port control register configuration API. + * - Full control over Unicast and Multicast MAC configurations. + * + * Operation flow: + * + * Initialization phase + * This phase complete the initialization of the the mv64340_private + * struct. + * User information regarding port configuration has to be set + * prior to calling the port initialization routine. + * + * In this phase any port Tx/Rx activity is halted, MIB counters + * are cleared, PHY address is set according to user parameter and + * access to DRAM and internal SRAM memory spaces. + * + * Driver ring initialization + * Allocating memory for the descriptor rings and buffers is not + * within the scope of this driver. Thus, the user is required to + * allocate memory for the descriptors ring and buffers. Those + * memory parameters are used by the Rx and Tx ring initialization + * routines in order to curve the descriptor linked list in a form + * of a ring. + * Note: Pay special attention to alignment issues when using + * cached descriptors/buffers. In this phase the driver store + * information in the mv64340_private struct regarding each queue + * ring. + * + * Driver start + * This phase prepares the Ethernet port for Rx and Tx activity. + * It uses the information stored in the mv64340_private struct to + * initialize the various port registers. + * + * Data flow: + * All packet references to/from the driver are done using + * struct pkt_info. + * This struct is a unified struct used with Rx and Tx operations. + * This way the user is not required to be familiar with neither + * Tx nor Rx descriptors structures. + * The driver's descriptors rings are management by indexes. + * Those indexes controls the ring resources and used to indicate + * a SW resource error: + * 'current' + * This index points to the current available resource for use. For + * example in Rx process this index will point to the descriptor + * that will be passed to the user upon calling the receive routine. + * In Tx process, this index will point to the descriptor + * that will be assigned with the user packet info and transmitted. + * 'used' + * This index points to the descriptor that need to restore its + * resources. For example in Rx process, using the Rx buffer return + * API will attach the buffer returned in packet info to the + * descriptor pointed by 'used'. In Tx process, using the Tx + * descriptor return will merely return the user packet info with + * the command status of the transmitted buffer pointed by the + * 'used' index. Nevertheless, it is essential to use this routine + * to update the 'used' index. + * 'first' + * This index supports Tx Scatter-Gather. It points to the first + * descriptor of a packet assembled of multiple buffers. For example + * when in middle of Such packet we have a Tx resource error the + * 'curr' index get the value of 'first' to indicate that the ring + * returned to its state before trying to transmit this packet. + * + * Receive operation: + * The eth_port_receive API set the packet information struct, + * passed by the caller, with received information from the + * 'current' SDMA descriptor. + * It is the user responsibility to return this resource back + * to the Rx descriptor ring to enable the reuse of this source. + * Return Rx resource is done using the eth_rx_return_buff API. + * + * Transmit operation: + * The eth_port_send API supports Scatter-Gather which enables to + * send a packet spanned over multiple buffers. This means that + * for each packet info structure given by the user and put into + * the Tx descriptors ring, will be transmitted only if the 'LAST' + * bit will be set in the packet info command status field. This + * API also consider restriction regarding buffer alignments and + * sizes. + * The user must return a Tx resource after ensuring the buffer + * has been transmitted to enable the Tx ring indexes to update. + * + * BOARD LAYOUT + * This device is on-board. No jumper diagram is necessary. + * + * EXTERNAL INTERFACE + * + * Prior to calling the initialization routine eth_port_init() the user + * must set the following fields under mv64340_private struct: + * port_num User Ethernet port number. + * port_mac_addr[6] User defined port MAC address. + * port_config User port configuration value. + * port_config_extend User port config extend value. + * port_sdma_config User port SDMA config value. + * port_serial_control User port serial control value. + * + * This driver introduce a set of default values: + * PORT_CONFIG_VALUE Default port configuration value + * PORT_CONFIG_EXTEND_VALUE Default port extend configuration value + * PORT_SDMA_CONFIG_VALUE Default sdma control value + * PORT_SERIAL_CONTROL_VALUE Default port serial control value + * + * This driver data flow is done using the struct pkt_info which + * is a unified struct for Rx and Tx operations: + * + * byte_cnt Tx/Rx descriptor buffer byte count. + * l4i_chk CPU provided TCP Checksum. For Tx operation + * only. + * cmd_sts Tx/Rx descriptor command status. + * buf_ptr Tx/Rx descriptor buffer pointer. + * return_info Tx/Rx user resource return information. + */ + +/* defines */ +/* SDMA command macros */ +#define ETH_ENABLE_TX_QUEUE(eth_port) \ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1) + +#define ETH_DISABLE_TX_QUEUE(eth_port) \ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), \ + (1 << 8)) + +#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ + (1 << rx_queue)) + +#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ + (1 << (8 + rx_queue))) + +#define LINK_UP_TIMEOUT 100000 +#define PHY_BUSY_TIMEOUT 10000000 + +/* locals */ + +/* PHY routines */ +static int ethernet_phy_get(unsigned int eth_port_num); + +/* Ethernet Port routines */ +static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, + int option); + +/* + * eth_port_init - Initialize the Ethernet port driver + * + * DESCRIPTION: + * This function prepares the ethernet port to start its activity: + * 1) Completes the ethernet port driver struct initialization toward port + * start routine. + * 2) Resets the device to a quiescent state in case of warm reboot. + * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. + * 4) Clean MAC tables. The reset status of those tables is unknown. + * 5) Set PHY address. + * Note: Call this routine prior to eth_port_start routine and after + * setting user values in the user fields of Ethernet port control + * struct. + * + * INPUT: + * struct mv64340_private *mp Ethernet port control struct + * + * OUTPUT: + * See description. + * + * RETURN: + * None. + */ +static void eth_port_init(struct mv64340_private * mp) +{ + mp->port_config = PORT_CONFIG_VALUE; + mp->port_config_extend = PORT_CONFIG_EXTEND_VALUE; +#if defined(__BIG_ENDIAN) + mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE; +#elif defined(__LITTLE_ENDIAN) + mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE | + ETH_BLM_RX_NO_SWAP | ETH_BLM_TX_NO_SWAP; +#else +#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be defined! +#endif + mp->port_serial_control = PORT_SERIAL_CONTROL_VALUE; + + mp->port_rx_queue_command = 0; + mp->port_tx_queue_command = 0; + + mp->rx_resource_err = 0; + mp->tx_resource_err = 0; + + eth_port_reset(mp->port_num); + + eth_port_init_mac_tables(mp->port_num); + + ethernet_phy_reset(mp->port_num); +} + +/* + * eth_port_start - Start the Ethernet port activity. + * + * DESCRIPTION: + * This routine prepares the Ethernet port for Rx and Tx activity: + * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that + * has been initialized a descriptor's ring (using + * ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx) + * 2. Initialize and enable the Ethernet configuration port by writing to + * the port's configuration and command registers. + * 3. Initialize and enable the SDMA by writing to the SDMA's + * configuration and command registers. After completing these steps, + * the ethernet port SDMA can starts to perform Rx and Tx activities. + * + * Note: Each Rx and Tx queue descriptor's list must be initialized prior + * to calling this function (use ether_init_tx_desc_ring for Tx queues + * and ether_init_rx_desc_ring for Rx queues). + * + * INPUT: + * struct mv64340_private *mp Ethernet port control struct + * + * OUTPUT: + * Ethernet port is ready to receive and transmit. + * + * RETURN: + * false if the port PHY is not up. + * true otherwise. + */ +static int eth_port_start(struct mv64340_private *mp) +{ + unsigned int eth_port_num = mp->port_num; + int tx_curr_desc, rx_curr_desc; + unsigned int phy_reg_data; + + /* Assignment of Tx CTRP of given queue */ + tx_curr_desc = mp->tx_curr_desc_q; + MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), + (struct eth_tx_desc *) mp->tx_desc_dma + tx_curr_desc); + + /* Assignment of Rx CRDP of given queue */ + rx_curr_desc = mp->rx_curr_desc_q; + MV_WRITE(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), + (struct eth_rx_desc *) mp->rx_desc_dma + rx_curr_desc); + + /* Add the assigned Ethernet address to the port's address table */ + eth_port_uc_addr_set(mp->port_num, mp->port_mac_addr); + + /* Assign port configuration and command. */ + MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), + mp->port_config); + + MV_WRITE(MV64340_ETH_PORT_CONFIG_EXTEND_REG(eth_port_num), + mp->port_config_extend); + + MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), + mp->port_serial_control); + + MV_SET_REG_BITS(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), + ETH_SERIAL_PORT_ENABLE); + + /* Assign port SDMA configuration */ + MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), + mp->port_sdma_config); + + /* Enable port Rx. */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port_num), + mp->port_rx_queue_command); + + /* Check if link is up */ + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); + + if (!(phy_reg_data & 0x20)) + return 0; + + return 1; +} + +/* + * eth_port_uc_addr_set - This function Set the port Unicast address. + * + * DESCRIPTION: + * This function Set the port Ethernet MAC address. + * + * INPUT: + * unsigned int eth_port_num Port number. + * char * p_addr Address to be set + * + * OUTPUT: + * Set MAC address low and high registers. also calls eth_port_uc_addr() + * To set the unicast table with the proper information. + * + * RETURN: + * N/A. + * + */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr) +{ + unsigned int mac_h; + unsigned int mac_l; + + mac_l = (p_addr[4] << 8) | (p_addr[5]); + mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | + (p_addr[2] << 8) | (p_addr[3] << 0); + + MV_WRITE(MV64340_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); + MV_WRITE(MV64340_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); + + /* Accept frames of this address */ + eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR); + + return; +} + +/* + * eth_port_uc_addr - This function Set the port unicast address table + * + * DESCRIPTION: + * This function locates the proper entry in the Unicast table for the + * specified MAC nibble and sets its properties according to function + * parameters. + * + * INPUT: + * unsigned int eth_port_num Port number. + * unsigned char uc_nibble Unicast MAC Address last nibble. + * int option 0 = Add, 1 = remove address. + * + * OUTPUT: + * This function add/removes MAC addresses from the port unicast address + * table. + * + * RETURN: + * true is output succeeded. + * false if option parameter is invalid. + * + */ +static int eth_port_uc_addr(unsigned int eth_port_num, + unsigned char uc_nibble, int option) +{ + unsigned int unicast_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + /* Locate the Unicast table entry */ + uc_nibble = (0xf & uc_nibble); + tbl_offset = (uc_nibble / 4) * 4; /* Register offset from unicast table base */ + reg_offset = uc_nibble % 4; /* Entry offset within the above register */ + + switch (option) { + case REJECT_MAC_ADDR: + /* Clear accepts frame bit at specified unicast DA table entry */ + unicast_reg = MV_READ((MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); + + unicast_reg &= (0x0E << (8 * reg_offset)); + + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); + break; + + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at unicast DA filter table entry */ + unicast_reg = + MV_READ( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); + + unicast_reg |= (0x01 << (8 * reg_offset)); + + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); + + break; + + default: + return 0; + } + + return 1; +} + +/* + * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables + * + * DESCRIPTION: + * Go through all the DA filter tables (Unicast, Special Multicast & + * Other Multicast) and set each entry to 0. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Multicast and Unicast packets are rejected. + * + * RETURN: + * None. + */ +static void eth_port_init_mac_tables(unsigned int eth_port_num) +{ + int table_index; + + /* Clear DA filter unicast table (Ex_dFUT) */ + for (table_index = 0; table_index <= 0xC; table_index += 4) + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + + for (table_index = 0; table_index <= 0xFC; table_index += 4) { + /* Clear DA filter special multicast table (Ex_dFSMT) */ + MV_WRITE( + (MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + /* Clear DA filter other multicast table (Ex_dFOMT) */ + MV_WRITE((MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + } +} + +/* + * eth_clear_mib_counters - Clear all MIB counters + * + * DESCRIPTION: + * This function clears all MIB counters of a specific ethernet port. + * A read from the MIB counter will reset the counter. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * After reading all MIB counters, the counters resets. + * + * RETURN: + * MIB counter value. + * + */ +static void eth_clear_mib_counters(unsigned int eth_port_num) +{ + int i; + + /* Perform dummy reads from MIB counters */ + for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4) + MV_READ(MV64340_ETH_MIB_COUNTERS_BASE(eth_port_num) + i); +} + + +/* + * ethernet_phy_get - Get the ethernet port PHY address. + * + * DESCRIPTION: + * This routine returns the given ethernet port PHY address. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None. + * + * RETURN: + * PHY address. + * + */ +static int ethernet_phy_get(unsigned int eth_port_num) +{ + unsigned int reg_data; + + reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG); + + return ((reg_data >> (5 * eth_port_num)) & 0x1f); +} + +/* + * ethernet_phy_reset - Reset Ethernet port PHY. + * + * DESCRIPTION: + * This routine utilize the SMI interface to reset the ethernet port PHY. + * The routine waits until the link is up again or link up is timeout. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * The ethernet port PHY renew its link. + * + * RETURN: + * None. + * + */ +static int ethernet_phy_reset(unsigned int eth_port_num) +{ + unsigned int time_out = 50; + unsigned int phy_reg_data; + + /* Reset the PHY */ + eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); + phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ + eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); + + /* Poll on the PHY LINK */ + do { + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); + + if (time_out-- == 0) + return 0; + } while (!(phy_reg_data & 0x20)); + + return 1; +} + +/* + * eth_port_reset - Reset Ethernet port + * + * DESCRIPTION: + * This routine resets the chip by aborting any SDMA engine activity and + * clearing the MIB counters. The Receiver and the Transmit unit are in + * idle state after this command is performed and the port is disabled. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Channel activity is halted. + * + * RETURN: + * None. + * + */ +static void eth_port_reset(unsigned int eth_port_num) +{ + unsigned int reg_data; + + /* Stop Tx port activity. Check port Tx activity. */ + reg_data = + MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Tx activity to terminate. */ + do { + /* Check port cause register that all Tx queues are stopped */ + reg_data = + MV_READ + (MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + /* Stop Rx port activity. Check port Rx activity. */ + reg_data = + MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Rx activity to terminate. */ + do { + /* Check port cause register that all Rx queues are stopped */ + reg_data = + MV_READ + (MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + + /* Clear all MIB counters */ + eth_clear_mib_counters(eth_port_num); + + /* Reset the Enable bit in the Configuration Register */ + reg_data = + MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num)); + reg_data &= ~ETH_SERIAL_PORT_ENABLE; + MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), reg_data); + + return; +} + +/* + * ethernet_set_config_reg - Set specified bits in configuration register. + * + * DESCRIPTION: + * This function sets specified bits in the given ethernet + * configuration register. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int value 32 bit value. + * + * OUTPUT: + * The set bits in the value parameter are set in the configuration + * register. + * + * RETURN: + * None. + * + */ +static void ethernet_set_config_reg(unsigned int eth_port_num, + unsigned int value) +{ + unsigned int eth_config_reg; + + eth_config_reg = + MV_READ(MV64340_ETH_PORT_CONFIG_REG(eth_port_num)); + eth_config_reg |= value; + MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), + eth_config_reg); +} + +/* + * ethernet_get_config_reg - Get the port configuration register + * + * DESCRIPTION: + * This function returns the configuration register value of the given + * ethernet port. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None. + * + * RETURN: + * Port configuration register value. + */ +static unsigned int ethernet_get_config_reg(unsigned int eth_port_num) +{ + unsigned int eth_config_reg; + + eth_config_reg = MV_READ(MV64340_ETH_PORT_CONFIG_EXTEND_REG + (eth_port_num)); + return eth_config_reg; +} + + +/* + * eth_port_read_smi_reg - Read PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform PHY register read. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int *value Register value buffer. + * + * OUTPUT: + * Write the value of a specified PHY register into given buffer. + * + * RETURN: + * false if the PHY is busy or read data is not in valid state. + * true otherwise. + * + */ +static int eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int *value) +{ + int phy_addr = ethernet_phy_get(eth_port_num); + unsigned int time_out = PHY_BUSY_TIMEOUT; + unsigned int reg_value; + + /* first check that it is not busy */ + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + + MV_WRITE(MV64340_ETH_SMI_REG, + (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); + + time_out = PHY_BUSY_TIMEOUT; /* initialize the time out var again */ + + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_READ_VALID); + + /* Wait for the data to update in the SMI register */ + for (time_out = 0; time_out < PHY_BUSY_TIMEOUT; time_out++); + + reg_value = MV_READ(MV64340_ETH_SMI_REG); + + *value = reg_value & 0xffff; + + return 1; +} + +/* + * eth_port_write_smi_reg - Write to PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform writes to PHY registers. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int value Register value. + * + * OUTPUT: + * Write the given value to the specified PHY register. + * + * RETURN: + * false if the PHY is busy. + * true otherwise. + * + */ +static int eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int value) +{ + unsigned int time_out = PHY_BUSY_TIMEOUT; + unsigned int reg_value; + int phy_addr; + + phy_addr = ethernet_phy_get(eth_port_num); + + /* first check that it is not busy */ + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + MV_WRITE(MV64340_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) | + ETH_SMI_OPCODE_WRITE | (value & 0xffff)); + + return 1; +} + +/* + * eth_port_send - Send an Ethernet packet + * + * DESCRIPTION: + * This routine send a given packet described by p_pktinfo parameter. It + * supports transmitting of a packet spaned over multiple buffers. The + * routine updates 'curr' and 'first' indexes according to the packet + * segment passed to the routine. In case the packet segment is first, + * the 'first' index is update. In any case, the 'curr' index is updated. + * If the routine get into Tx resource error it assigns 'curr' index as + * 'first'. This way the function can abort Tx process of multiple + * descriptors per packet. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'curr' and 'first' indexes are updated. + * + * RETURN: + * ETH_QUEUE_FULL in case of Tx resource error. + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource. + * ETH_OK otherwise. + * + */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX +/* + * Modified to include the first descriptor pointer in case of SG + */ +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc; + volatile struct eth_tx_desc *current_descriptor; + volatile struct eth_tx_desc *first_descriptor; + u32 command_status, first_chip_ptr; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (mp->tx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; + + current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + if (current_descriptor == NULL) + return ETH_ERROR; + + tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + + if (command_status & ETH_TX_FIRST_DESC) { + tx_first_desc = tx_desc_curr; + mp->tx_first_desc_q = tx_first_desc; + + /* fill first descriptor */ + first_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + first_descriptor->l4i_chk = p_pkt_info->l4i_chk; + first_descriptor->cmd_sts = command_status; + first_descriptor->byte_cnt = p_pkt_info->byte_cnt; + first_descriptor->buf_ptr = p_pkt_info->buf_ptr; + first_descriptor->next_desc_ptr = mp->tx_desc_dma + + tx_next_desc * sizeof(struct eth_tx_desc); + wmb(); + } else { + tx_first_desc = mp->tx_first_desc_q; + first_descriptor = &mp->p_tx_desc_area[tx_first_desc]; + if (first_descriptor == NULL) { + printk("First desc is NULL !!\n"); + return ETH_ERROR; + } + if (command_status & ETH_TX_LAST_DESC) + current_descriptor->next_desc_ptr = 0x00000000; + else { + command_status |= ETH_BUFFER_OWNED_BY_DMA; + current_descriptor->next_desc_ptr = mp->tx_desc_dma + + tx_next_desc * sizeof(struct eth_tx_desc); + } + } + + if (p_pkt_info->byte_cnt < 8) { + printk(" < 8 problem \n"); + return ETH_ERROR; + } + + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + current_descriptor->l4i_chk = p_pkt_info->l4i_chk; + current_descriptor->cmd_sts = command_status; + + mp->tx_skb[tx_desc_curr] = (struct sk_buff*) p_pkt_info->return_info; + + wmb(); + + /* Set last desc with DMA ownership and interrupt enable. */ + if (command_status & ETH_TX_LAST_DESC) { + current_descriptor->cmd_sts = command_status | + ETH_TX_ENABLE_INTERRUPT | + ETH_BUFFER_OWNED_BY_DMA; + + if (!(command_status & ETH_TX_FIRST_DESC)) + first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA; + wmb(); + + first_chip_ptr = MV_READ(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(mp->port_num)); + + /* Apply send command */ + if (first_chip_ptr == 0x00000000) + MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(mp->port_num), (struct eth_tx_desc *) mp->tx_desc_dma + tx_first_desc); + + ETH_ENABLE_TX_QUEUE(mp->port_num); + + /* + * Finish Tx packet. Update first desc in case of Tx resource + * error */ + tx_first_desc = tx_next_desc; + mp->tx_first_desc_q = tx_first_desc; + } else { + if (! (command_status & ETH_TX_FIRST_DESC) ) { + current_descriptor->cmd_sts = command_status; + wmb(); + } + } + + /* Check for ring index overlap in the Tx desc ring */ + if (tx_next_desc == tx_desc_used) { + mp->tx_resource_err = 1; + mp->tx_curr_desc_q = tx_first_desc; + + return ETH_QUEUE_LAST_RESOURCE; + } + + mp->tx_curr_desc_q = tx_next_desc; + wmb(); + + return ETH_OK; +} +#else +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_curr; + int tx_desc_used; + volatile struct eth_tx_desc* current_descriptor; + unsigned int command_status; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (mp->tx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; + current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + + if (current_descriptor == NULL) + return ETH_ERROR; + + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + +/* XXX Is this for real ?!?!? */ + /* Buffers with a payload smaller than 8 bytes must be aligned to a + * 64-bit boundary. We use the memory allocated for Tx descriptor. + * This memory is located in TX_BUF_OFFSET_IN_DESC offset within the + * Tx descriptor. */ + if (p_pkt_info->byte_cnt <= 8) { + printk(KERN_ERR + "You have failed in the < 8 bytes errata - fixme\n"); + return ETH_ERROR; + } + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + mp->tx_skb[tx_desc_curr] = (struct sk_buff *) p_pkt_info->return_info; + + mb(); + + /* Set last desc with DMA ownership and interrupt enable. */ + current_descriptor->cmd_sts = command_status | + ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; + + /* Apply send command */ + ETH_ENABLE_TX_QUEUE(mp->port_num); + + /* Finish Tx packet. Update first desc in case of Tx resource error */ + tx_desc_curr = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + + /* Update the current descriptor */ + mp->tx_curr_desc_q = tx_desc_curr; + + /* Check for ring index overlap in the Tx desc ring */ + if (tx_desc_curr == tx_desc_used) { + mp->tx_resource_err = 1; + return ETH_QUEUE_LAST_RESOURCE; + } + + return ETH_OK; +} +#endif + +/* + * eth_tx_return_desc - Free all used Tx descriptors + * + * DESCRIPTION: + * This routine returns the transmitted packet information to the caller. + * It uses the 'first' index to support Tx desc return in case a transmit + * of a packet spanned over multiple buffer still in process. + * In case the Tx queue was in "resource error" condition, where there are + * no available Tx resources, the function resets the resource error flag. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'first' and 'used' indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_RETRY in case there is transmission in process. + * ETH_END_OF_JOB if the routine has nothing to release. + * ETH_OK otherwise. + * + */ +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_used, tx_desc_curr; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + int tx_first_desc; +#endif + volatile struct eth_tx_desc *p_tx_desc_used; + unsigned int command_status; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + tx_first_desc = mp->tx_first_desc_q; +#endif + p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; + + /* XXX Sanity check */ + if (p_tx_desc_used == NULL) + return ETH_ERROR; + + command_status = p_tx_desc_used->cmd_sts; + + /* Still transmitting... */ +#ifndef MV64340_CHECKSUM_OFFLOAD_TX + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + return ETH_RETRY; +#endif + /* Stop release. About to overlap the current available Tx descriptor */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + if (tx_desc_used == tx_first_desc && !mp->tx_resource_err) + return ETH_END_OF_JOB; +#else + if (tx_desc_used == tx_desc_curr && !mp->tx_resource_err) + return ETH_END_OF_JOB; +#endif + + /* Pass the packet information to the caller */ + p_pkt_info->cmd_sts = command_status; + p_pkt_info->return_info = mp->tx_skb[tx_desc_used]; + mp->tx_skb[tx_desc_used] = NULL; + + /* Update the next descriptor to release. */ + mp->tx_used_desc_q = (tx_desc_used + 1) % MV64340_TX_QUEUE_SIZE; + + /* Any Tx return cancels the Tx resource error status */ + mp->tx_resource_err = 0; + + return ETH_OK; +} + +/* + * eth_port_receive - Get received information from Rx ring. + * + * DESCRIPTION: + * This routine returns the received data to the caller. There is no + * data copying during routine operation. All information is returned + * using pointer to packet information struct passed from the caller. + * If the routine exhausts Rx ring resources then the resource error flag + * is set. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Rx ring current and used indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_QUEUE_FULL if Rx ring resources are exhausted. + * ETH_END_OF_JOB if there is no received data. + * ETH_OK otherwise. + */ +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int rx_next_curr_desc, rx_curr_desc, rx_used_desc; + volatile struct eth_rx_desc * p_rx_desc; + unsigned int command_status; + + /* Do not process Rx ring in case of Rx ring resource error */ + if (mp->rx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Rx Desc ring 'curr and 'used' indexes */ + rx_curr_desc = mp->rx_curr_desc_q; + rx_used_desc = mp->rx_used_desc_q; + + p_rx_desc = &mp->p_rx_desc_area[rx_curr_desc]; + + /* The following parameters are used to save readings from memory */ + command_status = p_rx_desc->cmd_sts; + + /* Nothing to receive... */ + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + return ETH_END_OF_JOB; + + p_pkt_info->byte_cnt = (p_rx_desc->byte_cnt) - RX_BUF_OFFSET; + p_pkt_info->cmd_sts = command_status; + p_pkt_info->buf_ptr = (p_rx_desc->buf_ptr) + RX_BUF_OFFSET; + p_pkt_info->return_info = mp->rx_skb[rx_curr_desc]; + p_pkt_info->l4i_chk = p_rx_desc->buf_size; + + /* Clean the return info field to indicate that the packet has been */ + /* moved to the upper layers */ + mp->rx_skb[rx_curr_desc] = NULL; + + /* Update current index in data structure */ + rx_next_curr_desc = (rx_curr_desc + 1) % MV64340_RX_QUEUE_SIZE; + mp->rx_curr_desc_q = rx_next_curr_desc; + + /* Rx descriptors exhausted. Set the Rx ring resource error flag */ + if (rx_next_curr_desc == rx_used_desc) + mp->rx_resource_err = 1; + + mb(); + return ETH_OK; +} + +/* + * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring. + * + * DESCRIPTION: + * This routine returns a Rx buffer back to the Rx ring. It retrieves the + * next 'used' descriptor and attached the returned buffer to it. + * In case the Rx ring was in "resource error" condition, where there are + * no available Rx resources, the function resets the resource error flag. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info Information on the returned buffer. + * + * OUTPUT: + * New available Rx resource in Rx descriptor ring. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_OK otherwise. + */ +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int used_rx_desc; /* Where to return Rx resource */ + volatile struct eth_rx_desc* p_used_rx_desc; + + /* Get 'used' Rx descriptor */ + used_rx_desc = mp->rx_used_desc_q; + p_used_rx_desc = &mp->p_rx_desc_area[used_rx_desc]; + + p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr; + p_used_rx_desc->buf_size = p_pkt_info->byte_cnt; + mp->rx_skb[used_rx_desc] = p_pkt_info->return_info; + + /* Flush the write pipe */ + mb(); + + /* Return the descriptor to DMA ownership */ + p_used_rx_desc->cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + + /* Flush descriptor and CPU pipe */ + mb(); + + /* Move the used descriptor pointer to the next descriptor */ + mp->rx_used_desc_q = (used_rx_desc + 1) % MV64340_RX_QUEUE_SIZE; + + /* Any Rx return cancels the Rx resource error status */ + mp->rx_resource_err = 0; + + return ETH_OK; +} diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h new file mode 100644 index 000000000..46a057d0c --- /dev/null +++ b/drivers/net/mv643xx_eth.h @@ -0,0 +1,601 @@ +#ifndef __MV64340_ETH_H__ +#define __MV64340_ETH_H__ + +#include +#include +#include +#include +#include + +#include + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +/* + * The first part is the high level driver of the gigE ethernet ports. + */ + +#define ETH_PORT0_IRQ_NUM 48 /* main high register, bit0 */ +#define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1 /* main high register, bit1 */ +#define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2 /* main high register, bit1 */ + +/* Checksum offload for Tx works */ +#define MV64340_CHECKSUM_OFFLOAD_TX +#define MV64340_NAPI +#define MV64340_TX_FAST_REFILL +#undef MV64340_COAL + +/* + * Number of RX / TX descriptors on RX / TX rings. + * Note that allocating RX descriptors is done by allocating the RX + * ring AND a preallocated RX buffers (skb's) for each descriptor. + * The TX descriptors only allocates the TX descriptors ring, + * with no pre allocated TX buffers (skb's are allocated by higher layers. + */ + +/* Default TX ring size is 1000 descriptors */ +#define MV64340_TX_QUEUE_SIZE 1000 + +/* Default RX ring size is 400 descriptors */ +#define MV64340_RX_QUEUE_SIZE 400 + +#define MV64340_TX_COAL 100 +#ifdef MV64340_COAL +#define MV64340_RX_COAL 100 +#endif + + +/* + * The second part is the low level driver of the gigE ethernet ports. * + */ + + +/* + * Header File for : MV-643xx network interface header + * + * DESCRIPTION: + * This header file contains macros typedefs and function declaration for + * the Marvell Gig Bit Ethernet Controller. + * + * DEPENDENCIES: + * None. + * + */ + +/* Default port configuration value */ +#define PORT_CONFIG_VALUE \ + ETH_UNICAST_NORMAL_MODE | \ + ETH_DEFAULT_RX_QUEUE_0 | \ + ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + ETH_RECEIVE_BC_IF_IP | \ + ETH_RECEIVE_BC_IF_ARP | \ + ETH_CAPTURE_TCP_FRAMES_DIS | \ + ETH_CAPTURE_UDP_FRAMES_DIS | \ + ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + ETH_DEFAULT_RX_BPDU_QUEUE_0 + +/* Default port extend configuration value */ +#define PORT_CONFIG_EXTEND_VALUE \ + ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + ETH_PARTITION_DISABLE + + +/* Default sdma control value */ +#define PORT_SDMA_CONFIG_VALUE \ + ETH_RX_BURST_SIZE_16_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + ETH_TX_BURST_SIZE_16_64BIT; + +#define GT_ETH_IPG_INT_RX(value) \ + ((value & 0x3fff) << 8) + +/* Default port serial control value */ +#define PORT_SERIAL_CONTROL_VALUE \ + ETH_FORCE_LINK_PASS | \ + ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + ETH_FORCE_BP_MODE_NO_JAM | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL | \ + ETH_RETRANSMIT_16_ATTEMPTS | \ + ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + ETH_DTE_ADV_0 | \ + ETH_DISABLE_AUTO_NEG_BYPASS | \ + ETH_AUTO_NEG_NO_CHANGE | \ + ETH_MAX_RX_PACKET_9700BYTE | \ + ETH_CLR_EXT_LOOPBACK | \ + ETH_SET_FULL_DUPLEX_MODE | \ + ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX + +#define RX_BUFFER_MAX_SIZE 0x4000000 +#define TX_BUFFER_MAX_SIZE 0x4000000 + +/* MAC accepet/reject macros */ +#define ACCEPT_MAC_ADDR 0 +#define REJECT_MAC_ADDR 1 + +/* Buffer offset from buffer pointer */ +#define RX_BUF_OFFSET 0x2 + +/* Gigabit Ethernet Unit Global Registers */ + +/* MIB Counters register definitions */ +#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 +#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 +#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 +#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc +#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 +#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 +#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 +#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c +#define ETH_MIB_FRAMES_64_OCTETS 0x20 +#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 +#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 +#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c +#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 +#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 +#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 +#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c +#define ETH_MIB_GOOD_FRAMES_SENT 0x40 +#define ETH_MIB_EXCESSIVE_COLLISION 0x44 +#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 +#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c +#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 +#define ETH_MIB_FC_SENT 0x54 +#define ETH_MIB_GOOD_FC_RECEIVED 0x58 +#define ETH_MIB_BAD_FC_RECEIVED 0x5c +#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 +#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 +#define ETH_MIB_OVERSIZE_RECEIVED 0x68 +#define ETH_MIB_JABBER_RECEIVED 0x6c +#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 +#define ETH_MIB_BAD_CRC_EVENT 0x74 +#define ETH_MIB_COLLISION 0x78 +#define ETH_MIB_LATE_COLLISION 0x7c + +/* Port serial status reg (PSR) */ +#define ETH_INTERFACE_GMII_MII 0 +#define ETH_INTERFACE_PCM BIT0 +#define ETH_LINK_IS_DOWN 0 +#define ETH_LINK_IS_UP BIT1 +#define ETH_PORT_AT_HALF_DUPLEX 0 +#define ETH_PORT_AT_FULL_DUPLEX BIT2 +#define ETH_RX_FLOW_CTRL_DISABLED 0 +#define ETH_RX_FLOW_CTRL_ENBALED BIT3 +#define ETH_GMII_SPEED_100_10 0 +#define ETH_GMII_SPEED_1000 BIT4 +#define ETH_MII_SPEED_10 0 +#define ETH_MII_SPEED_100 BIT5 +#define ETH_NO_TX 0 +#define ETH_TX_IN_PROGRESS BIT7 +#define ETH_BYPASS_NO_ACTIVE 0 +#define ETH_BYPASS_ACTIVE BIT8 +#define ETH_PORT_NOT_AT_PARTITION_STATE 0 +#define ETH_PORT_AT_PARTITION_STATE BIT9 +#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 +#define ETH_PORT_TX_FIFO_EMPTY BIT10 + + +/* These macros describes the Port configuration reg (Px_cR) bits */ +#define ETH_UNICAST_NORMAL_MODE 0 +#define ETH_UNICAST_PROMISCUOUS_MODE BIT0 +#define ETH_DEFAULT_RX_QUEUE_0 0 +#define ETH_DEFAULT_RX_QUEUE_1 BIT1 +#define ETH_DEFAULT_RX_QUEUE_2 BIT2 +#define ETH_DEFAULT_RX_QUEUE_3 (BIT2 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_4 BIT3 +#define ETH_DEFAULT_RX_QUEUE_5 (BIT3 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_6 (BIT3 | BIT2) +#define ETH_DEFAULT_RX_QUEUE_7 (BIT3 | BIT2 | BIT1) +#define ETH_DEFAULT_RX_ARP_QUEUE_0 0 +#define ETH_DEFAULT_RX_ARP_QUEUE_1 BIT4 +#define ETH_DEFAULT_RX_ARP_QUEUE_2 BIT5 +#define ETH_DEFAULT_RX_ARP_QUEUE_3 (BIT5 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_4 BIT6 +#define ETH_DEFAULT_RX_ARP_QUEUE_5 (BIT6 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_6 (BIT6 | BIT5) +#define ETH_DEFAULT_RX_ARP_QUEUE_7 (BIT6 | BIT5 | BIT4) +#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP 0 +#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP BIT7 +#define ETH_RECEIVE_BC_IF_IP 0 +#define ETH_REJECT_BC_IF_IP BIT8 +#define ETH_RECEIVE_BC_IF_ARP 0 +#define ETH_REJECT_BC_IF_ARP BIT9 +#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY BIT12 +#define ETH_CAPTURE_TCP_FRAMES_DIS 0 +#define ETH_CAPTURE_TCP_FRAMES_EN BIT14 +#define ETH_CAPTURE_UDP_FRAMES_DIS 0 +#define ETH_CAPTURE_UDP_FRAMES_EN BIT15 +#define ETH_DEFAULT_RX_TCP_QUEUE_0 0 +#define ETH_DEFAULT_RX_TCP_QUEUE_1 BIT16 +#define ETH_DEFAULT_RX_TCP_QUEUE_2 BIT17 +#define ETH_DEFAULT_RX_TCP_QUEUE_3 (BIT17 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_4 BIT18 +#define ETH_DEFAULT_RX_TCP_QUEUE_5 (BIT18 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_6 (BIT18 | BIT17) +#define ETH_DEFAULT_RX_TCP_QUEUE_7 (BIT18 | BIT17 | BIT16) +#define ETH_DEFAULT_RX_UDP_QUEUE_0 0 +#define ETH_DEFAULT_RX_UDP_QUEUE_1 BIT19 +#define ETH_DEFAULT_RX_UDP_QUEUE_2 BIT20 +#define ETH_DEFAULT_RX_UDP_QUEUE_3 (BIT20 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_4 (BIT21 +#define ETH_DEFAULT_RX_UDP_QUEUE_5 (BIT21 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_6 (BIT21 | BIT20) +#define ETH_DEFAULT_RX_UDP_QUEUE_7 (BIT21 | BIT20 | BIT19) +#define ETH_DEFAULT_RX_BPDU_QUEUE_0 0 +#define ETH_DEFAULT_RX_BPDU_QUEUE_1 BIT22 +#define ETH_DEFAULT_RX_BPDU_QUEUE_2 BIT23 +#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 +#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) +#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) + + +/* These macros describes the Port configuration extend reg (Px_cXR) bits*/ +#define ETH_CLASSIFY_EN BIT0 +#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL 0 +#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 BIT1 +#define ETH_PARTITION_DISABLE 0 +#define ETH_PARTITION_ENABLE BIT2 + + +/* Tx/Rx queue command reg (RQCR/TQCR)*/ +#define ETH_QUEUE_0_ENABLE BIT0 +#define ETH_QUEUE_1_ENABLE BIT1 +#define ETH_QUEUE_2_ENABLE BIT2 +#define ETH_QUEUE_3_ENABLE BIT3 +#define ETH_QUEUE_4_ENABLE BIT4 +#define ETH_QUEUE_5_ENABLE BIT5 +#define ETH_QUEUE_6_ENABLE BIT6 +#define ETH_QUEUE_7_ENABLE BIT7 +#define ETH_QUEUE_0_DISABLE BIT8 +#define ETH_QUEUE_1_DISABLE BIT9 +#define ETH_QUEUE_2_DISABLE BIT10 +#define ETH_QUEUE_3_DISABLE BIT11 +#define ETH_QUEUE_4_DISABLE BIT12 +#define ETH_QUEUE_5_DISABLE BIT13 +#define ETH_QUEUE_6_DISABLE BIT14 +#define ETH_QUEUE_7_DISABLE BIT15 + + +/* These macros describes the Port Sdma configuration reg (SDCR) bits */ +#define ETH_RIFB BIT0 +#define ETH_RX_BURST_SIZE_1_64BIT 0 +#define ETH_RX_BURST_SIZE_2_64BIT BIT1 +#define ETH_RX_BURST_SIZE_4_64BIT BIT2 +#define ETH_RX_BURST_SIZE_8_64BIT (BIT2 | BIT1) +#define ETH_RX_BURST_SIZE_16_64BIT BIT3 +#define ETH_BLM_RX_NO_SWAP BIT4 +#define ETH_BLM_RX_BYTE_SWAP 0 +#define ETH_BLM_TX_NO_SWAP BIT5 +#define ETH_BLM_TX_BYTE_SWAP 0 +#define ETH_DESCRIPTORS_BYTE_SWAP BIT6 +#define ETH_DESCRIPTORS_NO_SWAP 0 +#define ETH_TX_BURST_SIZE_1_64BIT 0 +#define ETH_TX_BURST_SIZE_2_64BIT BIT22 +#define ETH_TX_BURST_SIZE_4_64BIT BIT23 +#define ETH_TX_BURST_SIZE_8_64BIT (BIT23 | BIT22) +#define ETH_TX_BURST_SIZE_16_64BIT BIT24 + + + +/* These macros describes the Port serial control reg (PSCR) bits */ +#define ETH_SERIAL_PORT_DISABLE 0 +#define ETH_SERIAL_PORT_ENABLE BIT0 +#define ETH_FORCE_LINK_PASS BIT1 +#define ETH_DO_NOT_FORCE_LINK_PASS 0 +#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX 0 +#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX BIT2 +#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL 0 +#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL BIT3 +#define ETH_ADV_NO_FLOW_CTRL 0 +#define ETH_ADV_SYMMETRIC_FLOW_CTRL BIT4 +#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 +#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS BIT5 +#define ETH_FORCE_BP_MODE_NO_JAM 0 +#define ETH_FORCE_BP_MODE_JAM_TX BIT7 +#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR BIT8 +#define ETH_FORCE_LINK_FAIL 0 +#define ETH_DO_NOT_FORCE_LINK_FAIL BIT10 +#define ETH_RETRANSMIT_16_ATTEMPTS 0 +#define ETH_RETRANSMIT_FOREVER BIT11 +#define ETH_DISABLE_AUTO_NEG_SPEED_GMII BIT13 +#define ETH_ENABLE_AUTO_NEG_SPEED_GMII 0 +#define ETH_DTE_ADV_0 0 +#define ETH_DTE_ADV_1 BIT14 +#define ETH_DISABLE_AUTO_NEG_BYPASS 0 +#define ETH_ENABLE_AUTO_NEG_BYPASS BIT15 +#define ETH_AUTO_NEG_NO_CHANGE 0 +#define ETH_RESTART_AUTO_NEG BIT16 +#define ETH_MAX_RX_PACKET_1518BYTE 0 +#define ETH_MAX_RX_PACKET_1522BYTE BIT17 +#define ETH_MAX_RX_PACKET_1552BYTE BIT18 +#define ETH_MAX_RX_PACKET_9022BYTE (BIT18 | BIT17) +#define ETH_MAX_RX_PACKET_9192BYTE BIT19 +#define ETH_MAX_RX_PACKET_9700BYTE (BIT19 | BIT17) +#define ETH_SET_EXT_LOOPBACK BIT20 +#define ETH_CLR_EXT_LOOPBACK 0 +#define ETH_SET_FULL_DUPLEX_MODE BIT21 +#define ETH_SET_HALF_DUPLEX_MODE 0 +#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX BIT22 +#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 +#define ETH_SET_GMII_SPEED_TO_10_100 0 +#define ETH_SET_GMII_SPEED_TO_1000 BIT23 +#define ETH_SET_MII_SPEED_TO_10 0 +#define ETH_SET_MII_SPEED_TO_100 BIT24 + + +/* SMI reg */ +#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ +#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ +#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read operation */ +#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ + +/* SDMA command status fields macros */ + +/* Tx & Rx descriptors status */ +#define ETH_ERROR_SUMMARY (BIT0) + +/* Tx & Rx descriptors command */ +#define ETH_BUFFER_OWNED_BY_DMA (BIT31) + +/* Tx descriptors status */ +#define ETH_LC_ERROR (0 ) +#define ETH_UR_ERROR (BIT1 ) +#define ETH_RL_ERROR (BIT2 ) +#define ETH_LLC_SNAP_FORMAT (BIT9 ) + +/* Rx descriptors status */ +#define ETH_CRC_ERROR (0 ) +#define ETH_OVERRUN_ERROR (BIT1 ) +#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) +#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) +#define ETH_VLAN_TAGGED (BIT19) +#define ETH_BPDU_FRAME (BIT20) +#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) +#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) +#define ETH_OTHER_FRAME_TYPE (BIT22) +#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) +#define ETH_FRAME_TYPE_IP_V_4 (BIT24) +#define ETH_FRAME_HEADER_OK (BIT25) +#define ETH_RX_LAST_DESC (BIT26) +#define ETH_RX_FIRST_DESC (BIT27) +#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) +#define ETH_RX_ENABLE_INTERRUPT (BIT29) +#define ETH_LAYER_4_CHECKSUM_OK (BIT30) + +/* Rx descriptors byte count */ +#define ETH_FRAME_FRAGMENTED (BIT2) + +/* Tx descriptors command */ +#define ETH_LAYER_4_CHECKSUM_FIRST_DESC (BIT10) +#define ETH_FRAME_SET_TO_VLAN (BIT15) +#define ETH_TCP_FRAME (0 ) +#define ETH_UDP_FRAME (BIT16) +#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) +#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) +#define ETH_ZERO_PADDING (BIT19) +#define ETH_TX_LAST_DESC (BIT20) +#define ETH_TX_FIRST_DESC (BIT21) +#define ETH_GEN_CRC (BIT22) +#define ETH_TX_ENABLE_INTERRUPT (BIT23) +#define ETH_AUTO_MODE (BIT30) + +/* typedefs */ + +typedef enum _eth_func_ret_status { + ETH_OK, /* Returned as expected. */ + ETH_ERROR, /* Fundamental error. */ + ETH_RETRY, /* Could not process request. Try later. */ + ETH_END_OF_JOB, /* Ring has nothing to process. */ + ETH_QUEUE_FULL, /* Ring resource error. */ + ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ +} ETH_FUNC_RET_STATUS; + +typedef enum _eth_target { + ETH_TARGET_DRAM, + ETH_TARGET_DEVICE, + ETH_TARGET_CBS, + ETH_TARGET_PCI0, + ETH_TARGET_PCI1 +} ETH_TARGET; + +/* These are for big-endian machines. Little endian needs different + * definitions. + */ +#if defined(__BIG_ENDIAN) +struct eth_rx_desc { + u16 byte_cnt; /* Descriptor buffer byte count */ + u16 buf_size; /* Buffer size */ + u32 cmd_sts; /* Descriptor command status */ + u32 next_desc_ptr; /* Next descriptor pointer */ + u32 buf_ptr; /* Descriptor buffer pointer */ +}; + +struct eth_tx_desc { + u16 byte_cnt; /* buffer byte count */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u32 cmd_sts; /* Command/status field */ + u32 next_desc_ptr; /* Pointer to next descriptor */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ +}; + +#elif defined(__LITTLE_ENDIAN) +struct eth_rx_desc { + u32 cmd_sts; /* Descriptor command status */ + u16 buf_size; /* Buffer size */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u32 buf_ptr; /* Descriptor buffer pointer */ + u32 next_desc_ptr; /* Next descriptor pointer */ +}; + +struct eth_tx_desc { + u32 cmd_sts; /* Command/status field */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u16 byte_cnt; /* buffer byte count */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ + u32 next_desc_ptr; /* Pointer to next descriptor */ +}; +#else +#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined +#endif + +/* Unified struct for Rx and Tx operations. The user is not required to */ +/* be familier with neither Tx nor Rx descriptors. */ +struct pkt_info { + unsigned short byte_cnt; /* Descriptor buffer byte count */ + unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ + unsigned int cmd_sts; /* Descriptor command status */ + dma_addr_t buf_ptr; /* Descriptor buffer pointer */ + struct sk_buff * return_info; /* User resource return information */ +}; + + +/* Ethernet port specific infomation */ + +struct mv64340_private { + int port_num; /* User Ethernet port number */ + u8 port_mac_addr[6]; /* User defined port MAC address. */ + u32 port_config; /* User port configuration value */ + u32 port_config_extend; /* User port config extend value */ + u32 port_sdma_config; /* User port SDMA config value */ + u32 port_serial_control; /* User port serial control value */ + u32 port_tx_queue_command; /* Port active Tx queues summary */ + u32 port_rx_queue_command; /* Port active Rx queues summary */ + + int rx_resource_err; /* Rx ring resource error flag */ + int tx_resource_err; /* Tx ring resource error flag */ + + /* Tx/Rx rings managment indexes fields. For driver use */ + + /* Next available and first returning Rx resource */ + int rx_curr_desc_q, rx_used_desc_q; + + /* Next available and first returning Tx resource */ + int tx_curr_desc_q, tx_used_desc_q; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + int tx_first_desc_q; +#endif + +#ifdef MV64340_TX_FAST_REFILL + u32 tx_clean_threshold; +#endif + + volatile struct eth_rx_desc * p_rx_desc_area; + dma_addr_t rx_desc_dma; + unsigned int rx_desc_area_size; + struct sk_buff * rx_skb[MV64340_RX_QUEUE_SIZE]; + + volatile struct eth_tx_desc * p_tx_desc_area; + dma_addr_t tx_desc_dma; + unsigned int tx_desc_area_size; + struct sk_buff * tx_skb[MV64340_TX_QUEUE_SIZE]; + + struct work_struct tx_timeout_task; + + /* + * Former struct mv64340_eth_priv members start here + */ + struct net_device_stats stats; + spinlock_t lock; + /* Size of Tx Ring per queue */ + unsigned int tx_ring_size; + /* Ammont of SKBs outstanding on Tx queue */ + unsigned int tx_ring_skbs; + /* Size of Rx Ring per queue */ + unsigned int rx_ring_size; + /* Ammount of SKBs allocated to Rx Ring per queue */ + unsigned int rx_ring_skbs; + + /* + * rx_task used to fill RX ring out of bottom half context + */ + struct work_struct rx_task; + + /* + * Used in case RX Ring is empty, which can be caused when + * system does not have resources (skb's) + */ + struct timer_list timeout; + long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES))); + unsigned rx_timer_flag; + + u32 rx_int_coal; + u32 tx_int_coal; +}; + +/* ethernet.h API list */ + +/* Port operation control routines */ +static void eth_port_init(struct mv64340_private *mp); +static void eth_port_reset(unsigned int eth_port_num); +static int eth_port_start(struct mv64340_private *mp); + +static void ethernet_set_config_reg(unsigned int eth_port_num, + unsigned int value); +static unsigned int ethernet_get_config_reg(unsigned int eth_port_num); + +/* Port MAC address routines */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr); + +/* PHY and MIB routines */ +static int ethernet_phy_reset(unsigned int eth_port_num); + +static int eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, + unsigned int value); + +static int eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, + unsigned int *value); + +static void eth_clear_mib_counters(unsigned int eth_port_num); + +/* Port data flow control routines */ +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); + +#endif /* __MV64340_ETH_H__ */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index c4c9cb22a..c5f95959c 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -85,7 +85,7 @@ static char version[] = static struct myri_eth *root_myri_dev; #endif -static void myri_reset_off(unsigned long lp, unsigned long cregs) +static void myri_reset_off(void __iomem *lp, void __iomem *cregs) { /* Clear IRQ mask. */ sbus_writel(0, lp + LANAI_EIMASK); @@ -94,7 +94,7 @@ static void myri_reset_off(unsigned long lp, unsigned long cregs) sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL); } -static void myri_reset_on(unsigned long cregs) +static void myri_reset_on(void __iomem *cregs) { /* Enable RESET function. */ sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL); @@ -103,14 +103,14 @@ static void myri_reset_on(unsigned long cregs) sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); } -static void myri_disable_irq(unsigned long lp, unsigned long cregs) +static void myri_disable_irq(void __iomem *lp, void __iomem *cregs) { sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); sbus_writel(0, lp + LANAI_EIMASK); sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT); } -static void myri_enable_irq(unsigned long lp, unsigned long cregs) +static void myri_enable_irq(void __iomem *lp, void __iomem *cregs) { sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL); sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK); @@ -119,7 +119,7 @@ static void myri_enable_irq(unsigned long lp, unsigned long cregs) static inline void bang_the_chip(struct myri_eth *mp) { struct myri_shmem *shmem = mp->shmem; - unsigned long cregs = mp->cregs; + void __iomem *cregs = mp->cregs; sbus_writel(1, &shmem->send); sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL); @@ -128,7 +128,7 @@ static inline void bang_the_chip(struct myri_eth *mp) static int myri_do_handshake(struct myri_eth *mp) { struct myri_shmem *shmem = mp->shmem; - unsigned long cregs = mp->cregs; + void __iomem *cregs = mp->cregs; struct myri_channel *chan = &shmem->channel; int tick = 0; @@ -176,27 +176,27 @@ static int myri_do_handshake(struct myri_eth *mp) static int myri_load_lanai(struct myri_eth *mp) { struct net_device *dev = mp->dev; - struct myri_shmem *shmem = mp->shmem; - unsigned char *rptr; + struct myri_shmem __iomem *shmem = mp->shmem; + void __iomem *rptr; int i; myri_disable_irq(mp->lregs, mp->cregs); myri_reset_on(mp->cregs); - rptr = (unsigned char *) mp->lanai; + rptr = mp->lanai; for (i = 0; i < mp->eeprom.ramsz; i++) - sbus_writeb(0, &rptr[i]); + sbus_writeb(0, rptr + i); if (mp->eeprom.cpuvers >= CPUVERS_3_0) sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL); /* Load executable code. */ for (i = 0; i < sizeof(lanai4_code); i++) - sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]); + sbus_writeb(lanai4_code[i], rptr + (lanai4_code_off * 2) + i); /* Load data segment. */ for (i = 0; i < sizeof(lanai4_data); i++) - sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]); + sbus_writeb(lanai4_data[i], rptr + (lanai4_data_off * 2) + i); /* Set device address. */ sbus_writeb(0, &shmem->addr[0]); @@ -237,15 +237,15 @@ static int myri_load_lanai(struct myri_eth *mp) static void myri_clean_rings(struct myri_eth *mp) { - struct sendq *sq = mp->sq; - struct recvq *rq = mp->rq; + struct sendq __iomem *sq = mp->sq; + struct recvq __iomem *rq = mp->rq; int i; sbus_writel(0, &rq->tail); sbus_writel(0, &rq->head); for (i = 0; i < (RX_RING_SIZE+1); i++) { if (mp->rx_skbs[i] != NULL) { - struct myri_rxd *rxd = &rq->myri_rxd[i]; + struct myri_rxd __iomem *rxd = &rq->myri_rxd[i]; u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); @@ -261,7 +261,7 @@ static void myri_clean_rings(struct myri_eth *mp) for (i = 0; i < TX_RING_SIZE; i++) { if (mp->tx_skbs[i] != NULL) { struct sk_buff *skb = mp->tx_skbs[i]; - struct myri_txd *txd = &sq->myri_txd[i]; + struct myri_txd __iomem *txd = &sq->myri_txd[i]; u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); @@ -274,8 +274,8 @@ static void myri_clean_rings(struct myri_eth *mp) static void myri_init_rings(struct myri_eth *mp, int from_irq) { - struct recvq *rq = mp->rq; - struct myri_rxd *rxd = &rq->myri_rxd[0]; + struct recvq __iomem *rq = mp->rq; + struct myri_rxd __iomem *rxd = &rq->myri_rxd[0]; struct net_device *dev = mp->dev; int gfp_flags = GFP_KERNEL; int i; @@ -343,7 +343,7 @@ static void dump_ehdr_and_myripad(unsigned char *stuff) static void myri_tx(struct myri_eth *mp, struct net_device *dev) { - struct sendq *sq = mp->sq; + struct sendq __iomem *sq= mp->sq; int entry = mp->tx_old; int limit = sbus_readl(&sq->head); @@ -376,7 +376,7 @@ static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *de skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN); skb_pull(skb, dev->hard_header_len); - eth = skb->mac.ethernet; + eth = eth_hdr(skb); #ifdef DEBUG_HEADER DHDR(("myri_type_trans: ")); @@ -411,8 +411,8 @@ static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *de static void myri_rx(struct myri_eth *mp, struct net_device *dev) { - struct recvq *rq = mp->rq; - struct recvq *rqa = mp->rqack; + struct recvq __iomem *rq = mp->rq; + struct recvq __iomem *rqa = mp->rqack; int entry = sbus_readl(&rqa->head); int limit = sbus_readl(&rqa->tail); int drops; @@ -423,11 +423,11 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) drops = 0; DRX(("\n")); while (entry != limit) { - struct myri_rxd *rxdack = &rqa->myri_rxd[entry]; + struct myri_rxd __iomem *rxdack = &rqa->myri_rxd[entry]; u32 csum = sbus_readl(&rxdack->csum); int len = sbus_readl(&rxdack->myri_scatters[0].len); int index = sbus_readl(&rxdack->ctx); - struct myri_rxd *rxd = &rq->myri_rxd[rq->tail]; + struct myri_rxd __iomem *rxd = &rq->myri_rxd[rq->tail]; struct sk_buff *skb = mp->rx_skbs[index]; /* Ack it. */ @@ -545,7 +545,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct myri_eth *mp = (struct myri_eth *) dev->priv; - unsigned long lregs = mp->lregs; + void __iomem *lregs = mp->lregs; struct myri_channel *chan = &mp->shmem->channel; unsigned long flags; u32 status; @@ -610,8 +610,8 @@ static void myri_tx_timeout(struct net_device *dev) static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct myri_eth *mp = (struct myri_eth *) dev->priv; - struct sendq *sq = mp->sq; - struct myri_txd *txd; + struct sendq __iomem *sq = mp->sq; + struct myri_txd __iomem *txd; unsigned long flags; unsigned int head, tail; int len, entry; @@ -998,22 +998,20 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num) printk("MyriCOM: Cannot map MyriCOM registers.\n"); goto err; } - mp->lanai = (unsigned short *) (mp->regs + (256 * 1024)); - mp->lanai3 = (unsigned int *) mp->lanai; - mp->lregs = (unsigned long) &mp->lanai[0x10000]; + mp->lanai = mp->regs + (256 * 1024); + mp->lregs = mp->lanai + (0x10000 * 2); } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); mp->cregs = sbus_ioremap(&sdev->resource[0], 0, PAGE_SIZE, "MyriCOM Control Regs"); mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), PAGE_SIZE, "MyriCOM LANAI Regs"); - mp->lanai = (unsigned short *) + mp->lanai = sbus_ioremap(&sdev->resource[0], (512 * 1024), mp->eeprom.ramsz, "MyriCOM SRAM"); - mp->lanai3 = (unsigned int *) mp->lanai; } - DET(("Registers mapped: cregs[%lx] lregs[%lx] lanai[%p] lanai3[%p]\n", - mp->cregs, mp->lregs, mp->lanai, mp->lanai3)); + DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n", + mp->cregs, mp->lregs, mp->lanai)); if (mp->eeprom.cpuvers >= CPUVERS_4_0) mp->shmem_base = 0xf000; @@ -1022,7 +1020,8 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num) DET(("Shared memory base is %04x, ", mp->shmem_base)); - mp->shmem = (struct myri_shmem *) &mp->lanai[mp->shmem_base]; + mp->shmem = (struct myri_shmem __iomem *) + (mp->lanai + (mp->shmem_base * 2)); DET(("shmem mapped at %p\n", mp->shmem)); mp->rqack = &mp->shmem->channel.recvqa; diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 944ddfa65..9391e55a5 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -270,22 +270,21 @@ struct myri_eth { * to obtain good cache hit rates. */ spinlock_t irq_lock; - struct myri_shmem *shmem; /* Shared data structures. */ - unsigned long cregs; /* Control register space. */ - struct recvq *rqack; /* Where we ack rx's. */ - struct recvq *rq; /* Where we put buffers. */ - struct sendq *sq; /* Where we stuff tx's. */ + struct myri_shmem __iomem *shmem; /* Shared data structures. */ + void __iomem *cregs; /* Control register space. */ + struct recvq __iomem *rqack; /* Where we ack rx's. */ + struct recvq __iomem *rq; /* Where we put buffers. */ + struct sendq __iomem *sq; /* Where we stuff tx's. */ struct net_device *dev; /* Linux/NET dev struct. */ int tx_old; /* To speed up tx cleaning. */ - unsigned long lregs; /* Quick ptr to LANAI regs. */ + void __iomem *lregs; /* Quick ptr to LANAI regs. */ struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */ struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */ struct net_device_stats enet_stats; /* Interface stats. */ /* These are less frequently accessed. */ - unsigned long regs; /* MyriCOM register space. */ - unsigned short *lanai; /* View 2 of register space. */ - unsigned int *lanai3; /* View 3 of register space. */ + void __iomem *regs; /* MyriCOM register space. */ + void __iomem *lanai; /* View 2 of register space. */ unsigned int myri_bursts; /* SBUS bursts. */ struct myri_eeprom eeprom; /* Local copy of EEPROM. */ unsigned int reg_size; /* Size of register space. */ diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 88c626afe..fd44cb722 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -719,7 +719,7 @@ struct netdev_private { }; static void move_int_phy(struct net_device *dev, int addr); -static int eeprom_read(long ioaddr, int location); +static int eeprom_read(void __iomem *ioaddr, int location); static int mdio_read(struct net_device *dev, int reg); static void mdio_write(struct net_device *dev, int reg, u16 data); static void init_phy_fixup(struct net_device *dev); @@ -750,6 +750,9 @@ static void netdev_error(struct net_device *dev, int intr_status); static void netdev_rx(struct net_device *dev); static void netdev_tx_done(struct net_device *dev); static int natsemi_change_mtu(struct net_device *dev, int new_mtu); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void natsemi_poll_controller(struct net_device *dev); +#endif static void __set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void __get_stats(struct net_device *dev); @@ -766,9 +769,15 @@ static int netdev_close(struct net_device *dev); static int netdev_get_regs(struct net_device *dev, u8 *buf); static int netdev_get_eeprom(struct net_device *dev, u8 *buf); +static inline void __iomem *ns_ioaddr(struct net_device *dev) +{ + return (void __iomem *) dev->base_addr; +} + static void move_int_phy(struct net_device *dev, int addr) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); int target = 31; /* @@ -785,8 +794,8 @@ static void move_int_phy(struct net_device *dev, int addr) target--; if (target == np->phy_addr_external) target--; - writew(target, dev->base_addr + PhyCtrl); - readw(dev->base_addr + PhyCtrl); + writew(target, ioaddr + PhyCtrl); + readw(ioaddr + PhyCtrl); udelay(1); } @@ -797,7 +806,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, struct netdev_private *np; int i, option, irq, chip_idx = ent->driver_data; static int find_cnt = -1; - unsigned long ioaddr, iosize; + unsigned long iostart, iosize; + void __iomem *ioaddr; const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp; @@ -824,7 +834,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, } find_cnt++; - ioaddr = pci_resource_start(pdev, pcibar); + iostart = pci_resource_start(pdev, pcibar); iosize = pci_resource_len(pdev, pcibar); irq = pdev->irq; @@ -841,7 +851,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (i) goto err_pci_request_regions; - ioaddr = (unsigned long) ioremap (ioaddr, iosize); + ioaddr = ioremap(iostart, iosize); if (!ioaddr) { i = -ENOMEM; goto err_ioremap; @@ -856,7 +866,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, prev_eedata = eedata; } - dev->base_addr = ioaddr; + dev->base_addr = (unsigned long __force) ioaddr; dev->irq = irq; np = netdev_priv(dev); @@ -876,7 +886,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, * The address would be used to access a phy over the mii bus, but * the internal phy is accessed through mapped registers. */ - if (readl(dev->base_addr + ChipConfig) & CfgExtPhy) + if (readl(ioaddr + ChipConfig) & CfgExtPhy) dev->if_port = PORT_MII; else dev->if_port = PORT_TP; @@ -920,6 +930,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &natsemi_poll_controller; +#endif if (mtu) dev->mtu = mtu; @@ -965,7 +978,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (netif_msg_drv(np)) { printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr, + dev->name, natsemi_pci_info[chip_idx].name, iostart, pci_name(np->pci_dev)); for (i = 0; i < ETH_ALEN-1; i++) printk("%02x:", dev->dev_addr[i]); @@ -978,7 +991,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, return 0; err_register_netdev: - iounmap ((void *) dev->base_addr); + iounmap(ioaddr); err_ioremap: pci_release_regions(pdev); @@ -1010,12 +1023,13 @@ enum EEPROM_Cmds { EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), }; -static int eeprom_read(long addr, int location) +static int eeprom_read(void __iomem *addr, int location) { int i; int retval = 0; - long ee_addr = addr + EECtrl; + void __iomem *ee_addr = addr + EECtrl; int read_cmd = location | EE_ReadCmd; + writel(EE_Write0, ee_addr); /* Shift the read command bits out. */ @@ -1052,33 +1066,35 @@ static int eeprom_read(long addr, int location) /* clock transitions >= 20ns (25MHz) * One readl should be good to PCI @ 100MHz */ -#define mii_delay(dev) readl(dev->base_addr + EECtrl) +#define mii_delay(ioaddr) readl(ioaddr + EECtrl) static int mii_getbit (struct net_device *dev) { int data; + void __iomem *ioaddr = ns_ioaddr(dev); - writel(MII_ShiftClk, dev->base_addr + EECtrl); - data = readl(dev->base_addr + EECtrl); - writel(0, dev->base_addr + EECtrl); - mii_delay(dev); + writel(MII_ShiftClk, ioaddr + EECtrl); + data = readl(ioaddr + EECtrl); + writel(0, ioaddr + EECtrl); + mii_delay(ioaddr); return (data & MII_Data)? 1 : 0; } static void mii_send_bits (struct net_device *dev, u32 data, int len) { u32 i; + void __iomem *ioaddr = ns_ioaddr(dev); for (i = (1 << (len-1)); i; i >>= 1) { u32 mdio_val = MII_Write | ((data & i)? MII_Data : 0); - writel(mdio_val, dev->base_addr + EECtrl); - mii_delay(dev); - writel(mdio_val | MII_ShiftClk, dev->base_addr + EECtrl); - mii_delay(dev); + writel(mdio_val, ioaddr + EECtrl); + mii_delay(ioaddr); + writel(mdio_val | MII_ShiftClk, ioaddr + EECtrl); + mii_delay(ioaddr); } - writel(0, dev->base_addr + EECtrl); - mii_delay(dev); + writel(0, ioaddr + EECtrl); + mii_delay(ioaddr); } static int miiport_read(struct net_device *dev, int phy_id, int reg) @@ -1123,13 +1139,14 @@ static void miiport_write(struct net_device *dev, int phy_id, int reg, u16 data) static int mdio_read(struct net_device *dev, int reg) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); /* The 83815 series has two ports: * - an internal transceiver * - an external mii bus */ if (dev->if_port == PORT_TP) - return readw(dev->base_addr+BasicControl+(reg<<2)); + return readw(ioaddr+BasicControl+(reg<<2)); else return miiport_read(dev, np->phy_addr_external, reg); } @@ -1137,10 +1154,11 @@ static int mdio_read(struct net_device *dev, int reg) static void mdio_write(struct net_device *dev, int reg, u16 data) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); /* The 83815 series has an internal transceiver; handle separately */ if (dev->if_port == PORT_TP) - writew(data, dev->base_addr+BasicControl+(reg<<2)); + writew(data, ioaddr+BasicControl+(reg<<2)); else miiport_write(dev, np->phy_addr_external, reg, data); } @@ -1148,7 +1166,7 @@ static void mdio_write(struct net_device *dev, int reg, u16 data) static void init_phy_fixup(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ns_ioaddr(dev); int i; u32 cfg; u16 tmp; @@ -1180,7 +1198,7 @@ static void init_phy_fixup(struct net_device *dev) */ } mdio_write(dev, MII_BMCR, tmp); - readl(dev->base_addr + ChipConfig); + readl(ioaddr + ChipConfig); udelay(1); /* find out what phy this is */ @@ -1202,7 +1220,7 @@ static void init_phy_fixup(struct net_device *dev) default: break; } - cfg = readl(dev->base_addr + ChipConfig); + cfg = readl(ioaddr + ChipConfig); if (cfg & CfgExtPhy) return; @@ -1260,9 +1278,10 @@ static void init_phy_fixup(struct net_device *dev) static int switch_port_external(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); u32 cfg; - cfg = readl(dev->base_addr + ChipConfig); + cfg = readl(ioaddr + ChipConfig); if (cfg & CfgExtPhy) return 0; @@ -1272,8 +1291,8 @@ static int switch_port_external(struct net_device *dev) } /* 1) switch back to external phy */ - writel(cfg | (CfgExtPhy | CfgPhyDis), dev->base_addr + ChipConfig); - readl(dev->base_addr + ChipConfig); + writel(cfg | (CfgExtPhy | CfgPhyDis), ioaddr + ChipConfig); + readl(ioaddr + ChipConfig); udelay(1); /* 2) reset the external phy: */ @@ -1292,11 +1311,12 @@ static int switch_port_external(struct net_device *dev) static int switch_port_internal(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); int i; u32 cfg; u16 bmcr; - cfg = readl(dev->base_addr + ChipConfig); + cfg = readl(ioaddr + ChipConfig); if (!(cfg &CfgExtPhy)) return 0; @@ -1306,17 +1326,17 @@ static int switch_port_internal(struct net_device *dev) } /* 1) switch back to internal phy: */ cfg = cfg & ~(CfgExtPhy | CfgPhyDis); - writel(cfg, dev->base_addr + ChipConfig); - readl(dev->base_addr + ChipConfig); + writel(cfg, ioaddr + ChipConfig); + readl(ioaddr + ChipConfig); udelay(1); /* 2) reset the internal phy: */ - bmcr = readw(dev->base_addr+BasicControl+(MII_BMCR<<2)); - writel(bmcr | BMCR_RESET, dev->base_addr+BasicControl+(MII_BMCR<<2)); - readl(dev->base_addr + ChipConfig); + bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2)); + writel(bmcr | BMCR_RESET, ioaddr+BasicControl+(MII_BMCR<<2)); + readl(ioaddr + ChipConfig); udelay(10); for (i=0;ibase_addr+BasicControl+(MII_BMCR<<2)); + bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2)); if (!(bmcr & BMCR_RESET)) break; udelay(10); @@ -1392,6 +1412,7 @@ static void natsemi_reset(struct net_device *dev) u16 pmatch[3]; u16 sopass[3]; struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); /* * Resetting the chip causes some registers to be lost. @@ -1402,26 +1423,26 @@ static void natsemi_reset(struct net_device *dev) */ /* CFG */ - cfg = readl(dev->base_addr + ChipConfig) & CFG_RESET_SAVE; + cfg = readl(ioaddr + ChipConfig) & CFG_RESET_SAVE; /* WCSR */ - wcsr = readl(dev->base_addr + WOLCmd) & WCSR_RESET_SAVE; + wcsr = readl(ioaddr + WOLCmd) & WCSR_RESET_SAVE; /* RFCR */ - rfcr = readl(dev->base_addr + RxFilterAddr) & RFCR_RESET_SAVE; + rfcr = readl(ioaddr + RxFilterAddr) & RFCR_RESET_SAVE; /* PMATCH */ for (i = 0; i < 3; i++) { - writel(i*2, dev->base_addr + RxFilterAddr); - pmatch[i] = readw(dev->base_addr + RxFilterData); + writel(i*2, ioaddr + RxFilterAddr); + pmatch[i] = readw(ioaddr + RxFilterData); } /* SOPAS */ for (i = 0; i < 3; i++) { - writel(0xa+(i*2), dev->base_addr + RxFilterAddr); - sopass[i] = readw(dev->base_addr + RxFilterData); + writel(0xa+(i*2), ioaddr + RxFilterAddr); + sopass[i] = readw(ioaddr + RxFilterData); } /* now whack the chip */ - writel(ChipReset, dev->base_addr + ChipCmd); + writel(ChipReset, ioaddr + ChipCmd); for (i=0;ibase_addr + ChipCmd) & ChipReset)) + if (!(readl(ioaddr + ChipCmd) & ChipReset)) break; udelay(5); } @@ -1434,40 +1455,41 @@ static void natsemi_reset(struct net_device *dev) } /* restore CFG */ - cfg |= readl(dev->base_addr + ChipConfig) & ~CFG_RESET_SAVE; + cfg |= readl(ioaddr + ChipConfig) & ~CFG_RESET_SAVE; /* turn on external phy if it was selected */ if (dev->if_port == PORT_TP) cfg &= ~(CfgExtPhy | CfgPhyDis); else cfg |= (CfgExtPhy | CfgPhyDis); - writel(cfg, dev->base_addr + ChipConfig); + writel(cfg, ioaddr + ChipConfig); /* restore WCSR */ - wcsr |= readl(dev->base_addr + WOLCmd) & ~WCSR_RESET_SAVE; - writel(wcsr, dev->base_addr + WOLCmd); + wcsr |= readl(ioaddr + WOLCmd) & ~WCSR_RESET_SAVE; + writel(wcsr, ioaddr + WOLCmd); /* read RFCR */ - rfcr |= readl(dev->base_addr + RxFilterAddr) & ~RFCR_RESET_SAVE; + rfcr |= readl(ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE; /* restore PMATCH */ for (i = 0; i < 3; i++) { - writel(i*2, dev->base_addr + RxFilterAddr); - writew(pmatch[i], dev->base_addr + RxFilterData); + writel(i*2, ioaddr + RxFilterAddr); + writew(pmatch[i], ioaddr + RxFilterData); } for (i = 0; i < 3; i++) { - writel(0xa+(i*2), dev->base_addr + RxFilterAddr); - writew(sopass[i], dev->base_addr + RxFilterData); + writel(0xa+(i*2), ioaddr + RxFilterAddr); + writew(sopass[i], ioaddr + RxFilterData); } /* restore RFCR */ - writel(rfcr, dev->base_addr + RxFilterAddr); + writel(rfcr, ioaddr + RxFilterAddr); } static void natsemi_reload_eeprom(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); int i; - writel(EepromReload, dev->base_addr + PCIBusCfg); + writel(EepromReload, ioaddr + PCIBusCfg); for (i=0;ibase_addr + PCIBusCfg) & EepromReload)) + if (!(readl(ioaddr + PCIBusCfg) & EepromReload)) break; } if (i==NATSEMI_HW_TIMEOUT) { @@ -1481,7 +1503,7 @@ static void natsemi_reload_eeprom(struct net_device *dev) static void natsemi_stop_rxtx(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); int i; @@ -1503,7 +1525,7 @@ static void natsemi_stop_rxtx(struct net_device *dev) static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); int i; /* Reset the chip, just in case. */ @@ -1552,6 +1574,7 @@ static int netdev_open(struct net_device *dev) static void do_cable_magic(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); if (dev->if_port != PORT_TP) return; @@ -1565,15 +1588,15 @@ static void do_cable_magic(struct net_device *dev) * activity LED while idle. This process is based on instructions * from engineers at National. */ - if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) { + if (readl(ioaddr + ChipConfig) & CfgSpeed100) { u16 data; - writew(1, dev->base_addr + PGSEL); + writew(1, ioaddr + PGSEL); /* * coefficient visibility should already be enabled via * DSPCFG | 0x1000 */ - data = readw(dev->base_addr + TSTDAT) & 0xff; + data = readw(ioaddr + TSTDAT) & 0xff; /* * the value must be negative, and within certain values * (these values all come from National) @@ -1582,13 +1605,13 @@ static void do_cable_magic(struct net_device *dev) struct netdev_private *np = netdev_priv(dev); /* the bug has been triggered - fix the coefficient */ - writew(TSTDAT_FIXED, dev->base_addr + TSTDAT); + writew(TSTDAT_FIXED, ioaddr + TSTDAT); /* lock the value */ - data = readw(dev->base_addr + DSPCFG); + data = readw(ioaddr + DSPCFG); np->dspcfg = data | DSPCFG_LOCK; - writew(np->dspcfg, dev->base_addr + DSPCFG); + writew(np->dspcfg, ioaddr + DSPCFG); } - writew(0, dev->base_addr + PGSEL); + writew(0, ioaddr + PGSEL); } } @@ -1596,6 +1619,7 @@ static void undo_cable_magic(struct net_device *dev) { u16 data; struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); if (dev->if_port != PORT_TP) return; @@ -1603,18 +1627,18 @@ static void undo_cable_magic(struct net_device *dev) if (np->srr >= SRR_DP83816_A5) return; - writew(1, dev->base_addr + PGSEL); + writew(1, ioaddr + PGSEL); /* make sure the lock bit is clear */ - data = readw(dev->base_addr + DSPCFG); + data = readw(ioaddr + DSPCFG); np->dspcfg = data & ~DSPCFG_LOCK; - writew(np->dspcfg, dev->base_addr + DSPCFG); - writew(0, dev->base_addr + PGSEL); + writew(np->dspcfg, ioaddr + DSPCFG); + writew(0, ioaddr + PGSEL); } static void check_link(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); int duplex; u16 bmsr; @@ -1675,7 +1699,7 @@ static void check_link(struct net_device *dev) static void init_registers(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); init_phy_fixup(dev); @@ -1754,6 +1778,7 @@ static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); int next_tick = 5*HZ; if (netif_msg_timer(np)) { @@ -1765,7 +1790,6 @@ static void netdev_timer(unsigned long data) } if (dev->if_port == PORT_TP) { - long ioaddr = dev->base_addr; u16 dspcfg; spin_lock_irq(&np->lock); @@ -1808,7 +1832,7 @@ static void netdev_timer(unsigned long data) refill_rx(dev); enable_irq(dev->irq); if (!np->oom) { - writel(RxOn, dev->base_addr + ChipCmd); + writel(RxOn, ioaddr + ChipCmd); } else { next_tick = 1; } @@ -1842,7 +1866,7 @@ static void dump_ring(struct net_device *dev) static void tx_timeout(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); disable_irq(dev->irq); spin_lock_irq(&np->lock); @@ -2042,6 +2066,7 @@ static void reinit_ring(struct net_device *dev) static int start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); unsigned entry; /* Note: Ordering is important here, set the field with the @@ -2070,7 +2095,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } /* Wake the potentially-idle transmit channel. */ - writel(TxOn, dev->base_addr + ChipCmd); + writel(TxOn, ioaddr + ChipCmd); } else { dev_kfree_skb_irq(skb); np->stats.tx_dropped++; @@ -2135,7 +2160,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs { struct net_device *dev = dev_instance; struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); int boguscnt = max_interrupt_work; unsigned int handled = 0; @@ -2197,6 +2222,7 @@ static void netdev_rx(struct net_device *dev) int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); unsigned int buflen = np->rx_buf_sz; + void __iomem * ioaddr = ns_ioaddr(dev); /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ @@ -2278,13 +2304,13 @@ static void netdev_rx(struct net_device *dev) if (np->oom) mod_timer(&np->timer, jiffies + 1); else - writel(RxOn, dev->base_addr + ChipCmd); + writel(RxOn, ioaddr + ChipCmd); } static void netdev_error(struct net_device *dev, int intr_status) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); spin_lock(&np->lock); if (intr_status & LinkChange) { @@ -2343,7 +2369,7 @@ static void netdev_error(struct net_device *dev, int intr_status) static void __get_stats(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); /* The chip only need report frame silently dropped. */ @@ -2364,10 +2390,19 @@ static struct net_device_stats *get_stats(struct net_device *dev) return &np->stats; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void natsemi_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + intr_handler(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + #define HASH_TABLE 0x200 static void __set_rx_mode(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); u8 mc_filter[64]; /* Multicast hash filter */ u32 rx_mode; @@ -2413,7 +2448,7 @@ static int natsemi_change_mtu(struct net_device *dev, int new_mtu) /* synchronized against open : rtnl_lock() held by caller */ if (netif_running(dev)) { struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); disable_irq(dev->irq); spin_lock(&np->lock); @@ -2616,7 +2651,8 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) static int netdev_set_wol(struct net_device *dev, u32 newval) { struct netdev_private *np = netdev_priv(dev); - u32 data = readl(dev->base_addr + WOLCmd) & ~WakeOptsSummary; + void __iomem * ioaddr = ns_ioaddr(dev); + u32 data = readl(ioaddr + WOLCmd) & ~WakeOptsSummary; /* translate to bitmasks this chip understands */ if (newval & WAKE_PHY) @@ -2637,7 +2673,7 @@ static int netdev_set_wol(struct net_device *dev, u32 newval) } } - writel(data, dev->base_addr + WOLCmd); + writel(data, ioaddr + WOLCmd); return 0; } @@ -2645,7 +2681,8 @@ static int netdev_set_wol(struct net_device *dev, u32 newval) static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur) { struct netdev_private *np = netdev_priv(dev); - u32 regval = readl(dev->base_addr + WOLCmd); + void __iomem * ioaddr = ns_ioaddr(dev); + u32 regval = readl(ioaddr + WOLCmd); *supported = (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | WAKE_MAGIC); @@ -2680,6 +2717,7 @@ static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur) static int netdev_set_sopass(struct net_device *dev, u8 *newval) { struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); u16 *sval = (u16 *)newval; u32 addr; @@ -2688,22 +2726,22 @@ static int netdev_set_sopass(struct net_device *dev, u8 *newval) } /* enable writing to these registers by disabling the RX filter */ - addr = readl(dev->base_addr + RxFilterAddr) & ~RFCRAddressMask; + addr = readl(ioaddr + RxFilterAddr) & ~RFCRAddressMask; addr &= ~RxFilterEnable; - writel(addr, dev->base_addr + RxFilterAddr); + writel(addr, ioaddr + RxFilterAddr); /* write the three words to (undocumented) RFCR vals 0xa, 0xc, 0xe */ - writel(addr | 0xa, dev->base_addr + RxFilterAddr); - writew(sval[0], dev->base_addr + RxFilterData); + writel(addr | 0xa, ioaddr + RxFilterAddr); + writew(sval[0], ioaddr + RxFilterData); - writel(addr | 0xc, dev->base_addr + RxFilterAddr); - writew(sval[1], dev->base_addr + RxFilterData); + writel(addr | 0xc, ioaddr + RxFilterAddr); + writew(sval[1], ioaddr + RxFilterData); - writel(addr | 0xe, dev->base_addr + RxFilterAddr); - writew(sval[2], dev->base_addr + RxFilterData); + writel(addr | 0xe, ioaddr + RxFilterAddr); + writew(sval[2], ioaddr + RxFilterData); /* re-enable the RX filter */ - writel(addr | RxFilterEnable, dev->base_addr + RxFilterAddr); + writel(addr | RxFilterEnable, ioaddr + RxFilterAddr); return 0; } @@ -2711,6 +2749,7 @@ static int netdev_set_sopass(struct net_device *dev, u8 *newval) static int netdev_get_sopass(struct net_device *dev, u8 *data) { struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); u16 *sval = (u16 *)data; u32 addr; @@ -2720,18 +2759,18 @@ static int netdev_get_sopass(struct net_device *dev, u8 *data) } /* read the three words from (undocumented) RFCR vals 0xa, 0xc, 0xe */ - addr = readl(dev->base_addr + RxFilterAddr) & ~RFCRAddressMask; + addr = readl(ioaddr + RxFilterAddr) & ~RFCRAddressMask; - writel(addr | 0xa, dev->base_addr + RxFilterAddr); - sval[0] = readw(dev->base_addr + RxFilterData); + writel(addr | 0xa, ioaddr + RxFilterAddr); + sval[0] = readw(ioaddr + RxFilterData); - writel(addr | 0xc, dev->base_addr + RxFilterAddr); - sval[1] = readw(dev->base_addr + RxFilterData); + writel(addr | 0xc, ioaddr + RxFilterAddr); + sval[1] = readw(ioaddr + RxFilterData); - writel(addr | 0xe, dev->base_addr + RxFilterAddr); - sval[2] = readw(dev->base_addr + RxFilterData); + writel(addr | 0xe, ioaddr + RxFilterAddr); + sval[2] = readw(ioaddr + RxFilterData); - writel(addr, dev->base_addr + RxFilterAddr); + writel(addr, ioaddr + RxFilterAddr); return 0; } @@ -2894,10 +2933,11 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf) int j; u32 rfcr; u32 *rbuf = (u32 *)buf; + void __iomem * ioaddr = ns_ioaddr(dev); /* read non-mii page 0 of registers */ for (i = 0; i < NATSEMI_PG0_NREGS/2; i++) { - rbuf[i] = readl(dev->base_addr + i*4); + rbuf[i] = readl(ioaddr + i*4); } /* read current mii registers */ @@ -2905,20 +2945,20 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf) rbuf[i] = mdio_read(dev, i & 0x1f); /* read only the 'magic' registers from page 1 */ - writew(1, dev->base_addr + PGSEL); - rbuf[i++] = readw(dev->base_addr + PMDCSR); - rbuf[i++] = readw(dev->base_addr + TSTDAT); - rbuf[i++] = readw(dev->base_addr + DSPCFG); - rbuf[i++] = readw(dev->base_addr + SDCFG); - writew(0, dev->base_addr + PGSEL); + writew(1, ioaddr + PGSEL); + rbuf[i++] = readw(ioaddr + PMDCSR); + rbuf[i++] = readw(ioaddr + TSTDAT); + rbuf[i++] = readw(ioaddr + DSPCFG); + rbuf[i++] = readw(ioaddr + SDCFG); + writew(0, ioaddr + PGSEL); /* read RFCR indexed registers */ - rfcr = readl(dev->base_addr + RxFilterAddr); + rfcr = readl(ioaddr + RxFilterAddr); for (j = 0; j < NATSEMI_RFDR_NREGS; j++) { - writel(j*2, dev->base_addr + RxFilterAddr); - rbuf[i++] = readw(dev->base_addr + RxFilterData); + writel(j*2, ioaddr + RxFilterAddr); + rbuf[i++] = readw(ioaddr + RxFilterData); } - writel(rfcr, dev->base_addr + RxFilterAddr); + writel(rfcr, ioaddr + RxFilterAddr); /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { @@ -2943,10 +2983,11 @@ static int netdev_get_eeprom(struct net_device *dev, u8 *buf) { int i; u16 *ebuf = (u16 *)buf; + void __iomem * ioaddr = ns_ioaddr(dev); /* eeprom_read reads 16 bits, and indexes by 16 bits */ for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) { - ebuf[i] = eeprom_read(dev->base_addr, i); + ebuf[i] = eeprom_read(ioaddr, i); /* The EEPROM itself stores data bit-swapped, but eeprom_read * reads it back "sanely". So we swap it back here in order to * present it to userland as it is stored. */ @@ -3016,7 +3057,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static void enable_wol_mode(struct net_device *dev, int enable_intr) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); if (netif_msg_wol(np)) @@ -3049,7 +3090,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr) static int netdev_close(struct net_device *dev) { - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); if (netif_msg_ifdown(np)) @@ -3126,10 +3167,11 @@ static int netdev_close(struct net_device *dev) static void __devexit natsemi_remove1 (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + void __iomem * ioaddr = ns_ioaddr(dev); unregister_netdev (dev); pci_release_regions (pdev); - iounmap ((char *) dev->base_addr); + iounmap(ioaddr); free_netdev (dev); pci_set_drvdata(pdev, NULL); } @@ -3163,7 +3205,7 @@ static int natsemi_suspend (struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem * ioaddr = ns_ioaddr(dev); rtnl_lock(); if (netif_running (dev)) { diff --git a/drivers/net/ne.c b/drivers/net/ne.c index a4116f136..d9a9a0bb7 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -29,6 +29,7 @@ last in cleanup_modue() Richard Guenther : Added support for ISAPnP cards Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead. + Hayato Fujiwara : Add m32r support. */ @@ -128,6 +129,14 @@ bad_clone_list[] __initdata = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ +#ifdef CONFIG_PLAT_MAPPI +# define DCR_VAL 0x4b +#elif CONFIG_PLAT_OAKS32R +# define DCR_VAL 0x48 +#else +# define DCR_VAL 0x49 +#endif + static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_probe_isapnp(struct net_device *dev); @@ -387,7 +396,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 16; i++) SA_prom[i] = SA_prom[i+i]; /* We must set the 8390 for word mode. */ - outb_p(0x49, ioaddr + EN0_DCFG); + outb_p(DCR_VAL, ioaddr + EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; } else { @@ -395,7 +404,12 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) stop_page = NE1SM_STOP_PG; } +#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) + neX000 = ((SA_prom[14] == 0x57 && SA_prom[15] == 0x57) + || (SA_prom[14] == 0x42 && SA_prom[15] == 0x42)); +#else neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); +#endif ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00); @@ -476,10 +490,20 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; +#ifdef CONFIG_PLAT_MAPPI + outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, + ioaddr + E8390_CMD); /* 0x61 */ + for (i = 0 ; i < ETHER_ADDR_LEN ; i++) { + dev->dev_addr[i] = SA_prom[i] + = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); + printk(" %2.2x", SA_prom[i]); + } +#else for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; } +#endif printk("\n%s: %s found at %#x, using IRQ %d.\n", dev->name, name, ioaddr, dev->irq); @@ -487,7 +511,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; +#ifdef CONFIG_PLAT_OAKS32R + ei_status.word16 = 0; +#else ei_status.word16 = (wordlength == 2); +#endif ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 43f923c96..937b6198c 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -547,7 +547,7 @@ static unsigned short plip_type_trans(struct sk_buff *skb, struct net_device *de skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); - eth= skb->mac.ethernet; + eth = eth_hdr(skb); if(*eth->h_dest&1) { diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index e44b189c6..b64f284c1 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -122,6 +122,9 @@ static struct ppp_channel_ops async_ops = { * frees the memory that ppp_asynctty_receive is using. The best * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. + * + * FIXME: this is no longer true. The _close path for the ldisc is + * now guaranteed to be sane. */ static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; @@ -144,7 +147,8 @@ static void ap_put(struct asyncppp *ap) } /* - * Called when a tty is put into PPP line discipline. + * Called when a tty is put into PPP line discipline. Called in process + * context. */ static int ppp_asynctty_open(struct tty_struct *tty) @@ -255,6 +259,11 @@ ppp_asynctty_write(struct tty_struct *tty, struct file *file, return -EAGAIN; } +/* + * Called in process context only. May be re-entered by multiple + * ioctl calling threads. + */ + static int ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) @@ -716,7 +725,8 @@ flush: /* * Flush output from our internal buffers. - * Called for the TCFLSH ioctl. + * Called for the TCFLSH ioctl. Can be entered in parallel + * but this is covered by the xmit_lock. */ static void ppp_async_flush_output(struct asyncppp *ap) @@ -816,7 +826,9 @@ process_input_packet(struct asyncppp *ap) skb_trim(skb, 0); } -/* called when the tty driver has data for us. */ +/* Called when the tty driver has data for us. Runs parallel with the + other ldisc functions but will not be re-entered */ + static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf, char *flags, int count) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 651601105..a56741087 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1595,6 +1595,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb->mac.raw = skb->data; + skb->input_dev = ppp->dev; netif_rx(skb); ppp->dev->last_rx = jiffies; } diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index a8f890858..a59c8f354 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -175,6 +175,8 @@ ppp_print_buffer (const char *name, const __u8 *buf, int count) * frees the memory that ppp_synctty_receive is using. The best * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. + * + * FIXME: Fixed in tty_io nowdays. */ static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 64b35cc25..672e3cd2d 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -391,7 +391,7 @@ static int pppoe_rcv(struct sk_buff *skb, ph = (struct pppoe_hdr *) skb->nh.raw; - po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); + po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); if (!po) goto drop; @@ -440,7 +440,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, if (ph->code != PADT_CODE) goto abort; - po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); + po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); if (po) { struct sock *sk = po->sk; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index e686cb440..98cd7d888 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -7,7 +7,7 @@ Feb 4 2002 - created initially by ShuChen . May 20 2002 - Add link status force-mode and TBI mode support. ========================================================================= - 1. The media can be forced in 5 modes. + 1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes. Command: 'insmod r8169 media = SET_MEDIA' Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex. @@ -41,6 +41,7 @@ VERSION 1.2 <2002/11/30> #include #include #include +#include #include #include #include @@ -64,6 +65,14 @@ VERSION 1.2 <2002/11/30> #define dprintk(fmt, args...) do {} while (0) #endif /* RTL8169_DEBUG */ +#ifdef CONFIG_R8169_NAPI +#define rtl8169_rx_skb netif_receive_skb +#define rtl8169_rx_quota(count, quota) min(count, quota) +#else +#define rtl8169_rx_skb netif_rx +#define rtl8169_rx_quota(count, quota) count +#endif + /* media options */ #define MAX_UNITS 8 static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; @@ -90,15 +99,16 @@ static int multicast_filter_limit = 32; #define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ +#define R8169_NAPI_WEIGHT 64 #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ +#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ #define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) #define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 #define RTL8169_TX_TIMEOUT (6*HZ) -#define RTL8169_PHY_TIMEOUT (HZ) +#define RTL8169_PHY_TIMEOUT (10*HZ) /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) @@ -146,6 +156,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); static int rx_copybreak = 200; +static int use_dac; enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ @@ -194,7 +205,7 @@ enum RTL8169_register_content { SWInt = 0x0100, TxDescUnavail = 0x80, RxFIFOOver = 0x40, - RxUnderrun = 0x20, + LinkChg = 0x20, RxOverflow = 0x10, TxErr = 0x08, TxOK = 0x04, @@ -233,6 +244,14 @@ enum RTL8169_register_content { TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + /* TBICSR p.28 */ + TBIReset = 0x80000000, + TBILoopback = 0x40000000, + TBINwEnable = 0x20000000, + TBINwRestart = 0x10000000, + TBILinkOk = 0x02000000, + TBINwComplete = 0x01000000, + /* CPlusCmd p.31 */ RxVlan = (1 << 6), RxChkSum = (1 << 5), @@ -306,10 +325,10 @@ struct RxDesc { }; struct rtl8169_private { - void *mmio_addr; /* memory map physical address */ + void *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device_stats stats; /* statistics of net device */ - spinlock_t lock; /* spin lock flag */ + spinlock_t lock; /* spin lock flag */ int chipset; int mac_version; int phy_version; @@ -317,21 +336,31 @@ struct rtl8169_private { u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; u32 dirty_tx; - struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ - struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ + struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */ + struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */ dma_addr_t TxPhyAddr; dma_addr_t RxPhyAddr; struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ - struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ + struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Tx data buffers */ struct timer_list timer; - unsigned long phy_link_down_cnt; u16 cp_cmd; + u16 intr_mask; + int phy_auto_nego_reg; + int phy_1000_ctrl_reg; + + int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); + void (*get_settings)(struct net_device *, struct ethtool_cmd *); + void (*phy_reset_enable)(void *); + unsigned int (*phy_reset_pending)(void *); + unsigned int (*link_ok)(void *); }; MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(use_dac, "i"); +MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); MODULE_LICENSE("GPL"); static int rtl8169_open(struct net_device *dev); @@ -344,9 +373,14 @@ static int rtl8169_close(struct net_device *dev); static void rtl8169_set_rx_mode(struct net_device *dev); static void rtl8169_tx_timeout(struct net_device *dev); static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); +#ifdef CONFIG_R8169_NAPI +static int rtl8169_poll(struct net_device *dev, int *budget); +#endif static const u16 rtl8169_intr_mask = - RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; + SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; +static const u16 rtl8169_napi_event = + RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr; static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); @@ -364,11 +398,9 @@ static void mdio_write(void *ioaddr, int RegAddr, int value) for (i = 2000; i > 0; i--) { // Check if the RTL8169 has completed writing to the specified MII register - if (!(RTL_R32(PHYAR) & 0x80000000)) { + if (!(RTL_R32(PHYAR) & 0x80000000)) break; - } else { - udelay(100); - } + udelay(100); } } @@ -390,18 +422,264 @@ static int mdio_read(void *ioaddr, int RegAddr) return value; } +static unsigned int rtl8169_tbi_reset_pending(void *ioaddr) +{ + return RTL_R32(TBICSR) & TBIReset; +} + +static unsigned int rtl8169_xmii_reset_pending(void *ioaddr) +{ + return mdio_read(ioaddr, 0) & 0x8000; +} + +static unsigned int rtl8169_tbi_link_ok(void *ioaddr) +{ + return RTL_R32(TBICSR) & TBILinkOk; +} + +static unsigned int rtl8169_xmii_link_ok(void *ioaddr) +{ + return RTL_R8(PHYstatus) & LinkStatus; +} + +static void rtl8169_tbi_reset_enable(void *ioaddr) +{ + RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset); +} + +static void rtl8169_xmii_reset_enable(void *ioaddr) +{ + unsigned int val; + + val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff; + mdio_write(ioaddr, PHY_CTRL_REG, val); +} + +static void rtl8169_check_link_status(struct net_device *dev, + struct rtl8169_private *tp, void *ioaddr) +{ + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + if (tp->link_ok(ioaddr)) { + netif_carrier_on(dev); + printk(KERN_INFO PFX "%s: link up\n", dev->name); + } else + netif_carrier_off(dev); + spin_unlock_irqrestore(&tp->lock, flags); +} + +static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex) +{ + struct { + u16 speed; + u8 duplex; + u8 autoneg; + u8 media; + } link_settings[] = { + { SPEED_10, DUPLEX_HALF, AUTONEG_DISABLE, _10_Half }, + { SPEED_10, DUPLEX_FULL, AUTONEG_DISABLE, _10_Full }, + { SPEED_100, DUPLEX_HALF, AUTONEG_DISABLE, _100_Half }, + { SPEED_100, DUPLEX_FULL, AUTONEG_DISABLE, _100_Full }, + { SPEED_1000, DUPLEX_FULL, AUTONEG_DISABLE, _1000_Full }, + /* Make TBI happy */ + { SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff } + }, *p; + unsigned char option; + + option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff; + + if ((option != 0xff) && !idx) + printk(KERN_WARNING PFX "media option is deprecated.\n"); + + for (p = link_settings; p->media != 0xff; p++) { + if (p->media == option) + break; + } + *autoneg = p->autoneg; + *speed = p->speed; + *duplex = p->duplex; +} + static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); strcpy(info->driver, RTL8169_DRIVER_NAME); strcpy(info->version, RTL8169_VERSION ); strcpy(info->bus_info, pci_name(tp->pci_dev)); } +static int rtl8169_set_speed_tbi(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int ret = 0; + u32 reg; + + reg = RTL_R32(TBICSR); + if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && + (duplex == DUPLEX_FULL)) { + RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); + } else if (autoneg == AUTONEG_ENABLE) + RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); + else { + printk(KERN_WARNING PFX + "%s: incorrect speed setting refused in TBI mode\n", + dev->name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int rtl8169_set_speed_xmii(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int auto_nego, giga_ctrl; + + auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); + auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG); + giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null); + + if (autoneg == AUTONEG_ENABLE) { + auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl |= PHY_Cap_1000_Full; + } else { + if (speed == SPEED_10) + auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full; + else if (speed == SPEED_100) + auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full; + else if (speed == SPEED_1000) + giga_ctrl |= PHY_Cap_1000_Full; + + if (duplex == DUPLEX_HALF) + auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); + } + + tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + + mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego); + mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl); + mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | + PHY_Restart_Auto_Nego); + return 0; +} + +static int rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + ret = tp->set_speed(dev, autoneg, speed, duplex); + + if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) + mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); + + return ret; +} + +static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&tp->lock, flags); + ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex); + spin_unlock_irqrestore(&tp->lock, flags); + + return ret; +} + +static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + u32 status; + + cmd->supported = + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + cmd->transceiver = XCVR_INTERNAL; + + status = RTL_R32(TBICSR); + cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; + cmd->autoneg = !!(status & TBINwEnable); + + cmd->speed = SPEED_1000; + cmd->duplex = DUPLEX_FULL; /* Always set */ +} + +static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + u8 status; + + cmd->supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP; + + cmd->autoneg = 1; + cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; + + if (tp->phy_auto_nego_reg & PHY_Cap_10_Half) + cmd->advertising |= ADVERTISED_10baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_10_Full) + cmd->advertising |= ADVERTISED_10baseT_Full; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Half) + cmd->advertising |= ADVERTISED_100baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Full) + cmd->advertising |= ADVERTISED_100baseT_Full; + if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full) + cmd->advertising |= ADVERTISED_1000baseT_Full; + + status = RTL_R8(PHYstatus); + + if (status & _1000bpsF) + cmd->speed = SPEED_1000; + else if (status & _100bps) + cmd->speed = SPEED_100; + else if (status & _10bps) + cmd->speed = SPEED_10; + + cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? + DUPLEX_FULL : DUPLEX_HALF; +} + +static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + + tp->get_settings(dev, cmd); + + spin_unlock_irqrestore(&tp->lock, flags); + return 0; +} + + static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_settings = rtl8169_get_settings, + .set_settings = rtl8169_set_settings, }; static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, @@ -500,7 +778,7 @@ static void rtl8169_print_phy_version(struct rtl8169_private *tp) static void rtl8169_hw_phy_config(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; struct { u16 regs[5]; /* Beware of bit-sign propagation */ @@ -566,61 +844,47 @@ static void rtl8169_hw_phy_config(struct net_device *dev) mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0 } -static void rtl8169_hw_phy_reset(struct net_device *dev) -{ - struct rtl8169_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - int i, val; - - printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name); - - val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff; - mdio_write(ioaddr, 0, val); - - for (i = 50; i >= 0; i--) { - if (!(mdio_read(ioaddr, 0) & 0x8000)) - break; - udelay(100); /* Gross */ - } - - if (i < 0) { - printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n", - dev->name); - } -} - static void rtl8169_phy_timer(unsigned long __opaque) { struct net_device *dev = (struct net_device *)__opaque; - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; void *ioaddr = tp->mmio_addr; + unsigned long timeout = RTL8169_PHY_TIMEOUT; assert(tp->mac_version > RTL_GIGA_MAC_VER_B); assert(tp->phy_version < RTL_GIGA_PHY_VER_G); - if (RTL_R8(PHYstatus) & LinkStatus) - tp->phy_link_down_cnt = 0; - else { - tp->phy_link_down_cnt++; - if (tp->phy_link_down_cnt >= 12) { - int reg; + if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) + return; - // If link on 1000, perform phy reset. - reg = mdio_read(ioaddr, PHY_1000_CTRL_REG); - if (reg & PHY_Cap_1000_Full) - rtl8169_hw_phy_reset(dev); + spin_lock_irq(&tp->lock); - tp->phy_link_down_cnt = 0; - } + if (tp->phy_reset_pending(ioaddr)) { + /* + * A busy loop could burn quite a few cycles on nowadays CPU. + * Let's delay the execution of the timer for a few ticks. + */ + timeout = HZ/10; + goto out_mod_timer; } - mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); + if (tp->link_ok(ioaddr)) + goto out_unlock; + + printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name); + + tp->phy_reset_enable(ioaddr); + +out_mod_timer: + mod_timer(timer, jiffies + timeout); +out_unlock: + spin_unlock_irq(&tp->lock); } static inline void rtl8169_delete_timer(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || @@ -628,21 +892,17 @@ static inline void rtl8169_delete_timer(struct net_device *dev) return; del_timer_sync(timer); - - tp->phy_link_down_cnt = 0; } static inline void rtl8169_request_timer(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || (tp->phy_version >= RTL_GIGA_PHY_VER_G)) return; - tp->phy_link_down_cnt = 0; - init_timer(timer); timer->expires = jiffies + RTL8169_PHY_TIMEOUT; timer->data = (unsigned long)(dev); @@ -681,7 +941,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); if (rc) { - printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name); + printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name); goto err_out; } @@ -693,7 +953,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } else { - printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); + printk(KERN_ERR PFX + "Cannot find PowerManagement capability, aborting.\n"); goto err_out_free_res; } @@ -718,14 +979,15 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, rc = pci_request_regions(pdev, MODULENAME); if (rc) { - printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name); + printk(KERN_ERR PFX "%s: could not request regions.\n", + pdev->slot_name); goto err_out_disable; } tp->cp_cmd = PCIMulRW | RxChkSum; - if ((sizeof(dma_addr_t) > 32) && - !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) + if ((sizeof(dma_addr_t) > 4) && + !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) tp->cp_cmd |= PCIDAC; else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); @@ -800,8 +1062,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) void *ioaddr = NULL; static int board_idx = -1; static int printed_version = 0; + u8 autoneg, duplex; + u16 speed; int i, rc; - int option = -1, Cap10_100 = 0, Cap1000 = 0; assert(pdev != NULL); assert(ent != NULL); @@ -822,6 +1085,22 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) assert(dev != NULL); assert(tp != NULL); + if (RTL_R8(PHYstatus) & TBI_Enable) { + tp->set_speed = rtl8169_set_speed_tbi; + tp->get_settings = rtl8169_gset_tbi; + tp->phy_reset_enable = rtl8169_tbi_reset_enable; + tp->phy_reset_pending = rtl8169_tbi_reset_pending; + tp->link_ok = rtl8169_tbi_link_ok; + + tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */ + } else { + tp->set_speed = rtl8169_set_speed_xmii; + tp->get_settings = rtl8169_gset_xmii; + tp->phy_reset_enable = rtl8169_xmii_reset_enable; + tp->phy_reset_pending = rtl8169_xmii_reset_pending; + tp->link_ok = rtl8169_xmii_link_ok; + } + // Get MAC address. FIXME: read EEPROM for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); @@ -836,9 +1115,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; -// dev->do_ioctl = mii_ioctl; - - tp = dev->priv; // private data // +#ifdef CONFIG_R8169_NAPI + dev->poll = rtl8169_poll; + dev->weight = R8169_NAPI_WEIGHT; + printk(KERN_INFO PFX "NAPI enabled\n"); +#endif + tp->intr_mask = 0xffff; tp->pci_dev = pdev; tp->mmio_addr = ioaddr; @@ -885,95 +1167,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 } - // if TBI is not endbled - if (!(RTL_R8(PHYstatus) & TBI_Enable)) { - int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); - - option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; - // Force RTL8169 in 10/100/1000 Full/Half mode. - if (option > 0) { - printk(KERN_INFO "%s: Force-mode Enabled.\n", - dev->name); - Cap10_100 = 0, Cap1000 = 0; - switch (option) { - case _10_Half: - Cap10_100 = PHY_Cap_10_Half_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _10_Full: - Cap10_100 = PHY_Cap_10_Full_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _100_Half: - Cap10_100 = PHY_Cap_100_Half_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _100_Full: - Cap10_100 = PHY_Cap_100_Full_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _1000_Full: - Cap10_100 = PHY_Cap_100_Full_Or_Less; - Cap1000 = PHY_Cap_1000_Full; - break; - default: - break; - } - mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged - mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000); - } else { - printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", - dev->name); - - // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged - mdio_write(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_100_Full_Or_Less | (val & 0x1f)); + rtl8169_link_option(board_idx, &autoneg, &speed, &duplex); - // enable 1000 Full Mode - mdio_write(ioaddr, PHY_1000_CTRL_REG, - PHY_Cap_1000_Full); - - } - - // Enable auto-negotiation and restart auto-nigotiation - mdio_write(ioaddr, PHY_CTRL_REG, - PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); - udelay(100); - - // wait for auto-negotiation process - for (i = 10000; i > 0; i--) { - //check if auto-negotiation complete - if (mdio_read(ioaddr, PHY_STAT_REG) & - PHY_Auto_Neco_Comp) { - udelay(100); - option = RTL_R8(PHYstatus); - if (option & _1000bpsF) { - printk(KERN_INFO - "%s: 1000Mbps Full-duplex operation.\n", - dev->name); - } else { - printk(KERN_INFO - "%s: %sMbps %s-duplex operation.\n", - dev->name, - (option & _100bps) ? "100" : - "10", - (option & FullDup) ? "Full" : - "Half"); - } - break; - } else { - udelay(100); - } - } // end for-loop to wait for auto-negotiation process - - } else { - udelay(100); - printk(KERN_INFO - "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n", - dev->name, - (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed"); - - } + rtl8169_set_speed(dev, autoneg, speed, duplex); + + if (RTL_R8(PHYstatus) & TBI_Enable) + printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); return 0; } @@ -982,7 +1181,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); assert(dev != NULL); assert(tp != NULL); @@ -1001,7 +1200,7 @@ rtl8169_remove_one(struct pci_dev *pdev) static int rtl8169_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -1042,7 +1241,7 @@ static int rtl8169_resume(struct pci_dev *pdev) static int rtl8169_open(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; int retval; @@ -1074,6 +1273,8 @@ rtl8169_open(struct net_device *dev) rtl8169_hw_start(dev); rtl8169_request_timer(dev); + + rtl8169_check_link_status(dev, tp, tp->mmio_addr); out: return retval; @@ -1091,7 +1292,7 @@ err_free_irq: static void rtl8169_hw_start(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u32 i; @@ -1102,8 +1303,7 @@ rtl8169_hw_start(struct net_device *dev) for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; - else - udelay(10); + udelay(10); } RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -1114,8 +1314,8 @@ rtl8169_hw_start(struct net_device *dev) RTL_W16(RxMaxSize, RxPacketMaxSize); // Set Rx Config register - i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset]. - RxConfigMask); + i = rtl8169_rx_config | + (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, i); /* Set DMA burst size and Interframe Gap Time */ @@ -1126,7 +1326,8 @@ rtl8169_hw_start(struct net_device *dev) RTL_W16(CPlusCmd, tp->cp_cmd); if (tp->mac_version == RTL_GIGA_MAC_VER_D) { - dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n"); + dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. " + "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14) | PCIMulRW; RTL_W16(CPlusCmd, tp->cp_cmd); } @@ -1151,7 +1352,6 @@ rtl8169_hw_start(struct net_device *dev) RTL_W16(IntrMask, rtl8169_intr_mask); netif_start_queue(dev); - } static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) @@ -1248,7 +1448,7 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) static int rtl8169_init_ring(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); tp->cur_rx = tp->dirty_rx = 0; tp->cur_tx = tp->dirty_tx = 0; @@ -1302,10 +1502,11 @@ rtl8169_tx_clear(struct rtl8169_private *tp) static void rtl8169_tx_timeout(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u8 tmp8; + printk(KERN_INFO "%s: TX Timeout\n", dev->name); /* disable Tx, if not already */ tmp8 = RTL_R8(ChipCmd); if (tmp8 & CmdTxEnb) @@ -1328,9 +1529,9 @@ rtl8169_tx_timeout(struct net_device *dev) static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; - int entry = tp->cur_tx % NUM_TX_DESC; + unsigned int entry = tp->cur_tx % NUM_TX_DESC; u32 len = skb->len; if (unlikely(skb->len < ETH_ZLEN)) { @@ -1340,10 +1541,9 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) len = ETH_ZLEN; } - spin_lock_irq(&tp->lock); - if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { dma_addr_t mapping; + u32 status; mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE); @@ -1351,24 +1551,30 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) tp->Tx_skbuff[entry] = skb; tp->TxDescArray[entry].addr = cpu_to_le64(mapping); - tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit | - LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC))); + /* anti gcc 2.95.3 bugware */ + status = OWNbit | FSbit | LSbit | len | + (EORbit * !((entry + 1) % NUM_TX_DESC)); + tp->TxDescArray[entry].status = cpu_to_le32(status); RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; + smp_wmb(); } else goto err_drop; - if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { + u32 dirty = tp->dirty_tx; + netif_stop_queue(dev); + smp_rmb(); + if (dirty != tp->dirty_tx) + netif_wake_queue(dev); } -out: - spin_unlock_irq(&tp->lock); +out: return 0; err_drop: @@ -1382,17 +1588,18 @@ static void rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long dirty_tx, tx_left; + unsigned int dirty_tx, tx_left; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); dirty_tx = tp->dirty_tx; + smp_rmb(); tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { - int entry = dirty_tx % NUM_TX_DESC; + unsigned int entry = dirty_tx % NUM_TX_DESC; struct sk_buff *skb = tp->Tx_skbuff[entry]; u32 status; @@ -1415,6 +1622,7 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; + smp_wmb(); if (netif_queue_stopped(dev)) netif_wake_queue(dev); } @@ -1442,11 +1650,11 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, return ret; } -static void +static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long cur_rx, rx_left; + unsigned int cur_rx, rx_left, count; int delta; assert(dev != NULL); @@ -1455,9 +1663,10 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; + rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); while (rx_left > 0) { - int entry = cur_rx % NUM_RX_DESC; + unsigned int entry = cur_rx % NUM_RX_DESC; u32 status; rmb(); @@ -1494,7 +1703,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + rtl8169_rx_skb(skb); dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; @@ -1505,13 +1714,15 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, rx_left--; } + count = cur_rx - tp->cur_rx; tp->cur_rx = cur_rx; delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); - if (delta > 0) - tp->dirty_rx += delta; - else if (delta < 0) + if (delta < 0) { printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + delta = 0; + } + tp->dirty_rx += delta; /* * FIXME: until there is periodic timer to try and refill the ring, @@ -1522,6 +1733,8 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, */ if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); + + return count; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -1529,7 +1742,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0; @@ -1543,26 +1756,46 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) break; handled = 1; -/* - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; -*/ + + status &= tp->intr_mask; RTL_W16(IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); if (!(status & rtl8169_intr_mask)) break; + if (unlikely(status & SYSErr)) { + printk(KERN_ERR PFX "%s: PCI error (status: 0x%04x)." + " Device disabled.\n", dev->name, status); + RTL_W8(ChipCmd, 0x00); + RTL_W16(IntrMask, 0x0000); + RTL_R16(IntrMask); + break; + } + + if (status & LinkChg) + rtl8169_check_link_status(dev, tp, ioaddr); + +#ifdef CONFIG_R8169_NAPI + RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event); + tp->intr_mask = ~rtl8169_napi_event; + + if (likely(netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + else { + printk(KERN_INFO "%s: interrupt %x taken in poll\n", + dev->name, status); + } + break; +#else // Rx interrupt - if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) { + if (status & (RxOK | RxOverflow | RxFIFOOver)) { rtl8169_rx_interrupt(dev, tp, ioaddr); } // Tx interrupt - if (status & (TxOK | TxErr)) { - spin_lock(&tp->lock); + if (status & (TxOK | TxErr)) rtl8169_tx_interrupt(dev, tp, ioaddr); - spin_unlock(&tp->lock); - } +#endif boguscnt--; } while (boguscnt > 0); @@ -1576,10 +1809,40 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) return IRQ_RETVAL(handled); } +#ifdef CONFIG_R8169_NAPI +static int rtl8169_poll(struct net_device *dev, int *budget) +{ + unsigned int work_done, work_to_do = min(*budget, dev->quota); + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + + work_done = rtl8169_rx_interrupt(dev, tp, ioaddr); + rtl8169_tx_interrupt(dev, tp, ioaddr); + + *budget -= work_done; + dev->quota -= work_done; + + if ((work_done < work_to_do) || !netif_running(dev)) { + netif_rx_complete(dev); + tp->intr_mask = 0xffff; + /* + * 20040426: the barrier is not strictly required but the + * behavior of the irq handler could be less predictable + * without it. Btw, the lack of flush for the posted pci + * write is safe - FR + */ + smp_wmb(); + RTL_W16(IntrMask, rtl8169_intr_mask); + } + + return (work_done >= work_to_do); +} +#endif + static int rtl8169_close(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; @@ -1621,7 +1884,7 @@ rtl8169_close(struct net_device *dev) static void rtl8169_set_rx_mode(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ @@ -1655,10 +1918,8 @@ rtl8169_set_rx_mode(struct net_device *dev) spin_lock_irqsave(&tp->lock, flags); - tmp = - rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset]. - RxConfigMask); + tmp = rtl8169_rx_config | rx_mode | + (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, tmp); RTL_W32(MAR0 + 0, mc_filter[0]); @@ -1675,7 +1936,7 @@ rtl8169_set_rx_mode(struct net_device *dev) */ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 059f1a68a..402f779ff 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/s2io.c b/drivers/net/s2io.c index c4bd1793f..c68c1c0e7 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -235,10 +235,10 @@ static struct pci_device_id s2io_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, s2io_tbl); static struct pci_driver s2io_driver = { - name:"S2IO", - id_table:s2io_tbl, - probe:s2io_init_nic, - remove:__devexit_p(s2io_rem_nic), + .name = "S2IO", + .id_table = s2io_tbl, + .probe = s2io_init_nic, + .remove = __devexit_p(s2io_rem_nic), }; /* diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 425e89fe2..1a87a82a8 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -124,6 +124,7 @@ static struct mii_chip_info { { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, { "ICS LAN PHY", 0x0015, 0xF440, LAN }, { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, + { "NS 83847 PHY", 0x2000, 0x5C30, MIX }, { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN }, { "VIA 6103 PHY", 0x0101, 0x8f20, LAN }, {NULL,}, diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h index 0790e7b7a..c80ac3c55 100644 --- a/drivers/net/sk98lin/h/skdrv2nd.h +++ b/drivers/net/sk98lin/h/skdrv2nd.h @@ -53,60 +53,6 @@ #include "h/skrlmt.h" #include "h/skgedrv.h" -#define SK_PCI_ISCOMPLIANT(result, pdev) { \ - result = SK_FALSE; /* default */ \ - /* 3Com (0x10b7) */ \ - if (pdev->vendor == 0x10b7) { \ - /* Gigabit Ethernet Adapter (0x1700) */ \ - if ((pdev->device == 0x1700) || \ - (pdev->device == 0x80eb)) { \ - result = SK_TRUE; \ - } \ - /* SysKonnect (0x1148) */ \ - } else if (pdev->vendor == 0x1148) { \ - /* SK-98xx Gigabit Ethernet Server Adapter (0x4300) */ \ - /* SK-98xx V2.0 Gigabit Ethernet Adapter (0x4320) */ \ - if ((pdev->device == 0x4300) || \ - (pdev->device == 0x4320)) { \ - result = SK_TRUE; \ - } \ - /* D-Link (0x1186) */ \ - } else if (pdev->vendor == 0x1186) { \ - /* Gigabit Ethernet Adapter (0x4c00) */ \ - if ((pdev->device == 0x4c00)) { \ - result = SK_TRUE; \ - } \ - /* Marvell (0x11ab) */ \ - } else if (pdev->vendor == 0x11ab) { \ - /* Gigabit Ethernet Adapter (0x4320) */ \ - /* Gigabit Ethernet Adapter (0x4360) */ \ - /* Gigabit Ethernet Adapter (0x4361) */ \ - /* Belkin (0x5005) */ \ - if ((pdev->device == 0x4320) || \ - (pdev->device == 0x4360) || \ - (pdev->device == 0x4361) || \ - (pdev->device == 0x5005)) { \ - result = SK_TRUE; \ - } \ - /* CNet (0x1371) */ \ - } else if (pdev->vendor == 0x1371) { \ - /* GigaCard Network Adapter (0x434e) */ \ - if ((pdev->device == 0x434e)) { \ - result = SK_TRUE; \ - } \ - /* Linksys (0x1737) */ \ - } else if (pdev->vendor == 0x1737) { \ - /* Gigabit Network Adapter (0x1032) */ \ - /* Gigabit Network Adapter (0x1064) */ \ - if ((pdev->device == 0x1032) || \ - (pdev->device == 0x1064)) { \ - result = SK_TRUE; \ - } \ - } else { \ - result = SK_FALSE; \ - } \ -} - extern SK_MBUF *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned); extern void SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*); diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c index 5a7ce8ef8..abf857603 100644 --- a/drivers/net/sk98lin/skaddr.c +++ b/drivers/net/sk98lin/skaddr.c @@ -892,7 +892,7 @@ SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ { - int ReturnCode; + int ReturnCode = 0; #if (!defined(SK_SLIM) || defined(DEBUG)) if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); @@ -1424,7 +1424,7 @@ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { - int ReturnCode; + int ReturnCode = 0; #if (!defined(SK_SLIM) || defined(DEBUG)) if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 503fdff54..6cb5342a4 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -110,10 +110,7 @@ #include #include - -#ifdef CONFIG_PROC_FS #include -#endif #include "h/skdrv1st.h" #include "h/skdrv2nd.h" @@ -239,7 +236,7 @@ static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr); #ifdef CONFIG_PROC_FS static const char SK_Root_Dir_entry[] = "sk98lin"; -static struct proc_dir_entry *pSkRootDir = NULL; +static struct proc_dir_entry *pSkRootDir; extern struct file_operations sk_proc_fops; #endif @@ -255,303 +252,13 @@ static void DumpLong(char*, int); #endif /* global variables *********************************************************/ -static const char *BootString = BOOT_STRING; struct SK_NET_DEVICE *SkGeRootDev = NULL; -static int probed __initdata = 0; static SK_BOOL DoPrintInterfaceChange = SK_TRUE; /* local variables **********************************************************/ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *pSkRootDir; -#endif - - - -/***************************************************************************** - * - * skge_probe - find all SK-98xx adapters - * - * Description: - * This function scans the PCI bus for SK-98xx adapters. Resources for - * each adapter are allocated and the adapter is brought into Init 1 - * state. - * - * Returns: - * 0, if everything is ok - * !=0, on error - */ -static int __init skge_probe (void) -{ - int boards_found = 0; - int vendor_flag = SK_FALSE; - SK_AC *pAC; - DEV_NET *pNet = NULL; - struct pci_dev *pdev = NULL; - struct SK_NET_DEVICE *dev = NULL; - SK_BOOL DeviceFound = SK_FALSE; - SK_BOOL BootStringCount = SK_FALSE; - int retval; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *pProcFile; -#endif - - if (probed) - return -ENODEV; - probed++; - - - while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { - - if (pci_enable_device(pdev)) { - continue; - } - dev = NULL; - pNet = NULL; - - /* Don't handle Yukon2 cards at the moment */ - /* 12-feb-2004 ---- mlindner@syskonnect.de */ - if (pdev->vendor == 0x11ab) { - if ( (pdev->device == 0x4360) || (pdev->device == 0x4361) ) - continue; - } - - SK_PCI_ISCOMPLIANT(vendor_flag, pdev); - if (!vendor_flag) - continue; - - /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && - pci_set_dma_mask(pdev, (u64) 0xffffffff)) - continue; - - - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { - printk(KERN_ERR "Unable to allocate etherdev " - "structure!\n"); - break; - } - - pNet = dev->priv; - pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); - if (pNet->pAC == NULL){ - free_netdev(dev); - printk(KERN_ERR "Unable to allocate adapter " - "structure!\n"); - break; - } - - /* Print message */ - if (!BootStringCount) { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - BootStringCount = SK_TRUE; - printk("%s\n", BootString); - } - - memset(pNet->pAC, 0, sizeof(SK_AC)); - pAC = pNet->pAC; - pAC->PciDev = pdev; - pAC->PciDevId = pdev->device; - pAC->dev[0] = dev; - pAC->dev[1] = dev; - sprintf(pAC->Name, "SysKonnect SK-98xx"); - pAC->CheckQueue = SK_FALSE; - - pNet->Mtu = 1500; - pNet->Up = 0; - dev->irq = pdev->irq; - retval = SkGeInitPCI(pAC); - if (retval) { - printk("SKGE: PCI setup failed: %i\n", retval); - free_netdev(dev); - continue; - } - - SET_MODULE_OWNER(dev); - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; - dev->last_stats = &SkGeStats; - dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; - SET_NETDEV_DEV(dev, &pdev->dev); - -#ifdef SK_ZEROCOPY -#ifdef USE_SK_TX_CHECKSUM - - if (pAC->ChipsetType) { - /* Use only if yukon hardware */ - /* SK and ZEROCOPY - fly baby... */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } -#endif -#endif - - pAC->Index = boards_found; - - if (SkGeBoardInit(dev, pAC)) { - free_netdev(dev); - continue; - } - - /* Register net device */ - if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); - FreeResources(dev); - free_netdev(dev); - continue; - } - - /* Print adapter specific string from vpd */ - ProductStr(pAC); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - - /* Print configuration settings */ - printk(" PrefPort:%c RlmtMode:%s\n", - 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, - (pAC->RlmtMode==0) ? "Check Link State" : - ((pAC->RlmtMode==1) ? "Check Link State" : - ((pAC->RlmtMode==3) ? "Check Local Port" : - ((pAC->RlmtMode==7) ? "Check Segmentation" : - ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); - - SkGeYellowLED(pAC, pAC->IoBase, 1); - - - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); - - /* First adapter... Create proc and print message */ -#ifdef CONFIG_PROC_FS - if (!DeviceFound) { - DeviceFound = SK_TRUE; - SK_MEMCPY(&SK_Root_Dir_entry, BootString, - sizeof(SK_Root_Dir_entry) - 1); - - /*Create proc (directory)*/ - if(!pSkRootDir) { - pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); - if (!pSkRootDir) { - printk(KERN_WARNING "%s: Unable to create /proc/net/%s", - dev->name, SK_Root_Dir_entry); - } else { - pSkRootDir->owner = THIS_MODULE; - } - } - } - - /* Create proc file */ - if (pSkRootDir && - (pProcFile = create_proc_entry(dev->name, S_IRUGO, - pSkRootDir))) { - pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; - } - -#endif - - pNet->PortNr = 0; - pNet->NetNr = 0; - - boards_found++; - - /* More then one port found */ - if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { - printk(KERN_ERR "Unable to allocate etherdev " - "structure!\n"); - break; - } - - pAC->dev[1] = dev; - pNet = dev->priv; - pNet->PortNr = 1; - pNet->NetNr = 1; - pNet->pAC = pAC; - pNet->Mtu = 1500; - pNet->Up = 0; - - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; - dev->last_stats = &SkGeStats; - dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; - -#ifdef SK_ZEROCOPY -#ifdef USE_SK_TX_CHECKSUM - if (pAC->ChipsetType) { - /* SG and ZEROCOPY - fly baby... */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } -#endif -#endif - - if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); - free_netdev(dev); - pAC->dev[1] = pAC->dev[0]; - } else { -#ifdef CONFIG_PROC_FS - if (pSkRootDir - && (pProcFile = create_proc_entry(dev->name, - S_IRUGO, pSkRootDir))) { - pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; - } -#endif - - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); - - printk("%s: %s\n", dev->name, pAC->DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); - } - } - - /* Save the hardware revision */ - pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + - (pAC->GIni.GIPciHwRev & 0x0F); - - /* Set driver globals */ - pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; - pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; - - SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); - SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), - sizeof(SK_PNMI_STRUCT_DATA)); - - /* - * This is bollocks, but we need to tell the net-init - * code that it shall go for the next device. - */ -#ifndef MODULE - dev->base_addr = 0; -#endif - } - - /* - * If we're at this point we're going through skge_probe() for - * the first time. Return success (0) if we've initialized 1 - * or more boards. Otherwise, return failure (-ENODEV). - */ - - return boards_found; -} /* skge_probe */ - - /***************************************************************************** * * SkGeInitPCI - Init the PCI resources @@ -666,9 +373,6 @@ MODULE_PARM(Role_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(ConType, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(PrefPort, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(RlmtMode, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); -/* not used, just there because every driver should have them: */ -MODULE_PARM(options, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); -MODULE_PARM(debug, "i"); /* used for interrupt moderation */ MODULE_PARM(IntsPerSec, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); MODULE_PARM(Moderation, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -755,123 +459,12 @@ static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE; static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", }; #endif -static int debug = 0; /* not used */ -static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */ - static int IntsPerSec[SK_MAX_CARD_PARAM]; static char *Moderation[SK_MAX_CARD_PARAM]; static char *ModerationMask[SK_MAX_CARD_PARAM]; static char *AutoSizing[SK_MAX_CARD_PARAM]; static char *Stats[SK_MAX_CARD_PARAM]; - -/***************************************************************************** - * - * skge_init_module - module initialization function - * - * Description: - * Very simple, only call skge_probe and return approriate result. - * - * Returns: - * 0, if everything is ok - * !=0, on error - */ -static int __init skge_init_module(void) -{ - int cards; - SkGeRootDev = NULL; - - /* just to avoid warnings ... */ - debug = 0; - options[0] = 0; - - cards = skge_probe(); - if (cards == 0) { - printk("sk98lin: No adapter found.\n"); - } - return cards ? 0 : -ENODEV; -} /* skge_init_module */ - - -/***************************************************************************** - * - * skge_cleanup_module - module unload function - * - * Description: - * Disable adapter if it is still running, free resources, - * free device struct. - * - * Returns: N/A - */ -static void __exit skge_cleanup_module(void) -{ -DEV_NET *pNet; -SK_AC *pAC; -struct SK_NET_DEVICE *next; -unsigned long Flags; -SK_EVPARA EvPara; - - while (SkGeRootDev) { - pNet = (DEV_NET*) SkGeRootDev->priv; - pAC = pNet->pAC; - next = pAC->Next; - - netif_stop_queue(SkGeRootDev); - SkGeYellowLED(pAC, pAC->IoBase, 0); - - if(pAC->BoardLevel == SK_INIT_RUN) { - /* board is still alive */ - spin_lock_irqsave(&pAC->SlowPathLock, Flags); - EvPara.Para32[0] = 0; - EvPara.Para32[1] = -1; - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - EvPara.Para32[0] = 1; - EvPara.Para32[1] = -1; - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - SkEventDispatcher(pAC, pAC->IoBase); - /* disable interrupts */ - SK_OUT32(pAC->IoBase, B0_IMSK, 0); - SkGeDeInit(pAC, pAC->IoBase); - spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - pAC->BoardLevel = SK_INIT_DATA; - /* We do NOT check here, if IRQ was pending, of course*/ - } - - if(pAC->BoardLevel == SK_INIT_IO) { - /* board is still alive */ - SkGeDeInit(pAC, pAC->IoBase); - pAC->BoardLevel = SK_INIT_DATA; - } - - if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ - unregister_netdev(pAC->dev[1]); - free_netdev(pAC->dev[1]); - } - - FreeResources(SkGeRootDev); - - SkGeRootDev->get_stats = NULL; - /* - * otherwise unregister_netdev calls get_stats with - * invalid IO ... :-( - */ - unregister_netdev(SkGeRootDev); - free_netdev(SkGeRootDev); - kfree(pAC); - SkGeRootDev = next; - } - -#ifdef CONFIG_PROC_FS - /* clear proc-dir */ - remove_proc_entry(pSkRootDir->name, proc_net); -#endif - -} /* skge_cleanup_module */ - -module_init(skge_init_module); -module_exit(skge_cleanup_module); - - /***************************************************************************** * * SkGeBoardInit - do level 0 and 1 initialization @@ -3094,8 +2687,7 @@ SK_EVPARA EvPara; SkEventDispatcher(pAC, pAC->IoBase); for (i=0; iGIni.GIMacsFound; i++) { - spin_lock_irqsave( - &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); netif_stop_queue(pAC->dev[i]); } @@ -4774,12 +4366,10 @@ SK_BOOL DualNet; spin_lock_irqsave( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); - spin_lock_irqsave( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST); SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST); - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -4792,8 +4382,7 @@ SK_BOOL DualNet; spin_lock_irqsave( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); - spin_lock_irqsave( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); pAC->ActivePort = ToPort; #if 0 SetQueueSizes(pAC); @@ -4808,8 +4397,7 @@ SK_BOOL DualNet; pAC, pAC->ActivePort, DualNet)) { - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -4835,8 +4423,7 @@ SK_BOOL DualNet; SkGePollTxD(pAC, IoC, ToPort, SK_TRUE); ClearAndStartRx(pAC, FromPort); ClearAndStartRx(pAC, ToPort); - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -5311,8 +4898,317 @@ int l; #endif -/******************************************************************************* - * - * End of file - * - ******************************************************************************/ +static int __devinit skge_probe_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + SK_AC *pAC; + DEV_NET *pNet = NULL; + struct net_device *dev = NULL; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pProcFile; +#endif + static int boards_found = 0; + int error = -ENODEV; + + if (pci_enable_device(pdev)) + goto out; + + /* Configure DMA attributes. */ + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && + pci_set_dma_mask(pdev, (u64) 0xffffffff)) + goto out_disable_device; + + + if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + goto out_disable_device; + } + + pNet = dev->priv; + pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); + if (!pNet->pAC) { + printk(KERN_ERR "Unable to allocate adapter " + "structure!\n"); + goto out_free_netdev; + } + + memset(pNet->pAC, 0, sizeof(SK_AC)); + pAC = pNet->pAC; + pAC->PciDev = pdev; + pAC->PciDevId = pdev->device; + pAC->dev[0] = dev; + pAC->dev[1] = dev; + sprintf(pAC->Name, "SysKonnect SK-98xx"); + pAC->CheckQueue = SK_FALSE; + + pNet->Mtu = 1500; + pNet->Up = 0; + dev->irq = pdev->irq; + error = SkGeInitPCI(pAC); + if (error) { + printk("SKGE: PCI setup failed: %i\n", error); + goto out_free_netdev; + } + + SET_MODULE_OWNER(dev); + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; + SET_NETDEV_DEV(dev, &pdev->dev); + +#ifdef SK_ZEROCOPY +#ifdef USE_SK_TX_CHECKSUM + if (pAC->ChipsetType) { + /* Use only if yukon hardware */ + /* SK and ZEROCOPY - fly baby... */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + } +#endif +#endif + + pAC->Index = boards_found++; + + if (SkGeBoardInit(dev, pAC)) + goto out_free_netdev; + + /* Register net device */ + if (register_netdev(dev)) { + printk(KERN_ERR "SKGE: Could not register device.\n"); + goto out_free_resources; + } + + /* Print adapter specific string from vpd */ + ProductStr(pAC); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + + SkGeYellowLED(pAC, pAC->IoBase, 1); + + + memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6); + +#ifdef CONFIG_PROC_FS + pProcFile = create_proc_entry(dev->name, S_IRUGO, pSkRootDir); + if (pProcFile) { + pProcFile->proc_fops = &sk_proc_fops; + pProcFile->data = dev; + pProcFile->owner = THIS_MODULE; + } +#endif + + pNet->PortNr = 0; + pNet->NetNr = 0; + + boards_found++; + + /* More then one port found */ + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + goto out; + } + + pAC->dev[1] = dev; + pNet = dev->priv; + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + pNet->Mtu = 1500; + pNet->Up = 0; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; + +#ifdef SK_ZEROCOPY +#ifdef USE_SK_TX_CHECKSUM + if (pAC->ChipsetType) { + /* SG and ZEROCOPY - fly baby... */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + } +#endif +#endif + + if (register_netdev(dev)) { + printk(KERN_ERR "SKGE: Could not register device.\n"); + free_netdev(dev); + pAC->dev[1] = pAC->dev[0]; + } else { +#ifdef CONFIG_PROC_FS + pProcFile = create_proc_entry(dev->name, S_IRUGO, + pSkRootDir); + if (pProcFile) { + pProcFile->proc_fops = &sk_proc_fops; + pProcFile->data = dev; + pProcFile->owner = THIS_MODULE; + } +#endif + + memcpy(&dev->dev_addr, + &pAC->Addr.Net[1].CurrentMacAddress, 6); + + printk("%s: %s\n", dev->name, pAC->DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + } + } + + /* Save the hardware revision */ + pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + + (pAC->GIni.GIPciHwRev & 0x0F); + + /* Set driver globals */ + pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; + pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; + + memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA)); + memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA)); + + pci_set_drvdata(pdev, dev); + return 0; + + out_free_resources: + FreeResources(dev); + out_free_netdev: + free_netdev(dev); + out_disable_device: + pci_disable_device(pdev); + out: + return error; +} + +static void __devexit skge_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + DEV_NET *pNet = (DEV_NET *) dev->priv; + SK_AC *pAC = pNet->pAC; + int have_second_mac = 0; + + 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) { + remove_proc_entry(pAC->dev[1]->name, pSkRootDir); + unregister_netdev(pAC->dev[1]); + } + + SkGeYellowLED(pAC, pAC->IoBase, 0); + + if (pAC->BoardLevel == SK_INIT_RUN) { + SK_EVPARA EvPara; + unsigned long Flags; + + /* board is still alive */ + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = 0; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + SkGeDeInit(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + pAC->BoardLevel = SK_INIT_DATA; + /* We do NOT check here, if IRQ was pending, of course*/ + } + + if (pAC->BoardLevel == SK_INIT_IO) { + /* board is still alive */ + SkGeDeInit(pAC, pAC->IoBase); + pAC->BoardLevel = SK_INIT_DATA; + } + + FreeResources(dev); + free_netdev(dev); + if (have_second_mac) + free_netdev(pAC->dev[1]); + kfree(pAC); +} + +static struct pci_device_id skge_pci_tbl[] = { + { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#if 0 /* don't handle Yukon2 cards at the moment -- mlindner@syskonnect.de */ + { PCI_VENDOR_ID_MARVELL, 0x4360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +static struct pci_driver skge_driver = { + .name = "skge", + .id_table = skge_pci_tbl, + .probe = skge_probe_one, + .remove = __devexit_p(skge_remove_one), +}; + +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); + + pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); + if (!pSkRootDir) { + printk(KERN_WARNING "Unable to create /proc/net/%s", + SK_Root_Dir_entry); + return -ENOMEM; + } + pSkRootDir->owner = THIS_MODULE; +#endif + + error = pci_module_init(&skge_driver); + if (error) { +#ifdef CONFIG_PROC_FS + remove_proc_entry(pSkRootDir->name, proc_net); +#endif + } + + return error; +} + +static void __exit skge_exit(void) +{ + pci_unregister_driver(&skge_driver); +#ifdef CONFIG_PROC_FS + remove_proc_entry(pSkRootDir->name, proc_net); +#endif +} + +module_init(skge_init); +module_exit(skge_exit); diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 1eee9d37f..8308bcc14 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1095,7 +1095,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) */ if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { - bp->MacStat.tx_errors++; /* bump error counter */ + bp->MacStat.gen.tx_errors++; /* bump error counter */ // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); @@ -1546,8 +1546,8 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) skb->len, PCI_DMA_TODEVICE); txd->txd_os.dma_addr = 0; - smc->os.MacStat.tx_packets++; // Count transmitted packets. - smc->os.MacStat.tx_bytes+=skb->len; // Count bytes + smc->os.MacStat.gen.tx_packets++; // Count transmitted packets. + smc->os.MacStat.gen.tx_bytes+=skb->len; // Count bytes // free the skb dev_kfree_skb_irq(skb); @@ -1629,7 +1629,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, skb = rxd->rxd_os.skb; if (!skb) { PRINTK(KERN_INFO "No skb in rxd\n"); - smc->os.MacStat.rx_errors++; + smc->os.MacStat.gen.rx_errors++; goto RequeueRxd; } virt = skb->data; @@ -1682,13 +1682,14 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, } // Count statistics. - smc->os.MacStat.rx_packets++; // Count indicated receive packets. - smc->os.MacStat.rx_bytes+=len; // Count bytes + smc->os.MacStat.gen.rx_packets++; // Count indicated receive + // packets. + smc->os.MacStat.gen.rx_bytes+=len; // Count bytes. // virt points to header again if (virt[1] & 0x01) { // Check group (multicast) bit. - smc->os.MacStat.multicast++; + smc->os.MacStat.gen.multicast++; } // deliver frame to system @@ -1706,7 +1707,8 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, RequeueRxd: PRINTK(KERN_INFO "Rx: re-queue RXD.\n"); mac_drv_requeue_rxd(smc, rxd, frag_count); - smc->os.MacStat.rx_errors++; // Count receive packets not indicated. + smc->os.MacStat.gen.rx_errors++; // Count receive packets + // not indicated. } // mac_drv_rx_complete @@ -2081,7 +2083,7 @@ void smt_stat_counter(struct s_smc *smc, int stat) break; case 1: PRINTK(KERN_INFO "Receive fifo overflow.\n"); - smc->os.MacStat.rx_errors++; + smc->os.MacStat.gen.rx_errors++; break; default: PRINTK(KERN_INFO "Unknown status (%d).\n", stat); diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 6209a35aa..0c1995bc2 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -672,7 +672,9 @@ static int slip_receive_room(struct tty_struct *tty) * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when * a block of SLIP data has been received, which can now be decapsulated - * and sent on to some IP layer for further processing. + * and sent on to some IP layer for further processing. This will not + * be re-entered while running but other ldisc functions may be called + * in parallel */ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) @@ -841,9 +843,11 @@ sl_alloc(dev_t line) * SLIP line discipline is called for. Because we are * sure the tty line exists, we only have to link it to * a free SLIP channel... + * + * Called in process context serialized from other ldisc calls. */ -static int -slip_open(struct tty_struct *tty) + +static int slip_open(struct tty_struct *tty) { struct slip *sl; int err; @@ -876,11 +880,11 @@ slip_open(struct tty_struct *tty) tty->disc_data = sl; sl->line = tty_devnum(tty); sl->pid = current->pid; + + /* FIXME: already done before we were called - seems this can go */ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - + if (!test_bit(SLF_INUSE, &sl->flags)) { /* Perform the low-level SLIP initialization. */ if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0) @@ -923,6 +927,9 @@ err_exit: } /* + + FIXME: 1,2 are fixed 3 was never true anyway. + Let me to blame a bit. 1. TTY module calls this funstion on soft interrupt. 2. TTY module calls this function WITH MASKED INTERRUPTS! @@ -941,9 +948,8 @@ err_exit: /* * Close down a SLIP channel. - * This means flushing out any pending queues, and then restoring the - * TTY line discipline to what it was before it got hooked to SLIP - * (which usually is TTY again). + * This means flushing out any pending queues, and then returning. This + * call is serialized against other ldisc functions. */ static void slip_close(struct tty_struct *tty) diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 8ee249a38..f5071b047 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/smc91x.c b/drivers/net/smc91x.c index 85fae0965..5d224b642 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -55,6 +55,9 @@ * smc_phy_configure * - clean up (and fix stack overrun) in PHY * MII read/write functions + * 09/15/04 Hayato Fujiwara - Add m32r support. + * - Modify for SMP kernel; Change spin-locked + * regions. */ static const char version[] = "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre \n"; @@ -256,24 +259,18 @@ static void PRINT_PKT(u_char *buf, int length) /* this enables an interrupt in the interrupt mask register */ #define SMC_ENABLE_INT(x) do { \ - unsigned long flags; \ unsigned char mask; \ - spin_lock_irqsave(&lp->lock, flags); \ mask = SMC_GET_INT_MASK(); \ mask |= (x); \ SMC_SET_INT_MASK(mask); \ - spin_unlock_irqrestore(&lp->lock, flags); \ } while (0) /* this disables an interrupt from the interrupt mask register */ #define SMC_DISABLE_INT(x) do { \ - unsigned long flags; \ unsigned char mask; \ - spin_lock_irqsave(&lp->lock, flags); \ mask = SMC_GET_INT_MASK(); \ mask &= ~(x); \ SMC_SET_INT_MASK(mask); \ - spin_unlock_irqrestore(&lp->lock, flags); \ } while (0) /* @@ -580,9 +577,12 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned int numPages, poll_count, status, saved_bank; + unsigned long flags; DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + spin_lock_irqsave(&lp->lock, flags); + BUG_ON(lp->saved_skb != NULL); lp->saved_skb = skb; @@ -604,6 +604,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->stats.tx_errors++; lp->stats.tx_dropped++; dev_kfree_skb(skb); + spin_unlock_irqrestore(&lp->lock, flags); return 0; } @@ -652,6 +653,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } SMC_SELECT_BANK(saved_bank); + spin_unlock_irqrestore(&lp->lock, flags); return 0; } @@ -1166,6 +1168,8 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + spin_lock(&lp->lock); + saved_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(2); saved_pointer = SMC_GET_PTR(); @@ -1189,8 +1193,6 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!status) break; - spin_lock(&lp->lock); - if (status & IM_RCV_INT) { DBG(3, "%s: RX irq\n", dev->name); smc_rcv(dev); @@ -1239,7 +1241,6 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); } - spin_unlock(&lp->lock); } while (--timeout); /* restore register states */ @@ -1249,6 +1250,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout); + spin_unlock(&lp->lock); /* * We return IRQ_HANDLED unconditionally here even if there was * nothing to do. There is a possibility that a packet might @@ -1264,7 +1266,9 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void smc_timeout(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); + unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); DBG(2, "%s: %s\n", dev->name, __FUNCTION__); smc_reset(dev); @@ -1298,6 +1302,9 @@ static void smc_timeout(struct net_device *dev) } /* We can accept TX packets again */ dev->trans_start = jiffies; + + spin_unlock_irqrestore(&lp->lock, flags); + netif_wake_queue(dev); } @@ -1438,7 +1445,7 @@ smc_open(struct net_device *dev) * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { - DBG(2, (KERN_DEBUG "smc_open: no valid ethernet hw addr\n")); + DBG(2, "smc_open: no valid ethernet hw addr\n"); return -EINVAL; } @@ -1878,7 +1885,9 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr) if (retval) goto err_out; +#if !defined(__m32r__) set_irq_type(dev->irq, IRQT_RISING); +#endif #ifdef SMC_USE_PXA_DMA { int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, @@ -2154,10 +2163,12 @@ static struct device_driver smc_driver = { static int __init smc_init(void) { #ifdef MODULE +#ifdef CONFIG_ISA if (io == -1) printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", CARDNAME); +#endif #endif return driver_register(&smc_driver); diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 7679022c0..cf74b74c3 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -160,6 +160,19 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg) #define SMC_insw(a, r, p, l) insw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) +#elif defined(CONFIG_M32R) + +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 + +#define SMC_inb(a, r) inb((a) + (r) - 0xa0000000) +#define SMC_inw(a, r) inw((a) + (r) - 0xa0000000) +#define SMC_outb(v, a, r) outb(v, (a) + (r) - 0xa0000000) +#define SMC_outw(v, a, r) outw(v, (a) + (r) - 0xa0000000) +#define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) +#define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) + #else #define SMC_CAN_USE_8BIT 1 @@ -809,9 +822,10 @@ static const char * chip_ids[ 16 ] = { do { \ char *__ptr = (p); \ int __len = (l); \ - if (__len >= 2 && (long)__ptr & 2) { \ + if (__len >= 2 && (unsigned long)__ptr & 2) { \ __len -= 2; \ - SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\ + SMC_outw( *(u16 *)__ptr, ioaddr, DATA_REG ); \ + __ptr += 2; \ } \ SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \ if (__len & 2) { \ @@ -823,7 +837,7 @@ static const char * chip_ids[ 16 ] = { do { \ char *__ptr = (p); \ int __len = (l); \ - if ((long)__ptr & 2) { \ + if ((unsigned long)__ptr & 2) { \ /* \ * We want 32bit alignment here. \ * Since some buses perform a full 32bit \ @@ -831,7 +845,7 @@ static const char * chip_ids[ 16 ] = { * SMC_inw() here. Back both source (on chip \ * and destination) pointers of 2 bytes. \ */ \ - (long)__ptr &= ~2; \ + __ptr -= 2; \ __len += 2; \ SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ } \ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index ec05d1bd1..25d35022b 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -68,7 +68,7 @@ static struct bigmac *root_bigmac_dev; #define QEC_RESET_TRIES 200 -static int qec_global_reset(unsigned long gregs) +static int qec_global_reset(void __iomem *gregs) { int tries = QEC_RESET_TRIES; @@ -88,7 +88,7 @@ static int qec_global_reset(unsigned long gregs) static void qec_init(struct bigmac *bp) { - unsigned long gregs = bp->gregs; + void __iomem *gregs = bp->gregs; struct sbus_dev *qec_sdev = bp->qec_sdev; u8 bsizes = bp->bigmac_bursts; u32 regval; @@ -117,7 +117,7 @@ static void qec_init(struct bigmac *bp) #define TX_RESET_TRIES 32 #define RX_RESET_TRIES 32 -static void bigmac_tx_reset(unsigned long bregs) +static void bigmac_tx_reset(void __iomem *bregs) { int tries = TX_RESET_TRIES; @@ -137,7 +137,7 @@ static void bigmac_tx_reset(unsigned long bregs) } } -static void bigmac_rx_reset(unsigned long bregs) +static void bigmac_rx_reset(void __iomem *bregs) { int tries = RX_RESET_TRIES; @@ -159,7 +159,7 @@ static void bigmac_stop(struct bigmac *bp) bigmac_rx_reset(bp->bregs); } -static void bigmac_get_counters(struct bigmac *bp, unsigned long bregs) +static void bigmac_get_counters(struct bigmac *bp, void __iomem *bregs) { struct net_device_stats *stats = &bp->enet_stats; @@ -244,7 +244,7 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) #define MGMT_CLKON (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB|MGMT_PAL_DCLOCK) #define MGMT_CLKOFF (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB) -static void idle_transceiver(unsigned long tregs) +static void idle_transceiver(void __iomem *tregs) { int i = 20; @@ -256,7 +256,7 @@ static void idle_transceiver(unsigned long tregs) } } -static void write_tcvr_bit(struct bigmac *bp, unsigned long tregs, int bit) +static void write_tcvr_bit(struct bigmac *bp, void __iomem *tregs, int bit) { if (bp->tcvr_type == internal) { bit = (bit & 1) << 3; @@ -279,7 +279,7 @@ static void write_tcvr_bit(struct bigmac *bp, unsigned long tregs, int bit) } } -static int read_tcvr_bit(struct bigmac *bp, unsigned long tregs) +static int read_tcvr_bit(struct bigmac *bp, void __iomem *tregs) { int retval = 0; @@ -302,7 +302,7 @@ static int read_tcvr_bit(struct bigmac *bp, unsigned long tregs) return retval; } -static int read_tcvr_bit2(struct bigmac *bp, unsigned long tregs) +static int read_tcvr_bit2(struct bigmac *bp, void __iomem *tregs) { int retval = 0; @@ -325,7 +325,7 @@ static int read_tcvr_bit2(struct bigmac *bp, unsigned long tregs) } static void put_tcvr_byte(struct bigmac *bp, - unsigned long tregs, + void __iomem *tregs, unsigned int byte) { int shift = 4; @@ -336,7 +336,7 @@ static void put_tcvr_byte(struct bigmac *bp, } while (shift >= 0); } -static void bigmac_tcvr_write(struct bigmac *bp, unsigned long tregs, +static void bigmac_tcvr_write(struct bigmac *bp, void __iomem *tregs, int reg, unsigned short val) { int shift; @@ -376,7 +376,7 @@ static void bigmac_tcvr_write(struct bigmac *bp, unsigned long tregs, } static unsigned short bigmac_tcvr_read(struct bigmac *bp, - unsigned long tregs, + void __iomem *tregs, int reg) { unsigned short retval = 0; @@ -444,7 +444,7 @@ static unsigned short bigmac_tcvr_read(struct bigmac *bp, static void bigmac_tcvr_init(struct bigmac *bp) { - unsigned long tregs = bp->tregs; + void __iomem *tregs = bp->tregs; u32 mpal; idle_transceiver(tregs); @@ -482,7 +482,7 @@ static void bigmac_tcvr_init(struct bigmac *bp) static int bigmac_init(struct bigmac *, int); -static int try_next_permutation(struct bigmac *bp, unsigned long tregs) +static int try_next_permutation(struct bigmac *bp, void __iomem *tregs) { if (bp->sw_bmcr & BMCR_SPEED100) { int timeout; @@ -518,7 +518,7 @@ static int try_next_permutation(struct bigmac *bp, unsigned long tregs) static void bigmac_timer(unsigned long data) { struct bigmac *bp = (struct bigmac *) data; - unsigned long tregs = bp->tregs; + void __iomem *tregs = bp->tregs; int restart_timer = 0; bp->timer_ticks++; @@ -573,7 +573,7 @@ static void bigmac_timer(unsigned long data) */ static void bigmac_begin_auto_negotiation(struct bigmac *bp) { - unsigned long tregs = bp->tregs; + void __iomem *tregs = bp->tregs; int timeout; /* Grab new software copies of PHY registers. */ @@ -612,9 +612,9 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp) static int bigmac_init(struct bigmac *bp, int from_irq) { - unsigned long gregs = bp->gregs; - unsigned long cregs = bp->creg; - unsigned long bregs = bp->bregs; + void __iomem *gregs = bp->gregs; + void __iomem *cregs = bp->creg; + void __iomem *bregs = bp->bregs; unsigned char *e = &bp->dev->dev_addr[0]; /* Latch current counters into statistics. */ @@ -987,7 +987,7 @@ static struct net_device_stats *bigmac_get_stats(struct net_device *dev) static void bigmac_set_multicast(struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; - unsigned long bregs = bp->bregs; + void __iomem *bregs = bp->bregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index b4c5309b3..5674003fc 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -303,10 +303,10 @@ enum bigmac_timer_state { }; struct bigmac { - unsigned long gregs; /* QEC Global Registers */ - unsigned long creg; /* QEC BigMAC Channel Registers */ - unsigned long bregs; /* BigMAC Registers */ - unsigned long tregs; /* BigMAC Transceiver */ + void __iomem *gregs; /* QEC Global Registers */ + void __iomem *creg; /* QEC BigMAC Channel Registers */ + void __iomem *bregs; /* BigMAC Registers */ + void __iomem *tregs; /* BigMAC Transceiver */ struct bmac_init_block *bmac_block; /* RX and TX descriptors */ __u32 bblock_dvma; /* RX and TX descriptors */ diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 849b57634..e0ddf2be9 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/sungem.c b/drivers/net/sungem.c index e48ec3421..c78811b00 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -5,6 +5,9 @@ * * Support for Apple GMAC and assorted PHYs by * Benjamin Herrenscmidt (benh@kernel.crashing.org) + * + * NAPI and NETPOLL support + * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com) * * TODO: * - Get rid of all those nasty mdelay's and replace them @@ -181,6 +184,18 @@ static inline void phy_write(struct gem *gp, int reg, u16 val) __phy_write(gp, gp->mii_phy_addr, reg, val); } +static inline void gem_enable_ints(struct gem *gp) +{ + /* Enable all interrupts but TXDONE */ + writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); +} + +static inline void gem_disable_ints(struct gem *gp) +{ + /* Disable all interrupts, including TXDONE */ + writel(GREG_STAT_NAPI | GREG_STAT_TXDONE, gp->regs + GREG_IMASK); +} + static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) { if (netif_msg_intr(gp)) @@ -678,12 +693,12 @@ static __inline__ void gem_post_rxds(struct gem *gp, int limit) } } -static void gem_rx(struct gem *gp) +static int gem_rx(struct gem *gp, int work_to_do) { - int entry, drops; + int entry, drops, work_done = 0; u32 done; - if (netif_msg_intr(gp)) + if (netif_msg_rx_status(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", gp->dev->name, readl(gp->regs + RXDMA_DONE), gp->rx_new); @@ -700,6 +715,9 @@ static void gem_rx(struct gem *gp) if ((status & RXDCTRL_OWN) != 0) break; + if (work_done >= RX_RING_SIZE || work_done >= work_to_do) + break; + /* When writing back RX descriptor, GEM writes status * then buffer address, possibly in seperate transactions. * If we don't wait for the chip to write both, we could @@ -713,6 +731,9 @@ static void gem_rx(struct gem *gp) break; } + /* We can now account for the work we're about to do */ + work_done++; + skb = gp->rx_skbs[entry]; len = (status & RXDCTRL_BUFSZ) >> 16; @@ -775,7 +796,8 @@ static void gem_rx(struct gem *gp) skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff); skb->ip_summed = CHECKSUM_HW; skb->protocol = eth_type_trans(skb, gp->dev); - netif_rx(skb); + + netif_receive_skb(skb); gp->net_stats.rx_packets++; gp->net_stats.rx_bytes += len; @@ -792,35 +814,103 @@ static void gem_rx(struct gem *gp) if (drops) printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", gp->dev->name); + + return work_done; +} + +static int gem_poll(struct net_device *dev, int *budget) +{ + struct gem *gp = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&gp->lock, flags); + + do { + int work_to_do, work_done; + + /* Handle anomalies */ + if (gp->status & GREG_STAT_ABNORMAL) { + if (gem_abnormal_irq(dev, gp, gp->status)) + break; + } + + /* Run TX completion thread */ + spin_lock(&gp->tx_lock); + gem_tx(dev, gp, gp->status); + spin_unlock(&gp->tx_lock); + + spin_unlock_irqrestore(&gp->lock, flags); + + /* Run RX thread. We don't use any locking here, + * code willing to do bad things - like cleaning the + * rx ring - must call netif_poll_disable(), which + * schedule_timeout()'s if polling is already disabled. + */ + work_to_do = min(*budget, dev->quota); + + work_done = gem_rx(gp, work_to_do); + + *budget -= work_done; + dev->quota -= work_done; + + if (work_done >= work_to_do) + return 1; + + spin_lock_irqsave(&gp->lock, flags); + + gp->status = readl(gp->regs + GREG_STAT); + } while (gp->status & GREG_STAT_NAPI); + + __netif_rx_complete(dev); + gem_enable_ints(gp); + + spin_unlock_irqrestore(&gp->lock, flags); + return 0; } static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct gem *gp = dev->priv; - u32 gem_status = readl(gp->regs + GREG_STAT); + unsigned long flags; /* Swallow interrupts when shutting the chip down */ - if (gp->hw_running == 0) - goto out; + if (!gp->hw_running) + return IRQ_HANDLED; - spin_lock(&gp->lock); + spin_lock_irqsave(&gp->lock, flags); + + if (netif_rx_schedule_prep(dev)) { + u32 gem_status = readl(gp->regs + GREG_STAT); - if (gem_status & GREG_STAT_ABNORMAL) { - if (gem_abnormal_irq(dev, gp, gem_status)) - goto out; + if (gem_status == 0) { + spin_unlock_irqrestore(&gp->lock, flags); + return IRQ_NONE; + } + gp->status = gem_status; + gem_disable_ints(gp); + __netif_rx_schedule(dev); } - if (gem_status & (GREG_STAT_TXALL | GREG_STAT_TXINTME)) - gem_tx(dev, gp, gem_status); - if (gem_status & GREG_STAT_RXDONE) - gem_rx(gp); - -out: - spin_unlock(&gp->lock); + spin_unlock_irqrestore(&gp->lock, flags); + + /* If polling was disabled at the time we received that + * interrupt, we may return IRQ_HANDLED here while we + * should return IRQ_NONE. No big deal... + */ return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void gem_poll_controller(struct net_device *dev) +{ + /* gem_interrupt is safe to reentrance so no need + * to disable_irq here. + */ + gem_interrupt(dev->irq, dev, NULL); +} +#endif + static void gem_tx_timeout(struct net_device *dev) { struct gem *gp = dev->priv; @@ -842,10 +932,12 @@ static void gem_tx_timeout(struct net_device *dev) readl(gp->regs + MAC_RXCFG)); spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->reset_task_pending = 2; schedule_work(&gp->reset_task); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } @@ -863,6 +955,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) struct gem *gp = dev->priv; int entry; u64 ctrl; + unsigned long flags; ctrl = 0; if (skb->ip_summed == CHECKSUM_HW) { @@ -876,15 +969,20 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) (csum_stuff_off << 21)); } - spin_lock_irq(&gp->lock); + local_irq_save(flags); + if (!spin_trylock(&gp->tx_lock)) { + /* Tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); - spin_unlock_irq(&gp->lock); + spin_unlock_irqrestore(&gp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } entry = gp->tx_new; @@ -968,11 +1066,11 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, entry, skb->len); mb(); writel(gp->tx_new, gp->regs + TXDMA_KICK); - spin_unlock_irq(&gp->lock); + spin_unlock_irqrestore(&gp->tx_lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Jumbo-grams don't seem to work :-( */ @@ -999,9 +1097,11 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) } spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); dev->mtu = new_mtu; gp->reset_task_pending = 1; schedule_work(&gp->reset_task); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); flush_scheduled_work(); @@ -1011,7 +1111,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) #define STOP_TRIES 32 -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_stop(struct gem *gp) { int limit; @@ -1037,7 +1137,7 @@ static void gem_stop(struct gem *gp) printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_start_dma(struct gem *gp) { unsigned long val; @@ -1062,7 +1162,7 @@ static void gem_start_dma(struct gem *gp) } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ // XXX dbl check what that function should do when called on PCS PHY static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) { @@ -1149,7 +1249,7 @@ non_mii: /* A link-up condition has occurred, initialize and enable the * rest of the chip. * - * Must be invoked under gp->lock. + * Must be invoked under gp->lock and gp->tx_lock. */ static int gem_set_link_modes(struct gem *gp) { @@ -1256,7 +1356,7 @@ static int gem_set_link_modes(struct gem *gp) return 0; } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static int gem_mdio_link_not_up(struct gem *gp) { switch (gp->lstate) { @@ -1312,19 +1412,13 @@ static void gem_reset_task(void *data) { struct gem *gp = (struct gem *) data; - /* The link went down, we reset the ring, but keep - * DMA stopped. Todo: Use this function for reset - * on error as well. - */ - + netif_poll_disable(gp->dev); spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); if (gp->hw_running && gp->opened) { - /* Make sure we don't get interrupts or tx packets */ netif_stop_queue(gp->dev); - writel(0xffffffff, gp->regs + GREG_IMASK); - /* Reset the chip & rings */ gem_stop(gp); gem_init_rings(gp); @@ -1336,7 +1430,9 @@ static void gem_reset_task(void *data) } gp->reset_task_pending = 0; + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); + netif_poll_enable(gp->dev); } static void gem_link_timer(unsigned long data) @@ -1348,6 +1444,7 @@ static void gem_link_timer(unsigned long data) return; spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); /* If the link of task is still pending, we just * reschedule the link timer @@ -1417,10 +1514,11 @@ static void gem_link_timer(unsigned long data) restart: mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); out_unlock: + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_clean_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1471,7 +1569,7 @@ static void gem_clean_rings(struct gem *gp) } } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1521,7 +1619,7 @@ static void gem_init_rings(struct gem *gp) wmb(); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_phy(struct gem *gp) { u32 mifcfg; @@ -1659,7 +1757,7 @@ static void gem_init_phy(struct gem *gp) } } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_dma(struct gem *gp) { u64 desc_dma = (u64) gp->gblock_dvma; @@ -1697,7 +1795,7 @@ static void gem_init_dma(struct gem *gp) gp->regs + RXDMA_BLANK); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static u32 gem_setup_multicast(struct gem *gp) { @@ -1740,7 +1838,7 @@ gem_setup_multicast(struct gem *gp) return rxcfg; } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_mac(struct gem *gp) { unsigned char *e = &gp->dev->dev_addr[0]; @@ -1818,7 +1916,7 @@ static void gem_init_mac(struct gem *gp) writel(0xffffffff, gp->regs + MAC_MCMASK); } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_pause_thresholds(struct gem *gp) { u32 cfg; @@ -1954,7 +2052,7 @@ static int gem_check_invariants(struct gem *gp) return 0; } -/* Must be invoked under gp->lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_hw(struct gem *gp, int restart_link) { /* On Apple's gmac, I initialize the PHY only after @@ -2052,9 +2150,11 @@ static void gem_stop_phy(struct gem *gp) if (!gp->wake_on_lan) { spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); gem_stop(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); + spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); } @@ -2102,8 +2202,10 @@ static void gem_shutdown(struct gem *gp) unsigned long flags; spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); gem_stop(gp); - spin_unlock_irqrestore(&gp->lock, flags); + spin_unlock(&gp->tx_lock); + spin_unlock_irqrestore(&gp->lock, flags); } } @@ -2163,7 +2265,9 @@ static int gem_open(struct net_device *dev) /* Reset the chip */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_stop(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); gp->hw_running = 1; @@ -2177,6 +2281,7 @@ static int gem_open(struct net_device *dev) printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); #ifdef CONFIG_PPC_PMAC if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); @@ -2185,12 +2290,14 @@ static int gem_open(struct net_device *dev) gp->pm_timer.expires = jiffies + 10*HZ; add_timer(&gp->pm_timer); up(&gp->pm_sem); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return -EAGAIN; } spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); /* Allocate & setup ring buffers */ gem_init_rings(gp); @@ -2200,6 +2307,7 @@ static int gem_open(struct net_device *dev) gp->opened = 1; + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); up(&gp->pm_sem); @@ -2214,11 +2322,16 @@ static int gem_close(struct net_device *dev) /* Make sure we don't get distracted by suspend/resume */ down(&gp->pm_sem); + /* Note: we don't need to call netif_poll_disable() here because + * our caller (dev_close) already did it for us + */ + /* Stop traffic, mark us closed */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->opened = 0; - writel(0xffffffff, gp->regs + GREG_IMASK); + netif_stop_queue(dev); /* Stop chip */ @@ -2230,6 +2343,7 @@ static int gem_close(struct net_device *dev) /* Bye, the pm timer will finish the job */ free_irq(gp->pdev->irq, (void *) dev); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); /* Fire the PM timer that will shut us down in about 10 seconds */ @@ -2247,6 +2361,8 @@ static int gem_suspend(struct pci_dev *pdev, u32 state) struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = dev->priv; + netif_poll_disable(dev); + /* We hold the PM semaphore during entire driver * sleep time */ @@ -2258,18 +2374,18 @@ static int gem_suspend(struct pci_dev *pdev, u32 state) /* If the driver is opened, we stop the DMA */ if (gp->opened) { spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); /* Stop traffic, mark us closed */ netif_device_detach(dev); - writel(0xffffffff, gp->regs + GREG_IMASK); - /* Stop chip */ gem_stop(gp); /* Get rid of ring buffers */ gem_clean_rings(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) @@ -2303,12 +2419,14 @@ static int gem_resume(struct pci_dev *pdev) } #endif /* CONFIG_PPC_PMAC */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_stop(gp); gp->hw_running = 1; gem_init_rings(gp); gem_init_hw(gp, 1); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); netif_device_attach(dev); @@ -2317,6 +2435,8 @@ static int gem_resume(struct pci_dev *pdev) } up(&gp->pm_sem); + netif_poll_enable(dev); + return 0; } #endif /* CONFIG_PM */ @@ -2327,6 +2447,7 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) struct net_device_stats *stats = &gp->net_stats; spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); if (gp->hw_running) { stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); @@ -2346,6 +2467,7 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) writel(0, gp->regs + MAC_LCOLL); } + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return &gp->net_stats; @@ -2361,6 +2483,7 @@ static void gem_set_multicast(struct net_device *dev) return; spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); netif_stop_queue(dev); @@ -2385,6 +2508,7 @@ static void gem_set_multicast(struct net_device *dev) netif_wake_queue(dev); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } @@ -2416,6 +2540,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* Return current PHY settings */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); cmd->autoneg = gp->want_autoneg; cmd->speed = gp->phy_mii.speed; cmd->duplex = gp->phy_mii.duplex; @@ -2427,6 +2552,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) */ if (cmd->advertising == 0) cmd->advertising = cmd->supported; + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } else { // XXX PCS ? cmd->supported = @@ -2466,7 +2592,9 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* Apply settings and restart link process. */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, cmd); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2481,7 +2609,9 @@ static int gem_nway_reset(struct net_device *dev) /* Restart link process. */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, NULL); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2581,7 +2711,7 @@ static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_add static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) { u32 rom_reg_orig; - void *p; + void __iomem *p; if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) { if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0) @@ -2733,6 +2863,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->msg_enable = DEFAULT_MSG; spin_lock_init(&gp->lock); + spin_lock_init(&gp->tx_lock); init_MUTEX(&gp->pm_sem); init_timer(&gp->link_timer); @@ -2750,7 +2881,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->timer_ticks = 0; netif_carrier_off(dev); - gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); + gp->regs = ioremap(gemreg_base, gemreg_len); if (gp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -2768,7 +2899,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gem_apple_powerup(gp); #endif spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gem_stop(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); /* Fill up the mii_phy structure (even if we won't use it) */ @@ -2806,12 +2939,17 @@ static int __devinit gem_init_one(struct pci_dev *pdev, dev->get_stats = gem_get_stats; dev->set_multicast_list = gem_set_multicast; dev->do_ioctl = gem_ioctl; + dev->poll = gem_poll; + dev->weight = 64; dev->ethtool_ops = &gem_ethtool_ops; dev->tx_timeout = gem_tx_timeout; dev->watchdog_timeo = 5 * HZ; dev->change_mtu = gem_change_mtu; dev->irq = pdev->irq; dev->dma = 0; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = gem_poll_controller; +#endif if (register_netdev(dev)) { printk(KERN_ERR PFX "Cannot register net device, " @@ -2829,9 +2967,11 @@ static int __devinit gem_init_one(struct pci_dev *pdev, /* Detect & init PHY, start autoneg */ spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->hw_running = 1; gem_init_phy(gp); gem_begin_auto_negotiation(gp, NULL); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); if (gp->phy_type == phy_mii_mdio0 || @@ -2842,7 +2982,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, pci_set_drvdata(pdev, dev); /* GEM can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; @@ -2867,7 +3007,7 @@ err_out_iounmap: gem_shutdown(gp); up(&gp->pm_sem); - iounmap((void *) gp->regs); + iounmap(gp->regs); err_out_free_res: pci_release_regions(pdev); @@ -2901,7 +3041,7 @@ static void __devexit gem_remove_one(struct pci_dev *pdev) sizeof(struct gem_init_block), gp->init_block, gp->gblock_dvma); - iounmap((void *) gp->regs); + iounmap(gp->regs); pci_release_regions(pdev); free_netdev(dev); diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index eed77bfe1..00343226f 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -60,6 +60,9 @@ GREG_STAT_PCS | GREG_STAT_TXMAC | GREG_STAT_RXMAC | \ GREG_STAT_MAC | GREG_STAT_MIF | GREG_STAT_PCIERR) +#define GREG_STAT_NAPI (GREG_STAT_TXALL | GREG_STAT_TXINTME | \ + GREG_STAT_RXDONE | GREG_STAT_ABNORMAL) + /* The layout of GREG_IMASK and GREG_IACK is identical to GREG_STAT. * Bits set in GREG_IMASK will prevent that interrupt type from being * signalled to the cpu. GREG_IACK can be used to clear specific top-level @@ -950,7 +953,8 @@ enum link_state { struct gem { spinlock_t lock; - unsigned long regs; + spinlock_t tx_lock; + void __iomem *regs; int rx_new, rx_old; int tx_new, tx_old; @@ -969,6 +973,7 @@ struct gem { struct sk_buff *tx_skbs[RX_RING_SIZE]; u32 msg_enable; + u32 status; struct net_device_stats net_stats; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 13fdcca49..2cb1ac95a 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -203,12 +203,12 @@ MODULE_DEVICE_TABLE(pci, happymeal_pci_ids); */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) -static void sbus_hme_write32(unsigned long reg, u32 val) +static void sbus_hme_write32(void __iomem *reg, u32 val) { sbus_writel(val, reg); } -static u32 sbus_hme_read32(unsigned long reg) +static u32 sbus_hme_read32(void __iomem *reg) { return sbus_readl(reg); } @@ -232,12 +232,12 @@ static u32 sbus_hme_read_desc32(u32 *p) return *p; } -static void pci_hme_write32(unsigned long reg, u32 val) +static void pci_hme_write32(void __iomem *reg, u32 val) { writel(val, reg); } -static u32 pci_hme_read32(unsigned long reg) +static u32 pci_hme_read32(void __iomem *reg) { return readl(reg); } @@ -354,7 +354,7 @@ do { (__txd)->tx_addr = cpu_to_le32(__addr); \ /* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ -static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit) +static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) { hme_write32(hp, tregs + TCVR_BBDATA, bit); hme_write32(hp, tregs + TCVR_BBCLOCK, 0); @@ -362,7 +362,7 @@ static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit) } #if 0 -static u32 BB_GET_BIT(struct happy_meal *hp, unsigned long tregs, int internal) +static u32 BB_GET_BIT(struct happy_meal *hp, void __iomem *tregs, int internal) { u32 ret; @@ -378,7 +378,7 @@ static u32 BB_GET_BIT(struct happy_meal *hp, unsigned long tregs, int internal) } #endif -static u32 BB_GET_BIT2(struct happy_meal *hp, unsigned long tregs, int internal) +static u32 BB_GET_BIT2(struct happy_meal *hp, void __iomem *tregs, int internal) { u32 retval; @@ -397,7 +397,7 @@ static u32 BB_GET_BIT2(struct happy_meal *hp, unsigned long tregs, int internal) #define TCVR_FAILURE 0x80000000 /* Impossible MIF read value */ static int happy_meal_bb_read(struct happy_meal *hp, - unsigned long tregs, int reg) + void __iomem *tregs, int reg) { u32 tmp; int retval = 0; @@ -443,7 +443,7 @@ static int happy_meal_bb_read(struct happy_meal *hp, } static void happy_meal_bb_write(struct happy_meal *hp, - unsigned long tregs, int reg, + void __iomem *tregs, int reg, unsigned short value) { u32 tmp; @@ -488,7 +488,7 @@ static void happy_meal_bb_write(struct happy_meal *hp, #define TCVR_READ_TRIES 16 static int happy_meal_tcvr_read(struct happy_meal *hp, - unsigned long tregs, int reg) + void __iomem *tregs, int reg) { int tries = TCVR_READ_TRIES; int retval; @@ -520,7 +520,7 @@ static int happy_meal_tcvr_read(struct happy_meal *hp, #define TCVR_WRITE_TRIES 16 static void happy_meal_tcvr_write(struct happy_meal *hp, - unsigned long tregs, int reg, + void __iomem *tregs, int reg, unsigned short value) { int tries = TCVR_WRITE_TRIES; @@ -579,7 +579,7 @@ static void happy_meal_tcvr_write(struct happy_meal *hp, * service routine, and the chip is reset, or the link is ifconfig'd down * and then back up, this entire process repeats itself all over again. */ -static int try_next_permutation(struct happy_meal *hp, unsigned long tregs) +static int try_next_permutation(struct happy_meal *hp, void __iomem *tregs) { hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); @@ -603,7 +603,7 @@ static int try_next_permutation(struct happy_meal *hp, unsigned long tregs) return -1; } -static void display_link_mode(struct happy_meal *hp, unsigned long tregs) +static void display_link_mode(struct happy_meal *hp, void __iomem *tregs) { printk(KERN_INFO "%s: Link is up using ", hp->dev->name); if (hp->tcvr_type == external) @@ -625,7 +625,7 @@ static void display_link_mode(struct happy_meal *hp, unsigned long tregs) } } -static void display_forced_link_mode(struct happy_meal *hp, unsigned long tregs) +static void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs) { printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name); if (hp->tcvr_type == external) @@ -644,7 +644,7 @@ static void display_forced_link_mode(struct happy_meal *hp, unsigned long tregs) printk("Half Duplex.\n"); } -static int set_happy_link_modes(struct happy_meal *hp, unsigned long tregs) +static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs) { int full; @@ -708,7 +708,7 @@ static int happy_meal_init(struct happy_meal *hp); static int is_lucent_phy(struct happy_meal *hp) { - unsigned long tregs = hp->tcvregs; + void __iomem *tregs = hp->tcvregs; unsigned short mr2, mr3; int ret = 0; @@ -724,7 +724,7 @@ static int is_lucent_phy(struct happy_meal *hp) static void happy_meal_timer(unsigned long data) { struct happy_meal *hp = (struct happy_meal *) data; - unsigned long tregs = hp->tcvregs; + void __iomem *tregs = hp->tcvregs; int restart_timer = 0; spin_lock_irq(&hp->happy_lock); @@ -905,7 +905,7 @@ out: #define RX_RESET_TRIES 32 /* hp->happy_lock must be held */ -static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs) +static void happy_meal_tx_reset(struct happy_meal *hp, void __iomem *bregs) { int tries = TX_RESET_TRIES; @@ -925,7 +925,7 @@ static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs) } /* hp->happy_lock must be held */ -static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs) +static void happy_meal_rx_reset(struct happy_meal *hp, void __iomem *bregs) { int tries = RX_RESET_TRIES; @@ -947,7 +947,7 @@ static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs) #define STOP_TRIES 16 /* hp->happy_lock must be held */ -static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs) +static void happy_meal_stop(struct happy_meal *hp, void __iomem *gregs) { int tries = STOP_TRIES; @@ -967,7 +967,7 @@ static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs) } /* hp->happy_lock must be held */ -static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs) +static void happy_meal_get_counters(struct happy_meal *hp, void __iomem *bregs) { struct net_device_stats *stats = &hp->net_stats; @@ -990,7 +990,7 @@ static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs) } /* hp->happy_lock must be held */ -static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs) +static void happy_meal_poll_stop(struct happy_meal *hp, void __iomem *tregs) { ASD(("happy_meal_poll_stop: ")); @@ -1025,7 +1025,7 @@ static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs) #define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */ /* hp->happy_lock must be held */ -static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs) +static int happy_meal_tcvr_reset(struct happy_meal *hp, void __iomem *tregs) { u32 tconfig; int result, tries = TCVR_RESET_TRIES; @@ -1123,7 +1123,7 @@ static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs) * * hp->happy_lock must be held */ -static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs) +static void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tregs) { unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG); @@ -1318,7 +1318,7 @@ static void happy_meal_init_rings(struct happy_meal *hp) /* hp->happy_lock must be held */ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, - unsigned long tregs, + void __iomem *tregs, struct ethtool_cmd *ep) { int timeout; @@ -1443,11 +1443,11 @@ force_link: /* hp->happy_lock must be held */ static int happy_meal_init(struct happy_meal *hp) { - unsigned long gregs = hp->gregs; - unsigned long etxregs = hp->etxregs; - unsigned long erxregs = hp->erxregs; - unsigned long bregs = hp->bigmacregs; - unsigned long tregs = hp->tcvregs; + void __iomem *gregs = hp->gregs; + void __iomem *etxregs = hp->etxregs; + void __iomem *erxregs = hp->erxregs; + void __iomem *bregs = hp->bigmacregs; + void __iomem *tregs = hp->tcvregs; u32 regtmp, rxcfg; unsigned char *e = &hp->dev->dev_addr[0]; @@ -1736,9 +1736,9 @@ static int happy_meal_init(struct happy_meal *hp) /* hp->happy_lock must be held */ static void happy_meal_set_initial_advertisement(struct happy_meal *hp) { - unsigned long tregs = hp->tcvregs; - unsigned long bregs = hp->bigmacregs; - unsigned long gregs = hp->gregs; + void __iomem *tregs = hp->tcvregs; + void __iomem *bregs = hp->bigmacregs; + void __iomem *gregs = hp->gregs; happy_meal_stop(hp, gregs); hme_write32(hp, tregs + TCVR_IMASK, 0xffff); @@ -1910,7 +1910,7 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status) /* hp->happy_lock must be held */ static void happy_meal_mif_interrupt(struct happy_meal *hp) { - unsigned long tregs = hp->tcvregs; + void __iomem *tregs = hp->tcvregs; printk(KERN_INFO "%s: Link status change.\n", hp->dev->name); hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); @@ -2390,7 +2390,7 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) static void happy_meal_set_multicast(struct net_device *dev) { struct happy_meal *hp = dev->priv; - unsigned long bregs = hp->bigmacregs; + void __iomem *bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; @@ -3025,7 +3025,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) #endif struct happy_meal *hp; struct net_device *dev; - unsigned long hpreg_base; + void __iomem *hpreg_base; + unsigned long hpreg_res; int i, qfe_slot = -1; char prom_name[64]; int err; @@ -3084,7 +3085,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) qp->happy_meals[qfe_slot] = dev; } - hpreg_base = pci_resource_start(pdev, 0); + hpreg_res = pci_resource_start(pdev, 0); err = -ENODEV; if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); @@ -3096,7 +3097,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) goto err_out_clear_quattro; } - if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) { + if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == 0) { printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); goto err_out_free_res; } diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index f2784d217..34e9f953c 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -397,7 +397,7 @@ struct quattro; /* Happy happy, joy joy! */ struct happy_meal { - unsigned long gregs; /* Happy meal global registers */ + void __iomem *gregs; /* Happy meal global registers */ struct hmeal_init_block *happy_block; /* RX and TX descriptors (CPU addr) */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) @@ -423,14 +423,14 @@ struct happy_meal { struct net_device_stats net_stats; /* Statistical counters */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - u32 (*read32)(unsigned long); - void (*write32)(unsigned long, u32); + u32 (*read32)(void __iomem *); + void (*write32)(void __iomem *, u32); #endif - unsigned long etxregs; /* External transmitter regs */ - unsigned long erxregs; /* External receiver regs */ - unsigned long bigmacregs; /* BIGMAC core regs */ - unsigned long tcvregs; /* MIF transceiver regs */ + void __iomem *etxregs; /* External transmitter regs */ + void __iomem *erxregs; /* External receiver regs */ + void __iomem *bigmacregs; /* BIGMAC core regs */ + void __iomem *tcvregs; /* MIF transceiver regs */ dma_addr_t hblock_dvma; /* DVMA visible address happy block */ unsigned int happy_flags; /* Driver state flags */ diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index e80311524..6e4bb5781 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -230,9 +230,9 @@ struct lance_init_block { ((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem][0]))))) struct lance_private { - unsigned long lregs; /* Lance RAP/RDP regs. */ - unsigned long dregs; /* DMA controller regs. */ - volatile struct lance_init_block *init_block; + void __iomem *lregs; /* Lance RAP/RDP regs. */ + void __iomem *dregs; /* DMA controller regs. */ + struct lance_init_block *init_block; spinlock_t lock; @@ -270,7 +270,7 @@ struct lance_private { #define LANCE_REG_SIZE 0x04UL #define STOP_LANCE(__lp) \ -do { unsigned long __base = (__lp)->lregs; \ +do { void __iomem *__base = (__lp)->lregs; \ sbus_writew(LE_CSR0, __base + RAP); \ sbus_writew(LE_C0_STOP, __base + RDP); \ } while (0) @@ -314,7 +314,7 @@ static void load_csrs(struct lance_private *lp) static void lance_init_ring_dvma(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; dma_addr_t aib = lp->init_block_dvma; __u32 leptr; int i; @@ -371,7 +371,7 @@ static void lance_init_ring_dvma(struct net_device *dev) static void lance_init_ring_pio(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; u32 leptr; int i; @@ -501,8 +501,8 @@ static int init_restart_lance(struct lance_private *lp) static void lance_rx_dvma(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_rx_desc *rd; + struct lance_init_block *ib = lp->init_block; + struct lance_rx_desc *rd; u8 bits; int len, entry = lp->rx_new; struct sk_buff *skb; @@ -564,14 +564,14 @@ static void lance_rx_dvma(struct net_device *dev) static void lance_tx_dvma(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int i, j; spin_lock(&lp->lock); j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { - volatile struct lance_tx_desc *td = &ib->btx_ring [i]; + struct lance_tx_desc *td = &ib->btx_ring [i]; u8 bits = td->tmd1_bits; /* If we hit a packet not owned by us, stop */ @@ -641,12 +641,12 @@ out: spin_unlock(&lp->lock); } -static void lance_piocopy_to_skb(struct sk_buff *skb, volatile void *piobuf, int len) +static void lance_piocopy_to_skb(struct sk_buff *skb, void __iomem *piobuf, int len) { u16 *p16 = (u16 *) skb->data; u32 *p32; u8 *p8; - unsigned long pbuf = (unsigned long) piobuf; + void __iomem *pbuf = piobuf; /* We know here that both src and dest are on a 16bit boundary. */ *p16++ = sbus_readw(pbuf); @@ -674,8 +674,8 @@ static void lance_piocopy_to_skb(struct sk_buff *skb, volatile void *piobuf, int static void lance_rx_pio(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_rx_desc *rd; + struct lance_init_block *ib = lp->init_block; + struct lance_rx_desc *rd; unsigned char bits; int len, entry; struct sk_buff *skb; @@ -736,14 +736,14 @@ static void lance_rx_pio(struct net_device *dev) static void lance_tx_pio(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int i, j; spin_lock(&lp->lock); j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { - volatile struct lance_tx_desc *td = &ib->btx_ring [i]; + struct lance_tx_desc *td = &ib->btx_ring [i]; u8 bits = sbus_readb(&td->tmd1_bits); /* If we hit a packet not owned by us, stop */ @@ -880,7 +880,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void build_fake_packet(struct lance_private *lp) { struct net_device *dev = lp->dev; - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; u16 *packet; struct ethhdr *eth; int i, entry; @@ -916,7 +916,7 @@ struct net_device *last_dev; static int lance_open(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int status = 0; last_dev = dev; @@ -1006,9 +1006,9 @@ static int lance_reset(struct net_device *dev) return status; } -static void lance_piocopy_from_skb(volatile void *dest, unsigned char *src, int len) +static void lance_piocopy_from_skb(void __iomem *dest, unsigned char *src, int len) { - unsigned long piobuf = (unsigned long) dest; + void __iomem *piobuf = dest; u32 *p32; u16 *p16; u8 *p8; @@ -1064,11 +1064,11 @@ static void lance_piocopy_from_skb(volatile void *dest, unsigned char *src, int sbus_writeb(src[0], piobuf); } -static void lance_piozero(volatile void *dest, int len) +static void lance_piozero(void __iomem *dest, int len) { - unsigned long piobuf = (unsigned long) dest; + void __iomem *piobuf = dest; - if (piobuf & 1) { + if ((unsigned long)piobuf & 1) { sbus_writeb(0, piobuf); piobuf += 1; len -= 1; @@ -1079,7 +1079,7 @@ static void lance_piozero(volatile void *dest, int len) sbus_writeb(0, piobuf); return; } - if (piobuf & 2) { + if ((unsigned long)piobuf & 2) { sbus_writew(0, piobuf); piobuf += 2; len -= 2; @@ -1113,7 +1113,7 @@ static void lance_tx_timeout(struct net_device *dev) static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; int entry, skblen, len; skblen = skb->len; @@ -1174,8 +1174,8 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev) static void lance_load_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; - volatile u16 *mcast_table = (u16 *) &ib->filter; + struct lance_init_block *ib = lp->init_block; + u16 *mcast_table = (u16 *) &ib->filter; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; @@ -1224,7 +1224,7 @@ static void lance_load_multicast(struct net_device *dev) static void lance_set_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib = lp->init_block; + struct lance_init_block *ib = lp->init_block; u16 mode; if (!netif_running(dev)) @@ -1277,12 +1277,12 @@ static void lance_free_hwresources(struct lance_private *lp) sbus_iounmap(lp->lregs, LANCE_REG_SIZE); if (lp->init_block != NULL) { if (lp->pio_buffer) { - sbus_iounmap((unsigned long)lp->init_block, + sbus_iounmap(lp->init_block, sizeof(struct lance_init_block)); } else { sbus_free_consistent(lp->sdev, sizeof(struct lance_init_block), - (void *)lp->init_block, + lp->init_block, lp->init_block_dvma); } } @@ -1349,7 +1349,7 @@ static int __init sparc_lance_init(struct sbus_dev *sdev, lp->sdev = sdev; if (lebuffer) { - lp->init_block = (volatile struct lance_init_block *) + lp->init_block = sbus_ioremap(&lebuffer->resource[0], 0, sizeof(struct lance_init_block), "lebuffer"); if (lp->init_block == NULL) { @@ -1362,7 +1362,7 @@ static int __init sparc_lance_init(struct sbus_dev *sdev, lp->rx = lance_rx_pio; lp->tx = lance_tx_pio; } else { - lp->init_block = (volatile struct lance_init_block *) + lp->init_block = sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), &lp->init_block_dvma); if (lp->init_block == NULL || diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 39a4b40b4..1ed3ff5b3 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -49,7 +49,7 @@ static void qe_set_multicast(struct net_device *dev); #define QEC_RESET_TRIES 200 -static inline int qec_global_reset(unsigned long gregs) +static inline int qec_global_reset(void __iomem *gregs) { int tries = QEC_RESET_TRIES; @@ -73,8 +73,8 @@ static inline int qec_global_reset(unsigned long gregs) static inline int qe_stop(struct sunqe *qep) { - unsigned long cregs = qep->qcregs; - unsigned long mregs = qep->mregs; + void __iomem *cregs = qep->qcregs; + void __iomem *mregs = qep->mregs; int tries; /* Reset the MACE, then the QEC channel. */ @@ -130,9 +130,9 @@ static void qe_init_rings(struct sunqe *qep) static int qe_init(struct sunqe *qep, int from_irq) { struct sunqec *qecp = qep->parent; - unsigned long cregs = qep->qcregs; - unsigned long mregs = qep->mregs; - unsigned long gregs = qecp->gregs; + void __iomem *cregs = qep->qcregs; + void __iomem *mregs = qep->mregs; + void __iomem *gregs = qecp->gregs; unsigned char *e = &qep->dev->dev_addr[0]; u32 tmp; int i; @@ -699,7 +699,7 @@ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static u32 qe_get_link(struct net_device *dev) { struct sunqe *qep = dev->priv; - unsigned long mregs = qep->mregs; + void __iomem *mregs = qep->mregs; u8 phyconfig; spin_lock_irq(&qep->lock); diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h index b90ed5db4..af34f3611 100644 --- a/drivers/net/sunqe.h +++ b/drivers/net/sunqe.h @@ -311,7 +311,7 @@ struct qe_init_block { struct sunqe; struct sunqec { - unsigned long gregs; /* QEC Global Registers */ + void __iomem *gregs; /* QEC Global Registers */ struct sunqe *qes[4]; /* Each child MACE */ unsigned int qec_bursts; /* Support burst sizes */ struct sbus_dev *qec_sdev; /* QEC's SBUS device */ @@ -331,8 +331,8 @@ struct sunqe_buffers { ((__u32)((unsigned long)(&(((struct sunqe_buffers *)0)->mem[elem][0])))) struct sunqe { - unsigned long qcregs; /* QEC per-channel Registers */ - unsigned long mregs; /* Per-channel MACE Registers */ + void __iomem *qcregs; /* QEC per-channel Registers */ + void __iomem *mregs; /* Per-channel MACE Registers */ struct qe_init_block *qe_block; /* RX and TX descriptors */ __u32 qblock_dvma; /* RX and TX descriptors */ spinlock_t lock; /* Protects txfull state */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0e4615472..1a26b11fb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4,6 +4,9 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. + * + * Firmware is: + * Copyright (C) 2000-2003 Broadcom Corporation. */ #include @@ -57,8 +60,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.8" -#define DRV_MODULE_RELDATE "July 14, 2004" +#define DRV_MODULE_VERSION "3.10" +#define DRV_MODULE_RELDATE "September 14, 2004" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -328,7 +331,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val) pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); spin_unlock_irqrestore(&tp->indirect_lock, flags); } else { - unsigned long dest = tp->regs + off; + void __iomem *dest = tp->regs + off; writel(val, dest); readl(dest); /* always flush PCI write */ } @@ -336,7 +339,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val) static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val) { - unsigned long mbox = tp->regs + off; + void __iomem *mbox = tp->regs + off; writel(val, mbox); if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) readl(mbox); @@ -344,7 +347,7 @@ static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val) static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val) { - unsigned long mbox = tp->regs + off; + void __iomem *mbox = tp->regs + off; writel(val, mbox); if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) writel(val, mbox); @@ -442,9 +445,14 @@ static void tg3_switch_clocks(struct tg3 *tp) 0x1f); tp->pci_clock_ctrl = clock_ctrl; - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) { + tw32_f(TG3PCI_CLOCK_CTRL, + clock_ctrl | CLOCK_CTRL_625_CORE); + udelay(40); + } + } else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK)); @@ -980,7 +988,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) tp->link_config.orig_autoneg = tp->link_config.autoneg; } - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tp->link_config.speed = SPEED_10; tp->link_config.duplex = DUPLEX_HALF; tp->link_config.autoneg = AUTONEG_ENABLE; @@ -992,7 +1000,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { u32 mac_mode; - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); udelay(40); @@ -1114,29 +1122,33 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; - if (local_adv & ADVERTISE_PAUSE_CAP) { - if (local_adv & ADVERTISE_PAUSE_ASYM) { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); - else if (remote_adv & LPA_PAUSE_ASYM) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE); - } else { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); + if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) { + if (local_adv & ADVERTISE_PAUSE_CAP) { + if (local_adv & ADVERTISE_PAUSE_ASYM) { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + else if (remote_adv & LPA_PAUSE_ASYM) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE); + } else { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + } + } else if (local_adv & ADVERTISE_PAUSE_ASYM) { + if ((remote_adv & LPA_PAUSE_CAP) && + (remote_adv & LPA_PAUSE_ASYM)) + new_tg3_flags |= TG3_FLAG_TX_PAUSE; } - } else if (local_adv & ADVERTISE_PAUSE_ASYM) { - if ((remote_adv & LPA_PAUSE_CAP) && - (remote_adv & LPA_PAUSE_ASYM)) - new_tg3_flags |= TG3_FLAG_TX_PAUSE; - } - tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); - tp->tg3_flags |= new_tg3_flags; + tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); + tp->tg3_flags |= new_tg3_flags; + } else { + new_tg3_flags = tp->tg3_flags; + } if (new_tg3_flags & TG3_FLAG_RX_PAUSE) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; @@ -1487,6 +1499,18 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) current_speed = SPEED_INVALID; current_duplex = DUPLEX_INVALID; + if (tp->tg3_flags2 & TG3_FLG2_CAPACITIVE_COUPLING) { + u32 val; + + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007); + tg3_readphy(tp, MII_TG3_AUX_CTRL, &val); + if (!(val & (1 << 10))) { + val |= (1 << 10); + tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + goto relink; + } + } + bmsr = 0; for (i = 0; i < 100; i++) { tg3_readphy(tp, MII_BMSR, &bmsr); @@ -1566,7 +1590,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) tg3_setup_flow_control(tp, local_adv, remote_adv); } } - +relink: if (current_link_up == 0) { u32 tmp; @@ -1616,7 +1640,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES)) { + if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { /* Polled via timer. */ tw32_f(MAC_EVENT, 0); } else { @@ -1965,190 +1989,318 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, static int fiber_autoneg(struct tg3 *tp, u32 *flags) { int res = 0; + struct tg3_fiber_aneginfo aninfo; + int status = ANEG_FAILED; + unsigned int tick; + u32 tmp; - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) { - u32 dig_status; + tw32_f(MAC_TX_AUTO_NEG, 0); - dig_status = tr32(SG_DIG_STATUS); - *flags = 0; - if (dig_status & SG_DIG_PARTNER_ASYM_PAUSE) - *flags |= MR_LP_ADV_ASYM_PAUSE; - if (dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE) - *flags |= MR_LP_ADV_SYM_PAUSE; + tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; + tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); + udelay(40); - if ((dig_status & SG_DIG_AUTONEG_COMPLETE) && - !(dig_status & (SG_DIG_AUTONEG_ERROR | - SG_DIG_PARTNER_FAULT_MASK))) - res = 1; - } else { - struct tg3_fiber_aneginfo aninfo; - int status = ANEG_FAILED; - unsigned int tick; - u32 tmp; + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); + udelay(40); - tw32_f(MAC_TX_AUTO_NEG, 0); + memset(&aninfo, 0, sizeof(aninfo)); + aninfo.flags |= MR_AN_ENABLE; + aninfo.state = ANEG_STATE_UNKNOWN; + aninfo.cur_time = 0; + tick = 0; + while (++tick < 195000) { + status = tg3_fiber_aneg_smachine(tp, &aninfo); + if (status == ANEG_DONE || status == ANEG_FAILED) + break; - tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); - udelay(40); + udelay(1); + } - tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); - udelay(40); + tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); - memset(&aninfo, 0, sizeof(aninfo)); - aninfo.flags |= MR_AN_ENABLE; - aninfo.state = ANEG_STATE_UNKNOWN; - aninfo.cur_time = 0; - tick = 0; - while (++tick < 195000) { - status = tg3_fiber_aneg_smachine(tp, &aninfo); - if (status == ANEG_DONE || status == ANEG_FAILED) - break; + *flags = aninfo.flags; - udelay(1); - } + if (status == ANEG_DONE && + (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | + MR_LP_ADV_FULL_DUPLEX))) + res = 1; - tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); + return res; +} - *flags = aninfo.flags; +static void tg3_init_bcm8002(struct tg3 *tp) +{ + u32 mac_status = tr32(MAC_STATUS); + int i; - if (status == ANEG_DONE && - (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | - MR_LP_ADV_FULL_DUPLEX))) - res = 1; - } + /* Reset when initting first time or we have a link. */ + if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) && + !(mac_status & MAC_STATUS_PCS_SYNCED)) + return; - return res; + /* Set PLL lock range. */ + tg3_writephy(tp, 0x16, 0x8007); + + /* SW reset */ + tg3_writephy(tp, MII_BMCR, BMCR_RESET); + + /* Wait for reset to complete. */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 500; i++) + udelay(10); + + /* Config mode; select PMA/Ch 1 regs. */ + tg3_writephy(tp, 0x10, 0x8411); + + /* Enable auto-lock and comdet, select txclk for tx. */ + tg3_writephy(tp, 0x11, 0x0a10); + + tg3_writephy(tp, 0x18, 0x00a0); + tg3_writephy(tp, 0x16, 0x41ff); + + /* Assert and deassert POR. */ + tg3_writephy(tp, 0x13, 0x0400); + udelay(40); + tg3_writephy(tp, 0x13, 0x0000); + + tg3_writephy(tp, 0x11, 0x0a50); + udelay(40); + tg3_writephy(tp, 0x11, 0x0a10); + + /* Wait for signal to stabilize */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 15000; i++) + udelay(10); + + /* Deselect the channel register so we can read the PHYID + * later. + */ + tg3_writephy(tp, 0x10, 0x8011); } -static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) +static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) { - u32 orig_pause_cfg; - u16 orig_active_speed; - u8 orig_active_duplex; + u32 sg_dig_ctrl, sg_dig_status; + u32 serdes_cfg, expected_sg_dig_ctrl; + int workaround, port_a; int current_link_up; - int i; - orig_pause_cfg = - (tp->tg3_flags & (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE)); - orig_active_speed = tp->link_config.active_speed; - orig_active_duplex = tp->link_config.active_duplex; + serdes_cfg = 0; + expected_sg_dig_ctrl = 0; + workaround = 0; + port_a = 1; + current_link_up = 0; - tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); - tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); + if (tp->pci_chip_rev_id != CHIPREV_ID_5704_A0 && + tp->pci_chip_rev_id != CHIPREV_ID_5704_A1) { + workaround = 1; + if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) + port_a = 0; - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) { - /* Allow time for the hardware to auto-negotiate (195ms) */ - unsigned int tick = 0; + serdes_cfg = tr32(MAC_SERDES_CFG) & + ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20)); + } - while (++tick < 195000) { - if (tr32(SG_DIG_STATUS) & SG_DIG_AUTONEG_COMPLETE) - break; - udelay(1); + sg_dig_ctrl = tr32(SG_DIG_CTRL); + + if (tp->link_config.autoneg != AUTONEG_ENABLE) { + if (sg_dig_ctrl & (1 << 31)) { + if (workaround) { + u32 val = serdes_cfg; + + if (port_a) + val |= 0xc010880; + else + val |= 0x4010880; + tw32_f(MAC_SERDES_CFG, val); + } + tw32_f(SG_DIG_CTRL, 0x01388400); } - if (tick >= 195000) - printk(KERN_INFO PFX "%s: HW autoneg failed !\n", - tp->dev->name); + if (mac_status & MAC_STATUS_PCS_SYNCED) { + tg3_setup_flow_control(tp, 0, 0); + current_link_up = 1; + } + goto out; } - /* Reset when initting first time or we have a link. */ - if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || - (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { - /* Set PLL lock range. */ - tg3_writephy(tp, 0x16, 0x8007); + /* Want auto-negotiation. */ + expected_sg_dig_ctrl = 0x81388400; - /* SW reset */ - tg3_writephy(tp, MII_BMCR, BMCR_RESET); + /* Pause capability */ + expected_sg_dig_ctrl |= (1 << 11); - /* Wait for reset to complete. */ - /* XXX schedule_timeout() ... */ - for (i = 0; i < 500; i++) - udelay(10); + /* Asymettric pause */ + expected_sg_dig_ctrl |= (1 << 12); - /* Config mode; select PMA/Ch 1 regs. */ - tg3_writephy(tp, 0x10, 0x8411); + if (sg_dig_ctrl != expected_sg_dig_ctrl) { + if (workaround) + tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011880); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30)); + udelay(5); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl); - /* Enable auto-lock and comdet, select txclk for tx. */ - tg3_writephy(tp, 0x11, 0x0a10); + tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED; + } else if (mac_status & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET)) { + sg_dig_status = tr32(SG_DIG_STATUS); - tg3_writephy(tp, 0x18, 0x00a0); - tg3_writephy(tp, 0x16, 0x41ff); + if ((sg_dig_status & (1 << 1)) && + (mac_status & MAC_STATUS_PCS_SYNCED)) { + u32 local_adv, remote_adv; - /* Assert and deassert POR. */ - tg3_writephy(tp, 0x13, 0x0400); - udelay(40); - tg3_writephy(tp, 0x13, 0x0000); + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (sg_dig_status & (1 << 19)) + remote_adv |= LPA_PAUSE_CAP; + if (sg_dig_status & (1 << 20)) + remote_adv |= LPA_PAUSE_ASYM; - tg3_writephy(tp, 0x11, 0x0a50); - udelay(40); - tg3_writephy(tp, 0x11, 0x0a10); + tg3_setup_flow_control(tp, local_adv, remote_adv); + current_link_up = 1; + tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; + } else if (!(sg_dig_status & (1 << 1))) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) + tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; + else { + if (workaround) { + u32 val = serdes_cfg; + + if (port_a) + val |= 0xc010880; + else + val |= 0x4010880; + + tw32_f(MAC_SERDES_CFG, val); + } - /* Wait for signal to stabilize */ - /* XXX schedule_timeout() ... */ - for (i = 0; i < 15000; i++) - udelay(10); + tw32_f(SG_DIG_CTRL, 0x01388400); + udelay(40); - /* Deselect the channel register so we can read the PHYID - * later. - */ - tg3_writephy(tp, 0x10, 0x8011); + mac_status = tr32(MAC_STATUS); + if (mac_status & MAC_STATUS_PCS_SYNCED) { + tg3_setup_flow_control(tp, 0, 0); + current_link_up = 1; + } + } + } } - /* Enable link change interrupt unless serdes polling. */ - if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES)) - tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); - else - tw32_f(MAC_EVENT, 0); - udelay(40); +out: + return current_link_up; +} - current_link_up = 0; - if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) { - if (tp->link_config.autoneg == AUTONEG_ENABLE) { - u32 flags; +static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) +{ + int current_link_up = 0; + + if (!(mac_status & MAC_STATUS_PCS_SYNCED)) { + tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; + goto out; + } + + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + u32 flags; + int i; - if (fiber_autoneg(tp, &flags)) { - u32 local_adv, remote_adv; + if (fiber_autoneg(tp, &flags)) { + u32 local_adv, remote_adv; - local_adv = ADVERTISE_PAUSE_CAP; - remote_adv = 0; - if (flags & MR_LP_ADV_SYM_PAUSE) - remote_adv |= LPA_PAUSE_CAP; - if (flags & MR_LP_ADV_ASYM_PAUSE) - remote_adv |= LPA_PAUSE_ASYM; + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (flags & MR_LP_ADV_SYM_PAUSE) + remote_adv |= LPA_PAUSE_CAP; + if (flags & MR_LP_ADV_ASYM_PAUSE) + remote_adv |= LPA_PAUSE_ASYM; - tg3_setup_flow_control(tp, local_adv, remote_adv); + tg3_setup_flow_control(tp, local_adv, remote_adv); - tp->tg3_flags |= - TG3_FLAG_GOT_SERDES_FLOWCTL; - current_link_up = 1; - } - for (i = 0; i < 60; i++) { - udelay(20); - tw32_f(MAC_STATUS, - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - udelay(40); - if ((tr32(MAC_STATUS) & - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)) == 0) - break; - } - if (current_link_up == 0 && - (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { - current_link_up = 1; - } - } else { - /* Forcing 1000FD link up. */ - current_link_up = 1; tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; + current_link_up = 1; } - } else - tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; + for (i = 0; i < 30; i++) { + udelay(20); + tw32_f(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(40); + if ((tr32(MAC_STATUS) & + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + + mac_status = tr32(MAC_STATUS); + if (current_link_up == 0 && + (mac_status & MAC_STATUS_PCS_SYNCED) && + !(mac_status & MAC_STATUS_RCVD_CFG)) + current_link_up = 1; + } else { + /* Forcing 1000FD link up. */ + current_link_up = 1; + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; + + tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS)); + udelay(40); + } + +out: + return current_link_up; +} + +static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) +{ + u32 orig_pause_cfg; + u16 orig_active_speed; + u8 orig_active_duplex; + u32 mac_status; + int current_link_up; + int i; + + orig_pause_cfg = + (tp->tg3_flags & (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE)); + orig_active_speed = tp->link_config.active_speed; + orig_active_duplex = tp->link_config.active_duplex; + + if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) && + netif_carrier_ok(tp->dev) && + (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) { + mac_status = tr32(MAC_STATUS); + mac_status &= (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET | + MAC_STATUS_CFG_CHANGED | + MAC_STATUS_RCVD_CFG); + if (mac_status == (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET)) { + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + return 0; + } + } + + tw32_f(MAC_TX_AUTO_NEG, 0); + + tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); + tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); + + if (tp->phy_id == PHY_ID_BCM8002) + tg3_init_bcm8002(tp); + + /* Enable link change event even when serdes polling. */ + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + udelay(40); + + current_link_up = 0; + mac_status = tr32(MAC_STATUS); + + if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) + current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status); + else + current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; tw32_f(MAC_MODE, tp->mac_mode); @@ -2159,19 +2311,24 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); for (i = 0; i < 100; i++) { - udelay(20); - tw32_f(MAC_STATUS, - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - udelay(40); - if ((tr32(MAC_STATUS) & - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)) == 0) + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(5); + if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) break; } - if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) + mac_status = tr32(MAC_STATUS); + if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) { current_link_up = 0; + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + tw32_f(MAC_MODE, (tp->mac_mode | + MAC_MODE_SEND_CONFIGS)); + udelay(1); + tw32_f(MAC_MODE, tp->mac_mode); + } + } if (current_link_up == 1) { tp->link_config.active_speed = SPEED_1000; @@ -2203,15 +2360,6 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) tg3_link_report(tp); } - if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { - tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); - udelay(40); - if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); - } - } - return 0; } @@ -2219,7 +2367,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) { int err; - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { err = tg3_setup_fiber_phy(tp, force_reset); } else { err = tg3_setup_copper_phy(tp, force_reset); @@ -2738,11 +2886,11 @@ static void tg3_reset_task(void *_data) tg3_halt(tp); tg3_init_hw(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); - if (restart_timer) mod_timer(&tp->timer, jiffies + 1); } @@ -2812,6 +2960,7 @@ static void tg3_set_txd(struct tg3 *tp, int entry, dma_addr_t mapping, int len, u32 flags, u32 mss_and_is_end) { + struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; int is_end = (mss_and_is_end & 0x1); u32 mss = (mss_and_is_end >> 1); u32 vlan_tag = 0; @@ -2823,35 +2972,11 @@ static void tg3_set_txd(struct tg3 *tp, int entry, flags &= 0xffff; } vlan_tag |= (mss << TXD_MSS_SHIFT); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; - - txd->addr_hi = ((u64) mapping >> 32); - txd->addr_lo = ((u64) mapping & 0xffffffff); - txd->len_flags = (len << TXD_LEN_SHIFT) | flags; - txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; - } else { - struct tx_ring_info *txr = &tp->tx_buffers[entry]; - unsigned long txd; - txd = (tp->regs + - NIC_SRAM_WIN_BASE + - NIC_SRAM_TX_BUFFER_DESC); - txd += (entry * TXD_SIZE); - - /* Save some PIOs */ - if (sizeof(dma_addr_t) != sizeof(u32)) - writel(((u64) mapping >> 32), - txd + TXD_ADDR + TG3_64BIT_REG_HIGH); - - writel(((u64) mapping & 0xffffffff), - txd + TXD_ADDR + TG3_64BIT_REG_LOW); - writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS); - if (txr->prev_vlan_tag != vlan_tag) { - writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); - txr->prev_vlan_tag = vlan_tag; - } - } + txd->addr_hi = ((u64) mapping >> 32); + txd->addr_lo = ((u64) mapping & 0xffffffff); + txd->len_flags = (len << TXD_LEN_SHIFT) | flags; + txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) @@ -2892,7 +3017,11 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) * So we really do need to disable interrupts when taking * tx_lock here. */ - spin_lock_irqsave(&tp->tx_lock, flags); + local_irq_save(flags); + if (!spin_trylock(&tp->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* This is a hard error, log it. */ if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { @@ -2900,7 +3029,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&tp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } entry = tp->tx_prod; @@ -3040,19 +3169,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Packets are ready, update Tx producer idx local and on card. */ - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - } else { - /* First, make sure tg3 sees last descriptor fully - * in SRAM. - */ - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); - - tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - } + tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); tp->tx_prod = entry; if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) @@ -3063,7 +3180,7 @@ out_unlock: dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, @@ -3102,9 +3219,10 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_init_hw(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -3190,7 +3308,6 @@ static void tg3_free_rings(struct tg3 *tp) */ static void tg3_init_rings(struct tg3 *tp) { - unsigned long start, end; u32 i; /* Free up all the SKBs. */ @@ -3200,21 +3317,7 @@ static void tg3_init_rings(struct tg3 *tp) memset(tp->rx_std, 0, TG3_RX_RING_BYTES); memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - } else { - start = (tp->regs + - NIC_SRAM_WIN_BASE + - NIC_SRAM_TX_BUFFER_DESC); - end = start + TG3_TX_RING_BYTES; - while (start < end) { - writel(0, start); - start += 4; - } - for (i = 0; i < TG3_TX_RING_SIZE; i++) - tp->tx_buffers[i].prev_vlan_tag = 0; - } + memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); /* Initialize invariants of the rings, we only set this * stuff once. This works because the card does not @@ -3345,15 +3448,10 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (!tp->rx_rcb) goto err_out; - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tp->tx_desc_mapping); - if (!tp->tx_ring) - goto err_out; - } else { - tp->tx_ring = NULL; - tp->tx_desc_mapping = 0; - } + tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, + &tp->tx_desc_mapping); + if (!tp->tx_ring) + goto err_out; tp->hw_status = pci_alloc_consistent(tp->pdev, TG3_HW_STATUS_SIZE, @@ -3595,6 +3693,8 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind) } } +static void tg3_stop_fw(struct tg3 *); + /* tp->lock is held. */ static int tg3_chip_reset(struct tg3 *tp) { @@ -3602,7 +3702,7 @@ static int tg3_chip_reset(struct tg3 *tp) u32 flags_save; int i; - if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) + if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) tg3_nvram_lock(tp); /* @@ -3697,6 +3797,11 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) { + tg3_stop_fw(tp); + tw32(0x5000, 0x400); + } + tw32(GRC_MODE, tp->grc_mode); if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { @@ -3713,7 +3818,7 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->mac_mode = MAC_MODE_PORT_MODE_TBI; tw32_f(MAC_MODE, tp->mac_mode); } else @@ -3728,7 +3833,7 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(10); } if (i >= 100000 && - !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) { + !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) { printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, " "firmware will not restart magic=%08x\n", tp->dev->name, val); @@ -4810,10 +4915,7 @@ static int tg3_reset_hw(struct tg3 *tp) GRC_MODE_4X_NIC_SEND_RINGS | GRC_MODE_NO_TX_PHDR_CSUM | GRC_MODE_NO_RX_PHDR_CSUM); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) - tp->grc_mode |= GRC_MODE_HOST_SENDBDS; - else - tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS; + tp->grc_mode |= GRC_MODE_HOST_SENDBDS; if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) @@ -4966,18 +5068,11 @@ static int tg3_reset_hw(struct tg3 *tp) tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); - } else { - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - 0, - BDINFO_FLAGS_DISABLED, - NIC_SRAM_TX_BUFFER_DESC); - } + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, + tp->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); /* There is only one receive return ring on 5705/5750, no need * to explicitly disable the others. @@ -5243,14 +5338,14 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(MAC_LED_CTRL, tp->led_ctrl); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tw32_f(MAC_RX_MODE, RX_MODE_RESET); udelay(10); } tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { /* Set drive transmission level to 1.2V */ val = tr32(MAC_SERDES_CFG); @@ -5268,22 +5363,8 @@ static int tg3_reset_hw(struct tg3 *tp) tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - tp->phy_id == PHY_ID_SERDES) { - /* Enable hardware link auto-negotiation */ - u32 digctrl, txctrl; - - digctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_CRC16_CLEAR_N | - SG_DIG_LOCAL_DUPLEX_STATUS | SG_DIG_LOCAL_LINK_STATUS | - (2 << SG_DIG_SPEED_STATUS_SHIFT) | SG_DIG_FIBER_MODE | - SG_DIG_GBIC_ENABLE; - - txctrl = tr32(MAC_SERDES_CFG); - tw32_f(MAC_SERDES_CFG, txctrl | MAC_SERDES_CFG_EDGE_SELECT); - tw32_f(SG_DIG_CTRL, digctrl | SG_DIG_SOFT_RESET); - tr32(SG_DIG_CTRL); - udelay(5); - tw32_f(SG_DIG_CTRL, digctrl); - + (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { + /* Use hardware link auto-negotiation */ tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG; } @@ -5291,7 +5372,7 @@ static int tg3_reset_hw(struct tg3 *tp) if (err) return err; - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { u32 tmp; /* Clear CRC stats. */ @@ -5483,7 +5564,8 @@ static void tg3_timer(unsigned long __opaque) need_setup = 1; } if (! netif_carrier_ok(tp->dev) && - (mac_stat & MAC_STATUS_PCS_SYNCED)) { + (mac_stat & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET))) { need_setup = 1; } if (need_setup) { @@ -5536,8 +5618,8 @@ static int tg3_open(struct net_device *dev) spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - /* If you move this call, make sure TG3_FLAG_HOST_TXDS in - * tp->tg3_flags is accurate at that new place. + /* The placement of this call is tied + * to the setup and use of Host TX descriptors. */ err = tg3_alloc_consistent(tp); if (err) @@ -5879,7 +5961,7 @@ static unsigned long calc_crc_errors(struct tg3 *tp) { struct tg3_hw_stats *hw_stats = tp->hw_stats; - if (tp->phy_id != PHY_ID_SERDES && + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { unsigned long flags; @@ -6152,7 +6234,9 @@ static void tg3_set_rx_mode(struct net_device *dev) struct tg3 *tp = netdev_priv(dev); spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); __tg3_set_rx_mode(dev); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } @@ -6310,7 +6394,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (tp->phy_id != PHY_ID_SERDES) + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -6339,7 +6423,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.phy_is_low_power) return -EAGAIN; - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -6397,7 +6481,7 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - tp->phy_id == PHY_ID_SERDES && + tp->tg3_flags2 & TG3_FLG2_PHY_SERDES && !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP)) return -EINVAL; @@ -6493,10 +6577,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tg3_halt(tp); tg3_init_hw(tp); - netif_wake_queue(tp->dev); + tg3_netif_start(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -6506,8 +6589,8 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam struct tg3 *tp = netdev_priv(dev); epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; - epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0; - epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0; + epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0; + epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0; } static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) @@ -6522,18 +6605,18 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam else tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; if (epause->rx_pause) - tp->tg3_flags |= TG3_FLAG_PAUSE_RX; + tp->tg3_flags |= TG3_FLAG_RX_PAUSE; else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX; + tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE; if (epause->tx_pause) - tp->tg3_flags |= TG3_FLAG_PAUSE_TX; + tp->tg3_flags |= TG3_FLAG_TX_PAUSE; else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX; + tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; tg3_halt(tp); tg3_init_hw(tp); + tg3_netif_start(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -6620,7 +6703,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIREG: { u32 mii_regval; - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ spin_lock_irq(&tp->lock); @@ -6633,7 +6716,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ if (!capable(CAP_NET_ADMIN)) @@ -6720,7 +6803,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) { int j; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) return; tw32_f(GRC_EEPROM_ADDR, @@ -6807,8 +6890,8 @@ static int __devinit tg3_nvram_read(struct tg3 *tp, { int i; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) { - printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 5704\n"); + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n"); return -EINVAL; } @@ -6870,10 +6953,10 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = { { PCI_VENDOR_ID_BROADCOM, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */ { PCI_VENDOR_ID_BROADCOM, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */ { PCI_VENDOR_ID_BROADCOM, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */ - { PCI_VENDOR_ID_BROADCOM, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */ + { PCI_VENDOR_ID_BROADCOM, 0x0003, 0 }, /* BCM95700A9 */ { PCI_VENDOR_ID_BROADCOM, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */ { PCI_VENDOR_ID_BROADCOM, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */ - { PCI_VENDOR_ID_BROADCOM, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */ + { PCI_VENDOR_ID_BROADCOM, 0x0007, 0 }, /* BCM95701A7 */ { PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */ { PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */ { PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5703 }, /* BCM95703Ax1 */ @@ -6882,7 +6965,7 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = { /* 3com boards. */ { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */ { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */ - { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES }, /* 3C996SX */ + { PCI_VENDOR_ID_3COM, 0x1004, 0 }, /* 3C996SX */ { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */ { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */ @@ -6895,37 +6978,43 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = { /* Compaq boards. */ { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */ { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */ - { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES }, /* CHANGELING */ + { PCI_VENDOR_ID_COMPAQ, 0x007d, 0 }, /* CHANGELING */ { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */ { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */ /* IBM boards. */ - { PCI_VENDOR_ID_IBM, 0x0281, PHY_ID_SERDES } /* IBM??? */ + { PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */ }; -static int __devinit tg3_phy_probe(struct tg3 *tp) +static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp) { - u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; - u32 hw_phy_id, hw_phy_id_masked; - u32 val; - int i, eeprom_signature_found, err; + int i; - tp->phy_id = PHY_ID_INVALID; for (i = 0; i < ARRAY_SIZE(subsys_id_to_phy_id); i++) { if ((subsys_id_to_phy_id[i].subsys_vendor == tp->pdev->subsystem_vendor) && (subsys_id_to_phy_id[i].subsys_devid == - tp->pdev->subsystem_device)) { - tp->phy_id = subsys_id_to_phy_id[i].phy_id; - break; - } + tp->pdev->subsystem_device)) + return &subsys_id_to_phy_id[i]; } + return NULL; +} +static int __devinit tg3_phy_probe(struct tg3 *tp) +{ + u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; + u32 hw_phy_id, hw_phy_id_masked; + u32 val; + int eeprom_signature_found, eeprom_phy_serdes, err; + + tp->phy_id = PHY_ID_INVALID; eeprom_phy_id = PHY_ID_INVALID; + eeprom_phy_serdes = 0; eeprom_signature_found = 0; tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; + u32 nic_phy_id, cfg2; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); tp->nic_sram_data_cfg = nic_cfg; @@ -6933,21 +7022,19 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) eeprom_signature_found = 1; if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == - NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) { - eeprom_phy_id = PHY_ID_SERDES; - } else { - u32 nic_phy_id; + NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) + eeprom_phy_serdes = 1; - tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); - if (nic_phy_id != 0) { - u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; - u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); + if (nic_phy_id != 0) { + u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; + u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; - eeprom_phy_id = (id1 >> 16) << 10; - eeprom_phy_id |= (id2 & 0xfc00) << 16; - eeprom_phy_id |= (id2 & 0x03ff) << 0; - } - } + eeprom_phy_id = (id1 >> 16) << 10; + eeprom_phy_id |= (id2 & 0xfc00) << 16; + eeprom_phy_id |= (id2 & 0x03ff) << 0; + } else + eeprom_phy_id = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &led_cfg); @@ -7009,6 +7096,10 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP; + + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &cfg2); + if (cfg2 & (1 << 17)) + tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; } /* Reading the PHY ID register can conflict with ASF @@ -7035,20 +7126,31 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) { tp->phy_id = hw_phy_id; + if (hw_phy_id_masked == PHY_ID_BCM8002) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } else { - /* phy_id currently holds the value found in the - * subsys_id_to_phy_id[] table or PHY_ID_INVALID - * if a match was not found there. - */ - if (tp->phy_id == PHY_ID_INVALID) { - if (!eeprom_signature_found || - !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK)) - return -ENODEV; + if (eeprom_signature_found) { tp->phy_id = eeprom_phy_id; + if (eeprom_phy_serdes) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; + } else { + struct subsys_tbl_ent *p; + + /* No eeprom signature? Try the hardcoded + * subsys device table. + */ + p = lookup_by_subsys(tp); + if (!p) + return -ENODEV; + + tp->phy_id = p->phy_id; + if (!tp->phy_id || + tp->phy_id == PHY_ID_BCM8002) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } } - if (tp->phy_id != PHY_ID_SERDES && + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { u32 bmsr, adv_reg, tg3_ctrl; @@ -7105,7 +7207,7 @@ skip_phy_reset: if (!eeprom_signature_found) tp->led_ctrl = LED_CTRL_MODE_PHY_1; - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->link_config.advertising = (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | @@ -7124,11 +7226,11 @@ static void __devinit tg3_read_partno(struct tg3 *tp) unsigned char vpd_data[256]; int i; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) { + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { /* Sun decided not to put the necessary bits in the * NVRAM of their onboard tg3 parts :( */ - strcpy(tp->board_part_number, "Sun 5704"); + strcpy(tp->board_part_number, "Sun 570X"); return; } @@ -7189,27 +7291,21 @@ out_not_found: } #ifdef CONFIG_SPARC64 -static int __devinit tg3_is_sun_5704(struct tg3 *tp) +static int __devinit tg3_is_sun_570X(struct tg3 *tp) { struct pci_dev *pdev = tp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { int node = pcp->prom_node; - u32 venid, devid; + u32 venid; int err; err = prom_getproperty(node, "subsystem-vendor-id", (char *) &venid, sizeof(venid)); if (err == 0 || err == -1) return 0; - err = prom_getproperty(node, "subsystem-id", - (char *) &devid, sizeof(devid)); - if (err == 0 || err == -1) - return 0; - - if (venid == PCI_VENDOR_ID_SUN && - devid == PCI_DEVICE_ID_TIGON3_5704) + if (venid == PCI_VENDOR_ID_SUN) return 1; } return 0; @@ -7226,8 +7322,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) int err; #ifdef CONFIG_SPARC64 - if (tg3_is_sun_5704(tp)) - tp->tg3_flags2 |= TG3_FLG2_SUN_5704; + if (tg3_is_sun_570X(tp)) + tp->tg3_flags2 |= TG3_FLG2_SUN_570X; #endif /* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write @@ -7453,7 +7549,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) chiprevid == CHIPREV_ID_5701_B0 || chiprevid == CHIPREV_ID_5701_B2 || chiprevid == CHIPREV_ID_5701_B5) { - unsigned long sram_base; + void __iomem *sram_base; /* Write some dummy words into the SRAM status block * area, see if it reads back correctly. If the return @@ -7472,32 +7568,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) udelay(50); tg3_nvram_init(tp); - /* Always use host TXDs, it performs better in particular - * with multi-frag packets. The tests below are kept here - * as documentation should we change this decision again - * in the future. - */ - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; - -#if 0 - /* Determine if TX descriptors will reside in - * main memory or in the chip SRAM. - */ - if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; -#endif - grc_misc_cfg = tr32(GRC_MISC_CFG); grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; + /* Broadcom's driver says that CIOBE multisplit has a bug */ +#if 0 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) { tp->tg3_flags |= TG3_FLAG_SPLIT_MODE; tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ; } - +#endif if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) @@ -7524,7 +7605,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_read_partno(tp); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT; } else { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) @@ -7547,13 +7628,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * upon subsystem IDs. */ if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && - tp->phy_id != PHY_ID_SERDES) { + !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT | TG3_FLAG_USE_LINKCHG_REG); } /* For all SERDES we poll the MAC status register. */ - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->tg3_flags |= TG3_FLAG_POLL_SERDES; else tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; @@ -7624,7 +7705,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) mac_offset = 0x7c; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - !(tp->tg3_flags & TG3_FLG2_SUN_5704)) { + !(tp->tg3_flags & TG3_FLG2_SUN_570X)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -7646,7 +7727,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) dev->dev_addr[5] = (lo >> 0) & 0xff; } /* Next, try NVRAM. */ - else if (!(tp->tg3_flags & TG3_FLG2_SUN_5704) && + else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && !tg3_nvram_read(tp, mac_offset + 0, &hi) && !tg3_nvram_read(tp, mac_offset + 4, &lo)) { dev->dev_addr[0] = ((hi >> 16) & 0xff); @@ -7988,8 +8069,8 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5704: return "5704"; case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; - case PHY_ID_BCM8002: return "8002"; - case PHY_ID_SERDES: return "serdes"; + case PHY_ID_BCM8002: return "8002/serdes"; + case 0: return "serdes"; default: return "unknown"; }; } @@ -8096,6 +8177,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; + dev->features |= NETIF_F_LLTX; #if TG3_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->vlan_rx_register = tg3_vlan_rx_register; @@ -8141,7 +8223,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, spin_lock_init(&tp->indirect_lock); INIT_WORK(&tp->reset_task, tg3_reset_task, tp); - tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len); + tp->regs = ioremap(tg3reg_base, tg3reg_len); if (tp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -8257,6 +8339,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (tp->tg3_flags2 & TG3_FLG2_IS_5788) dev->features &= ~NETIF_F_HIGHDMA; + /* flow control autonegotiation is default behavior */ + tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " @@ -8288,11 +8373,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - printk(KERN_INFO "%s: HostTXDS[%d] RXcsums[%d] LinkChgREG[%d] " + printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " "MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] " "TSOcap[%d] \n", dev->name, - (tp->tg3_flags & TG3_FLAG_HOST_TXDS) != 0, (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0, @@ -8304,7 +8388,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, return 0; err_out_iounmap: - iounmap((void *) tp->regs); + iounmap(tp->regs); err_out_free_dev: free_netdev(dev); @@ -8326,7 +8410,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) struct tg3 *tp = netdev_priv(dev); unregister_netdev(dev); - iounmap((void *)tp->regs); + iounmap(tp->regs); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -8371,11 +8455,11 @@ static int tg3_suspend(struct pci_dev *pdev, u32 state) tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); - netif_device_attach(dev); tg3_netif_start(tp); + + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); } return err; @@ -8408,11 +8492,11 @@ static int tg3_resume(struct pci_dev *pdev) tg3_enable_ints(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); - return 0; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5c0c104f4..5a6bd6276 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -124,6 +124,7 @@ #define CHIPREV_ID_5705_A3 0x3003 #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 +#define CHIPREV_ID_5750_A3 0x4003 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -1548,7 +1549,7 @@ * exist only in the cards on-chip SRAM. All 16 send bds are under * the same mode, they may not be configured individually. * - * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags. + * This driver always uses host memory TX descriptors. * * To use host memory TX descriptors: * 1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register. @@ -1988,7 +1989,7 @@ struct tg3 { spinlock_t lock; spinlock_t indirect_lock; - unsigned long regs; + void __iomem *regs; struct net_device *dev; struct pci_dev *pdev; @@ -2004,7 +2005,6 @@ struct tg3 { spinlock_t tx_lock; - /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ struct tg3_tx_buffer_desc *tx_ring; struct tx_ring_info *tx_buffers; dma_addr_t tx_desc_mapping; @@ -2040,7 +2040,6 @@ struct tg3 { u32 rx_offset; u32 tg3_flags; -#define TG3_FLAG_HOST_TXDS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 #define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 @@ -2070,15 +2069,13 @@ struct tg3 { #define TG3_FLAG_JUMBO_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 -#define TG3_FLAG_PAUSE_RX 0x04000000 -#define TG3_FLAG_PAUSE_TX 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; #define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_SUN_5704 0x00000002 +#define TG3_FLG2_SUN_570X 0x00000002 #define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 @@ -2089,6 +2086,9 @@ struct tg3 { #define TG3_FLG2_PCI_EXPRESS 0x00000200 #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 #define TG3_FLG2_HW_AUTONEG 0x00000800 +#define TG3_FLG2_PHY_JUST_INITTED 0x00001000 +#define TG3_FLG2_PHY_SERDES 0x00002000 +#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2136,7 +2136,6 @@ struct tg3 { #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM8002 0x60010140 -#define PHY_ID_SERDES 0xfeedbee0 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f #define PHY_REV_BCM5401_B0 0x1 @@ -2159,7 +2158,7 @@ struct tg3 { (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index f34e40e8f..9e91287c1 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -84,7 +84,8 @@ config 3C359 config TMS380TR tristate "Generic TMS380 Token Ring ISA/PCI adapter support" - depends on TR && (PCI || ISA) + depends on TR && (PCI || ISA) && HOTPLUG + select FW_LOADER ---help--- This driver provides generic support for token ring adapters based on the Texas Instruments TMS380 series chipsets. This diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 69e9246d8..c11a992c8 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/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index ea82d131a..1ec45b2b9 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -221,6 +221,8 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device olympic_priv = dev->priv ; + spin_lock_init(&olympic_priv->olympic_lock) ; + init_waitqueue_head(&olympic_priv->srb_wait); init_waitqueue_head(&olympic_priv->trb_wait); #if OLYMPIC_DEBUG @@ -291,7 +293,7 @@ op_disable_dev: static int __devinit olympic_init(struct net_device *dev) { struct olympic_private *olympic_priv; - u8 *olympic_mmio, *init_srb,*adapter_addr; + u8 __iomem *olympic_mmio, *init_srb,*adapter_addr; unsigned long t; unsigned int uaa_addr; @@ -311,7 +313,6 @@ static int __devinit olympic_init(struct net_device *dev) } } - spin_lock_init(&olympic_priv->olympic_lock) ; /* Needed for cardbus */ if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { @@ -435,13 +436,15 @@ static int __devinit olympic_init(struct net_device *dev) static int olympic_open(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; unsigned long flags, t; char open_error[255] ; int i, open_finished = 1 ; DECLARE_WAITQUEUE(wait,current) ; + olympic_init(dev); + if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { return -EAGAIN; } @@ -706,10 +709,10 @@ static int olympic_open(struct net_device *dev) #endif if (olympic_priv->olympic_network_monitor) { - u8 *oat ; - u8 *opt ; - oat = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - opt = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + u8 __iomem *oat ; + u8 __iomem *opt ; + oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), @@ -755,7 +758,7 @@ static int olympic_open(struct net_device *dev) static void olympic_rx(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; struct olympic_rx_status *rx_status; struct olympic_rx_desc *rx_desc ; int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len; @@ -898,7 +901,10 @@ static void olympic_freemem(struct net_device *dev) int i; for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); + if (olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] != NULL) { + dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]); + olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] = NULL; + } if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { pci_unmap_single(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), @@ -925,9 +931,9 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs { struct net_device *dev= (struct net_device *)dev_id; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; u32 sisr; - u8 *adapter_check_area ; + u8 __iomem *adapter_check_area ; /* * Read sisr but don't reset it yet. @@ -944,9 +950,6 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs /* Hotswap gives us this on removal */ if (sisr == 0xffffffff) { printk(KERN_WARNING "%s: Hotswap adapter removal.\n",dev->name) ; - olympic_freemem(dev) ; - free_irq(dev->irq, dev) ; - dev->stop = NULL ; spin_unlock(&olympic_priv->olympic_lock) ; return IRQ_NONE; } @@ -961,9 +964,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs printk(KERN_ERR "The adapter must be reset to clear this condition.\n") ; printk(KERN_ERR "Please report this error to the driver maintainer and/\n") ; printk(KERN_ERR "or the linux-tr mailing list.\n") ; - olympic_freemem(dev) ; - free_irq(dev->irq, dev) ; - dev->stop = NULL ; + wake_up_interruptible(&olympic_priv->srb_wait); spin_unlock(&olympic_priv->olympic_lock) ; return IRQ_HANDLED; } /* SISR_ERR */ @@ -1006,9 +1007,6 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs writel(readl(olympic_mmio+LAPWWC),olympic_mmio+LAPA); adapter_check_area = olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWC)) & (~0xf800)) ; printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; - olympic_freemem(dev) ; - free_irq(dev->irq, dev) ; - dev->stop = NULL ; spin_unlock(&olympic_priv->olympic_lock) ; return IRQ_HANDLED; } /* SISR_ADAPTER_CHECK */ @@ -1049,7 +1047,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; unsigned long flags ; spin_lock_irqsave(&olympic_priv->olympic_lock, flags); @@ -1080,7 +1078,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) static int olympic_close(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb; unsigned long t,flags; DECLARE_WAITQUEUE(wait,current) ; @@ -1094,34 +1092,32 @@ static int olympic_close(struct net_device *dev) writeb(0,srb+1); writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + add_wait_queue(&olympic_priv->srb_wait,&wait) ; + set_current_state(TASK_INTERRUPTIBLE) ; + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - - t = jiffies ; - - add_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_INTERRUPTIBLE) ; while(olympic_priv->srb_queued) { - schedule() ; + + t = schedule_timeout(60*HZ); + if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR)); olympic_priv->srb_queued=0; break; } - if ((jiffies-t) > 60*HZ) { + + if (t == 0) { printk(KERN_WARNING "%s: SRB timed out. May not be fatal. \n",dev->name) ; - olympic_priv->srb_queued=0; - break ; } - set_current_state(TASK_INTERRUPTIBLE) ; + olympic_priv->srb_queued=0; } remove_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_RUNNING) ; olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; @@ -1152,9 +1148,9 @@ static int olympic_close(struct net_device *dev) static void olympic_set_rx_mode(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; - u8 *olympic_mmio = olympic_priv->olympic_mmio ; + u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; u8 options = 0; - u8 *srb; + u8 __iomem *srb; struct dev_mc_list *dmi ; unsigned char dev_mc_address[4] ; int i ; @@ -1220,8 +1216,8 @@ static void olympic_set_rx_mode(struct net_device *dev) static void olympic_srb_bh(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; - u8 *olympic_mmio = olympic_priv->olympic_mmio ; - u8 *srb; + u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; + u8 __iomem *srb; writel(olympic_priv->srb,olympic_mmio+LAPA); srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); @@ -1394,22 +1390,22 @@ static int olympic_set_mac_address (struct net_device *dev, void *addr) static void olympic_arb_cmd(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; - u8 *olympic_mmio=olympic_priv->olympic_mmio; - u8 *arb_block, *asb_block, *srb ; + u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; + u8 __iomem *arb_block, *asb_block, *srb ; u8 header_len ; u16 frame_len, buffer_len ; struct sk_buff *mac_frame ; - u8 *buf_ptr ; - u8 *frame_data ; + u8 __iomem *buf_ptr ; + u8 __iomem *frame_data ; u16 buff_off ; u16 lan_status = 0, lan_status_diff ; /* Initialize to stop compiler warning */ u8 fdx_prot_error ; u16 next_ptr; int i ; - arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; - asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; - srb = (u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; + arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (olympic_priv->olympic_lap + olympic_priv->asb) ; + srb = (olympic_priv->olympic_lap + olympic_priv->srb) ; if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ @@ -1513,29 +1509,6 @@ drop_frame: writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); netif_stop_queue(dev); olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; - for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); - if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), - olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); - } - olympic_priv->rx_status_last_received++; - olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - } - /* unmap rings */ - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, - sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr, - sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); - - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, - sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, - sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE); - - free_irq(dev->irq,dev); - dev->stop=NULL; printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; } /* If serious error */ @@ -1604,10 +1577,10 @@ drop_frame: static void olympic_asb_bh(struct net_device *dev) { struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; - u8 *arb_block, *asb_block ; + u8 __iomem *arb_block, *asb_block ; - arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; - asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; + arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (olympic_priv->olympic_lap + olympic_priv->asb) ; if (olympic_priv->asb_queued == 1) { /* Dropped through the first time */ @@ -1666,8 +1639,8 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt { struct net_device *dev = (struct net_device *)data ; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - u8 *oat = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - u8 *opt = (u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; int size = 0 ; int len=0; off_t begin=0; diff --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h index e209b79d6..2fc59c997 100644 --- a/drivers/net/tokenring/olympic.h +++ b/drivers/net/tokenring/olympic.h @@ -251,8 +251,8 @@ struct olympic_private { u16 arb; /* be16 */ u16 asb; /* be16 */ - u8 *olympic_mmio; - u8 *olympic_lap; + u8 __iomem *olympic_mmio; + u8 __iomem *olympic_lap; struct pci_dev *pdev ; char *olympic_card_name ; diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig index 6182cf4e3..e2cdaf876 100644 --- a/drivers/net/tulip/Kconfig +++ b/drivers/net/tulip/Kconfig @@ -40,9 +40,7 @@ config TULIP (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type will say Y here.) Do read the Ethernet-HOWTO, available from - . More specific - information is contained in - . + . To compile this driver as a module, choose M here and read . The module will diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 962138008..05e8947f9 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 f3298d161..7353f28cc 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 *); @@ -884,6 +884,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 */ @@ -1773,20 +1787,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/typhoon.c b/drivers/net/typhoon.c index 142f5f52f..ea5643afd 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -248,11 +248,11 @@ struct typhoon { /* Tx cache line section */ struct transmit_ring txLoRing ____cacheline_aligned; struct pci_dev * tx_pdev; - unsigned long tx_ioaddr; + void __iomem *tx_ioaddr; u32 txlo_dma_addr; /* Irq/Rx cache line section */ - unsigned long ioaddr ____cacheline_aligned; + void __iomem *ioaddr ____cacheline_aligned; struct typhoon_indexes *indexes; u8 awaiting_resp; u8 duplex; @@ -373,7 +373,7 @@ typhoon_inc_rx_index(u32 *index, const int count) } static int -typhoon_reset(unsigned long ioaddr, int wait_type) +typhoon_reset(void __iomem *ioaddr, int wait_type) { int i, err = 0; int timeout; @@ -428,7 +428,7 @@ out: } static int -typhoon_wait_status(unsigned long ioaddr, u32 wait_value) +typhoon_wait_status(void __iomem *ioaddr, u32 wait_value) { int i, err = 0; @@ -1240,7 +1240,7 @@ typhoon_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } static int -typhoon_wait_interrupt(unsigned long ioaddr) +typhoon_wait_interrupt(void __iomem *ioaddr) { int i, err = 0; @@ -1348,7 +1348,7 @@ typhoon_init_rings(struct typhoon *tp) static int typhoon_download_firmware(struct typhoon *tp) { - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct pci_dev *pdev = tp->pdev; struct typhoon_file_header *fHdr; struct typhoon_section_header *sHdr; @@ -1497,7 +1497,7 @@ err_out: static int typhoon_boot_3XP(struct typhoon *tp, u32 initial_status) { - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; if(typhoon_wait_status(ioaddr, initial_status) < 0) { printk(KERN_ERR "%s: boot ready timeout\n", tp->name); @@ -1812,7 +1812,8 @@ static irqreturn_t typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *) dev_instance; - unsigned long ioaddr = dev->base_addr; + struct typhoon *tp = dev->priv; + void __iomem *ioaddr = tp->ioaddr; u32 intr_status; intr_status = readl(ioaddr + TYPHOON_REG_INTR_STATUS); @@ -1852,7 +1853,7 @@ static int typhoon_sleep(struct typhoon *tp, int state, u16 events) { struct pci_dev *pdev = tp->pdev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int err; @@ -1890,7 +1891,7 @@ static int typhoon_wakeup(struct typhoon *tp, int wait_type) { struct pci_dev *pdev = tp->pdev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; pci_set_power_state(pdev, 0); pci_restore_state(pdev, tp->pci_state); @@ -1911,7 +1912,7 @@ static int typhoon_start_runtime(struct typhoon *tp) { struct net_device *dev = tp->dev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int err; @@ -2006,7 +2007,7 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type) { struct typhoon_indexes *indexes = tp->indexes; struct transmit_ring *txLo = &tp->txLoRing; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int i; @@ -2070,7 +2071,7 @@ typhoon_tx_timeout(struct net_device *dev) { struct typhoon *tp = (struct typhoon *) dev->priv; - if(typhoon_reset(dev->base_addr, WaitNoSleep) < 0) { + if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) { printk(KERN_WARNING "%s: could not reset in tx timeout\n", dev->name); goto truely_dead; @@ -2091,7 +2092,7 @@ typhoon_tx_timeout(struct net_device *dev) truely_dead: /* Reset the hardware, and turn off carrier to avoid more timeouts */ - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); netif_carrier_off(dev); } @@ -2126,7 +2127,7 @@ out_sleep: if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) { printk(KERN_ERR "%s: unable to reboot into sleep img\n", dev->name); - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); goto out; } @@ -2192,7 +2193,7 @@ typhoon_resume(struct pci_dev *pdev) return 0; reset: - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); return -EBUSY; } @@ -2276,6 +2277,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct typhoon *tp; int card_id = (int) ent->driver_data; unsigned long ioaddr; + void __iomem *ioaddr_mapped; void *shared; dma_addr_t shared_dma; struct cmd_desc xp_cmd; @@ -2345,14 +2347,13 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* map our MMIO region */ ioaddr = pci_resource_start(pdev, 1); - ioaddr = (unsigned long) ioremap(ioaddr, 128); - if(!ioaddr) { + ioaddr_mapped = ioremap(ioaddr, 128); + if (!ioaddr_mapped) { printk(ERR_PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev)); err = -EIO; goto error_out_regions; } - dev->base_addr = ioaddr; /* allocate pci dma space for rx and tx descriptor rings */ @@ -2371,8 +2372,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->shared_dma = shared_dma; tp->pdev = pdev; tp->tx_pdev = pdev; - tp->ioaddr = dev->base_addr; - tp->tx_ioaddr = dev->base_addr; + tp->ioaddr = ioaddr_mapped; + tp->tx_ioaddr = ioaddr_mapped; tp->dev = dev; /* need to be able to restore PCI state after a suspend */ @@ -2385,7 +2386,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * 4) Get the hardware address. * 5) Put the card to sleep. */ - if(typhoon_reset(ioaddr, WaitSleep) < 0) { + if (typhoon_reset(ioaddr_mapped, WaitSleep) < 0) { printk(ERR_PFX "%s: could not reset 3XP\n", pci_name(pdev)); err = -EIO; goto error_out_dma; @@ -2518,13 +2519,13 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; error_out_reset: - typhoon_reset(ioaddr, NoWait); + typhoon_reset(ioaddr_mapped, NoWait); error_out_dma: pci_free_consistent(pdev, sizeof(struct typhoon_shared), shared, shared_dma); error_out_remap: - iounmap((void *) ioaddr); + iounmap(ioaddr_mapped); error_out_regions: pci_release_regions(pdev); error_out_dev: @@ -2542,8 +2543,8 @@ typhoon_remove_one(struct pci_dev *pdev) unregister_netdev(dev); pci_set_power_state(pdev, 0); pci_restore_state(pdev, tp->pci_state); - typhoon_reset(dev->base_addr, NoWait); - iounmap((char *) (dev->base_addr)); + typhoon_reset(tp->ioaddr, NoWait); + iounmap(tp->ioaddr); pci_free_consistent(pdev, sizeof(struct typhoon_shared), tp->shared, tp->shared_dma); pci_release_regions(pdev); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 6c9206301..20bfbb9c7 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -125,11 +125,16 @@ LK1.1.19 (Roger Luethi) - Increase Tx threshold for unspecified errors + LK1.2.0-2.6 (Roger Luethi) + - Massive clean-up + - Rewrite PHY, media handling (remove options, full_duplex, backoff) + - Fix Tx engine race for good + */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.1.20-2.6" -#define DRV_RELDATE "May-23-2004" +#define DRV_VERSION "1.2.0-2.6" +#define DRV_RELDATE "June-10-2004" /* A few user-configurable values. @@ -142,22 +147,10 @@ static int max_interrupt_work = 20; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; -/* Select a backoff algorithm (Ethernet capture effect) */ -static int backoff; - -/* Used to pass the media type, etc. - Both 'options[]' and 'full_duplex[]' should exist for driver - interoperability. - The media type is usually passed in 'options[]'. - The default is autonegotiation for speed and duplex. - This should rarely be overridden. - Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps. - Use option values 0x10 and 0x100 for forcing half duplex fixed speed. - Use option values 0x20 and 0x200 for forcing full duplex operation. -*/ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* + * In case you are looking for 'options[]' or 'full_duplex[]', they + * are gone. Use ethtool(8) instead. + */ /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Rhine has a 64 element 8390-like hash table. */ @@ -210,9 +203,6 @@ static const int multicast_filter_limit = 32; static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"; -static char shortname[] = DRV_NAME; - - /* This driver was written to use PCI memory space. Some early versions of the Rhine may only work correctly with I/O space accesses. */ #ifdef CONFIG_VIA_RHINE_MMIO @@ -239,15 +229,9 @@ MODULE_LICENSE("GPL"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(backoff, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm"); -MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex"); -MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)"); /* Theory of Operation @@ -350,24 +334,24 @@ The chip does not pad to minimum transmit length. enum rhine_revs { VT86C100A = 0x00, + VTunknown0 = 0x20, VT6102 = 0x40, VT8231 = 0x50, /* Integrated MAC */ VT8233 = 0x60, /* Integrated MAC */ VT8235 = 0x74, /* Integrated MAC */ VT8237 = 0x78, /* Integrated MAC */ - VTunknown0 = 0x7C, + VTunknown1 = 0x7C, VT6105 = 0x80, VT6105_B0 = 0x83, VT6105L = 0x8A, VT6107 = 0x8C, - VTunknown1 = 0x8E, - VT6105M = 0x90, + VTunknown2 = 0x8E, + VT6105M = 0x90, /* Management adapter */ }; enum rhine_quirks { rqWOL = 0x0001, /* Wake-On-LAN support */ rqForceReset = 0x0002, - rqDavicomPhy = 0x0020, rq6patterns = 0x0040, /* 6 instead of 4 patterns for WOL */ rqStatusWBRace = 0x0080, /* Tx Status Writeback Error possible */ rqRhineI = 0x0100, /* See comment below */ @@ -395,6 +379,7 @@ MODULE_DEVICE_TABLE(pci, rhine_pci_tbl); /* Offsets to the device registers. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, + ChipCmd1=0x09, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, @@ -403,8 +388,8 @@ enum register_offsets { ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, StickyHW=0x83, IntrStatus2=0x84, - WOLcrSet=0xA0, WOLcrClr=0xA4, WOLcrClr1=0xA6, - WOLcgClr=0xA7, + WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4, + WOLcrClr1=0xA6, WOLcgClr=0xA7, PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD, }; @@ -436,6 +421,15 @@ enum intr_status_bits { IntrTxErrSummary=0x082218, }; +/* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */ +enum wol_bits { + WOLucast = 0x10, + WOLmagic = 0x20, + WOLbmcast = 0x30, + WOLlnkon = 0x40, + WOLlnkoff = 0x80, +}; + /* The Rx and Tx buffer descriptors. */ struct rx_desc { s32 rx_status; @@ -464,13 +458,12 @@ enum desc_status_bits { /* Bits in ChipCmd. */ enum chip_cmd_bits { - CmdInit=0x0001, CmdStart=0x0002, CmdStop=0x0004, CmdRxOn=0x0008, - CmdTxOn=0x0010, CmdTxDemand=0x0020, CmdRxDemand=0x0040, - CmdEarlyRx=0x0100, CmdEarlyTx=0x0200, CmdFDuplex=0x0400, - CmdNoTxPoll=0x0800, CmdReset=0x8000, + CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08, + CmdTxOn=0x10, Cmd1TxDemand=0x20, CmdRxDemand=0x40, + Cmd1EarlyRx=0x01, Cmd1EarlyTx=0x02, Cmd1FDuplex=0x04, + Cmd1NoTxPoll=0x08, Cmd1Reset=0x80, }; -#define MAX_MII_CNT 4 struct rhine_private { /* Descriptor rings */ struct rx_desc *rx_ring; @@ -492,8 +485,8 @@ struct rhine_private { dma_addr_t tx_bufs_dma; struct pci_dev *pdev; + long pioaddr; struct net_device_stats stats; - struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ @@ -502,23 +495,16 @@ struct rhine_private { unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ - u16 chip_cmd; /* Current setting for ChipCmd */ + u8 wolopts; - /* These values are keep track of the transceiver/media in use. */ u8 tx_thresh, rx_thresh; - /* MII transceiver section. */ - unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ - unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ - u16 mii_status; /* last read MII status */ struct mii_if_info mii_if; }; static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); -static void rhine_check_duplex(struct net_device *dev); -static void rhine_timer(unsigned long data); static void rhine_tx_timeout(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); @@ -530,6 +516,16 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); +static void rhine_shutdown (struct device *gdev); + +#define RHINE_WAIT_FOR(condition) do { \ + int i=1024; \ + while (!(condition) && --i) \ + ; \ + if (debug > 1 && i < 512) \ + printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \ + DRV_NAME, 1024-i, __func__, __LINE__); \ +} while(0) static inline u32 get_intr_status(struct net_device *dev) { @@ -546,12 +542,13 @@ static inline u32 get_intr_status(struct net_device *dev) /* * Get power related registers into sane state. - * Returns content of power-event (WOL) registers. + * Notify user about past WOL event. */ static void rhine_power_init(struct net_device *dev) { long ioaddr = dev->base_addr; struct rhine_private *rp = netdev_priv(dev); + u16 wolstat; if (rp->quirks & rqWOL) { /* Make sure chip is in power state D0 */ @@ -566,63 +563,109 @@ static void rhine_power_init(struct net_device *dev) if (rp->quirks & rq6patterns) writeb(0x03, ioaddr + WOLcrClr1); + /* Save power-event status bits */ + wolstat = readb(ioaddr + PwrcsrSet); + if (rp->quirks & rq6patterns) + wolstat |= (readb(ioaddr + PwrcsrSet1) & 0x03) << 8; + /* Clear power-event status bits */ writeb(0xFF, ioaddr + PwrcsrClr); if (rp->quirks & rq6patterns) writeb(0x03, ioaddr + PwrcsrClr1); + + if (wolstat) { + char *reason; + switch (wolstat) { + case WOLmagic: + reason = "Magic packet"; + break; + case WOLlnkon: + reason = "Link went up"; + break; + case WOLlnkoff: + reason = "Link went down"; + break; + case WOLucast: + reason = "Unicast packet"; + break; + case WOLbmcast: + reason = "Multicast/broadcast packet"; + break; + default: + reason = "Unknown"; + } + printk(KERN_INFO "%s: Woke system up. Reason: %s.\n", + DRV_NAME, reason); + } } } -static void wait_for_reset(struct net_device *dev, u32 quirks, char *name) +static void rhine_chip_reset(struct net_device *dev) { long ioaddr = dev->base_addr; - int boguscnt = 20; + struct rhine_private *rp = netdev_priv(dev); + writeb(Cmd1Reset, ioaddr + ChipCmd1); IOSYNC; - if (readw(ioaddr + ChipCmd) & CmdReset) { + if (readb(ioaddr + ChipCmd1) & Cmd1Reset) { printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", name); + "Trying harder.\n", DRV_NAME); - /* Rhine-II needs to be forced sometimes */ - if (quirks & rqForceReset) + /* Force reset */ + if (rp->quirks & rqForceReset) writeb(0x40, ioaddr + MiscCmd); - /* VT86C100A may need long delay after reset (dlink) */ - /* Seen on Rhine-II as well (rl) */ - while ((readw(ioaddr + ChipCmd) & CmdReset) && --boguscnt) - udelay(5); - + /* Reset can take somewhat longer (rare) */ + RHINE_WAIT_FOR(!(readb(ioaddr + ChipCmd1) & Cmd1Reset)); } if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", name, - boguscnt ? "succeeded" : "failed"); + printk(KERN_INFO "%s: Reset %s.\n", dev->name, + (readb(ioaddr + ChipCmd1) & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO -static void __devinit enable_mmio(long ioaddr, u32 quirks) +static void __devinit enable_mmio(long pioaddr, u32 quirks) { int n; if (quirks & rqRhineI) { /* More recent docs say that this bit is reserved ... */ - n = inb(ioaddr + ConfigA) | 0x20; - outb(n, ioaddr + ConfigA); + n = inb(pioaddr + ConfigA) | 0x20; + outb(n, pioaddr + ConfigA); } else { - n = inb(ioaddr + ConfigD) | 0x80; - outb(n, ioaddr + ConfigD); + n = inb(pioaddr + ConfigD) | 0x80; + outb(n, pioaddr + ConfigD); } } #endif -static void __devinit reload_eeprom(long ioaddr) +/* + * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM + * (plus 0x6C for Rhine-I/II) + */ +static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev) { - int i; - outb(0x20, ioaddr + MACRegEEcsr); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) - break; + long ioaddr = dev->base_addr; + struct rhine_private *rp = netdev_priv(dev); + + outb(0x20, pioaddr + MACRegEEcsr); + RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20)); + +#ifdef USE_MMIO + /* + * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable + * MMIO. If reloading EEPROM was done first this could be avoided, but + * it is not known if that still works with the "win98-reboot" problem. + */ + enable_mmio(pioaddr, rp->quirks); +#endif + + /* Turn off EEPROM-controlled wake-up (magic packet) */ + if (rp->quirks & rqWOL) + writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); + } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -634,22 +677,33 @@ static void rhine_poll(struct net_device *dev) } #endif +static void rhine_hw_init(struct net_device *dev, long pioaddr) +{ + struct rhine_private *rp = netdev_priv(dev); + + /* Reset the chip to erase previous misconfiguration. */ + rhine_chip_reset(dev); + + /* Rhine-I needs extra time to recuperate before EEPROM reload */ + if (rp->quirks & rqRhineI) + msleep(5); + + /* Reload EEPROM controlled bytes cleared by soft reset */ + rhine_reload_eeprom(pioaddr, dev); +} + static int __devinit rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct rhine_private *rp; - int i, option, rc; + int i, rc; u8 pci_rev; u32 quirks; - static int card_idx = -1; - long ioaddr; + long pioaddr; long memaddr; - int io_size; - int phy, phy_idx = 0; -#ifdef USE_MMIO - long ioaddr0; -#endif + long ioaddr; + int io_size, phy_id; const char *name; /* when built into the kernel, we only print version if device is found */ @@ -659,26 +713,30 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, printk(version); #endif - card_idx++; - option = card_idx < MAX_UNITS ? options[card_idx] : 0; pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); io_size = 256; - if (pci_rev < VT6102) { - quirks = rqRhineI | rqDavicomPhy; + phy_id = 0; + quirks = 0; + name = "Rhine"; + if (pci_rev < VTunknown0) { + quirks = rqRhineI; io_size = 128; - name = "VT86C100A Rhine"; } - else { + else if (pci_rev >= VT6102) { quirks = rqWOL | rqForceReset; if (pci_rev < VT6105) { name = "Rhine II"; quirks |= rqStatusWBRace; /* Rhine-II exclusive */ } else { - name = "Rhine III"; + phy_id = 1; /* Integrated PHY, phy_id fixed to 1 */ if (pci_rev >= VT6105_B0) quirks |= rq6patterns; + if (pci_rev < VT6105M) + name = "Rhine III"; + else + name = "Rhine III (Management Adapter)"; } } @@ -702,28 +760,31 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, goto err_out; } - ioaddr = pci_resource_start(pdev, 0); + pioaddr = pci_resource_start(pdev, 0); memaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); - dev = alloc_etherdev(sizeof(*rp)); - if (dev == NULL) { + dev = alloc_etherdev(sizeof(struct rhine_private)); + if (!dev) { rc = -ENOMEM; - printk(KERN_ERR "init_ethernet failed for card #%d\n", - card_idx); + printk(KERN_ERR "alloc_etherdev failed\n"); goto err_out; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - rc = pci_request_regions(pdev, shortname); + 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; #ifdef USE_MMIO - ioaddr0 = ioaddr; - enable_mmio(ioaddr0, quirks); + enable_mmio(pioaddr, quirks); ioaddr = (long) ioremap(memaddr, io_size); if (!ioaddr) { @@ -737,7 +798,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, i = 0; while (mmio_verify_registers[i]) { int reg = mmio_verify_registers[i++]; - unsigned char a = inb(ioaddr0+reg); + unsigned char a = inb(pioaddr+reg); unsigned char b = readb(ioaddr+reg); if (a != b) { rc = -EIO; @@ -746,65 +807,38 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, goto err_out_unmap; } } +#else + ioaddr = pioaddr; #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); - - /* Reset the chip to erase previous misconfiguration. */ - writew(CmdReset, ioaddr + ChipCmd); - - wait_for_reset(dev, quirks, shortname); - - /* Reload the station address from the EEPROM. */ -#ifdef USE_MMIO - reload_eeprom(ioaddr0); - /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. - If reload_eeprom() was done first this could be avoided, but it is - not known if that still works with the "win98-reboot" problem. */ - enable_mmio(ioaddr0, quirks); -#else - reload_eeprom(ioaddr); -#endif + rhine_hw_init(dev, pioaddr); for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); if (!is_valid_ether_addr(dev->dev_addr)) { rc = -EIO; - printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx); + printk(KERN_ERR "Invalid MAC address\n"); goto err_out_unmap; } - if (quirks & rqWOL) { - /* - * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA - * turned on. it makes MAC receive magic packet - * automatically. So, we turn it off. (D-Link) - */ - writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); - } - - /* Select backoff algorithm */ - if (backoff) - writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff), - ioaddr + ConfigD); + /* For Rhine-I/II, phy_id is loaded from EEPROM */ + if (!phy_id) + phy_id = readb(ioaddr + 0x6C); 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; rp->mii_if.phy_id_mask = 0x1f; rp->mii_if.reg_num_mask = 0x1f; - if (dev->mem_start) - option = dev->mem_start; - /* The chip-specific entries in the device structure. */ dev->open = rhine_open; dev->hard_start_xmit = rhine_start_tx; @@ -826,20 +860,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x220) - rp->mii_if.full_duplex = 1; - } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - rp->mii_if.full_duplex = 1; - - if (rp->mii_if.full_duplex) { - printk(KERN_INFO "%s: Set to forced full duplex, " - "autonegotiation disabled.\n", dev->name); - rp->mii_if.force_media = 1; - } - printk(KERN_INFO "%s: VIA %s at 0x%lx, ", dev->name, name, #ifdef USE_MMIO @@ -855,17 +875,18 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, pci_set_drvdata(pdev, dev); - rp->phys[0] = 1; /* Standard for this chip. */ - for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, 1); + { + 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->phys[phy_idx++] = phy; - rp->mii_if.advertising = mdio_read(dev, phy, 4); + rp->mii_if.advertising = mdio_read(dev, phy_id, 4); printk(KERN_INFO "%s: MII PHY found at address " "%d, status 0x%4.4x advertising %4.4x " - "Link %4.4x.\n", dev->name, phy, + "Link %4.4x.\n", dev->name, phy_id, mii_status, rp->mii_if.advertising, - mdio_read(dev, phy, 5)); + mdio_read(dev, phy_id, 5)); /* set IFF_RUNNING */ if (mii_status & BMSR_LSTATUS) @@ -873,27 +894,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, else netif_carrier_off(dev); - break; - } - } - rp->mii_cnt = phy_idx; - rp->mii_if.phy_id = rp->phys[0]; - - /* Allow forcing the media type. */ - if (option > 0) { - if (option & 0x220) - rp->mii_if.full_duplex = 1; - if (option & 0x330) { - printk(KERN_INFO " Forcing %dMbs %s-duplex " - "operation.\n", - (option & 0x300 ? 100 : 10), - (option & 0x220 ? "full" : "half")); - if (rp->mii_cnt) - mdio_write(dev, rp->phys[0], MII_BMCR, - ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ - ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */ } } + rp->mii_if.phy_id = phy_id; return 0; @@ -1065,6 +1068,21 @@ static void free_tbufs(struct net_device* dev) } } +static void rhine_check_media(struct net_device *dev, unsigned int init_media) +{ + struct rhine_private *rp = netdev_priv(dev); + long ioaddr = dev->base_addr; + + mii_check_media(&rp->mii_if, debug, init_media); + + if (rp->mii_if.full_duplex) + writeb(readb(ioaddr + ChipCmd1) | Cmd1FDuplex, + ioaddr + ChipCmd1); + else + writeb(readb(ioaddr + ChipCmd1) & ~Cmd1FDuplex, + ioaddr + ChipCmd1); +} + static void init_registers(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1080,7 +1098,6 @@ static void init_registers(struct net_device *dev) writeb(0x20, ioaddr + TxConfig); rp->tx_thresh = 0x20; rp->rx_thresh = 0x60; /* Written in rhine_set_rx_mode(). */ - rp->mii_if.full_duplex = 0; writel(rp->rx_ring_dma, ioaddr + RxRingPtr); writel(rp->tx_ring_dma, ioaddr + TxRingPtr); @@ -1094,17 +1111,44 @@ static void init_registers(struct net_device *dev) IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - rp->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; - if (rp->mii_if.force_media) - rp->chip_cmd |= CmdFDuplex; - writew(rp->chip_cmd, ioaddr + ChipCmd); + writew(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8), + ioaddr + ChipCmd); + rhine_check_media(dev, 1); +} + +/* Enable MII link status auto-polling (required for IntrLinkChange) */ +static void rhine_enable_linkmon(long ioaddr) +{ + writeb(0, ioaddr + MIICmd); + writeb(MII_BMSR, ioaddr + MIIRegAddr); + writeb(0x80, ioaddr + MIICmd); + + RHINE_WAIT_FOR((readb(ioaddr + MIIRegAddr) & 0x20)); + + writeb(MII_BMSR | 0x40, ioaddr + MIIRegAddr); +} + +/* Disable MII link status auto-polling (required for MDIO access) */ +static void rhine_disable_linkmon(long ioaddr, u32 quirks) +{ + writeb(0, ioaddr + MIICmd); + + if (quirks & rqRhineI) { + writeb(0x01, ioaddr + MIIRegAddr); // MII_BMSR + + /* Can be called from ISR. Evil. */ + mdelay(1); + + /* 0x80 must be set immediately before turning it off */ + writeb(0x80, ioaddr + MIICmd); - rhine_check_duplex(dev); + RHINE_WAIT_FOR(readb(ioaddr + MIIRegAddr) & 0x20); - /* The LED outputs of various MII xcvrs should be configured. */ - /* For NS or Mison phys, turn on bit 1 in register 0x17 */ - mdio_write(dev, rp->phys[0], 0x17, mdio_read(dev, rp->phys[0], 0x17) | - 0x0001); + /* Heh. Now clear 0x80 again. */ + writeb(0, ioaddr + MIICmd); + } + else + RHINE_WAIT_FOR(readb(ioaddr + MIIRegAddr) & 0x80); } /* Read and write over the MII Management Data I/O (MDIO) interface. */ @@ -1112,156 +1156,72 @@ static void init_registers(struct net_device *dev) static int mdio_read(struct net_device *dev, int phy_id, int regnum) { long ioaddr = dev->base_addr; - int boguscnt = 1024; + struct rhine_private *rp = netdev_priv(dev); + int result; - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); + rhine_disable_linkmon(ioaddr, rp->quirks); + + /* rhine_disable_linkmon already cleared MIICmd */ writeb(phy_id, ioaddr + MIIPhyAddr); writeb(regnum, ioaddr + MIIRegAddr); writeb(0x40, ioaddr + MIICmd); /* Trigger read */ - boguscnt = 1024; - while ((readb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0) - ; - return readw(ioaddr + MIIData); + RHINE_WAIT_FOR(!(readb(ioaddr + MIICmd) & 0x40)); + result = readw(ioaddr + MIIData); + + rhine_enable_linkmon(ioaddr); + return result; } static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) { struct rhine_private *rp = netdev_priv(dev); long ioaddr = dev->base_addr; - int boguscnt = 1024; - if (phy_id == rp->phys[0]) { - switch (regnum) { - case MII_BMCR: /* Is user forcing speed/duplex? */ - if (value & 0x9000) /* Autonegotiation. */ - rp->mii_if.force_media = 0; - else - rp->mii_if.full_duplex = (value & 0x0100) ? 1 : 0; - break; - case MII_ADVERTISE: - rp->mii_if.advertising = value; - break; - } - } + rhine_disable_linkmon(ioaddr, rp->quirks); - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); + /* rhine_disable_linkmon already cleared MIICmd */ writeb(phy_id, ioaddr + MIIPhyAddr); writeb(regnum, ioaddr + MIIRegAddr); writew(value, ioaddr + MIIData); - writeb(0x20, ioaddr + MIICmd); /* Trigger write. */ -} + writeb(0x20, ioaddr + MIICmd); /* Trigger write */ + RHINE_WAIT_FOR(!(readb(ioaddr + MIICmd) & 0x20)); + rhine_enable_linkmon(ioaddr); +} static int rhine_open(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); long ioaddr = dev->base_addr; - int i; - - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); + int rc; - i = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name, + rc = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name, dev); - if (i) - return i; + if (rc) + return rc; if (debug > 1) printk(KERN_DEBUG "%s: rhine_open() irq %d.\n", dev->name, rp->pdev->irq); - i = alloc_ring(dev); - if (i) - return i; + rc = alloc_ring(dev); + if (rc) + return rc; alloc_rbufs(dev); alloc_tbufs(dev); - wait_for_reset(dev, rp->quirks, dev->name); + rhine_chip_reset(dev); init_registers(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), - mdio_read(dev, rp->phys[0], MII_BMSR)); + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); - /* Set the timer to check for link beat. */ - init_timer(&rp->timer); - rp->timer.expires = jiffies + 2 * HZ/100; - rp->timer.data = (unsigned long)dev; - rp->timer.function = &rhine_timer; /* timer handler */ - add_timer(&rp->timer); - return 0; } -static void rhine_check_duplex(struct net_device *dev) -{ - struct rhine_private *rp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int mii_lpa = mdio_read(dev, rp->phys[0], MII_LPA); - int negotiated = mii_lpa & rp->mii_if.advertising; - int duplex; - - if (rp->mii_if.force_media || mii_lpa == 0xffff) - return; - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (rp->mii_if.full_duplex != duplex) { - rp->mii_if.full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on " - "MII #%d link partner capability of %4.4x.\n", - dev->name, duplex ? "full" : "half", - rp->phys[0], mii_lpa); - if (duplex) - rp->chip_cmd |= CmdFDuplex; - else - rp->chip_cmd &= ~CmdFDuplex; - writew(rp->chip_cmd, ioaddr + ChipCmd); - } -} - - -static void rhine_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rhine_private *rp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int next_tick = 10*HZ; - int mii_status; - - if (debug > 3) { - printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", - dev->name, readw(ioaddr + IntrStatus)); - } - - spin_lock_irq (&rp->lock); - - rhine_check_duplex(dev); - - /* make IFF_RUNNING follow the MII status bit "Link established" */ - mii_status = mdio_read(dev, rp->phys[0], MII_BMSR); - if ((mii_status & BMSR_LSTATUS) != (rp->mii_status & BMSR_LSTATUS)) { - if (mii_status & BMSR_LSTATUS) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - } - rp->mii_status = mii_status; - - spin_unlock_irq(&rp->lock); - - rp->timer.expires = jiffies + next_tick; - add_timer(&rp->timer); -} - - static void rhine_tx_timeout(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1270,16 +1230,13 @@ static void rhine_tx_timeout(struct net_device *dev) printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " "%4.4x, resetting...\n", dev->name, readw(ioaddr + IntrStatus), - mdio_read(dev, rp->phys[0], MII_BMSR)); + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); spin_lock(&rp->lock); - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); - /* clear all descriptors */ free_tbufs(dev); free_rbufs(dev); @@ -1287,7 +1244,7 @@ static void rhine_tx_timeout(struct net_device *dev) alloc_rbufs(dev); /* Reinitialize the hardware. */ - wait_for_reset(dev, rp->quirks, dev->name); + rhine_chip_reset(dev); init_registers(dev); spin_unlock(&rp->lock); @@ -1301,8 +1258,8 @@ static void rhine_tx_timeout(struct net_device *dev) static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + long ioaddr = dev->base_addr; unsigned entry; - u32 intr_status; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -1353,14 +1310,9 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) /* Non-x86 Todo: explicitly flush cache lines here. */ - /* - * Wake the potentially-idle transmit channel unless errors are - * pending (the ISR must sort them out first). - */ - intr_status = get_intr_status(dev); - if ((intr_status & IntrTxErrSummary) == 0) { - writew(CmdTxDemand | rp->chip_cmd, dev->base_addr + ChipCmd); - } + /* Wake the potentially-idle transmit channel */ + writeb(readb(ioaddr + ChipCmd1) | Cmd1TxDemand, + ioaddr + ChipCmd1); IOSYNC; if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN) @@ -1408,11 +1360,10 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs * if (intr_status & (IntrTxErrSummary | IntrTxDone)) { if (intr_status & IntrTxErrSummary) { - int cnt = 20; /* Avoid scavenging before Tx engine turned off */ - while ((readw(ioaddr+ChipCmd) & CmdTxOn) && --cnt) - udelay(5); - if (debug > 2 && !cnt) + RHINE_WAIT_FOR(!(readb(ioaddr+ChipCmd) & CmdTxOn)); + if (debug > 2 && + readb(ioaddr+ChipCmd) & CmdTxOn) printk(KERN_WARNING "%s: " "rhine_interrupt() Tx engine" "still on.\n", dev->name); @@ -1572,10 +1523,6 @@ static void rhine_rx(struct net_device *dev) rp->rx_buf_sz, PCI_DMA_FROMDEVICE); - /* *_IP_COPYSUM isn't defined anywhere and - eth_copy_and_sum is memcpy for all archs so - this is kind of pointless right now - ... or? */ eth_copy_and_sum(skb, rp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1627,10 +1574,6 @@ static void rhine_rx(struct net_device *dev) } rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } - - /* Pre-emptively restart Rx engine. */ - writew(readw(dev->base_addr + ChipCmd) | CmdRxOn | CmdRxDemand, - dev->base_addr + ChipCmd); } /* @@ -1664,7 +1607,10 @@ static void rhine_restart_tx(struct net_device *dev) { writel(rp->tx_ring_dma + entry * sizeof(struct tx_desc), ioaddr + TxRingPtr); - writew(CmdTxDemand | rp->chip_cmd, ioaddr + ChipCmd); + writeb(readb(ioaddr + ChipCmd) | CmdTxOn, + ioaddr + ChipCmd); + writeb(readb(ioaddr + ChipCmd1) | Cmd1TxDemand, + ioaddr + ChipCmd1); IOSYNC; } else { @@ -1684,20 +1630,8 @@ static void rhine_error(struct net_device *dev, int intr_status) spin_lock(&rp->lock); - if (intr_status & (IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) { - /* Link failed, restart autonegotiation. */ - if (rp->quirks & rqRhineI) - mdio_write(dev, rp->phys[0], MII_BMCR, 0x3300); - } else - rhine_check_duplex(dev); - if (debug) - printk(KERN_ERR "%s: MII status changed: " - "Autonegotiation advertising %4.4x partner " - "%4.4x.\n", dev->name, - mdio_read(dev, rp->phys[0], MII_ADVERTISE), - mdio_read(dev, rp->phys[0], MII_LPA)); - } + if (intr_status & IntrLinkChange) + rhine_check_media(dev, 0); if (intr_status & IntrStatsMax) { rp->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); rp->stats.rx_missed_errors += readw(ioaddr + RxMissed); @@ -1790,7 +1724,7 @@ static void rhine_set_rx_mode(struct net_device *dev) i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); @@ -1856,6 +1790,39 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value) debug = value; } +static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rhine_private *rp = netdev_priv(dev); + + if (!(rp->quirks & rqWOL)) + return; + + spin_lock_irq(&rp->lock); + wol->supported = WAKE_PHY | WAKE_MAGIC | + WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ + wol->wolopts = rp->wolopts; + spin_unlock_irq(&rp->lock); +} + +static int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rhine_private *rp = netdev_priv(dev); + u32 support = WAKE_PHY | WAKE_MAGIC | + WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ + + if (!(rp->quirks & rqWOL)) + return -EINVAL; + + if (wol->wolopts & ~support) + return -EINVAL; + + spin_lock_irq(&rp->lock); + rp->wolopts = wol->wolopts; + spin_unlock_irq(&rp->lock); + + return 0; +} + static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, @@ -1864,6 +1831,8 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, + .get_wol = rhine_get_wol, + .set_wol = rhine_set_wol, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, }; @@ -1888,8 +1857,6 @@ static int rhine_close(struct net_device *dev) long ioaddr = dev->base_addr; struct rhine_private *rp = netdev_priv(dev); - del_timer_sync(&rp->timer); - spin_lock_irq(&rp->lock); netif_stop_queue(dev); @@ -1936,12 +1903,110 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static void rhine_shutdown (struct device *gendev) +{ + struct pci_dev *pdev = to_pci_dev(gendev); + struct net_device *dev = pci_get_drvdata(pdev); + struct rhine_private *rp = netdev_priv(dev); + + long ioaddr = dev->base_addr; + + rhine_power_init(dev); + + /* Make sure we use pattern 0, 1 and not 4, 5 */ + if (rp->quirks & rq6patterns) + writeb(0x04, ioaddr + 0xA7); + + if (rp->wolopts & WAKE_MAGIC) + writeb(WOLmagic, ioaddr + WOLcrSet); + + if (rp->wolopts & (WAKE_BCAST|WAKE_MCAST)) + writeb(WOLbmcast, ioaddr + WOLcgSet); + + if (rp->wolopts & WAKE_PHY) + writeb(WOLlnkon | WOLlnkoff, ioaddr + WOLcrSet); + + if (rp->wolopts & WAKE_UCAST) + writeb(WOLucast, ioaddr + WOLcrSet); + + /* Enable legacy WOL (for old motherboards) */ + writeb(0x01, ioaddr + PwcfgSet); + writeb(readb(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW); + + /* Hit power state D3 (sleep) */ + writeb(readb(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + + /* TODO: Check use of pci_enable_wake() */ + +} + +#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 = "via-rhine", + .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 f053d2a9e..57a6d2924 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -78,6 +78,8 @@ #include #include #include +#include +#include #include "via-velocity.h" @@ -226,7 +228,10 @@ VELOCITY_PARAM(wol_opts, "Wake On Lan options"); VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); -static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent); +static int rx_copybreak = 200; +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); + static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info); static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); static void velocity_print_info(struct velocity_info *vptr); @@ -238,10 +243,8 @@ static void velocity_set_multi(struct net_device *dev); static struct net_device_stats *velocity_get_stats(struct net_device *dev); static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int velocity_close(struct net_device *dev); -static int velocity_rx_srv(struct velocity_info *vptr, int status); static int velocity_receive_frame(struct velocity_info *, int idx); static int velocity_alloc_rx_buf(struct velocity_info *, int idx); -static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type); static void velocity_free_rd_ring(struct velocity_info *vptr); static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); static int velocity_soft_reset(struct velocity_info *vptr); @@ -254,25 +257,40 @@ static void enable_flow_control_ability(struct velocity_info *vptr); static void enable_mii_autopoll(struct mac_regs * regs); static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata); static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data); -static int velocity_set_wol(struct velocity_info *vptr); -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context); -static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context); static u32 mii_check_media_mode(struct mac_regs * regs); static u32 check_connection_type(struct mac_regs * regs); -static void velocity_init_cam_filter(struct velocity_info *vptr); 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); static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); static struct notifier_block velocity_inetaddr_notifier = { - notifier_call:velocity_netdev_event, + .notifier_call = velocity_netdev_event, }; -#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 @@ -289,8 +307,9 @@ static struct velocity_info_tbl chip_info_table[] = { */ static struct pci_device_id velocity_id_table[] __devinitdata = { - {0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]}, - {0,} + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table}, + {0, } }; MODULE_DEVICE_TABLE(pci, velocity_id_table); @@ -326,12 +345,22 @@ 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); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_netdev(dev); + + velocity_nics--; } /** @@ -435,7 +464,7 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) { struct mac_regs * regs = vptr->mac_regs; - /* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */ + /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); WORD_REG_BITS_ON(MCFG_VIDFR, ®s->MCFG); @@ -477,13 +506,13 @@ static void velocity_rx_reset(struct velocity_info *vptr) struct mac_regs * regs = vptr->mac_regs; int i; - vptr->rd_used = vptr->rd_curr = 0; + vptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0; /* * Init state, all RD entries belong to the NIC */ for (i = 0; i < vptr->options.numrx; ++i) - vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC); + vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC; writew(vptr->options.numrx, ®s->RBRDU); writel(vptr->rd_pool_dma, ®s->RDBaseLo); @@ -558,10 +587,15 @@ static void velocity_init_registers(struct velocity_info *vptr, writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); /* - * Bback off algorithm use original IEEE standard + * Back off algorithm use original IEEE standard */ BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); + /* + * Init CAM filter + */ + velocity_init_cam_filter(vptr); + /* * Set packet filter: Receive directed and broadcast address */ @@ -586,8 +620,6 @@ static void velocity_init_registers(struct velocity_info *vptr, mac_tx_queue_run(regs, i); } - velocity_init_cam_filter(vptr); - init_flow_control_register(vptr); writel(CR0_STOP, ®s->CR0Clr); @@ -595,7 +627,6 @@ static void velocity_init_registers(struct velocity_info *vptr, mii_status = velocity_get_opt_media_mode(vptr); netif_stop_queue(vptr->dev); - mac_clear_isr(regs); mii_init(vptr, mii_status); @@ -662,7 +693,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi struct mac_regs * regs; int ret = -ENOMEM; - if (velocity_nics++ >= MAX_UNITS) { + if (velocity_nics >= MAX_UNITS) { printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", velocity_nics); return -ENODEV; @@ -694,7 +725,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi vptr->dev = dev; - dev->priv = vptr; dev->irq = pdev->irq; ret = pci_enable_device(pdev); @@ -729,7 +759,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->dev_addr[i] = readb(®s->PAR[i]); - velocity_get_options(&vptr->options, velocity_nics - 1, dev->name); + velocity_get_options(&vptr->options, velocity_nics, dev->name); /* * Mask out the options cannot be set to the chip @@ -775,6 +805,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); +#ifdef CONFIG_PM + { + 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 + velocity_nics++; out: return ret; @@ -827,9 +867,8 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i vptr->io_size = info->io_size; vptr->num_txq = info->txqueue; vptr->multicast_limit = MCAM_SIZE; - spin_lock_init(&vptr->lock); - spin_lock_init(&vptr->xmit_lock); + INIT_LIST_HEAD(&vptr->list); } /** @@ -966,6 +1005,60 @@ static void velocity_free_rings(struct velocity_info *vptr) pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma); } +static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) +{ + struct mac_regs *regs = vptr->mac_regs; + int avail, dirty, unusable; + + /* + * RD number must be equal to 4X per hardware spec + * (programming guide rev 1.20, p.13) + */ + if (vptr->rd_filled < 4) + return; + + wmb(); + + unusable = vptr->rd_filled & 0x0003; + dirty = vptr->rd_dirty - unusable; + for (avail = vptr->rd_filled & 0xfffc; avail; avail--) { + dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; + vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC; + } + + writew(vptr->rd_filled & 0xfffc, ®s->RBRDU); + vptr->rd_filled = unusable; +} + +static int velocity_rx_refill(struct velocity_info *vptr) +{ + int dirty = vptr->rd_dirty, done = 0, ret = 0; + + do { + struct rx_desc *rd = vptr->rd_ring + dirty; + + /* Fine for an all zero Rx desc at init time as well */ + if (rd->rdesc0.owner == OWNED_BY_NIC) + break; + + if (!vptr->rd_info[dirty].skb) { + ret = velocity_alloc_rx_buf(vptr, dirty); + if (ret < 0) + break; + } + done++; + dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; + } while (dirty != vptr->rd_curr); + + if (done) { + vptr->rd_dirty = dirty; + vptr->rd_filled += done; + velocity_give_many_rx_descs(vptr); + } + + return ret; +} + /** * velocity_init_rd_ring - set up receive ring * @vptr: velocity to configure @@ -976,9 +1069,7 @@ static void velocity_free_rings(struct velocity_info *vptr) static int velocity_init_rd_ring(struct velocity_info *vptr) { - int i, ret = -ENOMEM; - struct rx_desc *rd; - struct velocity_rd_info *rd_info; + int ret = -ENOMEM; unsigned int rsize = sizeof(struct velocity_rd_info) * vptr->options.numrx; @@ -987,28 +1078,20 @@ static int velocity_init_rd_ring(struct velocity_info *vptr) goto out; memset(vptr->rd_info, 0, rsize); - /* Init the RD ring entries */ - for (i = 0; i < vptr->options.numrx; i++) { - rd = &(vptr->rd_ring[i]); - rd_info = &(vptr->rd_info[i]); + vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; - ret = velocity_alloc_rx_buf(vptr, i); - if (ret < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: failed to allocate RX buffer.\n", - vptr->dev->name); - velocity_free_rd_ring(vptr); - goto out; - } - rd->rdesc0.owner = OWNED_BY_NIC; + ret = velocity_rx_refill(vptr); + if (ret < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", vptr->dev->name); + velocity_free_rd_ring(vptr); } - vptr->rd_used = vptr->rd_curr = 0; out: return ret; } /** - * velocity_free_rd_ring - set up receive ring + * velocity_free_rd_ring - free receive ring * @vptr: velocity to clean up * * Free the receive buffers for each ring slot and any @@ -1025,7 +1108,7 @@ static void velocity_free_rd_ring(struct velocity_info *vptr) for (i = 0; i < vptr->options.numrx; i++) { struct velocity_rd_info *rd_info = &(vptr->rd_info[i]); - if (!rd_info->skb_dma) + if (!rd_info->skb) continue; pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1073,8 +1156,10 @@ static int velocity_init_td_ring(struct velocity_info *vptr) for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { td = &(vptr->td_rings[j][i]); td_info = &(vptr->td_infos[j][i]); - td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ; - td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ; + td_info->buf = vptr->tx_bufs + + (j * vptr->options.numtx + i) * PKT_BUF_SZ; + td_info->buf_dma = vptr->tx_bufs_dma + + (j * vptr->options.numtx + i) * PKT_BUF_SZ; } vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0; } @@ -1146,40 +1231,27 @@ static void velocity_free_td_ring(struct velocity_info *vptr) static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct rx_desc *rd; struct net_device_stats *stats = &vptr->stats; - struct mac_regs * regs = vptr->mac_regs; int rd_curr = vptr->rd_curr; int works = 0; - while (1) { - - rd = &(vptr->rd_ring[rd_curr]); + do { + struct rx_desc *rd = vptr->rd_ring + rd_curr; - if ((vptr->rd_info[rd_curr]).skb == NULL) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) - break; - } - - if (works++ > 15) + if (!vptr->rd_info[rd_curr].skb) break; if (rd->rdesc0.owner == OWNED_BY_NIC) break; + rmb(); + /* * Don't drop CE or RL error frame although RXOK is off - * FIXME: need to handle copybreak */ if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) { - if (velocity_receive_frame(vptr, rd_curr) == 0) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name); - break; - } - } else { + if (velocity_receive_frame(vptr, rd_curr) < 0) stats->rx_dropped++; - } } else { if (rd->rdesc0.RSR & RSR_CRC) stats->rx_crc_errors++; @@ -1191,26 +1263,20 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) rd->inten = 1; - if (++vptr->rd_used >= 4) { - int i, rd_prev = rd_curr; - for (i = 0; i < 4; i++) { - if (--rd_prev < 0) - rd_prev = vptr->options.numrx - 1; - - rd = &(vptr->rd_ring[rd_prev]); - rd->rdesc0.owner = OWNED_BY_NIC; - } - writew(4, &(regs->RBRDU)); - vptr->rd_used -= 4; - } - vptr->dev->last_rx = jiffies; rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; - } + } while (++works <= 15); + vptr->rd_curr = rd_curr; + + if (works > 0 && velocity_rx_refill(vptr) < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: rx buf allocation failure\n", vptr->dev->name); + } + VAR_USED(stats); return works; } @@ -1241,6 +1307,65 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) } } +/** + * velocity_rx_copy - in place Rx copy for small packets + * @rx_skb: network layer packet buffer candidate + * @pkt_size: received data size + * @rd: receive packet descriptor + * @dev: network device + * + * Replace the current skb that is scheduled for Rx processing by a + * shorter, immediatly allocated skb, if the received packet is small + * enough. This function returns a negative value if the received + * packet is too big or if memory is exhausted. + */ +static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *new_skb; + + new_skb = dev_alloc_skb(pkt_size + 2); + if (new_skb) { + new_skb->dev = vptr->dev; + new_skb->ip_summed = rx_skb[0]->ip_summed; + + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) + skb_reserve(new_skb, 2); + + memcpy(new_skb->data, rx_skb[0]->tail, pkt_size); + *rx_skb = new_skb; + ret = 0; + } + + } + return ret; +} + +/** + * velocity_iph_realign - IP header alignment + * @vptr: velocity we are handling + * @skb: network layer packet buffer + * @pkt_size: received data size + * + * Align IP header on a 2 bytes boundary. This behavior can be + * configured by the user. + */ +static inline void velocity_iph_realign(struct velocity_info *vptr, + struct sk_buff *skb, int pkt_size) +{ + /* FIXME - memmove ? */ + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + int i; + + for (i = pkt_size; i >= 0; i--) + *(skb->data + i + 2) = *(skb->data + i); + skb_reserve(skb, 2); + } +} + /** * velocity_receive_frame - received packet processor * @vptr: velocity we are handling @@ -1252,9 +1377,11 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) static int velocity_receive_frame(struct velocity_info *vptr, int idx) { + void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); struct net_device_stats *stats = &vptr->stats; struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); struct rx_desc *rd = &(vptr->rd_ring[idx]); + int pkt_len = rd->rdesc0.len; struct sk_buff *skb; if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { @@ -1269,22 +1396,8 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) skb = rd_info->skb; skb->dev = vptr->dev; - pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, - PCI_DMA_FROMDEVICE); - rd_info->skb_dma = (dma_addr_t) NULL; - rd_info->skb = NULL; - - /* FIXME - memmove ? */ - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - int i; - for (i = rd->rdesc0.len + 4; i >= 0; i--) - *(skb->data + i + 2) = *(skb->data + i); - skb->data += 2; - skb->tail += 2; - } - - skb_put(skb, (rd->rdesc0.len - 4)); - skb->protocol = eth_type_trans(skb, skb->dev); + pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, + vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* * Drop frame not meeting IEEE 802.3 @@ -1297,13 +1410,23 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) } } + pci_action = pci_dma_sync_single_for_device; + velocity_rx_csum(rd, skb); - - /* - * FIXME: need rx_copybreak handling - */ - stats->rx_bytes += skb->len; + if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { + velocity_iph_realign(vptr, skb, pkt_len); + pci_action = pci_unmap_single; + rd_info->skb = NULL; + } + + pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + skb_put(skb, pkt_len - 4); + skb->protocol = eth_type_trans(skb, skb->dev); + + stats->rx_bytes += pkt_len; netif_rx(skb); return 0; @@ -1962,32 +2085,6 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) } -/** - * ether_crc - ethernet CRC function - * - * Compute an ethernet CRC hash of the data block provided. This - * is not performance optimised but is not needed in performance - * critical code paths. - * - * FIXME: could we use shared code here ? - */ - -static inline u32 ether_crc(int length, unsigned char *data) -{ - static unsigned const ethernet_polynomial = 0x04c11db7U; - - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - return crc; -} - /** * velocity_set_multi - filter list change callback * @dev: network device @@ -2123,13 +2220,13 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ static struct pci_driver velocity_driver = { - name:VELOCITY_NAME, - id_table:velocity_id_table, - probe:velocity_found1, - remove:velocity_remove1, + .name = VELOCITY_NAME, + .id_table = velocity_id_table, + .probe = velocity_found1, + .remove = __devexit_p(velocity_remove1), #ifdef CONFIG_PM - suspend:velocity_suspend, - resume:velocity_resume, + .suspend = velocity_suspend, + .resume = velocity_resume, #endif }; @@ -2145,11 +2242,11 @@ static struct pci_driver velocity_driver = { static int __init velocity_init_module(void) { int ret; - ret = pci_module_init(&velocity_driver); -#ifdef CONFIG_PM - register_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif + velocity_register_notifier(); + ret = pci_module_init(&velocity_driver); + if (ret < 0) + velocity_unregister_notifier(); return ret; } @@ -2164,9 +2261,7 @@ static int __init velocity_init_module(void) static void __exit velocity_cleanup_module(void) { -#ifdef CONFIG_PM - unregister_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif + velocity_unregister_notifier(); pci_unregister_driver(&velocity_driver); } @@ -2992,172 +3087,6 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity } -static int velocity_suspend(struct pci_dev *pdev, u32 state) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - - if(!netif_running(vptr->dev)) - return 0; - - netif_device_detach(vptr->dev); - - spin_lock_irqsave(&vptr->lock, flags); - pci_save_state(pdev, vptr->pci_state); -#ifdef ETHTOOL_GWOL - if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { - velocity_get_ip(vptr); - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - velocity_set_wol(vptr); - pci_enable_wake(pdev, 3, 1); - pci_set_power_state(pdev, 3); - } else { - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - pci_disable_device(pdev); - pci_set_power_state(pdev, state); - } -#else - pci_set_power_state(pdev, state); -#endif - spin_unlock_irqrestore(&vptr->lock, flags); - return 0; -} - -static int velocity_resume(struct pci_dev *pdev) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - int i; - - if(!netif_running(vptr->dev)) - return 0; - - pci_set_power_state(pdev, 0); - pci_enable_wake(pdev, 0, 0); - pci_restore_state(pdev, vptr->pci_state); - - mac_wol_reset(vptr->mac_regs); - - spin_lock_irqsave(&vptr->lock, flags); - velocity_restore_context(vptr, &vptr->context); - velocity_init_registers(vptr, VELOCITY_INIT_WOL); - mac_disable_int(vptr->mac_regs); - - velocity_tx_srv(vptr, 0); - - for (i = 0; i < vptr->num_txq; i++) { - if (vptr->td_used[i]) { - mac_tx_queue_wake(vptr->mac_regs, i); - } - } - - mac_enable_int(vptr->mac_regs); - spin_unlock_irqrestore(&vptr->lock, flags); - netif_device_attach(vptr->dev); - - return 0; -} - -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); - } - return NOTIFY_DONE; -} -#endif - -/* - * Purpose: Functions to set WOL. - */ - -const static unsigned short crc16_tab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - - -static u32 mask_pattern[2][4] = { - {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ - {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ -}; - -/** - * ether_crc16 - compute ethernet CRC - * @len: buffer length - * @cp: buffer - * @crc16: initial CRC - * - * Compute a CRC value for a block of data. - * FIXME: can we use generic functions ? - */ - -static u16 ether_crc16(int len, u8 * cp, u16 crc16) -{ - while (len--) - crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff]; - return (crc16); -} - -/** - * bit_reverse - 16bit reverse - * @data: 16bit data t reverse - * - * Reverse the order of a 16bit value and return the reversed bits - */ - -static u16 bit_reverse(u16 data) -{ - u32 new = 0x00000000; - int ii; - - - for (ii = 0; ii < 16; ii++) { - new |= ((u32) (data & 1) << (31 - ii)); - data >>= 1; - } - - return (u16) (new >> 16); -} - /** * wol_calc_crc - WOL CRC * @pattern: data pattern @@ -3166,7 +3095,7 @@ static u16 bit_reverse(u16 data) * Compute the wake on lan crc hashes for the packet header * we are interested in. */ - + u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; @@ -3186,12 +3115,12 @@ u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) continue; } mask >>= 1; - crc = ether_crc16(1, &(pattern[i * 8 + j]), crc); + crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1); } } /* Finally, invert the result once to get the correct data */ crc = ~crc; - return bit_reverse(crc); + return bitreverse(crc) >> 16; } /** @@ -3203,13 +3132,18 @@ u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) * * FIXME: check static buffer is safe here */ - + static int velocity_set_wol(struct velocity_info *vptr) { struct mac_regs * regs = vptr->mac_regs; static u8 buf[256]; int i; + static u32 mask_pattern[2][4] = { + {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ + {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ + }; + writew(0xFFFF, ®s->WOLCRClr); writeb(WOLCFG_SAB | WOLCFG_SAM, ®s->WOLCFGSet); writew(WOLCR_MAGIC_EN, ®s->WOLCRSet); @@ -3236,7 +3170,8 @@ static int velocity_set_wol(struct velocity_info *vptr) memcpy(arp->ar_tip, vptr->ip_addr, 4); - crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]); + crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, + (u8 *) & mask_pattern[0][0]); writew(crc, ®s->PatternCRC[0]); writew(WOLCR_ARP_EN, ®s->WOLCRSet); @@ -3275,3 +3210,92 @@ static int velocity_set_wol(struct velocity_info *vptr) return 0; } +static int velocity_suspend(struct pci_dev *pdev, u32 state) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + + if(!netif_running(vptr->dev)) + return 0; + + netif_device_detach(vptr->dev); + + spin_lock_irqsave(&vptr->lock, flags); + pci_save_state(pdev, vptr->pci_state); +#ifdef ETHTOOL_GWOL + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { + velocity_get_ip(vptr); + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + velocity_set_wol(vptr); + pci_enable_wake(pdev, 3, 1); + pci_set_power_state(pdev, 3); + } else { + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + } +#else + pci_set_power_state(pdev, state); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +static int velocity_resume(struct pci_dev *pdev) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + int i; + + if(!netif_running(vptr->dev)) + return 0; + + pci_set_power_state(pdev, 0); + pci_enable_wake(pdev, 0, 0); + pci_restore_state(pdev, vptr->pci_state); + + mac_wol_reset(vptr->mac_regs); + + spin_lock_irqsave(&vptr->lock, flags); + velocity_restore_context(vptr, &vptr->context); + velocity_init_registers(vptr, VELOCITY_INIT_WOL); + mac_disable_int(vptr->mac_regs); + + velocity_tx_srv(vptr, 0); + + for (i = 0; i < vptr->num_txq; i++) { + if (vptr->td_used[i]) { + mac_tx_queue_wake(vptr->mac_regs, i); + } + } + + mac_enable_int(vptr->mac_regs); + spin_unlock_irqrestore(&vptr->lock, flags); + netif_device_attach(vptr->dev); + + return 0; +} + +static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; + + if (ifa) { + 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; +} +#endif diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 2175b8696..9a187de48 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -37,7 +37,6 @@ #define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1} #define REV_ID_VT6110 (0) -#define DEVICE_ID (0x3119) #define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0) #define WORD_REG_BITS_ON(x,p) do { writew(readw((p))|(x),(p));} while (0) @@ -1320,7 +1319,7 @@ static inline void mac_set_cam_mask(struct mac_regs * regs, u8 * mask, enum velo /* disable CAMEN */ writeb(0, ®s->CAMADDR); - /* Select CAM mask */ + /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } @@ -1361,7 +1360,7 @@ static inline void mac_set_cam(struct mac_regs * regs, int idx, u8 *addr, enum v writeb(0, ®s->CAMADDR); - /* Select CAM mask */ + /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } @@ -1402,7 +1401,7 @@ static inline void mac_get_cam(struct mac_regs * regs, int idx, u8 *addr, enum v writeb(0, ®s->CAMADDR); - /* Select CAM mask */ + /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } @@ -1734,14 +1733,13 @@ 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; struct net_device_stats stats; -#if CONFIG_PM +#ifdef CONFIG_PM u32 pci_state[16]; #endif @@ -1772,7 +1770,8 @@ struct velocity_info { struct velocity_td_info *td_infos[TX_QUEUE_NO]; int rd_curr; - int rd_used; + int rd_dirty; + u32 rd_filled; struct rx_desc *rd_ring; struct velocity_rd_info *rd_info; /* It's an array */ @@ -1793,7 +1792,6 @@ struct velocity_info { u8 mCAMmask[(MCAM_SIZE / 8)]; spinlock_t lock; - spinlock_t xmit_lock; int wol_opts; u8 wol_passwd[6]; diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index cd1cd8569..07bfe107a 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/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 4cbda752b..fffe12085 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -351,8 +351,8 @@ struct dscc4_dev_priv { #endif /* Functions prototypes */ -static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); -static inline void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); +static void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); +static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); static int dscc4_found1(struct pci_dev *, unsigned long ioaddr); static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); static int dscc4_open(struct net_device *); @@ -366,7 +366,6 @@ static void dscc4_tx_timeout(struct net_device *); static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short); static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *); -static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int); #ifdef DSCC4_POLLING static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *); #endif @@ -866,6 +865,18 @@ static void dscc4_init_registers(struct dscc4_dev_priv *dpriv, //scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2); } +static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz) +{ + int ret = 0; + + if ((hz < 0) || (hz > DSCC4_HZ_MAX)) + ret = -EOPNOTSUPP; + else + dpriv->pci_priv->xtal_hz = hz; + + return ret; +} + static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) { struct dscc4_pci_priv *ppriv; @@ -1340,18 +1351,6 @@ static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return ret; } -static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz) -{ - int ret = 0; - - if ((hz < 0) || (hz > DSCC4_HZ_MAX)) - ret = -EOPNOTSUPP; - else - dpriv->pci_priv->xtal_hz = hz; - - return ret; -} - static int dscc4_match(struct thingie *p, int value) { int i; @@ -1531,7 +1530,7 @@ out: return IRQ_RETVAL(handled); } -static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, +static void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, struct dscc4_dev_priv *dpriv) { struct net_device *dev = dscc4_to_dev(dpriv); @@ -1700,7 +1699,7 @@ try: goto try; } -static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, +static void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct dscc4_dev_priv *dpriv) { struct net_device *dev = dscc4_to_dev(dpriv); diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c index b7f6504a5..690a02fdf 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd6457x.c @@ -463,8 +463,8 @@ static void sca_set_port(port_t *port) brv >>= 1; /* brv = 2^9 = 512 max in specs */ /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ - tmc = CLOCK_BASE / (brv * port->settings.clock_rate); - }while(br > 1 && tmc <= 128); + tmc = CLOCK_BASE / brv / port->settings.clock_rate; + }while (br > 1 && tmc <= 128); if (tmc < 1) { tmc = 1; @@ -473,7 +473,7 @@ static void sca_set_port(port_t *port) } else if (tmc > 255) tmc = 256; /* tmc=0 means 256 - low baud rates */ - port->settings.clock_rate = CLOCK_BASE / (brv * tmc); + port->settings.clock_rate = CLOCK_BASE / brv / tmc; } else { br = 9; /* Minimum clock rate */ tmc = 256; /* 8bit = 0 */ diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c index 058ff8048..9dccd9546 100644 --- a/drivers/net/wan/lmc/lmc_debug.c +++ b/drivers/net/wan/lmc/lmc_debug.c @@ -64,7 +64,7 @@ void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3) #endif } -inline void lmc_trace(struct net_device *dev, char *msg){ +void lmc_trace(struct net_device *dev, char *msg){ #ifdef LMC_TRACE unsigned long j = jiffies + 3; /* Wait for 50 ms */ diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h index e6af4921e..a4bfff8d1 100644 --- a/drivers/net/wan/pc300.h +++ b/drivers/net/wan/pc300.h @@ -164,9 +164,9 @@ typedef unsigned char ucchar; /* 8 bits, unsigned */ * (required to support Alpha systems) * ***************************************/ #ifdef __KERNEL__ -#define cpc_writeb(port,val) {writeb((ucchar)(val),(ulong)(port)); mb();} -#define cpc_writew(port,val) {writew((ushort)(val),(ulong)(port)); mb();} -#define cpc_writel(port,val) {writel((uclong)(val),(ulong)(port)); mb();} +#define cpc_writeb(port,val) {writeb((ucchar)(val),(port)); mb();} +#define cpc_writew(port,val) {writew((ushort)(val),(port)); mb();} +#define cpc_writel(port,val) {writel((uclong)(val),(port)); mb();} #define cpc_readb(port) readb(port) #define cpc_readw(port) readw(port) @@ -358,17 +358,17 @@ typedef struct pc300hw { uclong iophys; /* PLX registers I/O base */ uclong iosize; /* PLX registers I/O size */ uclong plxphys; /* PLX registers MMIO base (physical) */ - uclong plxbase; /* PLX registers MMIO base (virtual) */ + void __iomem * plxbase; /* PLX registers MMIO base (virtual) */ uclong plxsize; /* PLX registers MMIO size */ uclong scaphys; /* SCA registers MMIO base (physical) */ - uclong scabase; /* SCA registers MMIO base (virtual) */ + void __iomem * scabase; /* SCA registers MMIO base (virtual) */ uclong scasize; /* SCA registers MMIO size */ uclong ramphys; /* On-board RAM MMIO base (physical) */ - uclong rambase; /* On-board RAM MMIO base (virtual) */ + void __iomem * rambase; /* On-board RAM MMIO base (virtual) */ uclong alloc_ramsize; /* RAM MMIO size allocated by the PCI bridge */ uclong ramsize; /* On-board RAM MMIO size */ uclong falcphys; /* FALC registers MMIO base (physical) */ - uclong falcbase; /* FALC registers MMIO base (virtual) */ + void __iomem * falcbase;/* FALC registers MMIO base (virtual) */ uclong falcsize; /* FALC registers MMIO size */ } pc300hw_t; diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 29b82687b..7a972ca25 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -307,7 +307,7 @@ static void tx_dma_buf_pt_init(pc300_t * card, int ch) { int i; int ch_factor = ch * N_DMA_TX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { @@ -322,7 +322,7 @@ static void tx_dma_buf_init(pc300_t * card, int ch) { int i; int ch_factor = ch * N_DMA_TX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { @@ -337,7 +337,7 @@ static void rx_dma_buf_pt_init(pc300_t * card, int ch) { int i; int ch_factor = ch * N_DMA_RX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { @@ -352,7 +352,7 @@ static void rx_dma_buf_init(pc300_t * card, int ch) { int i; int ch_factor = ch * N_DMA_RX_BUF; - volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase + volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { @@ -365,7 +365,7 @@ static void rx_dma_buf_init(pc300_t * card, int ch) static void tx_dma_buf_check(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int i; ucshort first_bd = card->chan[ch].tx_first_bd; ucshort next_bd = card->chan[ch].tx_next_bd; @@ -374,10 +374,10 @@ static void tx_dma_buf_check(pc300_t * card, int ch) first_bd, TX_BD_ADDR(ch, first_bd), next_bd, TX_BD_ADDR(ch, next_bd)); for (i = first_bd, - ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, first_bd)); + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, first_bd)); i != ((next_bd + 1) & (N_DMA_TX_BUF - 1)); i = (i + 1) & (N_DMA_TX_BUF - 1), - ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i))) { + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i))) { printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), @@ -390,7 +390,7 @@ static void tx_dma_buf_check(pc300_t * card, int ch) /* Show all TX buffer descriptors */ static void tx1_dma_buf_check(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int i; ucshort first_bd = card->chan[ch].tx_first_bd; ucshort next_bd = card->chan[ch].tx_next_bd; @@ -404,7 +404,7 @@ static void tx1_dma_buf_check(pc300_t * card, int ch) (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)), (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch))); for (i = 0; i < N_DMA_TX_BUF; i++) { - ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i)); + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i)); printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d", ch, i, (uclong) cpc_readl(&ptdescr->next), (uclong) cpc_readl(&ptdescr->ptbuf), @@ -416,7 +416,7 @@ static void tx1_dma_buf_check(pc300_t * card, int ch) static void rx_dma_buf_check(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int i; ucshort first_bd = card->chan[ch].rx_first_bd; ucshort last_bd = card->chan[ch].rx_last_bd; @@ -424,7 +424,7 @@ static void rx_dma_buf_check(pc300_t * card, int ch) ch_factor = ch * N_DMA_RX_BUF; printk("#CH%d: f_bd = %d, l_bd = %d\n", ch, first_bd, last_bd); - for (i = 0, ptdescr = (pcsca_bd_t *) (card->hw.rambase + + for (i = 0, ptdescr = (card->hw.rambase + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); i < N_DMA_RX_BUF; i++, ptdescr++) { if (cpc_readb(&ptdescr->status) & DST_OSB) @@ -439,12 +439,12 @@ static void rx_dma_buf_check(pc300_t * card, int ch) int dma_get_rx_frame_size(pc300_t * card, int ch) { - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; ucshort first_bd = card->chan[ch].rx_first_bd; int rcvd = 0; volatile ucchar status; - ptdescr = (pcsca_bd_t *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd)); + ptdescr = (card->hw.rambase + RX_BD_ADDR(ch, first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { rcvd += cpc_readw(&ptdescr->len); first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); @@ -453,7 +453,7 @@ int dma_get_rx_frame_size(pc300_t * card, int ch) * (dma_buf_read will clean the buffer descriptors in this case). */ return (rcvd); } - ptdescr = (pcsca_bd_t *)(card->hw.rambase + cpc_readl(&ptdescr->next)); + ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); } return (-1); } @@ -465,7 +465,7 @@ int dma_get_rx_frame_size(pc300_t * card, int ch) int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) { int i, nchar; - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int tosend = len; ucchar nbuf = ((len - 1) / BD_DEF_LEN) + 1; @@ -474,11 +474,11 @@ int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) } for (i = 0; i < nbuf; i++) { - ptdescr = (pcsca_bd_t *) (card->hw.rambase + + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); nchar = cpc_min(BD_DEF_LEN, tosend); if (cpc_readb(&ptdescr->status) & DST_OSB) { - memcpy_toio((void *)(card->hw.rambase + cpc_readl(&ptdescr->ptbuf)), + memcpy_toio((card->hw.rambase + cpc_readl(&ptdescr->ptbuf)), &ptdata[len - tosend], nchar); cpc_writew(&ptdescr->len, nchar); card->chan[ch].nfree_tx_bd--; @@ -507,11 +507,11 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) { int nchar; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - volatile pcsca_bd_t *ptdescr; + volatile pcsca_bd_t __iomem *ptdescr; int rcvd = 0; volatile ucchar status; - ptdescr = (pcsca_bd_t *) (card->hw.rambase + + ptdescr = (card->hw.rambase + RX_BD_ADDR(ch, chan->rx_first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { nchar = cpc_readw(&ptdescr->len); @@ -527,7 +527,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) chan->rx_first_bd = (chan->rx_first_bd+1) & (N_DMA_RX_BUF-1); if (status & DST_EOM) break; - ptdescr = (pcsca_bd_t *) (card->hw.rambase + + ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); status = cpc_readb(&ptdescr->status); } @@ -536,7 +536,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) if (nchar != 0) { if (skb) { memcpy_fromio(skb_put(skb, nchar), - (void *)(card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar); + (card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar); } rcvd += nchar; } @@ -547,7 +547,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) if (status & DST_EOM) break; - ptdescr = (pcsca_bd_t *) (card->hw.rambase + cpc_readl(&ptdescr->next)); + ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); } if (rcvd != 0) { @@ -562,7 +562,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) void tx_dma_stop(pc300_t * card, int ch) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (5 + 2 * ch); ucchar drr_rst_bit = 1 << (1 + 2 * ch); @@ -573,7 +573,7 @@ void tx_dma_stop(pc300_t * card, int ch) void rx_dma_stop(pc300_t * card, int ch) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (4 + 2 * ch); ucchar drr_rst_bit = 1 << (2 * ch); @@ -584,7 +584,7 @@ void rx_dma_stop(pc300_t * card, int ch) void rx_dma_start(pc300_t * card, int ch) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; /* Start DMA */ @@ -609,7 +609,7 @@ void rx_dma_start(pc300_t * card, int ch) /*************************/ void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; unsigned long i = 0; while (cpc_readb(falcbase + F_REG(SIS, ch)) & SIS_CEC) { @@ -627,7 +627,7 @@ void falc_intr_enable(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; /* Interrupt pins are open-drain */ cpc_writeb(falcbase + F_REG(IPC, ch), @@ -674,7 +674,7 @@ void falc_intr_enable(pc300_t * card, int ch) void falc_open_timeslot(pc300_t * card, int ch, int timeslot) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch), @@ -690,7 +690,7 @@ void falc_open_timeslot(pc300_t * card, int ch, int timeslot) void falc_close_timeslot(pc300_t * card, int ch, int timeslot) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch), @@ -708,7 +708,7 @@ void falc_close_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; cpc_writeb(falcbase + F_REG(ICB1, ch), 0xff); cpc_writeb(falcbase + F_REG(TTR1, ch), 0); @@ -730,7 +730,7 @@ void falc_open_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; cpc_writeb(falcbase + F_REG(ICB1, ch), 0); if (conf->fr_mode == PC300_FR_UNFRAMED) { @@ -811,7 +811,7 @@ void falc_init_t1(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0); /* Switch to T1 mode (PCM 24) */ @@ -980,7 +980,7 @@ void falc_init_e1(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0); /* Switch to E1 mode (PCM 30) */ @@ -1157,7 +1157,7 @@ void falc_init_e1(pc300_t * card, int ch) void falc_init_hdlc(pc300_t * card, int ch) { - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1186,7 +1186,7 @@ void te_config(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar dummy; unsigned long flags; @@ -1246,7 +1246,7 @@ void falc_check_status(pc300_t * card, int ch, unsigned char frs0) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; /* Verify LOS */ if (frs0 & FRS0_LOS) { @@ -1402,7 +1402,7 @@ void falc_update_stats(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucshort counter; counter = cpc_readb(falcbase + F_REG(FECL, ch)); @@ -1455,7 +1455,7 @@ void falc_remote_loop(pc300_t * card, int ch, int loop_on) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (loop_on) { // EVENT_FALC_ABNORMAL @@ -1499,7 +1499,7 @@ void falc_local_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (loop_on) { cpc_writeb(falcbase + F_REG(LIM0, ch), @@ -1527,7 +1527,7 @@ void falc_payload_loop(pc300_t * card, int ch, int loop_on) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (loop_on) { // EVENT_FALC_ABNORMAL @@ -1580,7 +1580,7 @@ void turn_off_xlu(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1601,7 +1601,7 @@ void turn_off_xld(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1624,7 +1624,7 @@ void falc_generate_loop_up_code(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1657,7 +1657,7 @@ void falc_generate_loop_down_code(pc300_t * card, int ch) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (conf->media == IF_IFACE_T1) { cpc_writeb(falcbase + F_REG(FMR5, ch), @@ -1687,7 +1687,7 @@ void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (activate) { pfalc->prbs = 1; @@ -1973,11 +1973,11 @@ static void sca_tx_intr(pc300dev_t *dev) pc300ch_t *chan = (pc300ch_t *)dev->chan; pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; - volatile pcsca_bd_t * ptdescr; + volatile pcsca_bd_t __iomem * ptdescr; struct net_device_stats *stats = hdlc_stats(dev->dev); /* Clean up descriptors from previous transmission */ - ptdescr = (pcsca_bd_t *)(card->hw.rambase + + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) != TX_BD_ADDR(ch,chan->tx_first_bd)) && @@ -1988,8 +1988,7 @@ static void sca_tx_intr(pc300dev_t *dev) cpc_writew(&ptdescr->len, 0); chan->nfree_tx_bd++; chan->tx_first_bd = (chan->tx_first_bd + 1) & (N_DMA_TX_BUF - 1); - ptdescr = (pcsca_bd_t *)(card->hw.rambase + - TX_BD_ADDR(ch,chan->tx_first_bd)); + ptdescr = (card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); } #ifdef CONFIG_PC300_MLPPP @@ -2006,7 +2005,7 @@ static void sca_tx_intr(pc300dev_t *dev) static void sca_intr(pc300_t * card) { - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; volatile uclong status; int ch; int intr_count = 0; @@ -2187,7 +2186,7 @@ static void falc_t1_loop_detection(pc300_t * card, int ch, ucchar frs1) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) && !pfalc->loop_gen) { @@ -2212,7 +2211,7 @@ static void falc_e1_loop_detection(pc300_t * card, int ch, ucchar rsp) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) && !pfalc->loop_gen) { @@ -2237,7 +2236,7 @@ static void falc_t1_intr(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar isr0, isr3, gis; ucchar dummy; @@ -2284,7 +2283,7 @@ static void falc_e1_intr(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; - uclong falcbase = card->hw.falcbase; + void __iomem *falcbase = card->hw.falcbase; ucchar isr1, isr2, isr3, gis, rsp; ucchar dummy; @@ -2408,7 +2407,7 @@ static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs) void cpc_sca_status(pc300_t * card, int ch) { ucchar ilar; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; uclong flags; tx_dma_buf_check(card, ch); @@ -2544,7 +2543,7 @@ int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) int ch = chan->channel; void __user *arg = ifr->ifr_data; struct if_settings *settings = &ifr->ifr_settings; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -2863,8 +2862,8 @@ int ch_config(pc300dev_t * d) pc300ch_t *chan = (pc300ch_t *) d->chan; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; pc300_t *card = (pc300_t *) chan->card; - uclong scabase = card->hw.scabase; - uclong plxbase = card->hw.plxbase; + void __iomem *scabase = card->hw.scabase; + void __iomem *plxbase = card->hw.plxbase; int ch = chan->channel; uclong clkrate = chan->conf.phys_settings.clock_rate; uclong clktype = chan->conf.phys_settings.clock_type; @@ -3010,7 +3009,7 @@ int rx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; int ch = chan->channel; cpc_writeb(scabase + DSR_RX(ch), 0); @@ -3041,7 +3040,7 @@ int tx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; int ch = chan->channel; cpc_writeb(scabase + DSR_TX(ch), 0); @@ -3105,7 +3104,7 @@ void cpc_opench(pc300dev_t * d) pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; - uclong scabase = card->hw.scabase; + void __iomem *scabase = card->hw.scabase; ch_config(d); @@ -3211,7 +3210,7 @@ static uclong detect_ram(pc300_t * card) { uclong i; ucchar data; - uclong rambase = card->hw.rambase; + void __iomem *rambase = card->hw.rambase; card->hw.ramsize = PC300_RAMSIZE; /* Let's find out how much RAM is present on this board */ @@ -3227,7 +3226,7 @@ static uclong detect_ram(pc300_t * card) static void plx_init(pc300_t * card) { - struct RUNTIME_9050 *plx_ctl = (struct RUNTIME_9050 *) card->hw.plxbase; + struct RUNTIME_9050 __iomem *plx_ctl = card->hw.plxbase; /* Reset PLX */ cpc_writel(&plx_ctl->init_ctrl, @@ -3532,10 +3531,9 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if ((err = pci_enable_device(pdev)) != 0) goto err_release_sca; - card->hw.plxbase = (uclong) ioremap(card->hw.plxphys, card->hw.plxsize); - card->hw.rambase = (uclong) ioremap(card->hw.ramphys, - card->hw.alloc_ramsize); - card->hw.scabase = (uclong) ioremap(card->hw.scaphys, card->hw.scasize); + card->hw.plxbase = ioremap(card->hw.plxphys, card->hw.plxsize); + card->hw.rambase = ioremap(card->hw.ramphys, card->hw.alloc_ramsize); + card->hw.scabase = ioremap(card->hw.scaphys, card->hw.scasize); switch (device_id) { case PCI_DEVICE_ID_PC300_TE_1: case PCI_DEVICE_ID_PC300_TE_2: @@ -3543,14 +3541,13 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) case PCI_DEVICE_ID_PC300_TE_M_2: request_mem_region(card->hw.falcphys, card->hw.falcsize, "FALC Registers"); - card->hw.falcbase = (uclong) ioremap(card->hw.falcphys, - card->hw.falcsize); + card->hw.falcbase = ioremap(card->hw.falcphys, card->hw.falcsize); break; case PCI_DEVICE_ID_PC300_RX_1: case PCI_DEVICE_ID_PC300_RX_2: default: - card->hw.falcbase = 0; + card->hw.falcbase = NULL; break; } @@ -3616,11 +3613,11 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; err_io_unmap: - iounmap((void *) card->hw.plxbase); - iounmap((void *) card->hw.scabase); - iounmap((void *) card->hw.rambase); + iounmap(card->hw.plxbase); + iounmap(card->hw.scabase); + iounmap(card->hw.rambase); if (card->hw.type == PC300_TE) { - iounmap((void *) card->hw.falcbase); + iounmap(card->hw.falcbase); release_mem_region(card->hw.falcphys, card->hw.falcsize); } err_release_sca: @@ -3649,15 +3646,15 @@ static void __devexit cpc_remove_one(struct pci_dev *pdev) for (i = 0; i < card->hw.nchan; i++) { unregister_hdlc_device(card->chan[i].d.dev); } - iounmap((void *) card->hw.plxbase); - iounmap((void *) card->hw.scabase); - iounmap((void *) card->hw.rambase); + iounmap(card->hw.plxbase); + iounmap(card->hw.scabase); + iounmap(card->hw.rambase); release_mem_region(card->hw.plxphys, card->hw.plxsize); release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize); release_mem_region(card->hw.scaphys, card->hw.scasize); release_region(card->hw.iophys, card->hw.iosize); if (card->hw.type == PC300_TE) { - iounmap((void *) card->hw.falcbase); + iounmap(card->hw.falcbase); release_mem_region(card->hw.falcphys, card->hw.falcsize); } for (i = 0; i < card->hw.nchan; i++) diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 79d6894ac..9e50d5d02 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -192,13 +192,14 @@ static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal) */ void cpc_tty_init(pc300dev_t *pc300dev) { - int port, aux; + unsigned long port; + int aux; st_cpc_tty_area * cpc_tty; /* hdlcX - X=interface number */ port = pc300dev->dev->name[4] - '0'; if (port >= CPC_TTY_NPORTS) { - printk("%s-tty: invalid interface selected (0-%i): %i", + printk("%s-tty: invalid interface selected (0-%i): %li", pc300dev->dev->name, CPC_TTY_NPORTS-1,port); return; @@ -634,14 +635,8 @@ static void cpc_tty_flush_buffer(struct tty_struct *tty) } CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name); - - wake_up_interruptible(&tty->write_wait); - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){ - CPC_TTY_DBG("%s: call line disc. wake up\n",cpc_tty->name); - tty->ldisc.write_wakeup(tty); - } + tty_wakeup(tty); return; } @@ -688,25 +683,32 @@ static void cpc_tty_hangup(struct tty_struct *tty) */ static void cpc_tty_rx_work(void * data) { - int port, i, j; + unsigned long port; + int i, j; st_cpc_tty_area *cpc_tty; volatile st_cpc_rx_buf * buf; char flags=0,flg_rx=1; + struct tty_ldisc *ld; if (cpc_tty_cnt == 0) return; + for (i=0; (i < 4) && flg_rx ; i++) { flg_rx = 0; - port = (int) data; + port = (unsigned long)data; for (j=0; j < CPC_TTY_NPORTS; j++) { cpc_tty = &cpc_tty_area[port]; if ((buf=cpc_tty->buf_rx.first) != 0) { - - if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { - CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); - cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (char *)(buf->data), - &flags, buf->size); + if(cpc_tty->tty) { + ld = tty_ldisc_ref(cpc_tty->tty); + if(ld) { + if (ld->receive_buf) { + CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); + ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); + } + tty_ldisc_deref(ld); + } } cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; kfree((unsigned char *)buf); @@ -760,7 +762,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev) int rx_len, rx_aux; volatile unsigned char status; unsigned short first_bd = pc300chan->rx_first_bd; - st_cpc_rx_buf *new; + st_cpc_rx_buf *new=NULL; unsigned char dsr_rx; if (pc300dev->cpc_tty == NULL) { @@ -789,6 +791,10 @@ void cpc_tty_receive(pc300dev_t *pc300dev) cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), RX_BD_ADDR(ch, pc300chan->rx_last_bd)); } + if (new) { + kfree(new); + new = NULL; + } return; } @@ -834,7 +840,8 @@ void cpc_tty_receive(pc300dev_t *pc300dev) cpc_tty->name); cpc_tty_rx_disc_frame(pc300chan); rx_len = 0; - kfree((unsigned char *)new); + kfree(new); + new = NULL; break; /* read next frame - while(1) */ } @@ -843,7 +850,8 @@ void cpc_tty_receive(pc300dev_t *pc300dev) cpc_tty_rx_disc_frame(pc300chan); stats->rx_dropped++; rx_len = 0; - kfree((unsigned char *)new); + kfree(new); + new = NULL; break; /* read next frame - while(1) */ } @@ -910,13 +918,7 @@ static void cpc_tty_tx_work(void *data) CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); return; } - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){ - CPC_TTY_DBG("%s:call line disc. wakeup\n",cpc_tty->name); - tty->ldisc.write_wakeup (tty); - } - - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } /* diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c index b00fb7837..e66c250ea 100644 --- a/drivers/net/wan/sdla_chdlc.c +++ b/drivers/net/wan/sdla_chdlc.c @@ -3628,11 +3628,7 @@ static void tty_poll_work (void* data) if ((tty=card->tty)==NULL) return; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); #if defined(SERIAL_HAVE_POLL_WAIT) wake_up_interruptible(&tty->poll_wait); #endif @@ -3857,6 +3853,7 @@ static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) char fp=0; struct tty_struct *tty; int i; + struct tty_ldisc *ld; if (!card->tty_open){ dbg_printk(KERN_INFO "%s: TTY not open during receive\n", @@ -3944,8 +3941,11 @@ static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) len -= offset; } sdla_peek(&card->hw, addr, card->tty_rx+offset, len); - if (tty->ldisc.receive_buf){ - tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen); + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty,card->tty_rx,&fp,olen); + tty_ldisc_deref(ld); }else{ if (net_ratelimit()){ printk(KERN_INFO @@ -4252,14 +4252,10 @@ static void wanpipe_tty_flush_buffer(struct tty_struct *tty) if (!tty) return; - wake_up_interruptible(&tty->write_wait); #if defined(SERIAL_HAVE_POLL_WAIT) wake_up_interruptible(&tty->poll_wait); #endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - + tty_wakeup(tty); return; } diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 52f40883d..2efccb055 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -3678,7 +3678,7 @@ static int process_udp_mgmt_pkt(sdla_t* card) break; } - (void *)ptr_trc_el = card->u.f.curr_trc_el; + ptr_trc_el = (void *)card->u.f.curr_trc_el; buffer_length = 0; fr_udp_pkt->data[0x00] = 0x00; @@ -3729,7 +3729,7 @@ static int process_udp_mgmt_pkt(sdla_t* card) ptr_trc_el ++; if((void *)ptr_trc_el > card->u.f.trc_el_last) - (void*)ptr_trc_el = card->u.f.trc_el_base; + ptr_trc_el = (void*)card->u.f.trc_el_base; buffer_length += sizeof(fpipemon_trc_hdr_t); if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index 501e9a752..c8bc6da57 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -937,7 +937,7 @@ int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, curlen); addr += curlen; - (char*)buf += curlen; + buf = (char*)buf + curlen; len -= curlen; } @@ -1019,7 +1019,7 @@ int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, curlen); addr += curlen; - (char*)buf += curlen; + buf = (char*)buf + curlen; len -= curlen; } @@ -2001,7 +2001,7 @@ static int detect_s514 (sdlahw_t* hw) (void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, (unsigned long)MAX_SIZEOF_S514_MEMORY); /* map the physical control register memory to virtual memory */ - (void *)hw->vector = ioremap( + hw->vector = (unsigned long)ioremap( (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), (unsigned long)16); diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c index be10f8c41..74e151ace 100644 --- a/drivers/net/wan/sdlamain.c +++ b/drivers/net/wan/sdlamain.c @@ -976,7 +976,7 @@ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) dump.length -= len; dump.offset += len; - (char*)dump.ptr += len; + dump.ptr = (char*)dump.ptr + len; } sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index f7442d52d..2329c23af 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -767,9 +768,9 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) struct in_ifaddr *ifa; u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ #ifdef CONFIG_INET - if ((in_dev=in_dev_get(dev)) != NULL) + rcu_read_lock(); + if ((in_dev = __in_dev_get(dev)) != NULL) { - read_lock(&in_dev->lock); for (ifa=in_dev->ifa_list; ifa != NULL; ifa=ifa->ifa_next) { if (strcmp(dev->name, ifa->ifa_label) == 0) @@ -779,9 +780,8 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) break; } } - read_unlock(&in_dev->lock); - in_dev_put(in_dev); } + rcu_read_unlock(); #endif /* I hope both addr and mask are in the net order */ sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 8d38c1803..041b15b0f 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -1815,7 +1816,8 @@ static int writeConfigRid(struct airo_info*ai, int lock) { if (!test_bit (FLAG_COMMIT, &ai->flags)) return SUCCESS; - clear_bit (FLAG_COMMIT | FLAG_RESET, &ai->flags); + clear_bit (FLAG_COMMIT, &ai->flags); + clear_bit (FLAG_RESET, &ai->flags); checkThrottle(ai); cfgr = ai->config; @@ -1979,9 +1981,6 @@ static int mpi_send_packet (struct net_device *dev) ai->txfids[0].tx_desc.eoc = 1; ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); - memcpy((char *)ai->txfids[0].card_ram_off, - (char *)&ai->txfids[0].tx_desc, sizeof(TxFid)); - /* * Magic, the cards firmware needs a length count (2 bytes) in the host buffer * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen @@ -2011,6 +2010,7 @@ static int mpi_send_packet (struct net_device *dev) return ERROR; *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); + ai->txfids[0].tx_desc.len += sizeof(pMic); /* copy data into airo dma buffer */ memcpy (sendbuf, buffer, sizeof(etherHead)); buffer += sizeof(etherHead); @@ -2029,6 +2029,9 @@ static int mpi_send_packet (struct net_device *dev) memcpy(sendbuf, buffer, len); } + memcpy((char *)ai->txfids[0].card_ram_off, + (char *)&ai->txfids[0].tx_desc, sizeof(TxFid)); + OUT4500(ai, EVACK, 8); dev_kfree_skb_any(skb); @@ -2183,6 +2186,12 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { struct airo_info *priv = dev->priv; u32 *fids = priv->fids; + if (test_bit(FLAG_MPI, &priv->flags)) { + /* Not implemented yet for MPI350 */ + netif_stop_queue(dev); + return -ENETDOWN; + } + if ( skb == NULL ) { printk( KERN_ERR "airo: skb == NULL!!!\n" ); return 0; @@ -2248,12 +2257,14 @@ struct net_device_stats *airo_get_stats(struct net_device *dev) { struct airo_info *local = dev->priv; - /* Get stats out of the card if available */ - if (down_trylock(&local->sem) != 0) { - set_bit(JOB_STATS, &local->flags); - wake_up_interruptible(&local->thr_wait); - } else - airo_read_stats(local); + if (!test_bit(JOB_STATS, &local->flags)) { + /* Get stats out of the card if available */ + if (down_trylock(&local->sem) != 0) { + set_bit(JOB_STATS, &local->flags); + wake_up_interruptible(&local->thr_wait); + } else + airo_read_stats(local); + } return &local->stats; } @@ -2339,6 +2350,9 @@ static void del_airo_dev( struct net_device *dev ); void stop_airo_card( struct net_device *dev, int freeres ) { struct airo_info *ai = dev->priv; + + set_bit(FLAG_RADIO_DOWN, &ai->flags); + disable_MAC(ai, 1); disable_interrupts(ai); free_irq( dev->irq, dev ); takedown_proc_entry( dev, ai ); @@ -3405,13 +3419,8 @@ static void disable_MAC( struct airo_info *ai, int lock ) { } static void enable_interrupts( struct airo_info *ai ) { - /* Reset the status register */ - u16 status = IN4500( ai, EVSTAT ); - OUT4500( ai, EVACK, status ); /* Enable the interrupts */ OUT4500( ai, EVINTEN, STATUS_INTS ); - /* Note there is a race condition between the last two lines that - I don't know how to get rid of right now... */ } static void disable_interrupts( struct airo_info *ai ) { @@ -3459,7 +3468,7 @@ static void mpi_receive_802_3(struct airo_info *ai) memcpy(buffer + ETH_ALEN * 2, ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, len - ETH_ALEN * 2 - off); - if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off)) { + if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { badmic: dev_kfree_skb_irq (skb); goto badrx; @@ -3669,18 +3678,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) status = readCapabilityRid(ai, &cap_rid, lock); if ( status != SUCCESS ) return ERROR; - /* - * This driver supports MPI350 firmwares up to, and - * including 5.30.17 - */ - if (test_bit(FLAG_MPI, &ai->flags) && - strncmp (cap_rid.prodVer, "5.00.", 5) && - strncmp (cap_rid.prodVer, "5b00.", 5) && - strncmp (cap_rid.prodVer, "5.02.", 5) && - strncmp (cap_rid.prodVer, "5.20.", 5) && - strncmp (cap_rid.prodVer, "5.30.", 5)) - printk(KERN_ERR "airo: Firmware version %s is not supported. Use it at your own risk!\n", cap_rid.prodVer); - status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock); if ( status == SUCCESS ) { if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) @@ -3715,9 +3712,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) /* Check to see if there are any insmod configured rates to add */ - if ( rates ) { + if ( rates[0] ) { int i = 0; - if ( rates[0] ) memset(ai->config.rates,0,sizeof(ai->config.rates)); + memset(ai->config.rates,0,sizeof(ai->config.rates)); for( i = 0; i < 8 && rates[i]; i++ ) { ai->config.rates[i] = rates[i]; } @@ -3784,7 +3781,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { // Im really paranoid about letting it run forever! int max_tries = 600000; - u16 cmd; if (IN4500(ai, EVSTAT) & EV_CMD) OUT4500(ai, EVACK, EV_CMD); @@ -3793,26 +3789,23 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { OUT4500(ai, PARAM1, pCmd->parm1); OUT4500(ai, PARAM2, pCmd->parm2); OUT4500(ai, COMMAND, pCmd->cmd); - while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0 && - (cmd = IN4500(ai, COMMAND)) != 0 ) - if (cmd == pCmd->cmd) - // PC4500 didn't notice command, try again - OUT4500(ai, COMMAND, pCmd->cmd); - if ( max_tries == -1 ) { - printk( KERN_ERR - "airo: Max tries exceeded when issueing command\n" ); - return ERROR; - } while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { + if ((IN4500(ai, COMMAND)) == pCmd->cmd) + // PC4500 didn't notice command, try again + OUT4500(ai, COMMAND, pCmd->cmd); if (!in_atomic() && (max_tries & 255) == 0) schedule(); } + if ( max_tries == -1 ) { printk( KERN_ERR - "airo: Max tries exceeded waiting for command\n" ); - return ERROR; + "airo: Max tries exceeded when issueing command\n" ); + if (IN4500(ai, COMMAND) & COMMAND_BUSY) + OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); + return ERROR; } + // command completed pRsp->status = IN4500(ai, STATUS); pRsp->rsp0 = IN4500(ai, RESP0); @@ -4508,8 +4501,6 @@ static ssize_t proc_read( struct file *file, len = priv->readlen - pos; if (copy_to_user(buffer, priv->rbuffer + pos, len)) return -EFAULT; - if (pos + len > priv->writelen) - priv->writelen = pos + len; *offset = pos + len; return len; } @@ -5520,7 +5511,6 @@ static int airo_pci_resume(struct pci_dev *pdev) mpi_init_descriptors(ai); setup_card(ai, dev->dev_addr, 0); clear_bit(FLAG_RADIO_OFF, &ai->flags); - clear_bit(FLAG_RADIO_DOWN, &ai->flags); clear_bit(FLAG_PENDING_XMIT, &ai->flags); } else { OUT4500(ai, EVACK, EV_AWAKEN); @@ -5605,6 +5595,30 @@ static void __exit airo_cleanup_module( void ) * would not work at all... - Jean II */ +static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) +{ + int quality = 0; + + if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) { + if (memcmp(cap_rid->prodName, "350", 3)) + if (status_rid->signalQuality > 0x20) + quality = 0; + else + quality = 0x20 - status_rid->signalQuality; + else + if (status_rid->signalQuality > 0xb0) + quality = 0; + else if (status_rid->signalQuality < 0x10) + quality = 0xa0; + else + quality = 0xb0 - status_rid->signalQuality; + } + return quality; +} + +#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) +#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50); + /*------------------------------------------------------------------*/ /* * Wireless Handler : get protocol name @@ -6292,7 +6306,8 @@ static int airo_set_txpow(struct net_device *dev, readCapabilityRid(local, &cap_rid, 1); if (vwrq->disabled) { - set_bit (FLAG_RADIO_OFF | FLAG_COMMIT, &local->flags); + set_bit (FLAG_RADIO_OFF, &local->flags); + set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ } if (vwrq->flags != IW_TXPOW_MWATT) { @@ -6431,7 +6446,7 @@ static int airo_get_range(struct net_device *dev, range->num_frequency = k; /* Hum... Should put the right values there */ - range->max_qual.qual = 10; + range->max_qual.qual = airo_get_max_quality(&cap_rid); range->max_qual.level = 0x100 - 120; /* -120 dBm */ range->max_qual.noise = 0; range->sensitivity = 65535; @@ -6498,7 +6513,7 @@ static int airo_get_range(struct net_device *dev, /* Experimental measurements - boundary 11/5.5 Mb/s */ /* Note : with or without the (local->rssi), results * are somewhat different. - Jean II */ - range->avg_qual.qual = 6; + range->avg_qual.qual = airo_get_avg_quality(&cap_rid); if (local->rssi) range->avg_qual.level = 186; /* -70 dBm */ else @@ -7112,6 +7127,7 @@ static void airo_read_wireless_stats(struct airo_info *local) { StatusRid status_rid; StatsRid stats_rid; + CapabilityRid cap_rid; u32 *vals = stats_rid.vals; /* Get stats out of the card */ @@ -7120,6 +7136,7 @@ static void airo_read_wireless_stats(struct airo_info *local) up(&local->sem); return; } + readCapabilityRid(local, &cap_rid, 0); readStatusRid(local, &status_rid, 0); readStatsRid(local, &stats_rid, RID_STATS, 0); up(&local->sem); @@ -7128,7 +7145,7 @@ static void airo_read_wireless_stats(struct airo_info *local) local->wstats.status = status_rid.mode; /* Signal quality and co. But where is the noise level ??? */ - local->wstats.qual.qual = status_rid.signalQuality; + local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); if (local->rssi) local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm; else @@ -7155,12 +7172,14 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) { struct airo_info *local = dev->priv; - /* Get stats out of the card if available */ - if (down_trylock(&local->sem) != 0) { - set_bit(JOB_WSTATS, &local->flags); - wake_up_interruptible(&local->thr_wait); - } else - airo_read_wireless_stats(local); + if (!test_bit(JOB_WSTATS, &local->flags)) { + /* Get stats out of the card if available */ + if (down_trylock(&local->sem) != 0) { + set_bit(JOB_WSTATS, &local->flags); + wake_up_interruptible(&local->thr_wait); + } else + airo_read_wireless_stats(local); + } return &local->wstats; } @@ -7187,9 +7206,11 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { { case AIROGCAP: ridcode = RID_CAPABILITIES; break; case AIROGCFG: ridcode = RID_CONFIG; - disable_MAC (ai, 1); - writeConfigRid (ai, 1); - enable_MAC (ai, &rsp, 1); + if (test_bit(FLAG_COMMIT, &ai->flags)) { + disable_MAC (ai, 1); + writeConfigRid (ai, 1); + enable_MAC (ai, &rsp, 1); + } break; case AIROGSLIST: ridcode = RID_SSID; break; case AIROGVLIST: ridcode = RID_APLIST; break; @@ -7269,6 +7290,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { case AIROPCAP: ridcode = RID_CAPABILITIES; break; case AIROPAPLIST: ridcode = RID_APLIST; break; case AIROPCFG: ai->config.len = 0; + clear_bit(FLAG_COMMIT, &ai->flags); ridcode = RID_CONFIG; break; case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 20bd0dfef..51c54132c 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -1,4 +1,4 @@ -/* airport.c 0.13e +/* airport.c * * A driver for "Hermes" chipset based Apple Airport wireless * card. @@ -11,6 +11,9 @@ * 0.06 : fix possible hang on powerup, add sleep support */ +#define DRIVER_NAME "airport" +#define PFX DRIVER_NAME ": " + #include #include @@ -25,6 +28,7 @@ #include #include #include +#include #include #include @@ -50,7 +54,7 @@ static int airport_suspend(struct macio_dev *mdev, u32 state) { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -84,15 +88,14 @@ static int airport_resume(struct macio_dev *mdev) { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/5); + msleep(200); enable_irq(dev->irq); @@ -126,7 +129,7 @@ static int airport_detach(struct macio_dev *mdev) { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct airport *card = priv->card; if (card->ndev_registered) @@ -144,8 +147,7 @@ airport_detach(struct macio_dev *mdev) macio_release_resource(mdev, 0); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); macio_set_drvdata(mdev, NULL); free_netdev(dev); @@ -171,14 +173,12 @@ static int airport_hard_reset(struct orinoco_private *priv) disable_irq(dev->irq); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); enable_irq(dev->irq); - schedule_timeout(HZ); + ssleep(1); #endif return 0; @@ -194,24 +194,24 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); + printk(KERN_ERR PFX "wrong interrupt/addresses in OF tree\n"); return -ENODEV; } /* Allocate space for private device-specific data */ dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); if (! dev) { - printk(KERN_ERR "airport: can't allocate device datas\n"); + printk(KERN_ERR PFX "can't allocate device datas\n"); return -ENODEV; } - priv = dev->priv; + priv = netdev_priv(dev); card = priv->card; hw = &priv->hw; card->mdev = mdev; if (macio_request_resource(mdev, 0, "airport")) { - printk(KERN_ERR "airport: can't request IO resource !\n"); + printk(KERN_ERR PFX "can't request IO resource !\n"); free_netdev(dev); return -EBUSY; } @@ -224,11 +224,11 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) /* Setup interrupts & base address */ dev->irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr); + printk(KERN_DEBUG PFX "Airport at physical address %lx\n", phys_addr); dev->base_addr = phys_addr; card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); if (!card->vaddr) { - printk("airport: ioremap() failed\n"); + printk(PFX "ioremap() failed\n"); goto failed; } @@ -237,24 +237,23 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) /* Power up card */ pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); /* Reset it before we get the interrupt */ hermes_init(hw); if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) { - printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq); + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); goto failed; } card->irq_requested = 1; /* Tell the stack we exist */ if (register_netdev(dev) != 0) { - printk(KERN_ERR "airport: register_netdev() failed\n"); + printk(KERN_ERR PFX "register_netdev() failed\n"); goto failed; } - printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name); + printk(KERN_DEBUG PFX "card registered for interface %s\n", dev->name); card->ndev_registered = 1; return 0; failed: @@ -263,7 +262,8 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) } /* airport_attach */ -static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt )"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Benjamin Herrenschmidt )"; MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); @@ -280,7 +280,7 @@ static struct of_match airport_match[] = static struct macio_driver airport_driver = { - .name = "airport", + .name = DRIVER_NAME, .match_table = airport_match, .probe = airport_attach, .remove = airport_detach, diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index cde68a443..fd8953c63 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -2430,12 +2430,13 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = -ENOMEM; break; } - + if (copy_from_user(new_firmware, com.data, com.len)) { + kfree(new_firmware); rc = -EFAULT; break; } - + if (priv->firmware) kfree(priv->firmware); diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index d5ec3dedb..730090118 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -13,8 +13,8 @@ * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no * particular order). * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * Copyright (C) 2001, David Gibson, IBM + * Copyright (C) 2000, David Gibson, Linuxcare Australia. + * (C) Copyright David Gibson, IBM Corp. 2001-2003. * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -53,10 +53,9 @@ #include "hermes.h" MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); -MODULE_AUTHOR("David Gibson "); -#ifdef MODULE_LICENSE +MODULE_AUTHOR("Pavel Roskin " + " & David Gibson "); MODULE_LICENSE("Dual MPL/GPL"); -#endif /* These are maximum timeouts. Most often, card wil react much faster */ #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ @@ -226,7 +225,7 @@ int hermes_init(hermes_t *hw) * * Callable from any context, but locking is your problem. */ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, - hermes_response_t *resp) + struct hermes_response *resp) { int err; int k; @@ -392,7 +391,6 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset) return -EIO; } - return 0; } diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 126923ffd..429d57240 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -12,7 +12,8 @@ * project, the Linux wvlan_cs driver, Lucent's HCF-Light * (wvlan_hcf.c) library, and the NetBSD wireless driver. * - * Copyright (C) 2000, David Gibson, Linuxcare Australia + * Copyright (C) 2000, David Gibson, Linuxcare Australia. + * (C) Copyright David Gibson, IBM Corp. 2001-2003. * * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. * @@ -124,29 +125,52 @@ /* * Command codes */ -/*--- Controller Commands --------------------------*/ +/*--- Controller Commands ----------------------------*/ #define HERMES_CMD_INIT (0x0000) #define HERMES_CMD_ENABLE (0x0001) #define HERMES_CMD_DISABLE (0x0002) #define HERMES_CMD_DIAG (0x0003) -/*--- Buffer Mgmt Commands --------------------------*/ +/*--- Buffer Mgmt Commands ---------------------------*/ #define HERMES_CMD_ALLOC (0x000A) #define HERMES_CMD_TX (0x000B) -#define HERMES_CMD_CLRPRST (0x0012) -/*--- Regulate Commands --------------------------*/ +/*--- Regulate Commands ------------------------------*/ #define HERMES_CMD_NOTIFY (0x0010) #define HERMES_CMD_INQUIRE (0x0011) -/*--- Configure Commands --------------------------*/ +/*--- Configure Commands -----------------------------*/ #define HERMES_CMD_ACCESS (0x0021) #define HERMES_CMD_DOWNLD (0x0022) +/*--- Serial I/O Commands ----------------------------*/ +#define HERMES_CMD_READMIF (0x0030) +#define HERMES_CMD_WRITEMIF (0x0031) + /*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_MONITOR (0x0038) -#define HERMES_MONITOR_ENABLE (0x000b) -#define HERMES_MONITOR_DISABLE (0x000f) +#define HERMES_CMD_TEST (0x0038) + + +/* Test command arguments */ +#define HERMES_TEST_SET_CHANNEL 0x0800 +#define HERMES_TEST_MONITOR 0x0b00 +#define HERMES_TEST_STOP 0x0f00 + +/* Authentication algorithms */ +#define HERMES_AUTH_OPEN 1 +#define HERMES_AUTH_SHARED_KEY 2 + +/* WEP settings */ +#define HERMES_WEP_PRIVACY_INVOKED 0x0001 +#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 +#define HERMES_WEP_HOST_ENCRYPT 0x0010 +#define HERMES_WEP_HOST_DECRYPT 0x0080 + +/* Symbol hostscan options */ +#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 +#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 +#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 +#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 /* * Frame structures and constants @@ -157,16 +181,6 @@ #define HERMES_802_3_OFFSET (14+32) #define HERMES_802_2_OFFSET (14+32+14) -struct hermes_rx_descriptor { - u16 status; - u32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rxflow; - u32 reserved; -} __attribute__ ((packed)); - #define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_BADCRC (0x0001) #define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) @@ -201,7 +215,11 @@ struct hermes_tx_descriptor { #define HERMES_INQ_TALLIES (0xF100) #define HERMES_INQ_SCAN (0xF101) +#define HERMES_INQ_CHANNELINFO (0xF102) +#define HERMES_INQ_HOSTSCAN (0xF103) +#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) #define HERMES_INQ_LINKSTATUS (0xF200) +#define HERMES_INQ_SEC_STAT_AGERE (0xF202) struct hermes_tallies_frame { u16 TxUnicastFrames; @@ -233,23 +251,58 @@ struct hermes_tallies_frame { /* Grabbed from wlan-ng - Thanks Mark... - Jean II * This is the result of a scan inquiry command */ /* Structure describing info about an Access Point */ -struct hermes_scan_apinfo { +struct prism2_scan_apinfo { u16 channel; /* Channel where the AP sits */ u16 noise; /* Noise level */ u16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval ? */ - u16 capabilities; /* Capabilities ? */ + u16 beacon_interv; /* Beacon interval */ + u16 capabilities; /* Capabilities */ + u16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ u8 rates[10]; /* Bit rate supported */ - u16 proberesp_rate; /* ???? */ + u16 proberesp_rate; /* Data rate of the response frame */ + u16 atim; /* ATIM window time, Kus (hostscan only) */ } __attribute__ ((packed)); -/* Container */ -struct hermes_scan_frame { - u16 rsvd; /* ??? */ - u16 scanreason; /* ??? */ - struct hermes_scan_apinfo aps[35]; /* Scan result */ + +/* Same stuff for the Lucent/Agere card. + * Thanks to h1kari - Jean II */ +struct agere_scan_apinfo { + u16 channel; /* Channel where the AP sits */ + u16 noise; /* Noise level */ + u16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon interval */ + u16 capabilities; /* Capabilities */ + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ + u16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ } __attribute__ ((packed)); + +/* Moustafa: Scan structure for Symbol cards */ +struct symbol_scan_apinfo { + u8 channel; /* Channel where the AP sits */ + u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ + u16 noise; /* Noise level */ + u16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon interval */ + u16 capabilities; /* Capabilities */ + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ + u16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ + u16 rates[5]; /* Bit rate supported */ + u16 basic_rates; /* Basic rates bitmask */ + u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ + u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ +} __attribute__ ((packed)); + +union hermes_scan_info { + struct agere_scan_apinfo a; + struct prism2_scan_apinfo p; + struct symbol_scan_apinfo s; +}; + #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) @@ -262,6 +315,20 @@ struct hermes_linkstatus { u16 linkstatus; /* Link status */ } __attribute__ ((packed)); +struct hermes_response { + u16 status, resp0, resp1, resp2; +}; + +/* "ID" structure - used for ESSID and station nickname */ +struct hermes_idstring { + u16 len; + u16 val[16]; +} __attribute__ ((packed)); + +struct hermes_multicast { + u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)); + // #define HERMES_DEBUG_BUFFER 1 #define HERMES_DEBUG_BUFSIZE 4096 struct hermes_debug_entry { @@ -294,10 +361,6 @@ typedef struct hermes { #endif } hermes_t; -typedef struct hermes_response { - u16 status, resp0, resp1, resp2; -} hermes_response_t; - /* Register access convenience macros */ #define hermes_read_reg(hw, off) ((hw)->io_space ? \ inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \ @@ -312,9 +375,11 @@ typedef struct hermes_response { #define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) /* Function prototypes */ -void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing); +void hermes_struct_init(hermes_t *hw, ulong address, int io_space, + int reg_spacing); int hermes_init(hermes_t *hw); -int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp); +int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, + struct hermes_response *resp); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h index 761c5422e..4f46b4809 100644 --- a/drivers/net/wireless/hermes_rid.h +++ b/drivers/net/wireless/hermes_rid.h @@ -4,21 +4,21 @@ /* * Configuration RIDs */ -#define HERMES_RID_CNFPORTTYPE 0xFC00 /* used */ -#define HERMES_RID_CNFOWNMACADDR 0xFC01 /* used */ -#define HERMES_RID_CNFDESIREDSSID 0xFC02 /* used */ -#define HERMES_RID_CNFOWNCHANNEL 0xFC03 /* used */ -#define HERMES_RID_CNFOWNSSID 0xFC04 /* used */ +#define HERMES_RID_CNFPORTTYPE 0xFC00 +#define HERMES_RID_CNFOWNMACADDR 0xFC01 +#define HERMES_RID_CNFDESIREDSSID 0xFC02 +#define HERMES_RID_CNFOWNCHANNEL 0xFC03 +#define HERMES_RID_CNFOWNSSID 0xFC04 #define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 -#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 /* used */ +#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 #define HERMES_RID_CNFMAXDATALEN 0xFC07 #define HERMES_RID_CNFWDSADDRESS 0xFC08 -#define HERMES_RID_CNFPMENABLED 0xFC09 /* used */ +#define HERMES_RID_CNFPMENABLED 0xFC09 #define HERMES_RID_CNFPMEPS 0xFC0A -#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B /* used */ -#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C /* used */ -#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D /* used */ -#define HERMES_RID_CNFOWNNAME 0xFC0E /* used */ +#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B +#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C +#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D +#define HERMES_RID_CNFOWNNAME 0xFC0E #define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 #define HERMES_RID_CNFWDSADDRESS1 0xFC11 #define HERMES_RID_CNFWDSADDRESS2 0xFC12 @@ -27,17 +27,18 @@ #define HERMES_RID_CNFWDSADDRESS5 0xFC15 #define HERMES_RID_CNFWDSADDRESS6 0xFC16 #define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 -#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 /* used */ +#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 +#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 -#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 /* used */ -#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 /* used */ -#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 /* used */ -#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 /* used */ -#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 /* used */ -#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 /* used */ -#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 /* used */ +#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 +#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 +#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 +#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 +#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 +#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 +#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 #define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HERMES_RID_CNFAUTHENTICATION 0xFC2A /* used */ +#define HERMES_RID_CNFAUTHENTICATION 0xFC2A #define HERMES_RID_CNFMAXASSOCSTA 0xFC2B #define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B #define HERMES_RID_CNFTXCONTROL 0xFC2C @@ -53,14 +54,14 @@ #define HERMES_RID_CNFTIMCTRL 0xFC40 #define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 #define HERMES_RID_CNFENHSECURITY 0xFC43 -#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 /* used */ -#define HERMES_RID_CNFCREATEIBSS 0xFC81 /* used */ -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 /* used */ -#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 /* used */ -#define HERMES_RID_CNFTXRATECONTROL 0xFC84 /* used */ -#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 /* used */ +#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 +#define HERMES_RID_CNFCREATEIBSS 0xFC81 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 +#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 +#define HERMES_RID_CNFTXRATECONTROL 0xFC84 +#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 #define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A -#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C /* used */ +#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 #define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 @@ -75,18 +76,21 @@ #define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B #define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C #define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D +#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB #define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 /* used */ +#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 #define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 /* used */ +#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 #define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 +#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 #define HERMES_RID_CNFBASICRATES 0xFCB3 #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HERMES_RID_CNFTICKTIME 0xFCE0 /* used */ +#define HERMES_RID_CNFTICKTIME 0xFCE0 #define HERMES_RID_CNFSCANREQUEST 0xFCE1 #define HERMES_RID_CNFJOINREQUEST 0xFCE2 #define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 #define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 +#define HERMES_RID_CNFHOSTSCAN 0xFCE5 /* * Information RIDs @@ -100,30 +104,31 @@ #define HERMES_RID_NICID 0xFD0B #define HERMES_RID_MFISUPRANGE 0xFD0C #define HERMES_RID_CFISUPRANGE 0xFD0D -#define HERMES_RID_CHANNELLIST 0xFD10 /* used */ +#define HERMES_RID_CHANNELLIST 0xFD10 #define HERMES_RID_REGULATORYDOMAINS 0xFD11 #define HERMES_RID_TEMPTYPE 0xFD12 #define HERMES_RID_CIS 0xFD13 -#define HERMES_RID_STAID 0xFD20 /* used */ +#define HERMES_RID_STAID 0xFD20 #define HERMES_RID_STASUPRANGE 0xFD21 #define HERMES_RID_MFIACTRANGES 0xFD22 #define HERMES_RID_CFIACTRANGES2 0xFD23 -#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 /* used */ +#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 #define HERMES_RID_PORTSTATUS 0xFD40 -#define HERMES_RID_CURRENTSSID 0xFD41 /* used */ -#define HERMES_RID_CURRENTBSSID 0xFD42 /* used */ -#define HERMES_RID_COMMSQUALITY 0xFD43 /* used */ -#define HERMES_RID_CURRENTTXRATE 0xFD44 /* used */ +#define HERMES_RID_CURRENTSSID 0xFD41 +#define HERMES_RID_CURRENTBSSID 0xFD42 +#define HERMES_RID_COMMSQUALITY 0xFD43 +#define HERMES_RID_CURRENTTXRATE 0xFD44 #define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 #define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 #define HERMES_RID_PROTOCOLRSPTIME 0xFD47 -#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 /* used */ -#define HERMES_RID_LONGRETRYLIMIT 0xFD49 /* used */ -#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A /* used */ +#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 +#define HERMES_RID_LONGRETRYLIMIT 0xFD49 +#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A #define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B #define HERMES_RID_CFPOLLABLE 0xFD4C #define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D #define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F +#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 #define HERMES_RID_CURRENTTXRATE1 0xFD80 #define HERMES_RID_CURRENTTXRATE2 0xFD81 #define HERMES_RID_CURRENTTXRATE3 0xFD82 @@ -133,21 +138,11 @@ #define HERMES_RID_OWNMACADDR 0xFD86 #define HERMES_RID_SCANRESULTSTABLE 0xFD88 #define HERMES_RID_PHYTYPE 0xFDC0 -#define HERMES_RID_CURRENTCHANNEL 0xFDC1 /* used */ +#define HERMES_RID_CURRENTCHANNEL 0xFDC1 #define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 #define HERMES_RID_CCAMODE 0xFDC3 -#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 /* used */ +#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 #define HERMES_RID_BUILDSEQ 0xFFFE #define HERMES_RID_FWID 0xFFFF -/* "ID" structure - used for ESSID and station nickname */ -struct hermes_idstring { - u16 len; - u16 val[16]; -} __attribute__ ((packed)); - -typedef struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)) hermes_multicast_t; - #endif diff --git a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h index 07d626ea1..53dd5248f 100644 --- a/drivers/net/wireless/ieee802_11.h +++ b/drivers/net/wireless/ieee802_11.h @@ -76,4 +76,3 @@ struct ieee802_11_hdr { #define IEEE802_11_SCTL_SEQ 0xFFF0 #endif /* _IEEE802_11_H */ - diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 8161a1c00..284aabeff 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1,17 +1,23 @@ -/* orinoco.c 0.13e - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for Hermes or Prism 2 chipset based PCMCIA wireless * adaptors, with Lucent/Agere, Intersil or Symbol firmware. * - * Copyright (C) 2000 David Gibson, Linuxcare Australia + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson + * + * (C) Copyright David Gibson, IBM Corporation 2001-2003. + * Copyright (C) 2000 David Gibson, Linuxcare Australia. * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * Copyright (C) 2001 Benjamin Herrenschmidt + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * Copyright (C) 2001 Benjamin Herrenschmidt * * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.stud.fh-dortmund.de/~andy/wvlan/ * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -24,7 +30,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David + * . Portions created by David * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights * Reserved. * @@ -58,7 +64,7 @@ * o Add PM timeout (holdover duration) * o Enable "iwconfig eth0 key off" and friends (toggle flags) * o Enable "iwconfig eth0 power unicast/all" (toggle flags) - * o Try with an intel card. It report firmware 1.01, behave like + * o Try with an Intel card. It report firmware 1.01, behave like * an antiquated firmware, however on windows it says 2.00. Yuck ! * o Workaround firmware bug in allocate buffer (Intel 1.01) * o Finish external renaming to orinoco... @@ -68,8 +74,8 @@ * o Update to Wireless 11 -> add retry limit/lifetime support * o Tested with a D-Link DWL 650 card, fill in firmware support * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) - * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( - * It work on D-Link *only* after a tcpdump. Weird... + * o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-( + * It works on D-Link *only* after a tcpdump. Weird... * And still doesn't work on Intel card. Grrrr... * o Update the mode after a setport3 * o Add preamble setting for Symbol cards (not yet enabled) @@ -82,7 +88,7 @@ * o Clean up RID definitions in hermes.h, other cleanups * * v0.04b -> v0.04c - 24/4/2001 - Jean II - * o Tim Hurley reported a D-Link card + * o Tim Hurley reported a D-Link card * with vendor 02 and firmware 0.08. Added in the capabilities... * o Tested Lucent firmware 7.28, everything works... * @@ -105,15 +111,15 @@ * o Remove deferred power enabling code * * v0.05c -> v0.05d - 5/5/2001 - Jean II - * o Workaround to SNAP decapsulate frame from LinkSys AP - * original patch from : Dong Liu + * o Workaround to SNAP decapsulate frame from Linksys AP + * original patch from : Dong Liu * (note : the memcmp bug was mine - fixed) * o Remove set_retry stuff, no firmware support it (bloat--). * * v0.05d -> v0.06 - 25/5/2001 - Jean II - * Original patch from "Hong Lin" , - * "Ian Kinner" - * and "David Smith" + * Original patch from "Hong Lin" , + * "Ian Kinner" + * and "David Smith" * o Init of priv->tx_rate_ctrl in firmware specific section. * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh ! * o Spectrum card always need cor_reset (for every reset) @@ -134,15 +140,15 @@ * * v0.06c -> v0.06d - 6/7/2001 - David Gibson * o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus' - * wishes to reduce the number of unecessary messages. + * wishes to reduce the number of unnecessary messages. * o Removed bogus message on CRC error. - * o Merged fixeds for v0.08 Prism 2 firmware from William Waghorn - * + * o Merged fixes for v0.08 Prism 2 firmware from William Waghorn + * * o Slight cleanup/re-arrangement of firmware detection code. * * v0.06d -> v0.06e - 1/8/2001 - David Gibson * o Removed some redundant global initializers (orinoco_cs.c). - * o Added some module metadataa + * o Added some module metadata * * v0.06e -> v0.06f - 14/8/2001 - David Gibson * o Wording fix to license @@ -159,7 +165,7 @@ * v0.07 -> v0.07a - 1/10/3001 - Jean II * o Add code to read Symbol firmware revision, inspired by latest code * in Spectrum24 by Lee John Keyser-Allen - Thanks Lee ! - * o Thanks to Jared Valentine for "providing" me + * o Thanks to Jared Valentine for "providing" me * a 3Com card with a recent firmware, fill out Symbol firmware * capabilities of latest rev (2.20), as well as older Symbol cards. * o Disable Power Management in newer Symbol firmware, the API @@ -172,7 +178,7 @@ * o Turned has_big_wep on for Intersil cards. That's not true for all of * them but we should at least let the capable ones try. * o Wait for BUSY to clear at the beginning of hermes_bap_seek(). I - * realised that my assumption that the driver's serialization + * realized that my assumption that the driver's serialization * would prevent the BAP being busy on entry was possibly false, because * things other than seeks may make the BAP busy. * o Use "alternate" (oui 00:00:00) encapsulation by default. @@ -181,12 +187,12 @@ * o Don't try to make __initdata const (the version string). This can't * work because of the way the __initdata sectioning works. * o Added MODULE_LICENSE tags. - * o Support for PLX (transparent PCMCIA->PCI brdge) cards. - * o Changed to using the new type-facist min/max. + * o Support for PLX (transparent PCMCIA->PCI bridge) cards. + * o Changed to using the new type-fascist min/max. * * v0.08 -> v0.08a - 9/10/2001 - David Gibson * o Inserted some missing acknowledgements/info into the Changelog. - * o Fixed some bugs in the normalisation of signel level reporting. + * o Fixed some bugs in the normalization of signal level reporting. * o Fixed bad bug in WEP key handling on Intersil and Symbol firmware, * which led to an instant crash on big-endian machines. * @@ -342,7 +348,7 @@ * o Bugfix in orinoco_stop() - it used to fail if hw_unavailable * was set, which was usually true on PCMCIA hot removes. * o Track LINKSTATUS messages, silently drop Tx packets before - * we are connected (avoids cofusing the firmware), and only + * we are connected (avoids confusing the firmware), and only * give LINKSTATUS printk()s if the status has changed. * * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson @@ -397,7 +403,8 @@ * o Disconnect wireless extensions from fundamental configuration. * o (maybe) Software WEP support (patch from Stano Meduna). * o (maybe) Use multiple Tx buffers - driver handling queue - * rather than firmware. */ + * rather than firmware. + */ /* Locking and synchronization: * @@ -414,7 +421,10 @@ * flag after taking the lock, and if it is set, give up on whatever * they are doing and drop the lock again. The orinoco_lock() * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is non-zero). */ + * hw_unavailable is non-zero). + */ + +#define DRIVER_NAME "orinoco" #include @@ -444,11 +454,9 @@ /* Module information */ /********************************************************************/ -MODULE_AUTHOR("David Gibson "); +MODULE_AUTHOR("Pavel Roskin & David Gibson "); MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif /* Level of debugging. Used in the macros in orinoco.h */ #ifdef ORINOCO_DEBUG @@ -464,11 +472,6 @@ MODULE_PARM(suppress_linkstatus, "i"); /* Compile time configuration and compatibility stuff */ /********************************************************************/ -/* Wireless extensions backwards compatibility */ -#ifndef SIOCIWFIRSTPRIV -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ - /* We do this this way to avoid ifdefs in the actual code */ #ifdef WIRELESS_SPY #define SPY_NUMBER(priv) (priv->spy_number) @@ -497,25 +500,29 @@ MODULE_PARM(suppress_linkstatus, "i"); #define DUMMY_FID 0xFFFF -#define RUP_EVEN(a) (((a) + 1) & (~1)) - /*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ HERMES_MAX_MULTICAST : 0)*/ #define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) +#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ + | HERMES_EV_TX | HERMES_EV_TXEXC \ + | HERMES_EV_WTERR | HERMES_EV_INFO \ + | HERMES_EV_INFDROP ) + /********************************************************************/ /* Data tables */ /********************************************************************/ /* The frequency of each channel in MHz */ -const long channel_frequency[] = { +static const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; -#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) +#define NUM_CHANNELS ARRAY_SIZE(channel_frequency) -/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */ -struct { +/* This tables gives the actual meanings of the bitrate IDs returned + * by the firmware. */ +static struct { int bitrate; /* in 100s of kilobits */ int automatic; u16 agere_txratectrl; @@ -530,7 +537,7 @@ struct { {55, 1, 7, 7}, {110, 0, 5, 8}, }; -#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) +#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) /********************************************************************/ /* Data types */ @@ -555,133 +562,54 @@ u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) +struct hermes_rx_descriptor { + u16 status; + u32 time; + u8 silence; + u8 signal; + u8 rate; + u8 rxflow; + u32 reserved; +} __attribute__ ((packed)); + /********************************************************************/ /* Function prototypes */ /********************************************************************/ -static void orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc); - -static struct net_device_stats *orinoco_get_stats(struct net_device *dev); -static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev); - -/* Hardware control routines */ - +static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int __orinoco_program_rids(struct net_device *dev); - -static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); -static int __orinoco_hw_setup_wep(struct orinoco_private *priv); -static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]); -static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]); -static long orinoco_hw_get_freq(struct orinoco_private *priv); -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, - s32 *rates, int max); static void __orinoco_set_multicast_list(struct net_device *dev); - -/* Interrupt handling routines */ -static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw); -static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw); - -/* ioctl() routines */ static int orinoco_debug_dump_recs(struct net_device *dev); /********************************************************************/ -/* Function prototypes */ +/* Internal helper functions */ /********************************************************************/ -int __orinoco_up(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - err = __orinoco_program_rids(dev); - if (err) { - printk(KERN_ERR "%s: Error %d configuring card\n", - dev->name, err); - return err; - } - - /* Fire things up again */ - hermes_set_irqmask(hw, ORINOCO_INTEN); - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d enabling MAC port\n", - dev->name, err); - return err; - } - - netif_start_queue(dev); - - return 0; -} - -int __orinoco_down(struct net_device *dev) +static inline void set_port_type(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - netif_stop_queue(dev); - - if (! priv->hw_unavailable) { - if (! priv->broken_disableport) { - err = hermes_disable_port(hw, 0); - if (err) { - /* Some firmwares (e.g. Intersil 1.3.x) seem - * to have problems disabling the port, oh - * well, too bad. */ - printk(KERN_WARNING "%s: Error %d disabling MAC port\n", - dev->name, err); - priv->broken_disableport = 1; - } + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->createibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->createibss = 0; + } else { + priv->port_type = priv->ibss_port; + priv->createibss = 1; } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev->name); } - - /* firmware will have to reassociate */ - priv->last_linkstatus = 0xffff; - priv->connected = 0; - - return 0; } -int orinoco_reinit_firmware(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - err = hermes_init(hw); - if (err) - return err; - - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO) { - /* Try workaround for old Symbol firmware bug */ - printk(KERN_WARNING "%s: firmware ALLOC bug detected " - "(old Symbol firmware?). Trying to work around... ", - dev->name); - - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err) - printk("failed!\n"); - else - printk("ok.\n"); - } - - return err; -} +/********************************************************************/ +/* Device methods */ +/********************************************************************/ static int orinoco_open(struct net_device *dev) { @@ -722,843 +650,562 @@ int orinoco_stop(struct net_device *dev) return err; } -static int __orinoco_program_rids(struct net_device *dev) +static struct net_device_stats *orinoco_get_stats(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + + return &priv->stats; +} + +static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + unsigned long flags; - /* Set the MAC address */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", dev->name, err); - return err; + if (! netif_device_present(dev)) { + printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", + dev->name); + return NULL; /* FIXME: Can we do better than this? */ } - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel == 0) { - printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name); - if (priv->createibss) - priv->channel = 10; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel\n", dev->name, err); - return err; - } + err = orinoco_lock(priv, &flags); + if (err) + return NULL; /* FIXME: Erg, we've been signalled, how + * do we propagate this back up? */ - if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, - priv->createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err); - return err; + if (priv->iw_mode == IW_MODE_ADHOC) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (SPY_NUMBER(priv)) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; } + } else { + struct { + u16 qual, signal, noise; + } __attribute__ ((packed)) cq; - if ((strlen(priv->desired_essid) == 0) && (priv->createibss) - && (!priv->has_ibss_any)) { - printk(KERN_WARNING "%s: This firmware requires an \ -ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - } + err = HERMES_READ_RECORD(hw, USER_BAP, + HERMES_RID_COMMSQUALITY, &cq); + + wstats->qual.qual = (int)le16_to_cpu(cq.qual); + wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; + wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; + wstats->qual.updated = 7; } - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", dev->name, err); - return err; - } - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", dev->name, err); - return err; - } + /* We can't really wait for the tallies inquiry command to + * complete, so we just use the previous results and trigger + * a new tallies inquiry command for next time - Jean II */ + /* FIXME: We're in user context (I think?), so we should just + wait for the tallies to come through */ + err = hermes_inquire(hw, HERMES_INQ_TALLIES); + + orinoco_unlock(priv, &flags); - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err); - return err; - } + if (err) + return NULL; + + return wstats; +} - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", dev->name, err); +static void orinoco_set_multicast_list(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; - priv->has_sensitivity = 0; - } + if (orinoco_lock(priv, &flags) != 0) { + printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " + "called when hw_unavailable\n", dev->name); + return; } - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err); - return err; - } + __orinoco_set_multicast_list(dev); + orinoco_unlock(priv, &flags); +} - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting framentation\n", dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } +static int orinoco_change_mtu(struct net_device *dev, int new_mtu) +{ + struct orinoco_private *priv = netdev_priv(dev); - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } + if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) + return -EINVAL; - /* Set up encryption */ - if (priv->has_wep) { - err = __orinoco_hw_setup_wep(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating WEP\n", - dev->name, err); - return err; - } - } + if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > + (priv->nicbuf_size - ETH_HLEN) ) + return -EINVAL; - /* Set promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */ + dev->mtu = new_mtu; return 0; } -/* xyzzy */ -static int orinoco_reconfigure(struct net_device *dev) +/********************************************************************/ +/* Tx path */ +/********************************************************************/ + +static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - unsigned long flags; + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; int err = 0; + u16 txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct hermes_tx_descriptor desc; + unsigned long flags; - if (priv->broken_disableport) { - schedule_work(&priv->reset_work); - return 0; - } - - err = orinoco_lock(priv, &flags); - if (err) - return err; + TRACE_ENTER(dev->name); - - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", dev->name); - priv->broken_disableport = 1; - goto out; + TRACE_EXIT(dev->name); + return 1; } - - err = __orinoco_program_rids(dev); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", + + if (netif_queue_stopped(dev)) { + printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", dev->name); - goto out; + TRACE_EXIT(dev->name); + return 1; } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + + if (orinoco_lock(priv, &flags) != 0) { + printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", dev->name); - goto out; + TRACE_EXIT(dev->name); + return 1; } - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; + if (! priv->connected) { + /* Oops, the firmware hasn't established a connection, + silently drop the packet (this seems to be the + safest approach). */ + stats->tx_errors++; + orinoco_unlock(priv, &flags); + dev_kfree_skb(skb); + TRACE_EXIT(dev->name); + return 0; } - orinoco_unlock(priv, &flags); - return err; - -} - -/* This must be called from user context, without locks held - use - * schedule_work() */ -static void orinoco_reset(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; + /* Length of the packet body */ + /* FIXME: what if the skb is smaller than this? */ + len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); - err = orinoco_lock(priv, &flags); - if (err) - /* When the hardware becomes available again, whatever - * detects that is responsible for re-initializing - * it. So no need for anything further*/ - return; + eh = (struct ethhdr *)skb->data; - netif_stop_queue(dev); + memset(&desc, 0, sizeof(desc)); + desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); + if (err) { + printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } - /* Shut off interrupts. Depending on what state the hardware - * is in, this might not work, but we'll try anyway */ - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); - priv->hw_unavailable++; - priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ - priv->connected = 0; + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ + struct header_struct hdr; + data_len = len; + data_off = HERMES_802_3_OFFSET + sizeof(hdr); + p = skb->data + ETH_HLEN; - orinoco_unlock(priv, &flags); + /* 802.3 header */ + memcpy(hdr.dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.src, eh->h_source, ETH_ALEN); + hdr.len = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); + + hdr.ethertype = eh->h_proto; + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), + txfid, HERMES_802_3_OFFSET); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = HERMES_802_3_OFFSET; + p = skb->data; + } - if (priv->hard_reset) - err = (*priv->hard_reset)(priv); + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), + txfid, data_off); if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d performing hard reset\n", + printk(KERN_ERR "%s: Error %d writing packet to BAP\n", dev->name, err); - /* FIXME: shutdown of some sort */ - return; + stats->tx_errors++; + goto fail; } - err = orinoco_reinit_firmware(dev); + /* Finally, we actually initiate the send */ + netif_stop_queue(dev); + + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, + txfid, NULL); if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", + netif_start_queue(dev); + printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); - return; + stats->tx_errors++; + goto fail; } - spin_lock_irq(&priv->lock); /* This has to be called from user context */ + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; - priv->hw_unavailable--; + orinoco_unlock(priv, &flags); - /* priv->open or priv->hw_unavailable might have changed while - * we dropped the lock */ - if (priv->open && (! priv->hw_unavailable)) { - err = __orinoco_up(dev); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - dev->trans_start = jiffies; - } + dev_kfree_skb(skb); - spin_unlock_irq(&priv->lock); + TRACE_EXIT(dev->name); - return; -} + return 0; + fail: + TRACE_EXIT(dev->name); -/********************************************************************/ -/* Internal helper functions */ -/********************************************************************/ - -static inline void -set_port_type(struct orinoco_private *priv) -{ - switch (priv->iw_mode) { - case IW_MODE_INFRA: - priv->port_type = 1; - priv->createibss = 0; - break; - case IW_MODE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->createibss = 0; - } else { - priv->port_type = priv->ibss_port; - priv->createibss = 1; - } - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev->name); - } -} - -/* Does the frame have a SNAP header indicating it should be - * de-encapsulated to Ethernet-II? */ -static inline int -is_ethersnap(struct header_struct *hdr) -{ - /* We de-encapsulate all packets which, a) have SNAP headers - * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header - * and where b) the OUI of the SNAP header is 00:00:00 or - * 00:00:f8 - we need both because different APs appear to use - * different OUIs for some reason */ - return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) - && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); + orinoco_unlock(priv, &flags); + return err; } -static void -orinoco_set_multicast_list(struct net_device *dev) +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; + u16 fid = hermes_read_regn(hw, ALLOCFID); - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " - "called when hw_unavailable\n", dev->name); + if (fid != priv->txfid) { + if (fid != DUMMY_FID) + printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", + dev->name, fid); return; + } else { + netif_wake_queue(dev); } - __orinoco_set_multicast_list(dev); - orinoco_unlock(priv, &flags); + hermes_write_regn(hw, ALLOCFID, DUMMY_FID); } -/********************************************************************/ -/* Hardware control functions */ -/********************************************************************/ +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + stats->tx_packets++; -static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); +} + +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - hermes_t *hw = &priv->hw; + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + u16 fid = hermes_read_regn(hw, TXCOMPLFID); + struct hermes_tx_descriptor desc; int err = 0; - if (priv->bitratemode >= BITRATE_TABLE_SIZE) { - printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", - priv->ndev->name, priv->bitratemode); - return -EINVAL; - } + if (fid == DUMMY_FID) + return; /* Nothing's really happened */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[priv->bitratemode].agere_txratectrl); - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[priv->bitratemode].intersil_txratectrl); - break; - default: - BUG(); + err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " + "(FID=%04X error %d)\n", + dev->name, fid, err); + } else { + DEBUG(1, "%s: Tx error, status %d\n", + dev->name, le16_to_cpu(desc.status)); } + + stats->tx_errors++; - return err; + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } - -static int __orinoco_hw_setup_wep(struct orinoco_private *priv) +static void orinoco_tx_timeout(struct net_device *dev) { - hermes_t *hw = &priv->hw; - int err = 0; - int master_wep_flag; - int auth_flag; + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + struct hermes *hw = &priv->hw; - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &priv->keys); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - priv->wep_on); - if (err) - return err; - break; + printk(KERN_WARNING "%s: Tx timeout! " + "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", + dev->name, hermes_read_regn(hw, ALLOCFID), + hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - master_wep_flag = 0; /* Off */ - if (priv->wep_on) { - int keylen; - int i; + stats->tx_errors++; - /* Fudge around firmware weirdness */ - keylen = le16_to_cpu(priv->keys[priv->tx_key].len); - - /* Write all 4 keys */ - for(i = 0; i < ORINOCO_MAX_KEYS; i++) { -/* int keylen = le16_to_cpu(priv->keys[i].len); */ - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, i, keylen); - return -E2BIG; - } + schedule_work(&priv->reset_work); +} - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFDEFAULTKEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen), - priv->keys[i].data); - if (err) - return err; - } +/********************************************************************/ +/* Rx path (data frames) */ +/********************************************************************/ - /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, - priv->tx_key); - if (err) - return err; - - if (priv->wep_restrict) { - auth_flag = 2; - master_wep_flag = 3; - } else { - /* Authentication is where Intersil and Symbol - * firmware differ... */ - auth_flag = 1; - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - master_wep_flag = 3; /* Symbol */ - else - master_wep_flag = 1; /* Intersil */ - } +/* Does the frame have a SNAP header indicating it should be + * de-encapsulated to Ethernet-II? */ +static inline int is_ethersnap(struct header_struct *hdr) +{ + /* We de-encapsulate all packets which, a) have SNAP headers + * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header + * and where b) the OUI of the SNAP header is 00:00:00 or + * 00:00:f8 - we need both because different APs appear to use + * different OUIs for some reason */ + return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) + && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); +} +static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, + int level, int noise) +{ + struct orinoco_private *priv = netdev_priv(dev); + int i; - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION, auth_flag); - if (err) - return err; + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].level = level - 0x95; + priv->spy_stat[i].noise = noise - 0x95; + priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; + priv->spy_stat[i].updated = 7; } - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPFLAGS_INTERSIL, - master_wep_flag); - if (err) - return err; +} - break; +static void orinoco_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct hermes_rx_descriptor *desc) +{ + struct orinoco_private *priv = netdev_priv(dev); - default: - if (priv->wep_on) { - printk(KERN_ERR "%s: WEP enabled, although not supported!\n", - priv->ndev->name); - return -EINVAL; - } + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if (SPY_NUMBER(priv)) { + orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, + desc->signal, desc->silence); } - - return 0; } -static int orinoco_hw_get_bssid(struct orinoco_private *priv, - char buf[ETH_ALEN]) +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - hermes_t *hw = &priv->hw; - int err = 0; - unsigned long flags; - - err = orinoco_lock(priv, &flags); - if (err) - return err; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, buf); + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + u16 rxfid, status; + int length, data_len, data_off; + char *p; + struct hermes_rx_descriptor desc; + struct header_struct hdr; + struct ethhdr *eh; + int err; - orinoco_unlock(priv, &flags); + rxfid = hermes_read_regn(hw, RXFID); - return err; -} + err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), + rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading Rx descriptor. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } -static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - struct hermes_idstring essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - unsigned long flags; + status = le16_to_cpu(desc.status); - err = orinoco_lock(priv, &flags); - if (err) - return err; + if (status & HERMES_RXSTAT_ERR) { + if (status & HERMES_RXSTAT_UNDECRYPTABLE) { + wstats->discard.code++; + DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + stats->rx_crc_errors++; + DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); + } + stats->rx_errors++; + goto drop; + } - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWNSSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - u16 rid; + /* For now we ignore the 802.11 header completely, assuming + that the card's firmware has handled anything vital */ - *active = 1; + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), + rxfid, HERMES_802_3_OFFSET); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } - rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : - HERMES_RID_CNFDESIREDSSID; - - err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; + length = ntohs(hdr.len); + + /* Sanity checks */ + if (length < 3) { /* No for even an 802.2 LLC header */ + /* At least on Symbol firmware with PCF we get quite a + lot of these legitimately - Poll frames with no + data. */ + stats->rx_dropped++; + goto drop; + } + if (length > IEEE802_11_DATA_LEN) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + goto drop; } - len = le16_to_cpu(essidbuf.len); + skb_reserve(skb, 2); /* This way the IP header is aligned */ - memset(buf, 0, IW_ESSID_MAX_SIZE+1); - memcpy(buf, p, len); - buf[len] = '\0'; + /* Handle decapsulation + * In most cases, the firmware tell us about SNAP frames. + * For some reason, the SNAP frames sent by LinkSys APs + * are not properly recognised by most firmwares. + * So, check ourselves */ + if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || + is_ethersnap(&hdr)) { + /* These indicate a SNAP within 802.2 LLC within + 802.11 frame which we'll need to de-encapsulate to + the original EthernetII frame. */ - fail_unlock: - orinoco_unlock(priv, &flags); + if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ + stats->rx_length_errors++; + goto drop; + } - return err; -} + /* Remove SNAP header, reconstruct EthernetII frame */ + data_len = length - ENCAPS_OVERHEAD; + data_off = HERMES_802_3_OFFSET + sizeof(hdr); -static long orinoco_hw_get_freq(struct orinoco_private *priv) -{ - - hermes_t *hw = &priv->hw; - int err = 0; - u16 channel; - long freq = 0; - unsigned long flags; + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); - err = orinoco_lock(priv, &flags); - if (err) - return err; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); - if (err) - goto out; + memcpy(eh, &hdr, 2 * ETH_ALEN); + eh->h_proto = hdr.ethertype; + } else { + /* All other cases indicate a genuine 802.3 frame. No + decapsulation needed. We just throw the whole + thing in, and hope the protocol layer can deal with + it as 802.3 */ + data_len = length; + data_off = HERMES_802_3_OFFSET; + /* FIXME: we re-read from the card data we already read here */ + } - /* Intersil firmware 1.3.5 returns 0 when the interface is down */ - if (channel == 0) { - err = -EBUSY; - goto out; + p = skb_put(skb, data_len); + err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2), + rxfid, data_off); + if (err) { + printk(KERN_ERR "%s: error %d reading frame. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; } - if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", - priv->ndev->name, channel); - err = -EBUSY; - goto out; + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + orinoco_stat_gather(dev, skb, &desc); - } - freq = channel_frequency[channel-1] * 100000; + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; - out: - orinoco_unlock(priv, &flags); + return; - if (err > 0) - err = -EBUSY; - return err ? err : freq; + drop: + stats->rx_dropped++; + + if (skb) + dev_kfree_skb_irq(skb); + return; } -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max) -{ - hermes_t *hw = &priv->hw; - struct hermes_idstring list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - unsigned long flags; +/********************************************************************/ +/* Rx path (info frames) */ +/********************************************************************/ - err = orinoco_lock(priv, &flags); - if (err) - return err; +static void print_linkstatus(struct net_device *dev, u16 status) +{ + char * s; - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, - sizeof(list), NULL, &list); - orinoco_unlock(priv, &flags); + if (suppress_linkstatus) + return; - if (err) - return err; + switch (status) { + case HERMES_LINKSTATUS_NOT_CONNECTED: + s = "Not Connected"; + break; + case HERMES_LINKSTATUS_CONNECTED: + s = "Connected"; + break; + case HERMES_LINKSTATUS_DISCONNECTED: + s = "Disconnected"; + break; + case HERMES_LINKSTATUS_AP_CHANGE: + s = "AP Changed"; + break; + case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: + s = "AP Out of Range"; + break; + case HERMES_LINKSTATUS_AP_IN_RANGE: + s = "AP In Range"; + break; + case HERMES_LINKSTATUS_ASSOC_FAILED: + s = "Association Failed"; + break; + default: + s = "UNKNOWN"; + } - num = le16_to_cpu(list.len); - *numrates = num; - num = min(num, max); - - for (i = 0; i < num; i++) { - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - } - - return 0; -} - -#if 0 -static void show_rx_frame(struct orinoco_rxframe_hdr *frame) -{ - printk(KERN_DEBUG "RX descriptor:\n"); - printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); - printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); - printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); - printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); - printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); - printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); - printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); - - printk(KERN_DEBUG "IEEE 802.11 header:\n"); - printk(KERN_DEBUG " frame_ctl = 0x%04x\n", - frame->p80211.frame_ctl); - printk(KERN_DEBUG " duration_id = 0x%04x\n", - frame->p80211.duration_id); - printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr1[0], frame->p80211.addr1[1], - frame->p80211.addr1[2], frame->p80211.addr1[3], - frame->p80211.addr1[4], frame->p80211.addr1[5]); - printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr2[0], frame->p80211.addr2[1], - frame->p80211.addr2[2], frame->p80211.addr2[3], - frame->p80211.addr2[4], frame->p80211.addr2[5]); - printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr3[0], frame->p80211.addr3[1], - frame->p80211.addr3[2], frame->p80211.addr3[3], - frame->p80211.addr3[4], frame->p80211.addr3[5]); - printk(KERN_DEBUG " seq_ctl = 0x%04x\n", - frame->p80211.seq_ctl); - printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr4[0], frame->p80211.addr4[1], - frame->p80211.addr4[2], frame->p80211.addr4[3], - frame->p80211.addr4[4], frame->p80211.addr4[5]); - printk(KERN_DEBUG " data_len = 0x%04x\n", - frame->p80211.data_len); - - printk(KERN_DEBUG "IEEE 802.3 header:\n"); - printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_dest[0], frame->p8023.h_dest[1], - frame->p8023.h_dest[2], frame->p8023.h_dest[3], - frame->p8023.h_dest[4], frame->p8023.h_dest[5]); - printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_source[0], frame->p8023.h_source[1], - frame->p8023.h_source[2], frame->p8023.h_source[3], - frame->p8023.h_source[4], frame->p8023.h_source[5]); - printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); - - printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); - printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); - printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); - printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); - printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", - frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); - printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); -} -#endif /* 0 */ - -/* - * Interrupt handler - */ -irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int count = MAX_IRQLOOPS_PER_IRQ; - u16 evstat, events; - /* These are used to detect a runaway interrupt situation */ - /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, - * we panic and shut down the hardware */ - static int last_irq_jiffy = 0; /* jiffies value the last time we were called */ - static int loops_this_jiffy = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable - we don't know if the irq was - * for us or not */ - return IRQ_HANDLED; - } - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - if (! events) { - orinoco_unlock(priv, &flags); - return IRQ_NONE; - } - - if (jiffies != last_irq_jiffy) - loops_this_jiffy = 0; - last_irq_jiffy = jiffies; - - while (events && count--) { - if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_WARNING "%s: IRQ handler is looping too " - "much! Resetting.\n", dev->name); - /* Disable interrupts for now */ - hermes_set_irqmask(hw, 0); - schedule_work(&priv->reset_work); - break; - } - - /* Check the card hasn't been removed */ - if (! hermes_present(hw)) { - DEBUG(0, "orinoco_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __orinoco_ev_tick(dev, hw); - if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(dev, hw); - if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(dev, hw); - if (events & HERMES_EV_INFO) - __orinoco_ev_info(dev, hw); - if (events & HERMES_EV_RX) - __orinoco_ev_rx(dev, hw); - if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(dev, hw); - if (events & HERMES_EV_TX) - __orinoco_ev_tx(dev, hw); - if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(dev, hw); - - hermes_write_regn(hw, EVACK, events); - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - }; - - orinoco_unlock(priv, &flags); - return IRQ_HANDLED; -} - -static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", dev->name); -} - -static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - dev->name); -} - -static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) -{ - if (net_ratelimit()) - printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); -} - -static void print_linkstatus(struct net_device *dev, u16 status) -{ - char * s; - - if (suppress_linkstatus) - return; - - switch (status) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } - - printk(KERN_INFO "%s: New link status: %s (%04x)\n", - dev->name, s, status); -} + printk(KERN_INFO "%s: New link status: %s (%04x)\n", + dev->name, s, status); +} static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { @@ -1614,19 +1261,17 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) le16_to_cpu(tallies.RxDiscards_WEPExcluded); wstats->discard.misc += le16_to_cpu(tallies.TxDiscardsWrongSA); -#if WIRELESS_EXT > 11 wstats->discard.fragment += le16_to_cpu(tallies.RxMsgInBadMsgFragments); wstats->discard.retries += le16_to_cpu(tallies.TxRetryLimitExceeded); /* wstats->miss.beacon - no match */ -#endif /* WIRELESS_EXT > 11 */ } break; case HERMES_INQ_LINKSTATUS: { struct hermes_linkstatus linkstatus; u16 newstatus; - + if (len != sizeof(linkstatus)) { printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", dev->name, len); @@ -1654,219 +1299,726 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) } break; default: - printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n", - dev->name, type); + printk(KERN_DEBUG "%s: Unknown information frame received " + "(type %04x).\n", dev->name, type); /* We don't actually do anything about it */ break; } } -static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) +{ + if (net_ratelimit()) + printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); +} + +/********************************************************************/ +/* Internal hardware control routines */ +/********************************************************************/ + +int __orinoco_up(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - u16 rxfid, status; - int length, data_len, data_off; - char *p; - struct hermes_rx_descriptor desc; - struct header_struct hdr; - struct ethhdr *eh; + struct hermes *hw = &priv->hw; int err; - rxfid = hermes_read_regn(hw, RXFID); - - err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), - rxfid, 0); + err = __orinoco_program_rids(dev); if (err) { - printk(KERN_ERR "%s: error %d reading Rx descriptor. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; + printk(KERN_ERR "%s: Error %d configuring card\n", + dev->name, err); + return err; } - status = le16_to_cpu(desc.status); - - if (status & HERMES_RXSTAT_ERR) { - if (status & HERMES_RXSTAT_UNDECRYPTABLE) { - wstats->discard.code++; - DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - } else { - stats->rx_crc_errors++; - DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); - } - stats->rx_errors++; - goto drop; + /* Fire things up again */ + hermes_set_irqmask(hw, ORINOCO_INTEN); + err = hermes_enable_port(hw, 0); + if (err) { + printk(KERN_ERR "%s: Error %d enabling MAC port\n", + dev->name, err); + return err; } - /* For now we ignore the 802.11 header completely, assuming - that the card's firmware has handled anything vital */ + netif_start_queue(dev); - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), - rxfid, HERMES_802_3_OFFSET); + return 0; +} + +int __orinoco_down(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + + netif_stop_queue(dev); + + if (! priv->hw_unavailable) { + if (! priv->broken_disableport) { + err = hermes_disable_port(hw, 0); + if (err) { + /* Some firmwares (e.g. Intersil 1.3.x) seem + * to have problems disabling the port, oh + * well, too bad. */ + printk(KERN_WARNING "%s: Error %d disabling MAC port\n", + dev->name, err); + priv->broken_disableport = 1; + } + } + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + } + + /* firmware will have to reassociate */ + priv->last_linkstatus = 0xffff; + priv->connected = 0; + + return 0; +} + +int orinoco_reinit_firmware(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + + err = hermes_init(hw); + if (err) + return err; + + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + if (err == -EIO) { + /* Try workaround for old Symbol firmware bug */ + printk(KERN_WARNING "%s: firmware ALLOC bug detected " + "(old Symbol firmware?). Trying to work around... ", + dev->name); + + priv->nicbuf_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + if (err) + printk("failed!\n"); + else + printk("ok.\n"); + } + + return err; +} + +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + if (priv->bitratemode >= BITRATE_TABLE_SIZE) { + printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", + priv->ndev->name, priv->bitratemode); + return -EINVAL; + } + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].agere_txratectrl); + break; + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].intersil_txratectrl); + break; + default: + BUG(); + } + + return err; +} + +static int __orinoco_hw_setup_wep(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + int master_wep_flag; + int auth_flag; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXKEY_AGERE, + priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFWEPKEYS_AGERE, + &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPENABLED_AGERE, + priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + master_wep_flag = 0; /* Off */ + if (priv->wep_on) { + int keylen; + int i; + + /* Fudge around firmware weirdness */ + keylen = le16_to_cpu(priv->keys[priv->tx_key].len); + + /* Write all 4 keys */ + for(i = 0; i < ORINOCO_MAX_KEYS; i++) { +/* int keylen = le16_to_cpu(priv->keys[i].len); */ + + if (keylen > LARGE_KEY_SIZE) { + printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", + priv->ndev->name, i, keylen); + return -E2BIG; + } + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFDEFAULTKEY0 + i, + HERMES_BYTES_TO_RECLEN(keylen), + priv->keys[i].data); + if (err) + return err; + } + + /* Write the index of the key used in transmission */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPDEFAULTKEYID, + priv->tx_key); + if (err) + return err; + + if (priv->wep_restrict) { + auth_flag = 2; + master_wep_flag = 3; + } else { + /* Authentication is where Intersil and Symbol + * firmware differ... */ + auth_flag = 1; + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) + master_wep_flag = 3; /* Symbol */ + else + master_wep_flag = 1; /* Intersil */ + } + + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION, + auth_flag); + if (err) + return err; + } + + /* Master WEP setting : on/off */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPFLAGS_INTERSIL, + master_wep_flag); + if (err) + return err; + + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev->name); + return -EINVAL; + } + } + + return 0; +} + +static int __orinoco_program_rids(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err; + struct hermes_idstring idbuf; + + /* Set the MAC address */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); if (err) { - printk(KERN_ERR "%s: error %d reading frame header. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; + printk(KERN_ERR "%s: Error %d setting MAC address\n", + dev->name, err); + return err; } - length = ntohs(hdr.len); - - /* Sanity checks */ - if (length < 3) { /* No for even an 802.2 LLC header */ - /* At least on Symbol firmware with PCF we get quite a - lot of these legitimately - Poll frames with no - data. */ - stats->rx_dropped++; - goto drop; + /* Set up the link mode */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, + priv->port_type); + if (err) { + printk(KERN_ERR "%s: Error %d setting port type\n", + dev->name, err); + return err; } - if (length > IEEE802_11_DATA_LEN) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - stats->rx_errors++; - goto drop; + /* Set the channel/frequency */ + if (priv->channel == 0) { + printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name); + if (priv->createibss) + priv->channel = 10; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, + priv->channel); + if (err) { + printk(KERN_ERR "%s: Error %d setting channel\n", + dev->name, err); + return err; + } + + if (priv->has_ibss) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFCREATEIBSS, + priv->createibss); + if (err) { + printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err); + return err; + } + + if ((strlen(priv->desired_essid) == 0) && (priv->createibss) + && (!priv->has_ibss_any)) { + printk(KERN_WARNING "%s: This firmware requires an " + "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + } + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting OWNSSID\n", + dev->name, err); + return err; + } + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", + dev->name, err); + return err; + } + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting nickname\n", + dev->name, err); + return err; + } + + /* Set AP density */ + if (priv->has_sensitivity) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, + priv->ap_density); + if (err) { + printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " + "Disabling sensitivity control\n", + dev->name, err); + + priv->has_sensitivity = 0; + } + } + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting RTS threshold\n", + dev->name, err); + return err; + } + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting fragmentation\n", + dev->name, err); + return err; + } + + /* Set bitrate */ + err = __orinoco_hw_set_bitrate(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting bitrate\n", + dev->name, err); + return err; + } + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMENABLED, + priv->pm_on); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMULTICASTRECEIVE, + priv->pm_mcast); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + priv->pm_period); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + priv->preamble); + if (err) { + printk(KERN_ERR "%s: Error %d setting preamble\n", + dev->name, err); + return err; + } + } + + /* Set up encryption */ + if (priv->has_wep) { + err = __orinoco_hw_setup_wep(priv); + if (err) { + printk(KERN_ERR "%s: Error %d activating WEP\n", + dev->name, err); + return err; + } + } + + /* Set promiscuity / multicast*/ + priv->promiscuous = 0; + priv->mc_count = 0; + __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */ + + return 0; +} + +/* FIXME: return int? */ +static void +__orinoco_set_multicast_list(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, mc_count; + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > MAX_MULTICAST(priv)) ) { + promisc = 1; + mc_count = 0; + } else { + promisc = 0; + mc_count = dev->mc_count; + } + + if (promisc != priv->promiscuous) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPROMISCUOUSMODE, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", + dev->name, err); + } else + priv->promiscuous = promisc; + } + + if (! promisc && (mc_count || priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + struct hermes_multicast mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* paranoia: is list shorter than mc_count? */ + BUG_ON(! p); + /* paranoia: bad address size in list? */ + BUG_ON(p->dmi_addrlen != ETH_ALEN); + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + if (p) + printk(KERN_WARNING "Multicast list is longer than mc_count\n"); + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, + HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->mc_count = mc_count; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; +} + +static int orinoco_reconfigure(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + unsigned long flags; + int err = 0; + + if (priv->broken_disableport) { + schedule_work(&priv->reset_work); + return 0; + } + + err = orinoco_lock(priv, &flags); + if (err) + return err; + + + err = hermes_disable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", + dev->name); + priv->broken_disableport = 1; + goto out; } - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length+ETH_HLEN+2+1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + err = __orinoco_program_rids(dev); + if (err) { + printk(KERN_WARNING "%s: Unable to reconfigure card\n", dev->name); - goto drop; + goto out; } - skb_reserve(skb, 2); /* This way the IP header is aligned */ + err = hermes_enable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + dev->name); + goto out; + } - /* Handle decapsulation - * In most cases, the firmware tell us about SNAP frames. - * For some reason, the SNAP frames sent by LinkSys APs - * are not properly recognised by most firmwares. - * So, check ourselves */ - if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || - ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_ethersnap(&hdr)) { - /* These indicate a SNAP within 802.2 LLC within - 802.11 frame which we'll need to de-encapsulate to - the original EthernetII frame. */ + out: + if (err) { + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); + schedule_work(&priv->reset_work); + err = 0; + } - if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ - stats->rx_length_errors++; - goto drop; - } + orinoco_unlock(priv, &flags); + return err; - /* Remove SNAP header, reconstruct EthernetII frame */ - data_len = length - ENCAPS_OVERHEAD; - data_off = HERMES_802_3_OFFSET + sizeof(hdr); +} - eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); +/* This must be called from user context, without locks held - use + * schedule_work() */ +static void orinoco_reset(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + unsigned long flags; - memcpy(eh, &hdr, 2 * ETH_ALEN); - eh->h_proto = hdr.ethertype; - } else { - /* All other cases indicate a genuine 802.3 frame. No - decapsulation needed. We just throw the whole - thing in, and hope the protocol layer can deal with - it as 802.3 */ - data_len = length; - data_off = HERMES_802_3_OFFSET; - /* FIXME: we re-read from the card data we already read here */ + err = orinoco_lock(priv, &flags); + if (err) + /* When the hardware becomes available again, whatever + * detects that is responsible for re-initializing + * it. So no need for anything further */ + return; + + netif_stop_queue(dev); + + /* Shut off interrupts. Depending on what state the hardware + * is in, this might not work, but we'll try anyway */ + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + priv->hw_unavailable++; + priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ + priv->connected = 0; + + orinoco_unlock(priv, &flags); + + if (priv->hard_reset) + err = (*priv->hard_reset)(priv); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d " + "performing hard reset\n", dev->name, err); + /* FIXME: shutdown of some sort */ + return; } - p = skb_put(skb, data_len); - err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), - rxfid, data_off); + err = orinoco_reinit_firmware(dev); if (err) { - printk(KERN_ERR "%s: error %d reading frame. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; + printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", + dev->name, err); + return; } - dev->last_rx = jiffies; - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - - /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, &desc); + spin_lock_irq(&priv->lock); /* This has to be called from user context */ - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; + priv->hw_unavailable--; - return; + /* priv->open or priv->hw_unavailable might have changed while + * we dropped the lock */ + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", + dev->name, err); + } else + dev->trans_start = jiffies; + } - drop: - stats->rx_dropped++; + spin_unlock_irq(&priv->lock); - if (skb) - dev_kfree_skb_irq(skb); return; } -static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - u16 fid = hermes_read_regn(hw, TXCOMPLFID); - struct hermes_tx_descriptor desc; - int err = 0; - - if (fid == DUMMY_FID) - return; /* Nothing's really happened */ - - err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " - "(FID=%04X error %d)\n", - dev->name, fid, err); - } else { - DEBUG(1, "%s: Tx error, status %d\n", - dev->name, le16_to_cpu(desc.status)); - } - - stats->tx_errors++; +/********************************************************************/ +/* Interrupt handler */ +/********************************************************************/ - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) +{ + printk(KERN_DEBUG "%s: TICK\n", dev->name); } -static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - - stats->tx_packets++; - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", + dev->name); } -static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) +irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + struct net_device *dev = (struct net_device *)dev_id; struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int count = MAX_IRQLOOPS_PER_IRQ; + u16 evstat, events; + /* These are used to detect a runaway interrupt situation */ + /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, + * we panic and shut down the hardware */ + static int last_irq_jiffy = 0; /* jiffies value the last time + * we were called */ + static int loops_this_jiffy = 0; + unsigned long flags; - u16 fid = hermes_read_regn(hw, ALLOCFID); + if (orinoco_lock(priv, &flags) != 0) { + /* If hw is unavailable - we don't know if the irq was + * for us or not */ + return IRQ_HANDLED; + } - if (fid != priv->txfid) { - if (fid != DUMMY_FID) - printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", - dev->name, fid); - return; - } else { - netif_wake_queue(dev); + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + if (! events) { + orinoco_unlock(priv, &flags); + return IRQ_NONE; } + + if (jiffies != last_irq_jiffy) + loops_this_jiffy = 0; + last_irq_jiffy = jiffies; - hermes_write_regn(hw, ALLOCFID, DUMMY_FID); + while (events && count--) { + if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { + printk(KERN_WARNING "%s: IRQ handler is looping too " + "much! Resetting.\n", dev->name); + /* Disable interrupts for now */ + hermes_set_irqmask(hw, 0); + schedule_work(&priv->reset_work); + break; + } + + /* Check the card hasn't been removed */ + if (! hermes_present(hw)) { + DEBUG(0, "orinoco_interrupt(): card removed\n"); + break; + } + + if (events & HERMES_EV_TICK) + __orinoco_ev_tick(dev, hw); + if (events & HERMES_EV_WTERR) + __orinoco_ev_wterr(dev, hw); + if (events & HERMES_EV_INFDROP) + __orinoco_ev_infdrop(dev, hw); + if (events & HERMES_EV_INFO) + __orinoco_ev_info(dev, hw); + if (events & HERMES_EV_RX) + __orinoco_ev_rx(dev, hw); + if (events & HERMES_EV_TXEXC) + __orinoco_ev_txexc(dev, hw); + if (events & HERMES_EV_TX) + __orinoco_ev_tx(dev, hw); + if (events & HERMES_EV_ALLOC) + __orinoco_ev_alloc(dev, hw); + + hermes_write_regn(hw, EVACK, events); + + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + }; + + orinoco_unlock(priv, &flags); + return IRQ_HANDLED; } +/********************************************************************/ +/* Initialization */ +/********************************************************************/ + struct sta_id { u16 id, variant, major, minor; } __attribute__ ((packed)); @@ -1901,11 +2053,11 @@ static void determine_firmware(struct net_device *dev) dev->name, err); memset(&sta_id, 0, sizeof(sta_id)); } + le16_to_cpus(&sta_id.id); le16_to_cpus(&sta_id.variant); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", dev->name, sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); @@ -2018,12 +2170,7 @@ static void determine_firmware(struct net_device *dev) } } -/* - * struct net_device methods - */ - -static int -orinoco_init(struct net_device *dev) +static int orinoco_init(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; @@ -2112,7 +2259,8 @@ orinoco_init(struct net_device *dev) err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, &priv->rts_thresh); if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + printk(KERN_ERR "%s: failed to read RTS threshold!\n", + dev->name); goto out; } @@ -2125,7 +2273,8 @@ orinoco_init(struct net_device *dev) err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", + dev->name); goto out; } @@ -2153,7 +2302,8 @@ orinoco_init(struct net_device *dev) /* Preamble setup */ if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, &priv->preamble); if (err) goto out; @@ -2202,357 +2352,204 @@ orinoco_init(struct net_device *dev) return err; } -struct net_device_stats * -orinoco_get_stats(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - - return &priv->stats; -} - -struct iw_statistics * -orinoco_get_wireless_stats(struct net_device *dev) +struct net_device *alloc_orinocodev(int sizeof_card, + int (*hard_reset)(struct orinoco_private *)) { - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err = 0; - unsigned long flags; - - if (! netif_device_present(dev)) { - printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", - dev->name); - return NULL; /* FIXME: Can we do better than this? */ - } + struct net_device *dev; + struct orinoco_private *priv; - err = orinoco_lock(priv, &flags); - if (err) - return NULL; /* FIXME: Erg, we've been signalled, how - * do we propagate this back up? */ + dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); + if (! dev) + return NULL; + priv = netdev_priv(dev); + priv->ndev = dev; + if (sizeof_card) + priv->card = (void *)((unsigned long)netdev_priv(dev) + + sizeof(struct orinoco_private)); + else + priv->card = NULL; - if (priv->iw_mode == IW_MODE_ADHOC) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; - } - } else { - struct { - u16 qual, signal, noise; - } __attribute__ ((packed)) cq; + /* Setup / override net_device fields */ + dev->init = orinoco_init; + dev->hard_start_xmit = orinoco_xmit; + dev->tx_timeout = orinoco_tx_timeout; + dev->watchdog_timeo = HZ; /* 1 second timeout */ + dev->get_stats = orinoco_get_stats; + dev->get_wireless_stats = orinoco_get_wireless_stats; + dev->do_ioctl = orinoco_ioctl; + dev->change_mtu = orinoco_change_mtu; + dev->set_multicast_list = orinoco_set_multicast_list; + /* we use the default eth_mac_addr for setting the MAC addr */ - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_COMMSQUALITY, &cq); - - wstats->qual.qual = (int)le16_to_cpu(cq.qual); - wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; - wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = 7; - } + /* Set up default callbacks */ + dev->open = orinoco_open; + dev->stop = orinoco_stop; + priv->hard_reset = hard_reset; - /* We can't really wait for the tallies inquiry command to - * complete, so we just use the previous results and trigger - * a new tallies inquiry command for next time - Jean II */ - /* FIXME: We're in user context (I think?), so we should just - wait for the tallies to come through */ - err = hermes_inquire(hw, HERMES_INQ_TALLIES); - - orinoco_unlock(priv, &flags); + spin_lock_init(&priv->lock); + priv->open = 0; + priv->hw_unavailable = 1; /* orinoco_init() must clear this + * before anything else touches the + * hardware */ + INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); - if (err) - return NULL; - - return wstats; -} + priv->last_linkstatus = 0xffff; + priv->connected = 0; -static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, - int level, int noise) -{ - struct orinoco_private *priv = netdev_priv(dev); - int i; + return dev; - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].level = level - 0x95; - priv->spy_stat[i].noise = noise - 0x95; - priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; - priv->spy_stat[i].updated = 7; - } } -void -orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc) -{ - struct orinoco_private *priv = netdev_priv(dev); - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, - desc->signal, desc->silence); - } -} +/********************************************************************/ +/* Wireless extensions */ +/********************************************************************/ -static int -orinoco_xmit(struct sk_buff *skb, struct net_device *dev) +static int orinoco_hw_get_bssid(struct orinoco_private *priv, + char buf[ETH_ALEN]) { - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; - u16 txfid = priv->txfid; - char *p; - struct ethhdr *eh; - int len, data_len, data_off; - struct hermes_tx_descriptor desc; unsigned long flags; - TRACE_ENTER(dev->name); + err = orinoco_lock(priv, &flags); + if (err) + return err; - if (! netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - TRACE_EXIT(dev->name); - return 1; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - TRACE_EXIT(dev->name); - return 1; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", - dev->name); - TRACE_EXIT(dev->name); -/* BUG(); */ - return 1; - } + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, + ETH_ALEN, NULL, buf); - if (! priv->connected) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - stats->tx_errors++; - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - TRACE_EXIT(dev->name); - return 0; - } + orinoco_unlock(priv, &flags); - /* Length of the packet body */ - /* FIXME: what if the skb is smaller than this? */ - len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); + return err; +} - eh = (struct ethhdr *)skb->data; +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + struct hermes_idstring essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + unsigned long flags; - memset(&desc, 0, sizeof(desc)); - desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); - err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); - if (err) { - printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } + err = orinoco_lock(priv, &flags); + if (err) + return err; - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWNSSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + u16 rid; - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ - struct header_struct hdr; - data_len = len; - data_off = HERMES_802_3_OFFSET + sizeof(hdr); - p = skb->data + ETH_HLEN; + *active = 1; - /* 802.3 header */ - memcpy(hdr.dest, eh->h_dest, ETH_ALEN); - memcpy(hdr.src, eh->h_source, ETH_ALEN); - hdr.len = htons(data_len + ENCAPS_OVERHEAD); + rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : + HERMES_RID_CNFDESIREDSSID; - /* 802.2 header */ - memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); - - hdr.ethertype = eh->h_proto; - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), - txfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } else { /* IEEE 802.3 frame */ - data_len = len + ETH_HLEN; - data_off = HERMES_802_3_OFFSET; - p = skb->data; - } + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; } - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL); - if (err) { - netif_start_queue(dev); - printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); - stats->tx_errors++; - goto fail; - } + len = le16_to_cpu(essidbuf.len); - dev->trans_start = jiffies; - stats->tx_bytes += data_off + data_len; + memset(buf, 0, IW_ESSID_MAX_SIZE+1); + memcpy(buf, p, len); + buf[len] = '\0'; + fail_unlock: orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - - TRACE_EXIT(dev->name); - - return 0; - fail: - TRACE_EXIT(dev->name); - - orinoco_unlock(priv, &flags); - return err; + return err; } -static void -orinoco_tx_timeout(struct net_device *dev) +static long orinoco_hw_get_freq(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - struct hermes *hw = &priv->hw; - - printk(KERN_WARNING "%s: Tx timeout! " - "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", - dev->name, hermes_read_regn(hw, ALLOCFID), - hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - - stats->tx_errors++; + + hermes_t *hw = &priv->hw; + int err = 0; + u16 channel; + long freq = 0; + unsigned long flags; - schedule_work(&priv->reset_work); -} + err = orinoco_lock(priv, &flags); + if (err) + return err; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); + if (err) + goto out; -static int -orinoco_change_mtu(struct net_device *dev, int new_mtu) -{ - struct orinoco_private *priv = netdev_priv(dev); + /* Intersil firmware 1.3.5 returns 0 when the interface is down */ + if (channel == 0) { + err = -EBUSY; + goto out; + } - if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) - return -EINVAL; + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", + priv->ndev->name, channel); + err = -EBUSY; + goto out; - if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > - (priv->nicbuf_size - ETH_HLEN) ) - return -EINVAL; + } + freq = channel_frequency[channel-1] * 100000; - dev->mtu = new_mtu; + out: + orinoco_unlock(priv, &flags); - return 0; + if (err > 0) + err = -EBUSY; + return err ? err : freq; } -/* FIXME: return int? */ -static void -__orinoco_set_multicast_list(struct net_device *dev) +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, + int *numrates, s32 *rates, int max) { - struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; + struct hermes_idstring list; + unsigned char *p = (unsigned char *)&list.val; int err = 0; - int promisc, mc_count; - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST(priv)) ) { - promisc = 1; - mc_count = 0; - } else { - promisc = 0; - mc_count = dev->mc_count; - } + int num; + int i; + unsigned long flags; - if (promisc != priv->promiscuous) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPROMISCUOUSMODE, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", - dev->name, err); - } else - priv->promiscuous = promisc; - } + err = orinoco_lock(priv, &flags); + if (err) + return err; - if (! promisc && (mc_count || priv->mc_count) ) { - struct dev_mc_list *p = dev->mc_list; - hermes_multicast_t mclist; - int i; + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, + sizeof(list), NULL, &list); + orinoco_unlock(priv, &flags); - for (i = 0; i < mc_count; i++) { - /* Paranoia: */ - if (! p) - BUG(); /* Multicast list shorter than mc_count */ - if (p->dmi_addrlen != ETH_ALEN) - BUG(); /* Bad address size in multicast list */ - - memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); - p = p->next; - } - - if (p) - printk(KERN_WARNING "Multicast list is longer than mc_count\n"); + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = min(num, max); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->mc_count = mc_count; + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ } - /* Since we can set the promiscuous flag when it wasn't asked - for, make sure the net_device knows about it. */ - if (priv->promiscuous) - dev->flags |= IFF_PROMISC; - else - dev->flags &= ~IFF_PROMISC; + return 0; } -/********************************************************************/ -/* Wireless extensions support */ -/********************************************************************/ - static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) { struct orinoco_private *priv = netdev_priv(dev); @@ -2582,10 +2579,8 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq /* Much of this shamelessly taken from wvlan_cs.c. No idea * what it all means -dgibson */ -#if WIRELESS_EXT > 10 range.we_version_compiled = WIRELESS_EXT; range.we_version_source = 11; -#endif /* WIRELESS_EXT > 10 */ range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ @@ -2612,22 +2607,17 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq range.max_qual.qual = 0; range.max_qual.level = 0; range.max_qual.noise = 0; -#if WIRELESS_EXT > 11 range.avg_qual.qual = 0; range.avg_qual.level = 0; range.avg_qual.noise = 0; -#endif /* WIRELESS_EXT > 11 */ - } else { range.max_qual.qual = 0x8b - 0x2f; range.max_qual.level = 0x2f - 0x95 - 1; range.max_qual.noise = 0x2f - 0x95 - 1; -#if WIRELESS_EXT > 11 /* Need to get better values */ range.avg_qual.qual = 0x24; range.avg_qual.level = 0xC2; range.avg_qual.noise = 0x9E; -#endif /* WIRELESS_EXT > 11 */ } err = orinoco_hw_get_bitratelist(priv, &numrates, @@ -2680,7 +2670,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq range.txpower[0] = 15; /* 15dBm */ range.txpower_capa = IW_TXPOW_DBM; -#if WIRELESS_EXT > 10 range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; range.retry_flags = IW_RETRY_LIMIT; range.r_time_flags = IW_RETRY_LIFETIME; @@ -2688,7 +2677,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq range.max_retry = 65535; /* ??? */ range.min_r_time = 0; range.max_r_time = 65535 * 1000; /* ??? */ -#endif /* WIRELESS_EXT > 10 */ if (copy_to_user(rrq->pointer, &range, sizeof(range))) return -EFAULT; @@ -2737,7 +2725,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; - + + /* Adjust key length to a supported value */ if (erq->length > SMALL_KEY_SIZE) { xlen = LARGE_KEY_SIZE; } else if (erq->length > 0) { @@ -2779,14 +2768,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er if (erq->pointer) { priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memset(priv->keys[index].data, 0, + sizeof(priv->keys[index].data)); memcpy(priv->keys[index].data, keybuf, erq->length); } priv->tx_key = setindex; priv->wep_on = enable; priv->wep_restrict = restricted; - out: orinoco_unlock(priv, &flags); @@ -3012,7 +3001,8 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) err = orinoco_lock(priv, &flags); if (err) return err; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val); + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, &val); orinoco_unlock(priv, &flags); if (err) @@ -3201,8 +3191,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) ratemode = priv->bitratemode; - if ( (ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE) ) - BUG(); + BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); rrq->value = bitrate_table[ratemode].bitrate * 100000; rrq->fixed = ! bitrate_table[ratemode].automatic; @@ -3354,7 +3343,6 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) return err; } -#if WIRELESS_EXT > 10 static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) { struct orinoco_private *priv = netdev_priv(dev); @@ -3406,7 +3394,6 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) return err; } -#endif /* WIRELESS_EXT > 10 */ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) { @@ -3500,7 +3487,6 @@ static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) *val = priv->prefer_port3; orinoco_unlock(priv, &flags); - return 0; } @@ -3790,7 +3776,6 @@ orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) wrq->u.txpower.flags = IW_TXPOW_DBM; break; -#if WIRELESS_EXT > 10 case SIOCSIWRETRY: err = -EOPNOTSUPP; break; @@ -3798,7 +3783,6 @@ orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCGIWRETRY: err = orinoco_ioctl_getretry(dev, &wrq->u.retry); break; -#endif /* WIRELESS_EXT > 10 */ case SIOCSIWSPY: err = orinoco_ioctl_setspy(dev, &wrq->u.data); @@ -4124,51 +4108,68 @@ static int orinoco_debug_dump_recs(struct net_device *dev) return 0; } -struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)) -{ - struct net_device *dev; - struct orinoco_private *priv; - - dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); - if (!dev) - return NULL; - priv = netdev_priv(dev); - priv->ndev = dev; - if (sizeof_card) - priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private)); - else - priv->card = NULL; - - /* Setup / override net_device fields */ - dev->init = orinoco_init; - dev->hard_start_xmit = orinoco_xmit; - dev->tx_timeout = orinoco_tx_timeout; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->get_stats = orinoco_get_stats; - dev->get_wireless_stats = orinoco_get_wireless_stats; - dev->do_ioctl = orinoco_ioctl; - dev->change_mtu = orinoco_change_mtu; - dev->set_multicast_list = orinoco_set_multicast_list; - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Set up default callbacks */ - dev->open = orinoco_open; - dev->stop = orinoco_stop; - priv->hard_reset = hard_reset; +/********************************************************************/ +/* Debugging */ +/********************************************************************/ - spin_lock_init(&priv->lock); - priv->open = 0; - priv->hw_unavailable = 1; /* orinoco_init() must clear this - * before anything else touches the - * hardware */ - INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); +#if 0 +static void show_rx_frame(struct orinoco_rxframe_hdr *frame) +{ + printk(KERN_DEBUG "RX descriptor:\n"); + printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); + printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); + printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); + printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); + printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); + printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); + printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); - priv->last_linkstatus = 0xffff; - priv->connected = 0; + printk(KERN_DEBUG "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); - return dev; + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); } +#endif /* 0 */ /********************************************************************/ /* Module initialization */ @@ -4185,7 +4186,9 @@ EXPORT_SYMBOL(orinoco_interrupt); /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco.c 0.13e (David Gibson and others)"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (David Gibson , " + "Pavel Roskin , et al)"; static int __init init_orinoco(void) { diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 972a8510f..c2f5f78f5 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -7,39 +7,19 @@ #ifndef _ORINOCO_H #define _ORINOCO_H +#define DRIVER_VERSION "0.13e" + #include #include #include #include #include -#include "hermes.h" - -/* Workqueue / task queue backwards compatibility stuff */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) -#include -#else -#include -#define work_struct tq_struct -#define INIT_WORK INIT_TQUEUE -#define schedule_work schedule_task -#endif - -/* Interrupt handler backwards compatibility stuff */ -#ifndef IRQ_NONE - -#define IRQ_NONE -#define IRQ_HANDLED -typedef void irqreturn_t; -#endif +#include "hermes.h" /* To enable debug messages */ //#define ORINOCO_DEBUG 3 -#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco driver requires Wireless extensions v10 or later." -#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ #define WIRELESS_SPY // enable iwspy support #define ORINOCO_MAX_KEY_SIZE 14 @@ -50,11 +30,6 @@ struct orinoco_key { char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); -#define ORINOCO_INTEN ( HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | \ - HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \ - HERMES_EV_INFDROP ) - - struct orinoco_private { void *card; /* Pointer to card dependent structure */ int (*hard_reset)(struct orinoco_private *); @@ -78,7 +53,6 @@ struct orinoco_private { hermes_t hw; u16 txfid; - /* Capabilities of the hardware/firmware */ int firmware_type; #define FIRMWARE_TYPE_AGERE 1 @@ -128,6 +102,10 @@ extern int orinoco_debug; #define TRACE_ENTER(devname) DEBUG(2, "%s: -> %s()\n", devname, __FUNCTION__); #define TRACE_EXIT(devname) DEBUG(2, "%s: <- %s()\n", devname, __FUNCTION__); +/********************************************************************/ +/* Exported prototypes */ +/********************************************************************/ + extern struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)); extern int __orinoco_up(struct net_device *dev); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 292eeffb6..4eb92ac6a 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c) +/* orinoco_cs.c (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -10,6 +10,9 @@ * Copyright notice & release notes in file orinoco.c */ +#define DRIVER_NAME "orinoco_cs" +#define PFX DRIVER_NAME ": " + #include #ifdef __IN_PCMCIA_PACKAGE__ #include @@ -47,9 +50,7 @@ MODULE_AUTHOR("David Gibson "); MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif /* Module parameters */ @@ -76,7 +77,7 @@ MODULE_PARM(ignore_cis_vcc, "i"); * device driver with appropriate cards, through the card * configuration database. */ -static dev_info_t dev_info = "orinoco_cs"; +static dev_info_t dev_info = DRIVER_NAME; /********************************************************************/ /* Data structures */ @@ -144,15 +145,6 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) /* PCMCIA stuff */ /********************************************************************/ -/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which - * does this, but it's not in 2.4 so we do our own for now. */ -static void -orinoco_cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - pcmcia_report_error(handle, &err); -} - /* * This creates an "instance" of the driver, allocating local data * structures for one device. The device is registered with Card @@ -174,7 +166,7 @@ orinoco_cs_attach(void) dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); if (! dev) return NULL; - priv = dev->priv; + priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ @@ -216,7 +208,7 @@ orinoco_cs_attach(void) ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { - orinoco_cs_error(link->handle, RegisterClient, ret); + cs_error(link->handle, RegisterClient, ret); orinoco_cs_detach(link); return NULL; } @@ -230,8 +222,7 @@ orinoco_cs_attach(void) * are freed. Otherwise, the structures will be freed when the device * is released. */ -static void -orinoco_cs_detach(dev_link_t * link) +static void orinoco_cs_detach(dev_link_t *link) { dev_link_t **linkp; struct net_device *dev = link->priv; @@ -240,10 +231,8 @@ orinoco_cs_detach(dev_link_t * link) for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; - if (*linkp == NULL) { - BUG(); - return; - } + + BUG_ON(*linkp == NULL); if (link->state & DEV_CONFIG) orinoco_cs_release(link); @@ -254,9 +243,9 @@ orinoco_cs_detach(dev_link_t * link) /* Unlink device structure, and free it */ *linkp = link->next; - DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); if (link->dev) { - DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + DEBUG(0, PFX "About to unregister net device %p\n", dev); unregister_netdev(dev); } @@ -269,15 +258,16 @@ orinoco_cs_detach(dev_link_t * link) * device available to the system. */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) +#define CS_CHECK(fn, ret) do { \ + last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ + } while (0) static void orinoco_cs_config(dev_link_t *link) { struct net_device *dev = link->priv; client_handle_t handle = link->handle; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; @@ -308,7 +298,8 @@ orinoco_cs_config(dev_link_t *link) link->state |= DEV_CONFIG; /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); + CS_CHECK(GetConfigurationInfo, + pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* @@ -412,8 +403,9 @@ orinoco_cs_config(dev_link_t *link) pcmcia_release_io(link->handle, &link->io); last_ret = pcmcia_get_next_tuple(handle, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { - printk(KERN_ERR "GetNextTuple(). No matching CIS configuration, " - "maybe you need the ignore_cis_vcc=1 parameter.\n"); + printk(KERN_ERR PFX "GetNextTuple(): No matching " + "CIS configuration, maybe you need the " + "ignore_cis_vcc=1 parameter.\n"); goto cs_failed; } } @@ -451,7 +443,8 @@ orinoco_cs_config(dev_link_t *link) * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, + pcmcia_request_configuration(link->handle, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; @@ -463,7 +456,7 @@ orinoco_cs_config(dev_link_t *link) dev->name[0] = '\0'; /* Tell the stack we exist */ if (register_netdev(dev) != 0) { - printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); + printk(KERN_ERR PFX "register_netdev() failed\n"); goto failed; } @@ -495,7 +488,7 @@ orinoco_cs_config(dev_link_t *link) return; cs_failed: - orinoco_cs_error(link->handle, last_fn, last_ret); + cs_error(link->handle, last_fn, last_ret); failed: orinoco_cs_release(link); @@ -510,7 +503,7 @@ static void orinoco_cs_release(dev_link_t *link) { struct net_device *dev = link->priv; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; /* We're committed to taking the device away now, so mark the @@ -538,7 +531,7 @@ orinoco_cs_event(event_t event, int priority, { dev_link_t *link = args->client_data; struct net_device *dev = link->priv; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; unsigned long flags; @@ -635,12 +628,14 @@ orinoco_cs_event(event_t event, int priority, /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson and others)"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (David Gibson , " + "Pavel Roskin , et al)"; static struct pcmcia_driver orinoco_driver = { .owner = THIS_MODULE, .drv = { - .name = "orinoco_cs", + .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, .detach = orinoco_cs_detach, @@ -660,7 +655,7 @@ exit_orinoco_cs(void) pcmcia_unregister_driver(&orinoco_driver); if (dev_list) - DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + DEBUG(0, PFX "Removing leftover devices.\n"); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) orinoco_cs_release(dev_list); @@ -670,4 +665,3 @@ exit_orinoco_cs(void) module_init(init_orinoco_cs); module_exit(exit_orinoco_cs); - diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 23222b951..3e58b7583 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -1,19 +1,23 @@ -/* orinoco_pci.c 0.13e +/* orinoco_pci.c * * Driver for Prism II devices that have a direct PCI interface * (i.e., not in a Pcmcia or PLX bridge) * * Specifically here we're talking about the Linksys WMP11 * + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson + * * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow + * Copyright (C) 2001 Daniel Barlow * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing * has been copied from it. linux-wlan-ng-0.1.10 is originally : * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. * This file originally written by: - * Copyright (C) 2001 Jean Tourrilhes + * Copyright (C) 2001 Jean Tourrilhes * And is now maintained by: - * Copyright (C) 2002 David Gibson, IBM Corporation + * (C) Copyright David Gibson, IBM Corp. 2002-2003. * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -85,6 +89,9 @@ * Jean II */ +#define DRIVER_NAME "orinoco_pci" +#define PFX DRIVER_NAME ": " + #include #include @@ -99,7 +106,6 @@ #include #include #include -#include #include #include #include @@ -174,7 +180,7 @@ orinoco_pci_cor_reset(struct orinoco_private *priv) } /* Did we timeout ? */ if(time_after_eq(jiffies, timeout)) { - printk(KERN_ERR "orinoco_pci: Busy timeout\n"); + printk(KERN_ERR PFX "Busy timeout\n"); return -ETIMEDOUT; } printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies); @@ -206,22 +212,21 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, if (! pci_iorange) goto fail; - /* Usual setup of structures */ + /* Allocate network device */ dev = alloc_orinocodev(0, NULL); if (! dev) { err = -ENOMEM; goto fail; } - priv = dev->priv; + priv = netdev_priv(dev); dev->base_addr = (unsigned long) pci_ioaddr; dev->mem_start = pci_iorange; dev->mem_end = pci_iorange + pci_iolen - 1; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); @@ -232,12 +237,13 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", + printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; goto fail; } dev->irq = pdev->irq; + /* Perform a COR reset to start the card */ if(orinoco_pci_cor_reset(priv) != 0) { printk(KERN_ERR "%s: Failed to start the card\n", dev->name); @@ -255,7 +261,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } - return 0; /* succeeded */ + return 0; + fail: if (dev) { if (dev->irq) @@ -275,11 +282,11 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unregister_netdev(dev); - if (dev->irq) + if (dev->irq) free_irq(dev->irq, dev); if (priv->hw.iobase) @@ -294,7 +301,7 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -325,7 +332,7 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state) static int orinoco_pci_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -357,7 +364,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev) } static struct pci_device_id orinoco_pci_pci_id_table[] = { + /* Intersil Prism 3 */ {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, + /* Intersil Prism 2.5 */ {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; @@ -365,7 +374,7 @@ static struct pci_device_id orinoco_pci_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table); static struct pci_driver orinoco_pci_driver = { - .name = "orinoco_pci", + .name = DRIVER_NAME, .id_table = orinoco_pci_pci_id_table, .probe = orinoco_pci_init_one, .remove = __devexit_p(orinoco_pci_remove_one), @@ -373,8 +382,11 @@ static struct pci_driver orinoco_pci_driver = { .resume = orinoco_pci_resume, }; -static char version[] __initdata = "orinoco_pci.c 0.13e (David Gibson & Jean Tourrilhes )"; -MODULE_AUTHOR("David Gibson "); +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson &" + " Jean Tourrilhes )"; +MODULE_AUTHOR("Pavel Roskin & David Gibson "); MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); MODULE_LICENSE("Dual MPL/GPL"); @@ -384,7 +396,7 @@ static int __init orinoco_pci_init(void) return pci_module_init(&orinoco_pci_driver); } -void __exit orinoco_pci_exit(void) +static void __exit orinoco_pci_exit(void) { pci_unregister_driver(&orinoco_pci_driver); } diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index b5660defd..d21ca78f0 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -1,9 +1,14 @@ -/* orinoco_plx.c 0.13e - * +/* orinoco_plx.c + * * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PLX9052. + * but are connected to the PCI bus by a PLX9052. + * + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson * - * Copyright (C) 2001 Daniel Barlow + * (C) Copyright David Gibson, IBM Corp. 2001-2003. + * Copyright (C) 2001 Daniel Barlow * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -33,77 +38,83 @@ * drop me mail with the id and "it works"/"it doesn't work". * * Note: if everything gets detected fine but it doesn't actually send - * or receive packets, your first port of call should probably be to + * or receive packets, your first port of call should probably be to * try newer firmware in the card. Especially if you're doing Ad-Hoc - * modes + * modes. * * The actual driving is done by orinoco.c, this is just resource * allocation stuff. The explanation below is courtesy of Ryan Niemi * on the linux-wlan-ng list at * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html + * + * The PLX9052-based cards (WL11000 and several others) are a + * different beast than the usual PCMCIA-based PRISM2 configuration + * expected by wlan-ng. Here's the general details on how the WL11000 + * PCI adapter works: + * + * - Two PCI I/O address spaces, one 0x80 long which contains the + * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA + * slot I/O address space. + * + * - One PCI memory address space, mapped to the PCMCIA memory space + * (containing the CIS). + * + * After identifying the I/O and memory space, you can read through + * the memory space to confirm the CIS's device ID or manufacturer ID + * to make sure it's the expected card. qKeep in mind that the PCMCIA + * spec specifies the CIS as the lower 8 bits of each word read from + * the CIS, so to read the bytes of the CIS, read every other byte + * (0,2,4,...). Passing that test, you need to enable the I/O address + * space on the PCMCIA card via the PCMCIA COR register. This is the + * first byte following the CIS. In my case (which may not have any + * relation to what's on the PRISM2 cards), COR was at offset 0x800 + * within the PCI memory space. Write 0x41 to the COR register to + * enable I/O mode and to select level triggered interrupts. To + * confirm you actually succeeded, read the COR register back and make + * sure it actually got set to 0x41, incase you have an unexpected + * card inserted. + * + * Following that, you can treat the second PCI I/O address space (the + * one that's not 0x80 in length) as the PCMCIA I/O space. + * + * Note that in the Eumitcom's source for their drivers, they register + * the interrupt as edge triggered when registering it with the + * Windows kernel. I don't recall how to register edge triggered on + * Linux (if it can be done at all). But in some experimentation, I + * don't see much operational difference between using either + * interrupt mode. Don't mess with the interrupt mode in the COR + * register though, as the PLX9052 wants level triggers with the way + * the serial EEPROM configures it on the WL11000. + * + * There's some other little quirks related to timing that I bumped + * into, but I don't recall right now. Also, there's two variants of + * the WL11000 I've seen, revision A1 and T2. These seem to differ + * slightly in the timings configured in the wait-state generator in + * the PLX9052. There have also been some comments from Eumitcom that + * cards shouldn't be hot swapped, apparently due to risk of cooking + * the PLX9052. I'm unsure why they believe this, as I can't see + * anything in the design that would really cause a problem, except + * for crashing drivers not written to expect it. And having developed + * drivers for the WL11000, I'd say it's quite tricky to write code + * that will successfully deal with a hot unplug. Very odd things + * happen on the I/O side of things. But anyway, be warned. Despite + * that, I've hot-swapped a number of times during debugging and + * driver development for various reasons (stuck WAIT# line after the + * radio card's firmware locks up). + * + * Hope this is enough info for someone to add PLX9052 support to the + * wlan-ng card. In the case of the WL11000, the PCI ID's are + * 0x1639/0x0200, with matching subsystem ID's. Other PLX9052-based + * manufacturers other than Eumitcom (or on cards other than the + * WL11000) may have different PCI ID's. + * + * If anyone needs any more specific info, let me know. I haven't had + * time to implement support myself yet, and with the way things are + * going, might not have time for a while.. + */ -The PLX9052-based cards (WL11000 and several others) are a different -beast than the usual PCMCIA-based PRISM2 configuration expected by -wlan-ng. Here's the general details on how the WL11000 PCI adapter -works: - - - Two PCI I/O address spaces, one 0x80 long which contains the PLX9052 - registers, and one that's 0x40 long mapped to the PCMCIA slot I/O - address space. - - - One PCI memory address space, mapped to the PCMCIA memory space - (containing the CIS). - -After identifying the I/O and memory space, you can read through the -memory space to confirm the CIS's device ID or manufacturer ID to make -sure it's the expected card. Keep in mind that the PCMCIA spec specifies -the CIS as the lower 8 bits of each word read from the CIS, so to read the -bytes of the CIS, read every other byte (0,2,4,...). Passing that test, -you need to enable the I/O address space on the PCMCIA card via the PCMCIA -COR register. This is the first byte following the CIS. In my case -(which may not have any relation to what's on the PRISM2 cards), COR was -at offset 0x800 within the PCI memory space. Write 0x41 to the COR -register to enable I/O mode and to select level triggered interrupts. To -confirm you actually succeeded, read the COR register back and make sure -it actually got set to 0x41, incase you have an unexpected card inserted. - -Following that, you can treat the second PCI I/O address space (the one -that's not 0x80 in length) as the PCMCIA I/O space. - -Note that in the Eumitcom's source for their drivers, they register the -interrupt as edge triggered when registering it with the Windows kernel. I -don't recall how to register edge triggered on Linux (if it can be done at -all). But in some experimentation, I don't see much operational -difference between using either interrupt mode. Don't mess with the -interrupt mode in the COR register though, as the PLX9052 wants level -triggers with the way the serial EEPROM configures it on the WL11000. - -There's some other little quirks related to timing that I bumped into, but -I don't recall right now. Also, there's two variants of the WL11000 I've -seen, revision A1 and T2. These seem to differ slightly in the timings -configured in the wait-state generator in the PLX9052. There have also -been some comments from Eumitcom that cards shouldn't be hot swapped, -apparently due to risk of cooking the PLX9052. I'm unsure why they -believe this, as I can't see anything in the design that would really -cause a problem, except for crashing drivers not written to expect it. And -having developed drivers for the WL11000, I'd say it's quite tricky to -write code that will successfully deal with a hot unplug. Very odd things -happen on the I/O side of things. But anyway, be warned. Despite that, -I've hot-swapped a number of times during debugging and driver development -for various reasons (stuck WAIT# line after the radio card's firmware -locks up). - -Hope this is enough info for someone to add PLX9052 support to the wlan-ng -card. In the case of the WL11000, the PCI ID's are 0x1639/0x0200, with -matching subsystem ID's. Other PLX9052-based manufacturers other than -Eumitcom (or on cards other than the WL11000) may have different PCI ID's. - -If anyone needs any more specific info, let me know. I haven't had time -to implement support myself yet, and with the way things are going, might -not have time for a while.. - ----end of mail--- -*/ +#define DRIVER_NAME "orinoco_plx" +#define PFX DRIVER_NAME ": " #include @@ -122,7 +133,6 @@ not have time for a while.. #include #include #include -#include #include #include #include @@ -132,13 +142,11 @@ not have time for a while.. #include "hermes.h" #include "orinoco.h" -static char dev_info[] = "orinoco_plx"; - -#define COR_OFFSET (0x3e0 / 2) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ +#define COR_OFFSET (0x3e0/2) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define PLX_INTCSR 0x4c /* Interrupt Control and Status Register */ -#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ +#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ +#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ static const u16 cis_magic[] = { 0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067 @@ -215,7 +223,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, /* and 3 to the PCMCIA slot I/O address space */ pccard_ioaddr = pci_resource_start(pdev, 3); pccard_iolen = pci_resource_len(pdev, 3); - if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { + if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) { printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n", pccard_iolen, pccard_ioaddr); pccard_ioaddr = 0; @@ -223,28 +231,30 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } + /* Allocate network device */ dev = alloc_orinocodev(0, NULL); if (! dev) { err = -ENOMEM; goto fail; } - priv = dev->priv; + priv = netdev_priv(dev); dev->base_addr = pccard_ioaddr; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG - "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n", - pci_name(pdev), pdev->irq, pccard_ioaddr); + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device " + "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, + pccard_ioaddr); - hermes_struct_init(&(priv->hw), dev->base_addr, - HERMES_IO, HERMES_16BIT_REGSPACING); + hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, + HERMES_16BIT_REGSPACING); pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq); + printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; goto fail; } @@ -254,10 +264,10 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, if (err) goto fail; - return 0; /* succeeded */ + return 0; - fail: - printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); + fail: + printk(KERN_DEBUG PFX "init_one(), FAIL!\n"); if (dev) { if (dev->irq) @@ -281,8 +291,7 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - if (! dev) - BUG(); + BUG_ON(! dev); unregister_netdev(dev); @@ -305,33 +314,34 @@ static struct pci_device_id orinoco_plx_pci_id_table[] = { {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, Eumitcom PCI WL11000, - Addtron AWA-100*/ + Addtron AWA-100 */ {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by - Brendan W. McAdams */ + Brendan W. McAdams */ {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by - Damien Persohn */ + Damien Persohn */ {0,}, }; MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table); static struct pci_driver orinoco_plx_driver = { - .name = "orinoco_plx", + .name = DRIVER_NAME, .id_table = orinoco_plx_pci_id_table, .probe = orinoco_plx_init_one, .remove = __devexit_p(orinoco_plx_remove_one), }; -static char version[] __initdata = "orinoco_plx.c 0.13e (Daniel Barlow , David Gibson )"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson ," + " Daniel Barlow )"; MODULE_AUTHOR("Daniel Barlow "); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif static int __init orinoco_plx_init(void) { @@ -339,7 +349,7 @@ static int __init orinoco_plx_init(void) return pci_module_init(&orinoco_plx_driver); } -void __exit orinoco_plx_exit(void) +static void __exit orinoco_plx_exit(void) { pci_unregister_driver(&orinoco_plx_driver); current->state = TASK_UNINTERRUPTIBLE; diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 56ab51cf5..b619f6dea 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -1,10 +1,10 @@ -/* orinoco_tmd.c 0.01 +/* orinoco_tmd.c * * Driver for Prism II devices which would usually be driven by orinoco_cs, * but are connected to the PCI bus by a TMD7160. * - * Copyright (C) 2003 Joerg Dorchain - * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow + * Copyright (C) 2003 Joerg Dorchain + * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -49,6 +49,9 @@ * Pheecom sells cards with the TMD chip as "ASIC version" */ +#define DRIVER_NAME "orinoco_tmd" +#define PFX DRIVER_NAME ": " + #include #include @@ -66,7 +69,6 @@ #include #include #include -#include #include #include #include @@ -76,10 +78,7 @@ #include "hermes.h" #include "orinoco.h" -static char dev_info[] = "orinoco_tmd"; - -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA | COR_FUNC_ENA) /* Enable PC card with level triggered irqs and irq requests */ - +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ static int orinoco_tmd_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -95,11 +94,11 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, if (err) return -EIO; - printk(KERN_DEBUG "TMD setup\n"); + printk(KERN_DEBUG PFX "TMD setup\n"); pccard_ioaddr = pci_resource_start(pdev, 2); pccard_iolen = pci_resource_len(pdev, 2); - if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { - printk(KERN_ERR "orinoco_tmd: I/O resource at 0x%lx len 0x%lx busy\n", + if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) { + printk(KERN_ERR PFX "I/O resource at 0x%lx len 0x%lx busy\n", pccard_ioaddr, pccard_iolen); pccard_ioaddr = 0; err = -EBUSY; @@ -110,34 +109,35 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, mdelay(1); reg = inb(addr); if (reg != COR_VALUE) { - printk(KERN_ERR "orinoco_tmd: Error setting TMD COR values %x should be %x\n", reg, COR_VALUE); + printk(KERN_ERR PFX "Error setting TMD COR values %x should be %x\n", reg, COR_VALUE); err = -EIO; goto fail; } + /* Allocate network device */ dev = alloc_orinocodev(0, NULL); if (! dev) { err = -ENOMEM; goto fail; } - priv = dev->priv; + priv = netdev_priv(dev); dev->base_addr = pccard_ioaddr; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG - "Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n", - pci_name(pdev), pdev->irq, pccard_ioaddr); + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device " + "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, + pccard_ioaddr); hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, HERMES_16BIT_REGSPACING); pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, - dev); + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_tmd: Error allocating IRQ %d.\n", + printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; goto fail; @@ -148,10 +148,10 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, if (err) goto fail; - return 0; /* succeeded */ + return 0; - fail: - printk(KERN_DEBUG "orinoco_tmd: init_one(), FAIL!\n"); + fail: + printk(KERN_DEBUG PFX "init_one(), FAIL!\n"); if (dev) { if (dev->irq) @@ -172,8 +172,7 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - if (! dev) - BUG(); + BUG_ON(! dev); unregister_netdev(dev); @@ -198,18 +197,17 @@ static struct pci_device_id orinoco_tmd_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table); static struct pci_driver orinoco_tmd_driver = { - .name = "orinoco_tmd", + .name = DRIVER_NAME, .id_table = orinoco_tmd_pci_id_table, .probe = orinoco_tmd_init_one, .remove = __devexit_p(orinoco_tmd_remove_one), }; -static char version[] __initdata = "orinoco_tmd.c 0.01 (Joerg Dorchain )"; +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Joerg Dorchain )"; MODULE_AUTHOR("Joerg Dorchain "); MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual MPL/GPL"); -#endif static int __init orinoco_tmd_init(void) { @@ -217,7 +215,7 @@ static int __init orinoco_tmd_init(void) return pci_module_init(&orinoco_tmd_driver); } -void __exit orinoco_tmd_exit(void) +static void __exit orinoco_tmd_exit(void) { pci_unregister_driver(&orinoco_tmd_driver); current->state = TASK_UNINTERRUPTIBLE; diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c index 3ee31021f..651189105 100644 --- a/drivers/net/wireless/prism54/isl_38xx.c +++ b/drivers/net/wireless/prism54/isl_38xx.c @@ -44,7 +44,7 @@ * register located at offset %ISL38XX_INT_IDENT_REG. */ void -isl38xx_disable_interrupts(void *device) +isl38xx_disable_interrupts(void __iomem *device) { isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); @@ -52,7 +52,7 @@ isl38xx_disable_interrupts(void *device) void isl38xx_handle_sleep_request(isl38xx_control_block *control_block, - int *powerstate, void *device_base) + int *powerstate, void __iomem *device_base) { /* device requests to go into sleep mode * check whether the transmit queues for data and management are empty */ @@ -88,7 +88,7 @@ isl38xx_handle_sleep_request(isl38xx_control_block *control_block, void isl38xx_handle_wakeup(isl38xx_control_block *control_block, - int *powerstate, void *device_base) + int *powerstate, void __iomem *device_base) { /* device is in active state, update the powerstate flag */ *powerstate = ISL38XX_PSM_ACTIVE_STATE; @@ -110,7 +110,7 @@ isl38xx_handle_wakeup(isl38xx_control_block *control_block, } void -isl38xx_trigger_device(int asleep, void *device_base) +isl38xx_trigger_device(int asleep, void __iomem *device_base) { struct timeval current_time; u32 reg, counter = 0; @@ -190,7 +190,7 @@ isl38xx_trigger_device(int asleep, void *device_base) } void -isl38xx_interface_reset(void *device_base, dma_addr_t host_address) +isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) { u32 reg; @@ -219,7 +219,7 @@ isl38xx_interface_reset(void *device_base, dma_addr_t host_address) } void -isl38xx_enable_common_interrupts(void *device_base) { +isl38xx_enable_common_interrupts(void __iomem *device_base) { u32 reg; reg = ( ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h index 0bd5ff6ad..d63fd641d 100644 --- a/drivers/net/wireless/prism54/isl_38xx.h +++ b/drivers/net/wireless/prism54/isl_38xx.h @@ -75,7 +75,7 @@ * from the %ISL38XX_PCI_POSTING_FLUSH offset. */ static inline void -isl38xx_w32_flush(void *base, u32 val, unsigned long offset) +isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset) { writel(val, base + offset); (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); @@ -157,13 +157,13 @@ typedef struct isl38xx_cb isl38xx_control_block; /* determine number of entries currently in queue */ int isl38xx_in_queue(isl38xx_control_block *cb, int queue); -void isl38xx_disable_interrupts(void *); -void isl38xx_enable_common_interrupts(void *); +void isl38xx_disable_interrupts(void __iomem *); +void isl38xx_enable_common_interrupts(void __iomem *); void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, - void *); -void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *); -void isl38xx_trigger_device(int, void *); -void isl38xx_interface_reset(void *, dma_addr_t); + void __iomem *); +void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *); +void isl38xx_trigger_device(int, void __iomem *); +void isl38xx_interface_reset(void __iomem *, dma_addr_t); #endif /* _ISL_38XX_H */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 7924b36a7..2d7e1cf88 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -334,9 +334,10 @@ prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, int rvalue; rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); - + fwrq->i = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); fwrq->m = r.u; - fwrq->e = 0; + fwrq->e = 3; return rvalue; } diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index d96d621f1..650f86a8c 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -58,7 +58,7 @@ static int isl_upload_firmware(islpci_private *priv) { u32 reg, rc; - void *device_base = priv->device_base; + void __iomem *device_base = priv->device_base; /* clear the RAMBoot and the Reset bit */ reg = readl(device_base + ISL38XX_CTRL_STAT_REG); @@ -113,7 +113,7 @@ isl_upload_firmware(islpci_private *priv) (fw_len > ISL38XX_MEMORY_WINDOW_SIZE) ? ISL38XX_MEMORY_WINDOW_SIZE : fw_len; - u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; + u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; /* set the cards base address for writting the data */ isl38xx_w32_flush(device_base, reg, @@ -183,7 +183,7 @@ islpci_interrupt(int irq, void *config, struct pt_regs *regs) u32 reg; islpci_private *priv = config; struct net_device *ndev = priv->ndev; - void *device = priv->device_base; + void __iomem *device = priv->device_base; int powerstate = ISL38XX_PSM_POWERSAVE_STATE; /* lock the interrupt handler */ @@ -405,7 +405,7 @@ islpci_close(struct net_device *ndev) static int prism54_bring_down(islpci_private *priv) { - void *device_base = priv->device_base; + void __iomem *device_base = priv->device_base; u32 reg; /* we are going to shutdown the device */ islpci_set_state(priv, PRV_STATE_PREBOOT); diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index e0ec5de03..628fb9107 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -109,7 +109,7 @@ typedef struct { u32 pci_state[16]; /* used for suspend/resume */ char firmware[33]; - void *device_base; /* ioremapped device base address */ + void __iomem *device_base; /* ioremapped device base address */ /* consistent DMA region */ void *driver_mem_address; /* base DMA address */ diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index e39bcddc3..1bb0ada59 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -54,7 +54,6 @@ #include #include -#ifdef CONFIG_NET_PCMCIA_RADIO #include #include @@ -68,7 +67,6 @@ typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ -#endif /* CONFIG_NET_PCMCIA_RADIO */ #include "rayctl.h" #include "ray_cs.h" @@ -112,9 +110,9 @@ static int ray_open(struct net_device *dev); static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ray_update_multi_list(struct net_device *dev, int all); -static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, +static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, int len); -static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, +static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, unsigned char *data); static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ @@ -140,14 +138,14 @@ static void verify_dl_startup(u_long); /* Prototypes for interrpt time functions **********************************/ static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs); static void clear_interrupt(ray_dev_t *local); -static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, +static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs); -static void release_frag_chain(ray_dev_t *local, struct rcs *prcs); -static void rx_authenticate(ray_dev_t *local, struct rcs *prcs, +static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); +static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); +static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); -static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, +static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); static void associate(ray_dev_t *local); @@ -540,7 +538,7 @@ static void ray_config(dev_link_t *link) CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); - local->sram = (UCHAR *)(ioremap(req.Base,req.Size)); + local->sram = ioremap(req.Base,req.Size); /*** Set up 16k window for shared memory (receive buffer) ***************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; @@ -550,7 +548,7 @@ static void ray_config(dev_link_t *link) CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle)); mem.CardOffset = 0x8000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); - local->rmem = (UCHAR *)(ioremap(req.Base,req.Size)); + local->rmem = ioremap(req.Base,req.Size); /*** Set up window for attribute memory ***********************************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; @@ -560,7 +558,7 @@ static void ray_config(dev_link_t *link) CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); - local->amem = (UCHAR *)(ioremap(req.Base,req.Size)); + local->amem = ioremap(req.Base,req.Size); DEBUG(3,"ray_config sram=%p\n",local->sram); DEBUG(3,"ray_config rmem=%p\n",local->rmem); @@ -593,12 +591,30 @@ cs_failed: ray_release(link); } /* ray_config */ + +static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) +{ + return dev->sram + CCS_BASE; +} + +static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) +{ + /* + * This looks nonsensical, since there is a separate + * RCS_BASE. But the difference between a "struct rcs" + * and a "struct ccs" ends up being in the _index_ off + * the base, so the base pointer is the same for both + * ccs/rcs. + */ + return dev->sram + CCS_BASE; +} + /*===========================================================================*/ static int ray_init(struct net_device *dev) { int i; UCHAR *p; - struct ccs *pccs; + struct ccs __iomem *pccs; ray_dev_t *local = (ray_dev_t *)dev->priv; dev_link_t *link = local->finder; DEBUG(1, "ray_init(0x%p)\n", dev); @@ -632,7 +648,7 @@ static int ray_init(struct net_device *dev) local->tib_length = local->startup_res.tib_length; DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length); /* Initialize CCS's to buffer free state */ - pccs = (struct ccs *)(local->sram + CCS_BASE); + pccs = ccs_base(local); for (i=0; ibuffer_status); } @@ -661,7 +677,7 @@ static int dl_startup_params(struct net_device *dev) { int ccsindex; ray_dev_t *local = (ray_dev_t *)dev->priv; - struct ccs *pccs; + struct ccs __iomem *pccs; dev_link_t *link = local->finder; DEBUG(1,"dl_startup_params entered\n"); @@ -682,7 +698,7 @@ static int dl_startup_params(struct net_device *dev) /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return -1; local->dl_param_ccs = ccsindex; - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); /* Interrupt the firmware to process the command */ @@ -767,7 +783,7 @@ static void init_startup_params(ray_dev_t *local) static void verify_dl_startup(u_long data) { ray_dev_t *local = (ray_dev_t *)data; - struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs; + struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; UCHAR status; dev_link_t *link = local->finder; @@ -807,7 +823,7 @@ static void verify_dl_startup(u_long data) static void start_net(u_long data) { ray_dev_t *local = (ray_dev_t *)data; - struct ccs *pccs; + struct ccs __iomem *pccs; int ccsindex; dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { @@ -816,7 +832,7 @@ static void start_net(u_long data) } /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return; - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_START_NETWORK, &pccs->cmd); writeb(0, &pccs->var.start_network.update_param); /* Interrupt the firmware to process the command */ @@ -834,7 +850,7 @@ static void join_net(u_long data) { ray_dev_t *local = (ray_dev_t *)data; - struct ccs *pccs; + struct ccs __iomem *pccs; int ccsindex; dev_link_t *link = local->finder; @@ -844,7 +860,7 @@ static void join_net(u_long data) } /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return; - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_JOIN_NETWORK, &pccs->cmd); writeb(0, &pccs->var.join_network.update_param); writeb(0, &pccs->var.join_network.net_initiated); @@ -1049,10 +1065,10 @@ static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR msg_type) { ray_dev_t *local = (ray_dev_t *)dev->priv; - struct ccs *pccs; + struct ccs __iomem *pccs; int ccsindex; int offset; - struct tx_msg *ptx; /* Address of xmit buffer in PC space */ + struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ short int addr; /* Address of xmit buffer in card space */ DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); @@ -1079,7 +1095,7 @@ static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, local->stats.tx_packets++; } - ptx = (struct tx_msg *)(local->sram + addr); + ptx = local->sram + addr; ray_build_header(local, ptx, msg_type, data); if (translate) { @@ -1092,7 +1108,7 @@ static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, } /* fill in the CCS */ - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; len += TX_HEADER_LENGTH + offset; writeb(CCS_TX_REQUEST, &pccs->cmd); writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); @@ -1119,21 +1135,21 @@ static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, return XMIT_OK; } /* end ray_hw_xmit */ /*===========================================================================*/ -static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data, +static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, int len) { unsigned short int proto = ((struct ethhdr *)data)->h_proto; if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ DEBUG(3,"ray_cs translate_frame DIX II\n"); /* Copy LLC header to card buffer */ - memcpy_toio((UCHAR *)&ptx->var, eth2_llc, sizeof(eth2_llc)); - memcpy_toio( ((UCHAR *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); + memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); + memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); if ((proto == 0xf380) || (proto == 0x3781)) { /* This is the selective translation table, only 2 entries */ - writeb(0xf8, (UCHAR *) &((struct snaphdr_t *)ptx->var)->org[3]); + writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); } /* Copy body of ethernet packet without ethernet header */ - memcpy_toio((UCHAR *)&ptx->var + sizeof(struct snaphdr_t), \ + memcpy_toio((void __iomem *)&ptx->var + sizeof(struct snaphdr_t), \ data + ETH_HLEN, len - ETH_HLEN); return (int) sizeof(struct snaphdr_t) - ETH_HLEN; } @@ -1141,16 +1157,16 @@ static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char * DEBUG(3,"ray_cs translate_frame 802\n"); if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ DEBUG(3,"ray_cs translate_frame evil IPX\n"); - memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN, len - ETH_HLEN); + memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; } - memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN, len - ETH_HLEN); + memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; } /* TBD do other frame types */ } /* end translate_frame */ /*===========================================================================*/ -static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, +static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, unsigned char *data) { writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); @@ -1633,7 +1649,7 @@ static iw_stats * ray_get_wireless_stats(struct net_device * dev) { ray_dev_t * local = (ray_dev_t *) dev->priv; dev_link_t *link = local->finder; - struct status *p = (struct status *)(local->sram + STATUS_BASE); + struct status __iomem *p = local->sram + STATUS_BASE; if(local == (ray_dev_t *) NULL) return (iw_stats *) NULL; @@ -1755,7 +1771,7 @@ static int interrupt_ecf(ray_dev_t *local, int ccs) static int get_free_tx_ccs(ray_dev_t *local) { int i; - struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE); + struct ccs __iomem *pccs = ccs_base(local); dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { @@ -1786,7 +1802,7 @@ static int get_free_tx_ccs(ray_dev_t *local) static int get_free_ccs(ray_dev_t *local) { int i; - struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE); + struct ccs __iomem *pccs = ccs_base(local); dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { @@ -1863,7 +1879,7 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) { ray_dev_t *local = (ray_dev_t *)dev->priv; dev_link_t *link = local->finder; - struct status *p = (struct status *)(local->sram + STATUS_BASE); + struct status __iomem *p = local->sram + STATUS_BASE; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_cs net_device_stats - device not present\n"); return &local->stats; @@ -1895,7 +1911,7 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, i dev_link_t *link = local->finder; int ccsindex; int i; - struct ccs *pccs; + struct ccs __iomem *pccs; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_update_parm - device not present\n"); @@ -1907,7 +1923,7 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, i DEBUG(0,"ray_update_parm - No free ccs\n"); return; } - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_UPDATE_PARAMS, &pccs->cmd); writeb(objid, &pccs->var.update_param.object_id); writeb(1, &pccs->var.update_param.number_objects); @@ -1926,11 +1942,11 @@ static void ray_update_multi_list(struct net_device *dev, int all) { struct dev_mc_list *dmi, **dmip; int ccsindex; - struct ccs *pccs; + struct ccs __iomem *pccs; int i = 0; ray_dev_t *local = (ray_dev_t *)dev->priv; dev_link_t *link = local->finder; - UCHAR *p = local->sram + HOST_TO_ECF_BASE; + void __iomem *p = local->sram + HOST_TO_ECF_BASE; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_update_multi_list - device not present\n"); @@ -1943,7 +1959,7 @@ static void ray_update_multi_list(struct net_device *dev, int all) DEBUG(1,"ray_update_multi - No free ccs\n"); return; } - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); if (all) { @@ -2011,8 +2027,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) struct net_device *dev = (struct net_device *)dev_id; dev_link_t *link; ray_dev_t *local; - struct ccs *pccs; - struct rcs *prcs; + struct ccs __iomem *pccs; + struct rcs __iomem *prcs; UCHAR rcsindex; UCHAR tmp; UCHAR cmd; @@ -2029,7 +2045,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); return IRQ_NONE; } - rcsindex = readb(&((struct scb *)(local->sram))->rcs_index); + rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { @@ -2039,7 +2055,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) } if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */ { - pccs = ((struct ccs *) (local->sram + CCS_BASE)) + rcsindex; + pccs = ccs_base(local) + rcsindex; cmd = readb(&pccs->cmd); status = readb(&pccs->buffer_status); switch (cmd) @@ -2153,7 +2169,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) } else /* It's an RCS */ { - prcs = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex; + prcs = rcs_base(local) + rcsindex; switch (readb(&prcs->interrupt_id)) { @@ -2194,11 +2210,11 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) return IRQ_HANDLED; } /* ray_interrupt */ /*===========================================================================*/ -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) +static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs) { int rx_len; unsigned int pkt_addr; - UCHAR *pmsg; + void __iomem *pmsg; DEBUG(4,"ray_rx process rx packet\n"); /* Calculate address of packet within Rx buffer */ @@ -2248,11 +2264,11 @@ static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) } /* end ray_rx */ /*===========================================================================*/ -static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, +static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len) { struct sk_buff *skb = NULL; - struct rcs *prcslink = prcs; + struct rcs __iomem *prcslink = prcs; ray_dev_t *local = dev->priv; UCHAR *rx_ptr; int total_len; @@ -2294,7 +2310,7 @@ static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_a + readb(&prcslink->var.rx_packet.rx_data_length[1]); if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF || tmp < 0) break; - prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + prcslink = rcs_base(local) + readb(&prcslink->link_field); } while (1); @@ -2355,7 +2371,7 @@ static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_a prcslink = prcs; DEBUG(1,"ray_cs rx_data in fragment loop\n"); do { - prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + prcslink = rcs_base(local) + readb(&prcslink->var.rx_packet.next_frag_rcs_index); rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) + readb(&prcslink->var.rx_packet.rx_data_length[1])) @@ -2529,9 +2545,9 @@ static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int le return length; } /*===========================================================================*/ -static void release_frag_chain(ray_dev_t *local, struct rcs* prcs) +static void release_frag_chain(ray_dev_t *local, struct rcs __iomem * prcs) { - struct rcs *prcslink = prcs; + struct rcs __iomem *prcslink = prcs; int tmp = 17; unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); @@ -2541,7 +2557,7 @@ static void release_frag_chain(ray_dev_t *local, struct rcs* prcs) DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); break; } - prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex; + prcslink = rcs_base(local) + rcsindex; rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); } writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); @@ -2569,7 +2585,7 @@ static void authenticate(ray_dev_t *local) local->authentication_state = AWAITING_RESPONSE; } /* end authenticate */ /*===========================================================================*/ -static void rx_authenticate(ray_dev_t *local, struct rcs *prcs, +static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len) { UCHAR buff[256]; @@ -2614,7 +2630,7 @@ static void rx_authenticate(ray_dev_t *local, struct rcs *prcs, /*===========================================================================*/ static void associate(ray_dev_t *local) { - struct ccs *pccs; + struct ccs __iomem *pccs; dev_link_t *link = local->finder; struct net_device *dev = link->priv; int ccsindex; @@ -2630,7 +2646,7 @@ static void associate(ray_dev_t *local) return; } DEBUG(1,"ray_cs Starting association with access point\n"); - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; /* fill in the CCS */ writeb(CCS_START_ASSOCIATION, &pccs->cmd); /* Interrupt the firmware to process the command */ @@ -2650,7 +2666,7 @@ static void associate(ray_dev_t *local) } /* end associate */ /*===========================================================================*/ -static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, +static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len) { /* UCHAR buff[256]; @@ -2798,8 +2814,8 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) { int addr; - struct ccs *pccs; - struct tx_msg *ptx; + struct ccs __iomem *pccs; + struct tx_msg __iomem *ptx; int ccsindex; /* If no tx buffers available, return */ @@ -2809,7 +2825,7 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) return -1; } - pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + pccs = ccs_base(local) + ccsindex; /* Address in card space */ addr = TX_BUF_BASE + (ccsindex << 11); @@ -2821,7 +2837,7 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1); writeb(0, &pccs->var.tx_request.pow_sav_mode); - ptx = (struct tx_msg *)(local->sram + addr); + ptx = local->sram + addr; /* fill in the mac header */ writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); writeb(0, &ptx->mac.frame_ctl_2); @@ -2931,15 +2947,6 @@ static void __exit exit_ray_cs(void) { DEBUG(0, "ray_cs: cleanup_module\n"); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("ray_cs", proc_root_driver); -#endif - - pcmcia_unregister_driver(&ray_driver); - while (dev_list != NULL) - ray_detach(dev_list); - #ifdef CONFIG_PROC_FS remove_proc_entry("driver/ray_cs/ray_cs", NULL); remove_proc_entry("driver/ray_cs/essid", NULL); @@ -2947,6 +2954,10 @@ static void __exit exit_ray_cs(void) remove_proc_entry("driver/ray_cs/translate", NULL); remove_proc_entry("driver/ray_cs", NULL); #endif + + pcmcia_unregister_driver(&ray_driver); + while (dev_list != NULL) + ray_detach(dev_list); } /* exit_ray_cs */ module_init(init_ray_cs); diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h index 6d4985061..c77afa14f 100644 --- a/drivers/net/wireless/ray_cs.h +++ b/drivers/net/wireless/ray_cs.h @@ -28,9 +28,9 @@ typedef struct ray_dev_t { dev_node_t node; window_handle_t amem_handle; /* handle to window for attribute memory */ window_handle_t rmem_handle; /* handle to window for rx buffer on card */ - UCHAR *sram; /* pointer to beginning of shared RAM */ - UCHAR *amem; /* pointer to attribute mem window */ - UCHAR *rmem; /* pointer to receive buffer window */ + void __iomem *sram; /* pointer to beginning of shared RAM */ + void __iomem *amem; /* pointer to attribute mem window */ + void __iomem *rmem; /* pointer to receive buffer window */ dev_link_t *finder; /* pointer back to dev_link_t for card */ struct timer_list timer; long tx_ccs_lock; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 98cee21f7..7f44588cb 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -106,6 +106,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; #include #include #include +#include #include #include @@ -1348,14 +1349,17 @@ static unsigned char *strip_make_packet(unsigned char *buffer, */ if (haddr.c[0] == 0xFF) { u32 brd = 0; - struct in_device *in_dev = in_dev_get(strip_info->dev); - if (in_dev == NULL) + struct in_device *in_dev; + + rcu_read_lock(); + in_dev = __in_dev_get(strip_info->dev); + if (in_dev == NULL) { + rcu_read_unlock(); return NULL; - read_lock(&in_dev->lock); + } if (in_dev->ifa_list) brd = in_dev->ifa_list->ifa_broadcast; - read_unlock(&in_dev->lock); - in_dev_put(in_dev); + rcu_read_unlock(); /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ if (!arp_query(haddr.c, brd, strip_info->dev)) { @@ -1500,17 +1504,18 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) } if (1) { - struct in_device *in_dev = in_dev_get(strip_info->dev); + struct in_device *in_dev; + brd = addr = 0; + rcu_read_lock(); + in_dev = __in_dev_get(strip_info->dev); if (in_dev) { - read_lock(&in_dev->lock); if (in_dev->ifa_list) { brd = in_dev->ifa_list->ifa_broadcast; addr = in_dev->ifa_list->ifa_local; } - read_unlock(&in_dev->lock); - in_dev_put(in_dev); } + rcu_read_unlock(); } @@ -2661,8 +2666,6 @@ static int strip_open(struct tty_struct *tty) tty->disc_data = strip_info; if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); /* * Restore default settings diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 1cbd34ba5..3047d8cfa 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -3822,17 +3822,18 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { u8 dce_status; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", - dev->name, dce_status); -#endif /* * Interrupt from the modem management controller. * This will clear it -- ignored for now. */ mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status)); + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", + dev->name, dce_status); +#endif } /* Check if not controller interrupt */ diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index e5d06ea62..884a53243 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -32,61 +32,65 @@ #include "cpu_buffer.h" #include "buffer_sync.h" -#define DEFAULT_EXPIRE (HZ / 4) - -static void wq_sync_buffers(void *); -static DECLARE_WORK(sync_wq, wq_sync_buffers, NULL); - -static struct timer_list sync_timer; -static void timer_ping(unsigned long data); -static void sync_cpu_buffers(void); +static LIST_HEAD(dying_tasks); +static LIST_HEAD(dead_tasks); +cpumask_t marked_cpus = CPU_MASK_NONE; +static spinlock_t task_mortuary = SPIN_LOCK_UNLOCKED; +void process_task_mortuary(void); - -/* We must make sure to process every entry in the CPU buffers - * before a task got the PF_EXITING flag, otherwise we will hold - * references to a possibly freed task_struct. We are safe with - * samples past the PF_EXITING point in do_exit(), because we - * explicitly check for that in cpu_buffer.c + +/* Take ownership of the task struct and place it on the + * list for processing. Only after two full buffer syncs + * does the task eventually get freed, because by then + * we are sure we will not reference it again. */ -static int exit_task_notify(struct notifier_block * self, unsigned long val, void * data) +static int task_free_notify(struct notifier_block * self, unsigned long val, void * data) { - sync_cpu_buffers(); - return 0; + struct task_struct * task = (struct task_struct *)data; + spin_lock(&task_mortuary); + list_add(&task->tasks, &dying_tasks); + spin_unlock(&task_mortuary); + return NOTIFY_OK; } - -/* There are two cases of tasks modifying task->mm->mmap list we - * must concern ourselves with. First, when a task is about to - * exit (exit_mmap()), we should process the buffer to deal with - * any samples in the CPU buffer, before we lose the ->mmap information - * we need. It is vital to get this case correct, otherwise we can - * end up trying to access a freed task_struct. + + +/* The task is on its way out. A sync of the buffer means we can catch + * any remaining samples for this task. */ -static int mm_notify(struct notifier_block * self, unsigned long val, void * data) +static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data) { - sync_cpu_buffers(); - return 0; + /* To avoid latency problems, we only process the current CPU, + * hoping that most samples for the task are on this CPU + */ + sync_buffer(smp_processor_id()); + return 0; } -/* Second, a task may unmap (part of) an executable mmap, - * so we want to process samples before that happens too. This is merely - * a QOI issue not a correctness one. +/* The task is about to try a do_munmap(). We peek at what it's going to + * do, and if it's an executable region, process the samples first, so + * we don't lose any. This does not have to be exact, it's a QoI issue + * only. */ static int munmap_notify(struct notifier_block * self, unsigned long val, void * data) { - /* Note that we cannot sync the buffers directly, because we might end up - * taking the the mmap_sem that we hold now inside of event_buffer_read() - * on a page fault, whilst holding buffer_sem - deadlock. - * - * This would mean a threaded reader of the event buffer, but we should - * prevent it anyway. - * - * Delaying the work in a context that doesn't hold the mmap_sem means - * that we won't lose samples from other mappings that current() may - * have. Note that either way, we lose any pending samples for what is - * being unmapped. - */ - schedule_work(&sync_wq); + unsigned long addr = (unsigned long)data; + struct mm_struct * mm = current->mm; + struct vm_area_struct * mpnt; + + down_read(&mm->mmap_sem); + + mpnt = find_vma(mm, addr); + if (mpnt && mpnt->vm_file && (mpnt->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + /* To avoid latency problems, we only process the current CPU, + * hoping that most samples for the task are on this CPU + */ + sync_buffer(smp_processor_id()); + return 0; + } + + up_read(&mm->mmap_sem); return 0; } @@ -100,7 +104,7 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v if (val != MODULE_STATE_COMING) return 0; - sync_cpu_buffers(); + /* FIXME: should we process all CPU buffers ? */ down(&buffer_sem); add_event_entry(ESCAPE_CODE); add_event_entry(MODULE_LOADED_CODE); @@ -110,16 +114,16 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v } -static struct notifier_block exit_task_nb = { - .notifier_call = exit_task_notify, +static struct notifier_block task_free_nb = { + .notifier_call = task_free_notify, }; -static struct notifier_block exec_unmap_nb = { - .notifier_call = munmap_notify, +static struct notifier_block task_exit_nb = { + .notifier_call = task_exit_notify, }; -static struct notifier_block exit_mmap_nb = { - .notifier_call = mm_notify, +static struct notifier_block munmap_nb = { + .notifier_call = munmap_notify, }; static struct notifier_block module_load_nb = { @@ -127,11 +131,12 @@ static struct notifier_block module_load_nb = { }; -static void end_sync_timer(void) +static void end_sync(void) { - del_timer_sync(&sync_timer); - /* timer might have queued work, make sure it's completed. */ - flush_scheduled_work(); + end_cpu_work(); + /* make sure we don't leak task structs */ + process_task_mortuary(); + process_task_mortuary(); } @@ -139,18 +144,15 @@ int sync_start(void) { int err; - init_timer(&sync_timer); - sync_timer.function = timer_ping; - sync_timer.expires = jiffies + DEFAULT_EXPIRE; - add_timer(&sync_timer); + start_cpu_work(); - err = profile_event_register(EXIT_TASK, &exit_task_nb); + err = task_handoff_register(&task_free_nb); if (err) goto out1; - err = profile_event_register(EXIT_MMAP, &exit_mmap_nb); + err = profile_event_register(PROFILE_TASK_EXIT, &task_exit_nb); if (err) goto out2; - err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb); + err = profile_event_register(PROFILE_MUNMAP, &munmap_nb); if (err) goto out3; err = register_module_notifier(&module_load_nb); @@ -160,13 +162,13 @@ int sync_start(void) out: return err; out4: - profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); + profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); out3: - profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); + profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); out2: - profile_event_unregister(EXIT_TASK, &exit_task_nb); + task_handoff_unregister(&task_free_nb); out1: - end_sync_timer(); + end_sync(); goto out; } @@ -174,10 +176,10 @@ out1: void sync_stop(void) { unregister_module_notifier(&module_load_nb); - profile_event_unregister(EXIT_TASK, &exit_task_nb); - profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); - profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); - end_sync_timer(); + profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); + profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); + task_handoff_unregister(&task_free_nb); + end_sync(); } @@ -337,40 +339,25 @@ static void add_sample(struct mm_struct * mm, struct op_sample * s, int in_kerne } } - + static void release_mm(struct mm_struct * mm) { - if (mm) - up_read(&mm->mmap_sem); + if (!mm) + return; + up_read(&mm->mmap_sem); + mmput(mm); } -/* Take the task's mmap_sem to protect ourselves from - * races when we do lookup_dcookie(). - */ static struct mm_struct * take_tasks_mm(struct task_struct * task) { - struct mm_struct * mm; - - /* Subtle. We don't need to keep a reference to this task's mm, - * because, for the mm to be freed on another CPU, that would have - * to go through the task exit notifier, which ends up sleeping - * on the buffer_sem we hold, so we end up with mutual exclusion - * anyway. - */ - task_lock(task); - mm = task->mm; - task_unlock(task); - - if (mm) { - /* needed to walk the task's VMAs */ + struct mm_struct * mm = get_task_mm(task); + if (mm) down_read(&mm->mmap_sem); - } - return mm; } - - + + static inline int is_ctx_switch(unsigned long val) { return val == ~0UL; @@ -417,24 +404,80 @@ static void increment_tail(struct oprofile_cpu_buffer * b) } +/* Move tasks along towards death. Any tasks on dead_tasks + * will definitely have no remaining references in any + * CPU buffers at this point, because we use two lists, + * and to have reached the list, it must have gone through + * one full sync already. + */ +void process_task_mortuary(void) +{ + struct list_head * pos; + struct list_head * pos2; + struct task_struct * task; + + spin_lock(&task_mortuary); + + list_for_each_safe(pos, pos2, &dead_tasks) { + task = list_entry(pos, struct task_struct, tasks); + list_del(&task->tasks); + free_task(task); + } + + list_for_each_safe(pos, pos2, &dying_tasks) { + task = list_entry(pos, struct task_struct, tasks); + list_del(&task->tasks); + list_add_tail(&task->tasks, &dead_tasks); + } + + spin_unlock(&task_mortuary); +} + + +static void mark_done(int cpu) +{ + int i; + + cpu_set(cpu, marked_cpus); + + for_each_online_cpu(i) { + if (!cpu_isset(i, marked_cpus)) + return; + } + + /* All CPUs have been processed at least once, + * we can process the mortuary once + */ + process_task_mortuary(); + + cpus_clear(marked_cpus); +} + + /* Sync one of the CPU's buffers into the global event buffer. * Here we need to go through each batch of samples punctuated * by context switch notes, taking the task's mmap_sem and doing * lookup in task->mm->mmap to convert EIP into dcookie/offset * value. */ -static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf) +void sync_buffer(int cpu) { + struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu]; struct mm_struct *mm = NULL; struct task_struct * new; unsigned long cookie = 0; int in_kernel = 1; unsigned int i; + unsigned long available; + + down(&buffer_sem); + add_cpu_switch(cpu); + /* Remember, only we can modify tail_pos */ - unsigned long const available = get_slots(cpu_buf); - + available = get_slots(cpu_buf); + for (i=0; i < available; ++i) { struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos]; @@ -462,50 +505,8 @@ static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf) increment_tail(cpu_buf); } release_mm(mm); -} - - -/* Process each CPU's local buffer into the global - * event buffer. - */ -static void sync_cpu_buffers(void) -{ - int i; - down(&buffer_sem); - - for (i = 0; i < NR_CPUS; ++i) { - struct oprofile_cpu_buffer * cpu_buf; - - if (!cpu_possible(i)) - continue; - - cpu_buf = &cpu_buffer[i]; - - add_cpu_switch(i); - sync_buffer(cpu_buf); - } + mark_done(cpu); up(&buffer_sem); - - mod_timer(&sync_timer, jiffies + DEFAULT_EXPIRE); -} - - -static void wq_sync_buffers(void * data) -{ - sync_cpu_buffers(); -} - - -/* It is possible that we could have no munmap() or - * other events for a period of time. This will lead - * the CPU buffers to overflow and lose samples and - * context switches. We try to reduce the problem - * by timing out when nothing happens for a while. - */ -static void timer_ping(unsigned long data) -{ - schedule_work(&sync_wq); - /* timer is re-added by the scheduled task */ } diff --git a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h index a8def27d8..08866f6a9 100644 --- a/drivers/oprofile/buffer_sync.h +++ b/drivers/oprofile/buffer_sync.h @@ -16,4 +16,7 @@ int sync_start(void); /* remove the hooks */ void sync_stop(void); +/* sync the given CPU's buffer */ +void sync_buffer(int cpu); + #endif /* OPROFILE_BUFFER_SYNC_H */ diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7ee6a3d99..420dc8e83 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -9,7 +9,7 @@ * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. * Eventually each CPU's buffer is processed into the global - * event buffer by sync_cpu_buffers(). + * event buffer by sync_buffer(). * * We use a local buffer for two reasons: an NMI or similar * interrupt cannot synchronise, and high sampling rates @@ -22,21 +22,23 @@ #include #include "cpu_buffer.h" +#include "buffer_sync.h" #include "oprof.h" struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; +static void wq_sync_buffer(void *); + +#define DEFAULT_TIMER_EXPIRE (HZ / 10) +int work_enabled; + static void __free_cpu_buffers(int num) { int i; - for (i=0; i < num; ++i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; - - if (!cpu_possible(i)) - continue; - - vfree(b->buffer); + for_each_online_cpu(i) { + if (cpu_buffer[i].buffer) + vfree(cpu_buffer[i].buffer); } } @@ -47,12 +49,9 @@ int alloc_cpu_buffers(void) unsigned long buffer_size = fs_cpu_buffer_size; - for (i=0; i < NR_CPUS; ++i) { + for_each_online_cpu(i) { struct oprofile_cpu_buffer * b = &cpu_buffer[i]; - if (!cpu_possible(i)) - continue; - b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size); if (!b->buffer) goto fail; @@ -64,9 +63,11 @@ int alloc_cpu_buffers(void) b->head_pos = 0; b->sample_received = 0; b->sample_lost_overflow = 0; - b->sample_lost_task_exit = 0; + b->cpu = i; + INIT_WORK(&b->work, wq_sync_buffer, b); } return 0; + fail: __free_cpu_buffers(i); return -ENOMEM; @@ -79,6 +80,40 @@ void free_cpu_buffers(void) } +void start_cpu_work(void) +{ + int i; + + work_enabled = 1; + + for_each_online_cpu(i) { + struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + + /* + * Spread the work by 1 jiffy per cpu so they dont all + * fire at once. + */ + schedule_delayed_work_on(i, &b->work, DEFAULT_TIMER_EXPIRE + i); + } +} + + +void end_cpu_work(void) +{ + int i; + + work_enabled = 0; + + for_each_online_cpu(i) { + struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + + cancel_delayed_work(&b->work); + } + + flush_scheduled_work(); +} + + /* compute number of available slots in cpu_buffer queue */ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) { @@ -145,21 +180,9 @@ void oprofile_add_sample(unsigned long eip, unsigned int is_kernel, /* notice a task switch */ if (cpu_buf->last_task != task) { cpu_buf->last_task = task; - if (!(task->flags & PF_EXITING)) { - cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; - cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task; - increment_head(cpu_buf); - } - } - - /* If the task is exiting it's not safe to take a sample - * as the task_struct is about to be freed. We can't just - * notify at release_task() time because of CLONE_DETACHED - * tasks that release_task() themselves. - */ - if (task->flags & PF_EXITING) { - cpu_buf->sample_lost_task_exit++; - return; + cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; + cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task; + increment_head(cpu_buf); } cpu_buf->buffer[cpu_buf->head_pos].eip = eip; @@ -178,3 +201,25 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) cpu_buf->last_is_kernel = -1; cpu_buf->last_task = NULL; } + + +/* + * This serves to avoid cpu buffer overflow, and makes sure + * the task mortuary progresses + * + * By using schedule_delayed_work_on and then schedule_delayed_work + * we guarantee this will stay on the correct cpu + */ +static void wq_sync_buffer(void * data) +{ + struct oprofile_cpu_buffer * b = (struct oprofile_cpu_buffer *)data; + if (b->cpu != smp_processor_id()) { + printk("WQ on CPU%d, prefer CPU%d\n", + smp_processor_id(), b->cpu); + } + sync_buffer(b->cpu); + + /* don't re-add the work if we're shutting down */ + if (work_enabled) + schedule_delayed_work(&b->work, DEFAULT_TIMER_EXPIRE); +} diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 66eafcdb1..23be2013a 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -12,15 +12,17 @@ #include #include +#include #include struct task_struct; -/* allocate a sample buffer for each CPU */ int alloc_cpu_buffers(void); - void free_cpu_buffers(void); +void start_cpu_work(void); +void end_cpu_work(void); + /* CPU buffer is composed of such entries (which are * also used for context switch notes) */ @@ -38,11 +40,12 @@ struct oprofile_cpu_buffer { struct op_sample * buffer; unsigned long sample_received; unsigned long sample_lost_overflow; - unsigned long sample_lost_task_exit; + int cpu; + struct work_struct work; } ____cacheline_aligned; extern struct oprofile_cpu_buffer cpu_buffer[]; -void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf); +void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); #endif /* OPROFILE_CPU_BUFFER_H */ diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 8e92b0388..3ec23d8a6 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -22,14 +22,10 @@ void oprofile_reset_stats(void) struct oprofile_cpu_buffer * cpu_buf; int i; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_possible(i)) - continue; - + for_each_cpu(i) { cpu_buf = &cpu_buffer[i]; cpu_buf->sample_received = 0; cpu_buf->sample_lost_overflow = 0; - cpu_buf->sample_lost_task_exit = 0; } atomic_set(&oprofile_stats.sample_lost_no_mm, 0); @@ -50,10 +46,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) if (!dir) return; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_possible(i)) - continue; - + for_each_cpu(i) { cpu_buf = &cpu_buffer[i]; snprintf(buf, 10, "cpu%d", i); cpudir = oprofilefs_mkdir(sb, dir, buf); @@ -66,8 +59,6 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) &cpu_buf->sample_received); oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_overflow", &cpu_buf->sample_lost_overflow); - oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_task_exit", - &cpu_buf->sample_lost_task_exit); } oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm", diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 3fae2c772..5f0318908 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -19,7 +19,7 @@ static int timer_notify(struct notifier_block * self, unsigned long val, void * { struct pt_regs * regs = (struct pt_regs *)data; int cpu = smp_processor_id(); - unsigned long eip = instruction_pointer(regs); + unsigned long eip = profile_pc(regs); oprofile_add_sample(eip, !user_mode(regs), 0, cpu); return 0; diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index 6e67ea060..45f2be4cc 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -11,7 +11,7 @@ * (at your option) any later version. * * by Alan Cox and - * Alex deVries + * Alex deVries */ #include diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 6357ec10e..0e1426ccd 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 - * (C) Copyright 2000 Alex deVries + * (C) Copyright 2000 Alex deVries * (C) Copyright 2001 John Marvin * (C) Copyright 2003 Grant Grundler * @@ -484,6 +484,7 @@ void superio_fixup_pci(struct pci_dev *pdev) pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci); /* Because of a defect in Super I/O, all reads of the PCI DMA status * registers, IDE status register and the IDE select register need to be diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index dfc8a8404..5b550ab81 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1194,7 +1194,7 @@ struct parport_operations parport_pc_ops = #ifdef CONFIG_PARPORT_PC_SUPERIO /* Super-IO chipset detection, Winbond, SMSC */ -static void __devinit show_parconfig_smsc37c669(int io, int key) +static int __devinit show_parconfig_smsc37c669(int io, int key) { int cr1,cr4,cra,cr23,cr26,cr27,i=0; static const char *modes[]={ "SPP and Bidirectional (PS/2)", @@ -1261,17 +1261,26 @@ static void __devinit show_parconfig_smsc37c669(int io, int key) superios[i].io = 0x278; superios[i].irq = 5; } + if (io != superios[i].io) { + /* how many bytes? */ + if (!request_region(superios[i].io, 3, "smsc parport")) { + superios[i].io = 0; + return 0; + } + } d=(cr26 &0x0f); if((d==1) || (d==3)) superios[i].dma= d; else superios[i].dma= PARPORT_DMA_NONE; + return 1; } } + return 0; } -static void __devinit show_parconfig_winbond(int io, int key) +static int __devinit show_parconfig_winbond(int io, int key) { int cr30,cr60,cr61,cr70,cr74,crf0,i=0; static const char *modes[] = { @@ -1327,14 +1336,23 @@ static void __devinit show_parconfig_winbond(int io, int key) printk(KERN_INFO "Super-IO: too many chips!\n"); else { superios[i].io = (cr60<<8)|cr61; + if (io != superios[i].io) { + /* how many bytes? */ + if (!request_region(superios[i].io, 3, "winbond parport")) { + superios[i].io = 0; + return 0; + } + } superios[i].irq = cr70&0x0f; superios[i].dma = (((cr74 & 0x07) > 3) ? PARPORT_DMA_NONE : (cr74 & 0x07)); + return 1; } } + return 0; } -static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) +static int __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) { const char *type = "unknown"; int id,progif=2; @@ -1342,7 +1360,7 @@ static void __devinit decode_winbond(int efer, int key, int devid, int devrev, i if (devid == devrev) /* simple heuristics, we happened to read some non-winbond register */ - return; + return 0; id=(devid<<8) | devrev; @@ -1367,19 +1385,20 @@ static void __devinit decode_winbond(int efer, int key, int devid, int devrev, i efer, key, devid, devrev, oldid, type); if (progif == 2) - show_parconfig_winbond(efer,key); + return show_parconfig_winbond(efer,key); + return 0; } -static void __devinit decode_smsc(int efer, int key, int devid, int devrev) +static int __devinit decode_smsc(int efer, int key, int devid, int devrev) { const char *type = "unknown"; - void (*func)(int io, int key); + int (*func)(int io, int key); int id; if (devid == devrev) /* simple heuristics, we happened to read some non-smsc register */ - return; + return 0; func=NULL; id=(devid<<8) | devrev; @@ -1395,7 +1414,8 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev) efer, key, devid, devrev, type); if (func) - func(efer,key); + return func(efer,key); + return 0; } @@ -1403,6 +1423,9 @@ static void __devinit winbond_check(int io, int key) { int devid,devrev,oldid,x_devid,x_devrev,x_oldid; + if (!request_region(io, 3, __FUNCTION__)) + return; + /* First probe without key */ outb(0x20,io); x_devid=inb(io+1); @@ -1423,15 +1446,21 @@ static void __devinit winbond_check(int io, int key) outb(0xaa,io); /* Magic Seal */ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) - return; /* protection against false positives */ + goto out; /* protection against false positives */ - decode_winbond(io,key,devid,devrev,oldid); + if (decode_winbond(io,key,devid,devrev,oldid)); + return; +out: + release_region(io, 3); } static void __devinit winbond_check2(int io,int key) { int devid,devrev,oldid,x_devid,x_devrev,x_oldid; + if (!request_region(io, 3, __FUNCTION__)) + return; + /* First probe without the key */ outb(0x20,io+2); x_devid=inb(io+2); @@ -1451,15 +1480,21 @@ static void __devinit winbond_check2(int io,int key) outb(0xaa,io); /* Magic Seal */ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) - return; /* protection against false positives */ + goto out; /* protection against false positives */ - decode_winbond(io,key,devid,devrev,oldid); + if (decode_winbond(io,key,devid,devrev,oldid)) + return; +out: + release_region(io, 3); } static void __devinit smsc_check(int io, int key) { int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev; + if (!request_region(io, 3, __FUNCTION__)) + return; + /* First probe without the key */ outb(0x0d,io); x_oldid=inb(io+1); @@ -1485,9 +1520,12 @@ static void __devinit smsc_check(int io, int key) if ((x_id == id) && (x_oldrev == oldrev) && (x_oldid == oldid) && (x_rev == rev)) - return; /* protection against false positives */ + goto out; /* protection against false positives */ - decode_smsc(io,key,oldid,oldrev); + if (decode_smsc(io,key,oldid,oldrev)) + return; +out: + release_region(io, 3); } @@ -2636,6 +2674,10 @@ enum parport_pc_pci_cards { netmos_9805, netmos_9815, netmos_9855, + netmos_9735, + netmos_9835, + netmos_9755, + netmos_9715 }; @@ -2709,6 +2751,10 @@ static struct parport_pc_pci { /* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */ /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */ /* netmos_9855 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */ + /* netmos_9735 */ { 1, { { 2, 3 }, } }, /* untested */ + /* netmos_9835 */ { 1, { { 2, 3 }, } }, /* untested */ + /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ + /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ }; static struct pci_device_id parport_pc_pci_tbl[] = { @@ -2786,6 +2832,14 @@ static struct pci_device_id parport_pc_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 377c7238c..474eacd34 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -35,7 +35,7 @@ ifndef CONFIG_X86 obj-y += syscall.o endif -host-progs := gen-devlist +hostprogs-y := gen-devlist # Dependencies on generated files need to be listed explicitly $(obj)/names.o: $(obj)/devlist.h $(obj)/classlist.h diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 3dc99c18a..9117a95a3 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -88,6 +88,18 @@ config HOTPLUG_PCI_ACPI When in doubt, say N. +config HOTPLUG_PCI_ACPI_IBM + tristate "ACPI PCI Hotplug driver IBM extensions" + depends on HOTPLUG_PCI_ACPI + help + Say Y here if you have an IBM system that supports PCI Hotplug using + ACPI. + + To compile this driver as a module, choose M here: the + module will be called acpiphp_ibm. + + When in doubt, say N. + config HOTPLUG_PCI_CPCI bool "CompactPCI Hotplug driver" depends on HOTPLUG_PCI diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index a972757a0..4fc3ed9b8 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 670c874fe..d9499874c 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -171,6 +171,18 @@ struct acpiphp_func { struct pci_resource *bus_head; }; +/** + * struct acpiphp_attention_info - device specific attention registration + * + * ACPI has no generic method of setting/getting attention status + * this allows for device specific driver registration + */ +struct acpiphp_attention_info +{ + int (*set_attn)(struct hotplug_slot *slot, u8 status); + int (*get_attn)(struct hotplug_slot *slot, u8 *status); + struct module *owner; +}; /* PCI bus bridge HID */ #define ACPI_PCI_HOST_HID "PNP0A03" @@ -212,6 +224,10 @@ struct acpiphp_func { /* function prototypes */ +/* acpiphp_core.c */ +extern int acpiphp_register_attention(struct acpiphp_attention_info*info); +extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info); + /* acpiphp_glue.c */ extern int acpiphp_glue_init (void); extern void acpiphp_glue_exit (void); diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index fb4155ad7..4539e61a3 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -51,6 +51,7 @@ int acpiphp_debug; /* local variables */ static int num_slots; +static struct acpiphp_attention_info *attention_info; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " @@ -60,12 +61,17 @@ 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); +EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); static int set_attention_status (struct hotplug_slot *slot, u8 value); static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_address (struct hotplug_slot *slot, u32 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); @@ -76,11 +82,54 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = { .disable_slot = disable_slot, .set_attention_status = set_attention_status, .get_power_status = get_power_status, + .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, .get_address = get_address, }; + +/** + * acpiphp_register_attention - set attention LED callback + * @info: must be completely filled with LED callbacks + * + * Description: this is used to register a hardware specific ACPI + * driver that manipulates the attention LED. All the fields in + * info must be set. + **/ +int acpiphp_register_attention(struct acpiphp_attention_info *info) +{ + int retval = -EINVAL; + + if (info && info->owner && info->set_attn && + info->get_attn && !attention_info) { + retval = 0; + attention_info = info; + } + return retval; +} + + +/** + * acpiphp_unregister_attention - unset attention LED callback + * @info: must match the pointer used to register + * + * Description: this is used to un-register a hardware specific acpi + * driver that manipulates the attention LED. The pointer to the + * info struct must be the same as the one used to set it. + **/ +int acpiphp_unregister_attention(struct acpiphp_attention_info *info) +{ + int retval = -EINVAL; + + if (info && attention_info == info) { + attention_info = NULL; + retval = 0; + } + return retval; +} + + /** * enable_slot - power on and enable a slot * @hotplug_slot: slot to enable @@ -117,33 +166,29 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) } -/** - * set_attention_status - set attention LED + /** + * set_attention_status - set attention LED + * @hotplug_slot: slot to set attention LED on + * @status: value to set attention LED to (0 or 1) * - * TBD: - * ACPI doesn't have known method to manipulate - * attention status LED. - * - */ -static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) -{ - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - switch (status) { - case 0: - /* FIXME turn light off */ - hotplug_slot->info->attention_status = 0; - break; - - case 1: - default: - /* FIXME turn light on */ - hotplug_slot->info->attention_status = 1; - break; - } - - return 0; -} + * attention status LED, so we use a callback that + * was registered with us. This allows hardware specific + * ACPI implementations to blink the light for us. + **/ + static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) + { + int retval = -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + if (attention_info && try_module_get(attention_info->owner)) { + retval = attention_info->set_attn(hotplug_slot, status); + module_put(attention_info->owner); + } else + attention_info = NULL; + return retval; + } + /** * get_power_status - get power status of a slot @@ -165,6 +210,32 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } + + /** + * get_attention_status - get attention LED status + * @hotplug_slot: slot to get status from + * @value: returns with value of attention LED + * + * ACPI doesn't have known method to determine the state + * of the attention status LED, so we use a callback that + * was registered with us. This allows hardware specific + * ACPI implementations to determine its state + **/ +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) +{ + int retval = -EINVAL; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + if (attention_info && try_module_get(attention_info->owner)) { + retval = attention_info->get_attn(hotplug_slot, value); + module_put(attention_info->owner); + } else + attention_info = NULL; + return retval; +} + + /** * get_latch_status - get latch status of a slot * @hotplug_slot: slot to get status @@ -307,7 +378,7 @@ static int __init init_slots(void) slot->acpi_slot = get_slot_from_id(i); slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); - slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = 0; slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d41795bb6..e400e4acc 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1301,20 +1301,6 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) } -/* - * attention LED ON: 1 - * OFF: 0 - * - * TBD - * no direct attention led status information via ACPI - * - */ -u8 acpiphp_get_attention_status(struct acpiphp_slot *slot) -{ - return 0; -} - - /* * latch closed: 1 * latch open: 0 diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c new file mode 100644 index 000000000..fe7866c1c --- /dev/null +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -0,0 +1,474 @@ +/* + * ACPI PCI Hot Plug IBM Extension + * + * Copyright (C) 2004 Vernon Mauery + * Copyright (C) 2004 IBM Corp. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acpiphp.h" +#include "pci_hotplug.h" + +#define DRIVER_VERSION "1.0.1" +#define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery " +#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension" + +static int debug; + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); +module_param(debug, bool, 644); +MODULE_PARM_DESC(debug, " Debugging mode enabled or not"); +#define MY_NAME "acpiphp_ibm" + +#undef dbg +#define dbg(format, arg...) \ +do { \ + if (debug) \ + printk(KERN_DEBUG "%s: " format, \ + MY_NAME , ## arg); \ +} while (0) + +#define FOUND_APCI 0x61504349 +/* these are the names for the IBM ACPI pseudo-device */ +#define IBM_HARDWARE_ID1 "IBM37D0" +#define IBM_HARDWARE_ID2 "IBM37D4" + +/* union apci_descriptor - allows access to the + * various device descriptors that are embedded in the + * aPCI table + */ +union apci_descriptor { + struct { + char sig[4]; + u8 len; + } header; + struct { + u8 type; + u8 len; + u16 slot_id; + u8 bus_id; + u8 dev_num; + u8 slot_num; + u8 slot_attr[2]; + u8 attn; + u8 status[2]; + u8 sun; + } slot; + struct { + u8 type; + u8 len; + } generic; +}; + +/* struct notification - keeps info about the device + * that cause the ACPI notification event + */ +struct notification { + struct acpi_device *device; + u8 event; +}; + +static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status); +static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status); +static void ibm_handle_events(acpi_handle handle, u32 event, void *context); +static int ibm_get_table_from_acpi(char **bufp); +static ssize_t ibm_read_apci_table(struct kobject *kobj, + char *buffer, loff_t pos, size_t size); +static acpi_status __init ibm_find_acpi_device(acpi_handle handle, + u32 lvl, void *context, void **rv); +static int __init ibm_acpiphp_init(void); +static void __exit ibm_acpiphp_exit(void); + +static acpi_handle ibm_acpi_handle; +static struct notification ibm_note; +static struct bin_attribute ibm_apci_table_attr = { + .attr = { + .name = "apci_table", + .owner = THIS_MODULE, + .mode = S_IRUGO, + }, + .read = ibm_read_apci_table, + .write = NULL, +}; +static struct acpiphp_attention_info ibm_attention_info = +{ + .set_attn = ibm_set_attention_status, + .get_attn = ibm_get_attention_status, + .owner = THIS_MODULE, +}; + + +/** + * ibm_set_attention_status - callback method to set the attention LED + * @slot: the hotplug_slot to work with + * @status: what to set the LED to (0 or 1) + * + * Description: this method is registered with the acpiphp module as a + * callback to do the device specific task of setting the LED status + **/ +static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status) +{ + int retval = 0; + union acpi_object args[2]; + struct acpi_object_list params = { .pointer = args, .count = 2 }; + acpi_status stat; + unsigned long rc = 0; + struct acpiphp_slot *acpi_slot; + + acpi_slot = ((struct slot *)(slot->private))->acpi_slot; + + dbg("%s: set slot %d attention status to %d\n", __FUNCTION__, + acpi_slot->sun, (status ? 1 : 0)); + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = acpi_slot->sun; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = (status) ? 1 : 0; + + stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", ¶ms, &rc); + if (ACPI_FAILURE(stat)) { + retval = -ENODEV; + err("APLS evaluation failed: 0x%08x\n", stat); + } else if (!rc) { + retval = -ERANGE; + err("APLS method failed: 0x%08lx\n", rc); + } + return retval; +} + +/** + * ibm_get_attention_status - callback method to get attention LED status + * @slot: the hotplug_slot to work with + * @status: returns what the LED is set to (0 or 1) + * + * Description: this method is registered with the acpiphp module as a + * callback to do the device specific task of getting the LED status + * + * Because there is no direct method of getting the LED status directly + * from an ACPI call, we read the aPCI table and parse out our + * slot descriptor to read the status from that. + **/ +static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status) +{ + int retval = -EINVAL, ind = 0, size; + char *table = NULL; + struct acpiphp_slot *acpi_slot; + union apci_descriptor *des; + + acpi_slot = ((struct slot *)(slot->private))->acpi_slot; + + size = ibm_get_table_from_acpi(&table); + if (size <= 0 || !table) + goto get_attn_done; + // read the header + des = (union apci_descriptor *)&table[ind]; + if (memcmp(des->header.sig, "aPCI", 4) != 0) + goto get_attn_done; + des = (union apci_descriptor *)&table[ind += des->header.len]; + while (ind < size && (des->generic.type != 0x82 || + des->slot.slot_id != acpi_slot->sun)) + des = (union apci_descriptor *)&table[ind += des->generic.len]; + if (ind < size && des->slot.slot_id == acpi_slot->sun) { + retval = 0; + if (des->slot.attn & 0xa0 || des->slot.status[1] & 0x08) + *status = 1; + else + *status = 0; + } + + dbg("%s: get slot %d attention status is %d retval=%x\n", + __FUNCTION__, acpi_slot->sun, *status, retval); + +get_attn_done: + kfree(table); + return retval; +} + +/** + * ibm_handle_events - listens for ACPI events for the IBM37D0 device + * @handle: an ACPI handle to the device that caused the event + * @event: the event info (device specific) + * @context: passed context (our notification struct) + * + * Description: this method is registered as a callback with the ACPI + * subsystem it is called when this device has an event to notify the OS of + * + * The events actually come from the device as two events that get + * synthesized into one event with data by this function. The event + * ID comes first and then the slot number that caused it. We report + * this as one event to the OS. + * + * From section 5.6.2.2 of the ACPI 2.0 spec, I understand that the OSPM will + * only re-enable the interrupt that causes this event AFTER this method + * has returned, thereby enforcing serial access for the notification struct. + **/ +static void ibm_handle_events(acpi_handle handle, u32 event, void *context) +{ + u8 detail = event & 0x0f; + u8 subevent = event & 0xf0; + struct notification *note = context; + + dbg("%s: Received notification %02x\n", __FUNCTION__, event); + + if (subevent == 0x80) { + dbg("%s: generationg bus event\n", __FUNCTION__); + acpi_bus_generate_event(note->device, note->event, detail); + } else + note->event = event; +} + +/** + * ibm_get_table_from_acpi - reads the APLS buffer from ACPI + * @bufp: address to pointer to allocate for the table + * + * Description: this method reads the APLS buffer in from ACPI and + * stores the "stripped" table into a single buffer + * it allocates and passes the address back in bufp + * + * If NULL is passed in as buffer, this method only calculates + * the size of the table and returns that without filling + * in the buffer + * + * returns < 0 on error or the size of the table on success + **/ +static int ibm_get_table_from_acpi(char **bufp) +{ + union acpi_object *package; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + char *lbuf = NULL; + int i, size = -EIO; + + status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer); + if (ACPI_FAILURE(status)) { + err("%s: APCI evaluation failed\n", __FUNCTION__); + return -ENODEV; + } + + package = (union acpi_object *) buffer.pointer; + if(!(package) || + (package->type != ACPI_TYPE_PACKAGE) || + !(package->package.elements)) { + err("%s: Invalid APCI object\n", __FUNCTION__); + goto read_table_done; + } + + for(size = 0, i = 0; i < package->package.count; i++) { + if (package->package.elements[i].type != ACPI_TYPE_BUFFER) { + err("%s: Invalid APCI element %d\n", __FUNCTION__, i); + goto read_table_done; + } + size += package->package.elements[i].buffer.length; + } + + if (bufp == NULL) + goto read_table_done; + + lbuf = kmalloc(size, GFP_KERNEL); + dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n", + __FUNCTION__, package->package.count, size, lbuf); + + if (lbuf) { + *bufp = lbuf; + memset(lbuf, 0, size); + } else { + size = -ENOMEM; + goto read_table_done; + } + + size = 0; + for (i=0; ipackage.count; i++) { + memcpy(&lbuf[size], + package->package.elements[i].buffer.pointer, + package->package.elements[i].buffer.length); + size += package->package.elements[i].buffer.length; + } + +read_table_done: + kfree(buffer.pointer); + return size; +} + +/** + * ibm_read_apci_table - callback for the sysfs apci_table file + * @kobj: the kobject this binary attribute is a part of + * @buffer: the kernel space buffer to fill + * @pos: the offset into the file + * @size: the number of bytes requested + * + * Description: gets registered with sysfs as the reader callback + * to be executed when /sys/bus/pci/slots/apci_table gets read + * + * Since we don't get notified on open and close for this file, + * things get really tricky here... + * our solution is to only allow reading the table in all at once + **/ +static ssize_t ibm_read_apci_table(struct kobject *kobj, + char *buffer, loff_t pos, size_t size) +{ + int bytes_read = -EINVAL; + char *table = NULL; + + dbg("%s: pos = %d, size = %zd\n", __FUNCTION__, (int)pos, size); + + if (pos == 0) { + bytes_read = ibm_get_table_from_acpi(&table); + if (bytes_read > 0 && bytes_read <= size) + memcpy(buffer, table, bytes_read); + kfree(table); + } + return bytes_read; +} + +/** + * ibm_find_acpi_device - callback to find our ACPI device + * @handle: the ACPI handle of the device we are inspecting + * @lvl: depth into the namespace tree + * @context: a pointer to our handle to fill when we find the device + * @rv: a return value to fill if desired + * + * Description: used as a callback when calling acpi_walk_namespace + * to find our device. When this method returns non-zero + * acpi_walk_namespace quits its search and returns our value + **/ +static acpi_status __init ibm_find_acpi_device(acpi_handle handle, + u32 lvl, void *context, void **rv) +{ + acpi_handle *phandle = (acpi_handle *)context; + acpi_status status; + struct acpi_device_info info; + struct acpi_buffer info_buffer = { + .length = sizeof(struct acpi_device_info), + .pointer = &info, + }; + + status = acpi_get_object_info(handle, &info_buffer); + if (ACPI_FAILURE(status)) { + err("%s: Failed to get device information", __FUNCTION__); + return 0; + } + info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0'; + + if(info.current_status && (info.valid & ACPI_VALID_HID) && + (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) || + !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) { + dbg("found hardware: %s, handle: %p\n", info.hardware_id.value, + handle); + *phandle = handle; + /* returning non-zero causes the search to stop + * and returns this value to the caller of + * acpi_walk_namespace, but it also causes some warnings + * in the acpi debug code to print... + */ + return FOUND_APCI; + } + return 0; +} + +static int __init ibm_acpiphp_init(void) +{ + int retval = 0; + acpi_status status; + struct acpi_device *device; + struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; + + dbg("%s\n", __FUNCTION__); + + if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, ibm_find_acpi_device, + &ibm_acpi_handle, NULL) != FOUND_APCI) { + err("%s: acpi_walk_namespace failed\n", __FUNCTION__); + retval = -ENODEV; + goto init_return; + } + dbg("%s: found IBM aPCI device\n", __FUNCTION__); + if (acpi_bus_get_device(ibm_acpi_handle, &device)) { + err("%s: acpi_bus_get_device failed\n", __FUNCTION__); + retval = -ENODEV; + goto init_return; + } + if (acpiphp_register_attention(&ibm_attention_info)) { + retval = -ENODEV; + goto init_return; + } + + ibm_note.device = device; + status = acpi_install_notify_handler( + ibm_acpi_handle, + ACPI_DEVICE_NOTIFY, + ibm_handle_events, + &ibm_note); + if (ACPI_FAILURE(status)) { + err("%s: Failed to register notification handler\n", + __FUNCTION__); + retval = -EBUSY; + goto init_cleanup; + } + + ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL); + retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr); + + return retval; + +init_cleanup: + acpiphp_unregister_attention(&ibm_attention_info); +init_return: + return retval; +} + +static void __exit ibm_acpiphp_exit(void) +{ + acpi_status status; + struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; + + dbg("%s\n", __FUNCTION__); + + if (acpiphp_unregister_attention(&ibm_attention_info)) + err("%s: attention info deregistration failed", __FUNCTION__); + + status = acpi_remove_notify_handler( + ibm_acpi_handle, + ACPI_DEVICE_NOTIFY, + ibm_handle_events); + if (ACPI_FAILURE(status)) + err("%s: Notification handler removal failed\n", + __FUNCTION__); + // remove the /sys entries + if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr)) + err("%s: removal of sysfs file apci_table failed\n", + __FUNCTION__); +} + +module_init(ibm_acpiphp_init); +module_exit(ibm_acpiphp_exit); diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 868623fd6..ed243605d 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "pci_hotplug.h" #include "cpci_hotplug.h" @@ -513,11 +514,10 @@ event_thread(void *data) break; while(controller->ops->query_enum()) { rc = check_slots(); - if(rc > 0) { + if (rc > 0) /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { + msleep(500); + else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; @@ -568,11 +568,10 @@ poll_thread(void *data) while(controller->ops->query_enum()) { rc = check_slots(); - if(rc > 0) { + if(rc > 0) /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { + msleep(500); + else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; @@ -595,8 +594,7 @@ poll_thread(void *data) } } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + msleep(100); } dbg("poll thread signals exit"); up(&thread_exit); diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index cb54fa8ab..0a01b0710 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 aa8a1a4d7..13d147989 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/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index b24b8cd45..b42346b02 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -759,11 +759,5 @@ extern int ibmphp_configure_card (struct pci_func *, u8); extern int ibmphp_unconfigure_card (struct slot **, int); extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; -static inline void long_delay (int delay) -{ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (delay); -} - #endif //__IBMPHP_H diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 89354eb0a..1307f7adc 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -190,7 +190,7 @@ static inline int power_on (struct slot *slot_cur) err ("command not completed successfully in power_on\n"); return -EIO; } - long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ + msleep(3000); /* For ServeRAID cards, and some 66 PCI */ return 0; } @@ -913,7 +913,7 @@ static int set_bus (struct slot * slot_cur) } /* This is for x440, once Brandon fixes the firmware, will not need this delay */ - long_delay (1 * HZ); + msleep(1000); debug ("%s -Exit\n", __FUNCTION__); return 0; } diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index 105dc70e6..04459b7c2 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -205,7 +206,7 @@ static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) // READ - step 4 : wait until start operation bit clears i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -221,7 +222,7 @@ static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) // READ - step 5 : read I2C status register i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -316,7 +317,7 @@ static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, // WRITE - step 4 : wait until start operation bit clears i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -333,7 +334,7 @@ static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, // WRITE - step 5 : read I2C status register i = CMD_COMPLETE_TOUT_SEC; while (i) { - long_delay (1 * HZ / 100); + msleep(10); wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -748,7 +749,7 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) done = TRUE; } if (!done) { - long_delay (1 * HZ); + msleep(1000); if (timeout < 1) { done = TRUE; err ("%s - Error command complete timeout\n", __FUNCTION__); @@ -891,7 +892,7 @@ static void poll_hpc (void) case POLL_SLEEP: /* don't sleep with a lock on the hardware */ up (&semOperations); - long_delay (POLL_INTERVAL_SEC * HZ); + msleep(POLL_INTERVAL_SEC * 1000); if (ibmphp_shutdown) break; @@ -908,8 +909,7 @@ static void poll_hpc (void) /* give up the harware semaphore */ up (&semOperations); /* sleep for a short time just for good measure */ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (HZ/10); + msleep(100); } up (&sem_exit); debug ("%s - Exit\n", __FUNCTION__); @@ -974,7 +974,7 @@ static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) if (SLOT_PWRGD (pslot->status)) { // power goes on and off after closing latch // check again to make sure power is still ON - long_delay (1 * HZ); + msleep(1000); rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); if (SLOT_PWRGD (status)) update = TRUE; @@ -1147,7 +1147,7 @@ static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, v if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) done = TRUE; if (!done) { - long_delay (1 * HZ); + msleep(1000); if (timeout < 1) { done = TRUE; err ("HPCreadslot - Error ctlr timeout\n"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 039213c29..dff5d88b7 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 b31ccbcea..9df420db2 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/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index cb0804b2d..b8ca99b42 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1017,7 +1017,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value) +static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pcie_link_speed lnk_speed; @@ -1120,7 +1120,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value return retval; } -static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value) +static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index f413495a2..6605d6bda 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/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index dd6dcdc73..1e679730d 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -54,8 +54,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -void eeh_register_disable_func(int (*)(struct pci_dev *)); - module_param(debug, bool, 0644); static int enable_slot(struct hotplug_slot *slot); @@ -407,18 +405,12 @@ static int __init rpaphp_init(void) { info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - /* let EEH know they can use hotplug */ - eeh_register_disable_func(&rpaphp_disable_slot); - /* read all the PRA info from the system */ return init_rpa(); } static void __exit rpaphp_exit(void) { - /* let EEH know we are going away */ - eeh_register_disable_func(NULL); - cleanup_slots(); } @@ -457,7 +449,7 @@ static int rpaphp_disable_slot(struct pci_dev *dev) static int disable_slot(struct hotplug_slot *hotplug_slot) { - int retval; + int retval = -EINVAL; struct slot *slot = (struct slot *)hotplug_slot->private; dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name); diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 0dd2d2369..76d722f34 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -186,7 +186,7 @@ static struct pci_dev * rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus) { struct device_node *eads_first_child = dn->child; - struct pci_dev *dev; + struct pci_dev *dev = NULL; int num; dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); @@ -341,7 +341,6 @@ exit: return rc; } - static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) { eeh_remove_device(dev); @@ -363,7 +362,7 @@ static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) int rpaphp_unconfig_pci_adapter(struct slot *slot) { int retval = 0; - struct list_head *ln; + struct list_head *ln, *tmp; dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); if (list_empty(&slot->dev.pci_funcs)) { @@ -374,7 +373,7 @@ int rpaphp_unconfig_pci_adapter(struct slot *slot) goto exit; } /* remove the devices from the pci core */ - list_for_each (ln, &slot->dev.pci_funcs) { + list_for_each_safe (ln, tmp, &slot->dev.pci_funcs) { struct rpaphp_pci_func *func; func = list_entry(ln, struct rpaphp_pci_func, sibling); @@ -430,10 +429,26 @@ static int setup_pci_slot(struct slot *slot) __FUNCTION__, slot->name); goto exit_rc; } - if (init_slot_pci_funcs(slot)) { - err("%s: init_slot_pci_funcs failed\n", __FUNCTION__); + + if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { + dbg("%s CONFIGURING pci adapter in slot[%s]\n", + __FUNCTION__, slot->name); + if (rpaphp_config_pci_adapter(slot)) { + err("%s: CONFIG pci adapter failed\n", __FUNCTION__); + goto exit_rc; + } + } else if (slot->hotplug_slot->info->adapter_status == CONFIGURED) { + if (init_slot_pci_funcs(slot)) { + err("%s: init_slot_pci_funcs failed\n", __FUNCTION__); + goto exit_rc; + } + + } else { + err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", + __FUNCTION__, slot->name); goto exit_rc; } + print_slot_pci_funcs(slot); if (!list_empty(&slot->dev.pci_funcs)) { slot->state = CONFIGURED; diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index c58541add..8519b9d05 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -244,7 +244,7 @@ int register_slot(struct slot *slot) int rpaphp_get_power_status(struct slot *slot, u8 * value) { - int rc = 0; + int rc = 0, level; if (slot->type == EMBEDDED) { dbg("%s set to POWER_ON for EMBEDDED slot %s\n", @@ -252,10 +252,14 @@ int rpaphp_get_power_status(struct slot *slot, u8 * value) *value = POWER_ON; } else { - rc = rtas_get_power_level(slot->power_domain, (int *) value); - if (rc) + rc = rtas_get_power_level(slot->power_domain, &level); + if (!rc) { + dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", + __FUNCTION__, slot->name, slot->power_domain, level); + *value = level; + } else err("failed to get power-level for slot(%s), rc=0x%x\n", - slot->location, rc); + slot->location, rc); } return rc; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 7f34ec941..4f7a11d87 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/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 7ca8e9369..d71925c26 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -2163,12 +2163,14 @@ int shpchp_disable_slot (struct slot *p_slot) u32 rc = 0; int ret = 0; unsigned int devfn; - struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate; + struct pci_bus *pci_bus; struct pci_func *func; if (!p_slot->ctrl) return 1; + pci_bus = p_slot->ctrl->pci_dev->subordinate; + /* Check to see if (latch closed, card present, power on) */ down(&p_slot->ctrl->crit_sect); diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index b1fab4532..752d72575 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "shpchp.h" @@ -300,8 +301,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) if (!(cmd_status & 0x1)) break; /* Check every 0.1 sec for a total of 1 sec*/ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); } cmd_status = readw(php_ctlr->creg + CMD_STATUS); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 9936879eb..64195d6d6 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -299,10 +299,23 @@ static int pci_device_suspend(struct device * dev, u32 state) { struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; + u32 dev_state; int i = 0; + /* Translate PM_SUSPEND_xx states to PCI device states */ + static u32 state_conversion[] = { + [PM_SUSPEND_ON] = 0, + [PM_SUSPEND_STANDBY] = 1, + [PM_SUSPEND_MEM] = 3, + [PM_SUSPEND_DISK] = 3, + }; + + if (state >= sizeof(state_conversion) / sizeof(state_conversion[1])) + return -EINVAL; + + dev_state = state_conversion[state]; if (drv && drv->suspend) - i = drv->suspend(pci_dev,state); + i = drv->suspend(pci_dev, dev_state); pci_save_state(pci_dev, pci_dev->saved_config_space); return i; @@ -390,10 +403,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/pci.c b/drivers/pci/pci.c index 05daa8cff..46d56c8cc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -291,10 +291,7 @@ pci_set_power_state(struct pci_dev *dev, int state) /* Mandatory power management transition delays */ /* see PCI PM 1.1 5.6.1 table 18 */ if(state == 3 || dev->current_state == 3) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); - } + msleep(10); else if(state == 2 || dev->current_state == 2) udelay(200); dev->current_state = state; @@ -748,7 +745,7 @@ static int __devinit pci_init(void) struct pci_dev *dev = NULL; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - pci_fixup_device(PCI_FIXUP_FINAL, dev); + pci_fixup_device(pci_fixup_final, dev); } return 0; } diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index c1f3d74cc..9670ed404 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -7,7 +7,7 @@ # so if you have anything to contribute, please visit the home page or # send a diff -u against the most recent pci.ids to pci-ids@ucw.cz. # -# Daily snapshot on Thu 2004-04-15 10:00:04 +# Daily snapshot on Mon 2004-07-12 10:00:27 # # Vendors, devices and subsystems. Please keep sorted. @@ -150,37 +150,58 @@ 0e11 4082 Smart Array 532 0e11 4083 Smart Array 5312 b1a4 NC7131 Gigabit Server Adapter + b203 Integrated Lights Out Controller + b204 Integrated Lights Out Processor f130 NetFlex-3/P ThunderLAN 1.0 f150 NetFlex-3/P ThunderLAN 2.3 0e55 HaSoTec GmbH # Formerly NCR 1000 LSI Logic / Symbios Logic 0001 53c810 - 1000 1000 8100S + 1000 1000 LSI53C810AE PCI to SCSI I/O Processor 0002 53c820 0003 53c825 + 1000 1000 LSI53C825AE PCI to SCSI I/O Processor (Ultra Wide) 0004 53c815 0005 53c810AP 0006 53c860 + 1000 1000 LSI53C860E PCI to Ultra SCSI I/O Processor 000a 53c1510 - 000b 53c896 + 1000 1000 LSI53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Nonintelligent mode) + 000b 53C896/897 + 1000 1000 LSI53C896/7 PCI to Dual Channel Ultra2 SCSI Multifunction Controller + 1000 1010 LSI22910 PCI to Dual Channel Ultra2 SCSI host adapter + 1000 1020 LSI21002 PCI to Dual Channel Ultra2 SCSI host adapter +# multifunction PCI card: Dual U2W SCSI, dual 10/100TX, graphics + 13e9 1000 6221L-4U 000c 53c895 + 1000 1010 LSI8951U PCI to Ultra2 SCSI host adapter + 1000 1020 LSI8952U PCI to Ultra2 SCSI host adapter + 1de1 3906 DC-390U2B SCSI adapter 1de1 3907 DC-390U2W 000d 53c885 000f 53c875 0e11 7004 Embedded Ultra Wide SCSI Controller + 1000 1000 LSI53C876/E PCI to Dual Channel SCSI Controller + 1000 1010 LSI22801 PCI to Dual Channel Ultra SCSI host adapter + 1000 1020 LSI22802 PCI to Dual Channel Ultra SCSI host adapter 1092 8760 FirePort 40 Dual SCSI Controller - 1de1 3904 DC390F Ultra Wide SCSI Controller + 1de1 3904 DC390F/U Ultra Wide SCSI Adapter 4c53 1000 CC7/CR7/CP7/VC7/VP7/VR7 mainboard 4c53 1050 CT7 mainboard - 0010 53c895 + 0010 53C1510 0e11 4040 Integrated Array Controller 0e11 4048 Integrated Array Controller + 1000 1000 53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Intelligent mode) 0012 53c895a + 1000 1000 LSI53C895A PCI to Ultra2 SCSI Controller 0013 53c875a + 1000 1000 LSI53C875A PCI to Ultra SCSI Controller 0020 53c1010 Ultra3 SCSI Adapter + 1000 1000 LSI53C1010-33 PCI to Dual Channel Ultra160 SCSI Controller 1de1 1020 DC-390U3W 0021 53c1010 66MHz Ultra3 SCSI Adapter + 1000 1000 LSI53C1000/1000R/1010R/1010-66 PCI to Ultra160 SCSI Controller 124b 1070 PMC-USCSI3 4c53 1080 CT8 mainboard 4c53 1300 P017 mezzanine (32-bit PMC) @@ -191,6 +212,7 @@ 1028 1010 LSI U320 SCSI Controller 0031 53c1030ZC PCI-X Fusion-MPT Dual Ultra320 SCSI 0032 53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI + 1000 1000 LSI53C1020/1030 PCI-X to Ultra320 SCSI Controller 0033 1030ZC_53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI 0040 53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI 1000 0033 MegaRAID SCSI 320-2XR @@ -203,8 +225,22 @@ 1000 0530 MegaRAID 530 SCSI 320-0X RAID Controller 1000 0531 MegaRAID 531 SCSI 320-4X RAID Controller 1000 0532 MegaRAID 532 SCSI 320-2X RAID Controller - 1028 0533 PowerEgde Expandable RAID Controller 4/QC - 8086 0532 Storage RAID Controller SRCU42X + 1028 0531 PowerEdge Expandable RAID Controller 4/QC + 8086 0530 MegaRAID Intel RAID Controller SRCZCRX + 8086 0532 MegaRAID Intel RAID Controller SRCU42X + 0408 MegaRAID + 1000 0001 MegaRAID SCSI 320-1E RAID Controller + 1000 0002 MegaRAID SCSI 320-2E RAID Controller + 1028 0001 Dell PowerEdge RAID Controller PERC4e/SC + 1028 0002 Dell PowerEdge RAID Controller PERC4e/DC + 1734 1065 FSC MegaRAID PCI Express ROMB + 8086 0002 MegaRAID Intel RAID Controller SRCU42E + 0409 MegaRAID + 1000 3004 MegaRAID SATA 300-4X RAID Controller + 1000 3008 MegaRAID SATA 300-8X RAID Controller + 8086 3008 MegaRAID Intel RAID Controller SRCS28X + 8086 3431 MegaRAID Intel RAID Controller Alief SROMBU42E + 8086 3499 MegaRAID Intel RAID Controller Harwich SROMBU42E 0621 FC909 Fibre Channel Adapter 0622 FC929 Fibre Channel Adapter 1000 1020 44929 O Dual Fibre Channel card @@ -228,13 +264,16 @@ 1960 MegaRAID 1000 0518 MegaRAID 518 SCSI 320-2 Controller 1000 0520 MegaRAID 520 SCSI 320-1 Controller - 1000 0522 MegaRAID 522 i4133 RAID Controller + 1000 0522 MegaRAID 522 i4 133 RAID Controller 1000 0523 MegaRAID SATA 150-6 RAID Controller 1000 4523 MegaRAID SATA 150-4 RAID Controller 1000 a520 MegaRAID ZCR SCSI 320-0 Controller 1028 0518 MegaRAID 518 DELL PERC 4/DC RAID Controller 1028 0520 MegaRAID 520 DELL PERC 4/SC RAID Controller 1028 0531 PowerEdge Expandable RAID Controller 4/QC + 1028 0533 PowerEdge Expandable RAID Controller 4/QC + 8086 0520 MegaRAID Intel RAID Controller SRCU41L + 8086 0523 MegaRAID Intel RAID Controller SRCS16 1001 Kolter Electronic 0010 PCI 1616 Measurement card with 32 digital I/O lines 0011 OPTO-PCI Opto-Isolated digital I/O board @@ -350,6 +389,8 @@ 1002 8008 Rage XL 1028 00ce PowerEdge 1400 1028 00d1 PowerEdge 2550 + 8086 3411 SDS2 Mainboard + 8086 3427 S875WP1-E mainboard 4753 Rage XC 1002 4753 Rage XC 4754 3D Rage I/II 215GT [Mach64 GT] @@ -435,10 +476,12 @@ 4e44 Radeon R300 ND [Radeon 9700 Pro] 4e45 Radeon R300 NE [Radeon 9500 Pro] 1002 0002 Radeon R300 NE [Radeon 9500 Pro] + 1681 0002 Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] # New PCI ID provided by ATI developer relations (correction to above) 4e46 RV350 NF [Radeon 9600] 4e47 Radeon R300 NG [FireGL X1] - 4e48 Radeon R350 [Radeon 9800] +# (added pro) + 4e48 Radeon R350 [Radeon 9800 Pro] # New PCI ID provided by ATI developer relations 4e49 Radeon R350 [Radeon 9800] 4e4a RV350 NJ [Radeon 9800 XT] @@ -451,10 +494,12 @@ 4e64 Radeon R300 [Radeon 9700 Pro] (Secondary) 4e65 Radeon R300 [Radeon 9500 Pro] (Secondary) 1002 0003 Radeon R300 NE [Radeon 9500 Pro] + 1681 0003 Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] (Secondary) # New PCI ID provided by ATI developer relations (correction to above) 4e66 RV350 NF [Radeon 9600] (Secondary) 4e67 Radeon R300 [FireGL X1] (Secondary) - 4e68 Radeon R350 [Radeon 9800] (Secondary) +# (added pro) + 4e68 Radeon R350 [Radeon 9800 Pro] (Secondary) # New PCI ID provided by ATI developer relations 4e69 Radeon R350 [Radeon 9800] (Secondary) 4e6a RV350 NJ [Radeon 9800 XT] (Secondary) @@ -535,6 +580,7 @@ 148c 2024 RV200 QW [Radeon 7500LE Dual Display] 148c 2025 RV200 QW [Radeon 7500 Evil Master Multi Display Edition] 148c 2036 RV200 QW [Radeon 7500 PCI Dual Display] + 174b 7146 RV200 QW [Radeon 7500 LE] 174b 7147 RV200 QW [Sapphire Radeon 7500LE] 174b 7161 Radeon RV200 QW [Radeon 7500 LE] 17af 0202 RV200 QW [Excalibur Radeon 7500LE] @@ -624,6 +670,7 @@ 5d44 RV280 [Radeon 9200 SE] (Secondary) 700f PCI Bridge [IGP 320M] 7010 PCI Bridge [IGP 340M] + 7c37 RV350 AQ [Radeon 9600 SE] cab0 AGP Bridge [IGP 320M] cab2 RS200/RS200M AGP Bridge [IGP 340M] 1003 ULSI Systems @@ -865,6 +912,8 @@ 1014 002e ServeRAID-3x 1014 022e ServeRAID-4H 0031 2 Port Serial Adapter +# AS400 iSeries PCI sync serial card + 1014 0031 2721 WAN IOA - 2 Port Sync Serial Adapter 0036 Miami 003a CPU to PCI Bridge 003c GXT250P/GXT255P Graphics Adapter @@ -924,6 +973,7 @@ 0180 Snipe chipset SCSI controller 1014 0241 iSeries 2757 DASD IOA 1014 0264 Quad Channel PCI-X U320 SCSI RAID Adapter (2780) + 1014 02BD Quad Channel PCI-X U320 DDR SCSI RAID Adapter (570F) 01a7 PCI-X to PCI-X Bridge 01bd ServeRAID Controller 1014 01be ServeRAID-4M @@ -946,7 +996,9 @@ 0266 PCI-X Dual Channel SCSI 0268 Gigabit Ethernet-SX Adapter (PCI-X) 0269 10/100/1000 Base-TX Ethernet Adapter (PCI-X) - 0302 XA-32 chipset [Summit] + 028C Citrine chipset SCSI controller + 1014 02BE Dual Channel PCI-X U320 DDR SCSI RAID Adapter (571B) + 0302 X-Architecture Bridge [Summit] ffff MPIC-2 interrupt controller 1015 LSI Logic Corp of Canada 1016 ICL Personal Systems @@ -1059,20 +1111,27 @@ 7454 AMD-8151 System Controller 7455 AMD-8151 AGP Bridge 7460 AMD-8111 PCI + 161f 3017 HDAMB 7461 AMD-8111 USB 7462 AMD-8111 Ethernet 7464 AMD-8111 USB + 161f 3017 HDAMB 7468 AMD-8111 LPC + 161f 3017 HDAMB 7469 AMD-8111 IDE + 161f 3017 HDAMB 746a AMD-8111 SMBus 2.0 746b AMD-8111 ACPI + 161f 3017 HDAMB 746d AMD-8111 AC97 Audio + 161f 3017 HDAMB 746e AMD-8111 MC97 Modem 756b AMD-8111 ACPI 1023 Trident Microsystems 0194 82C194 2000 4DWave DX 2001 4DWave NX + 122d 1400 Trident PCI288-Q3DII (NX) 2100 CyberBlade XP4m32 8400 CyberBlade/i7 1023 8400 CyberBlade i7 AGP @@ -1083,7 +1142,7 @@ 0e11 b16e CyberBlade i1 AGP 1023 8520 CyberBlade i1 AGP 8620 CyberBlade/i1 - 1014 0502 ThinkPad T30 + 1014 0502 ThinkPad R30/T30 8820 CyberBlade XPAi1 9320 TGUI 9320 9350 GUI Accelerator @@ -1179,34 +1238,32 @@ 5453 M5453 PCI AC-Link Controller Modem Device 7101 M7101 PCI PMU Power Management Controller 10b9 7101 M7101 PCI PMU Power Management Controller -1028 Dell Computer Corporation +1028 Dell 0001 PowerEdge Expandable RAID Controller 2/Si - 1028 0001 PowerEdge Expandable RAID Controller 2/Si - 0002 PowerEdge Expandable RAID Controller 3 - 1028 0002 PowerEdge Expandable RAID Controller 3/Di - 1028 00d1 PowerEdge Expandable RAID Controller 3/Di - 1028 00d9 PowerEdge Expandable RAID Controller 3/Di + 1028 0001 PowerEdge 2400 + 0002 PowerEdge Expandable RAID Controller 3/Di + 1028 0002 PowerEdge 4400 0003 PowerEdge Expandable RAID Controller 3/Si - 1028 0003 PowerEdge Expandable RAID Controller 3/Si - 0004 PowerEdge Expandable RAID Controller 3/Si - 1028 00d0 PowerEdge Expandable RAID Controller 3/Si + 1028 0003 PowerEdge 2450 0006 PowerEdge Expandable RAID Controller 3/Di - 0007 Remote Access Controller:DRAC III - 0008 Remote Access Controller - 0009 BMC/SMIC device not present - 000a PowerEdge Expandable RAID Controller 3 - 1028 0106 PowerEdge Expandable RAID Controller 3/Di - 1028 011b PowerEdge Expandable RAID Controller 3/Di - 1028 0121 PowerEdge Expandable RAID Controller 3/Di - 000c Remote Access Controller:ERA or ERA/O - 000d BMC/SMIC device - 000e PowerEdge Expandable RAID controller 4 - 1028 0123 PowerEdge Expandable RAID Controller 4/Di - 000f PowerEdge Expandable RAID controller 4 - 1028 013b MegaRAID DELL PERC 4/Di RAID On Motherboard - 1028 014a PowerEdge Expandable RAID Controller 4/Di - 1028 014c MegaRAID DELL PERC 4/Di RAID On Motherboard - 1028 014d MegaRAID DELL PERC 4/Di RAID On Motherboard + 0007 Remote Access Card III + 0008 Remote Access Card III + 0009 Remote Access Card III: BMC/SMIC device not present + 000a PowerEdge Expandable RAID Controller 3/Di + 000c Embedded Remote Access or ERA/O + 000d Embedded Remote Access: BMC/SMIC device + 000e PowerEdge Expandable RAID controller 4/Di + 000f PowerEdge Expandable RAID controller 4/Di + 0010 Remote Access Card 4 + 0011 Remote Access Card 4 Daughter Card + 0012 Remote Access Card 4 Daughter Card Virtual UART + 0013 PowerEdge Expandable RAID controller 4 + 1028 016c PowerEdge Expandable RAID Controller 4e/Si + 1028 016d PowerEdge Expandable RAID Controller 4e/Di + 1028 016e PowerEdge Expandable RAID Controller 4e/Di + 1028 016f PowerEdge Expandable RAID Controller 4e/Di + 1028 0170 PowerEdge Expandable RAID Controller 4e/Di + 0014 Remote Access Card 4 Daughter Card SMIC interface 1029 Siemens Nixdorf IS 102a LSI Logic 0000 HYDRA @@ -1518,6 +1575,7 @@ 1039 5513 SiS5513 EIDE Controller (A,B step) 1043 8035 CUSI-FX motherboard 5517 5517 + 5518 5518 [IDE] 5571 5571 5581 5581 Pentium Chipset 5582 5582 @@ -1542,6 +1600,7 @@ 1092 4920 SpeedStar A70 1569 6326 SiS6326 GUI Accelerator 6330 661FX/M661FX/M661MX/741/M741/760/M760 PCI/AGP + 1039 6330 [M]661FX/M661MX/[M]741/[M]760 PCI/AGP VGA Display Adapter 7001 USB 1.0 Controller 1039 7000 Onboard USB Controller 7002 USB 2.0 Controller @@ -1604,7 +1663,7 @@ 103c 1049 Tosca Console 103c 104a Tosca Secondary 103c 104b Maestro SP2 - 103c 1223 Halfdome Console + 103c 1223 Superdome Console 103c 1226 Keystone SP2 103c 1227 Powerbar SP2 103c 1282 Everest SP2 @@ -1642,7 +1701,7 @@ 4057 v8200 GeForce 3 8043 v8240 PAL 128M [P4T] Motherboard 807b v9280/TD [Geforce4 TI4200 8X With TV-Out and DVI] -1044 Distributed Processing Technology +1044 Adaptec (formerly DPT) 1012 Domino RAID Engine a400 SmartCache/Raid I-IV Controller a500 PCI Bridge @@ -1683,6 +1742,7 @@ 1044 c065 3010S Ultra3 Four Channel 1044 c066 3010S Fibre Channel a511 SmartRAID V Controller + 1044 c032 ASR-2005S I2O Zero Channel 1045 OPTi Inc. a0f8 82C750 [Vendetta] USB Controller c101 92C264 @@ -1786,6 +1846,7 @@ 1028 00e6 PCI4451 IEEE-1394 Controller (Dell Inspiron 8100) 8029 PCI4510 IEEE-1394 Controller 1071 8160 MIM2900 + 802e PCI7x20 1394a-2000 OHCI Two-Port PHY/Link-Layer Controller 8400 ACX 100 22Mbps Wireless Interface 00fc 16ec U.S. Robotics 22 Mbps Wireless PC Card (model 2210) 00fd 16ec U.S. Robotics 22Mbps Wireless PCI Adapter (model 2216) @@ -1894,6 +1955,8 @@ 0003 MPC8240 [Kahlua] 0004 MPC107 0006 MPC8245 [Unity] + 0008 MPC8540 + 0009 MPC8560 0100 MC145575 [HFC-PCI] 0431 KTI829c 100VG 1801 DSP56301 Digital Signal Processor @@ -1939,44 +2002,49 @@ 1058 Electronics & Telecommunications RSH 1059 Teknor Industrial Computers Inc 105a Promise Technology, Inc. - 0d30 20265 +# more correct description from promise linux sources + 0d30 PDC20265 (FastTrak100 Lite/Ultra100) 105a 4d33 Ultra100 0d38 20263 105a 4d39 Fasttrak66 1275 20275 3318 PDC20318 (SATA150 TX4) - 3319 PDC20319 (SATA150 TX4) - 3373 PDC20378 (SATA150 TX) + 3319 PDC20319 (FastTrak S150 TX4) + 8086 3427 S875WP1-E mainboard + 3371 PDC20371 (FastTrak S150 TX2plus) + 3373 PDC20378 (FastTrak 378/SATA 378) + 1043 80f5 PC-DL Deluxe motherboard 1462 702e K8T NEO FIS2R motherboard 3375 PDC20375 (SATA150 TX2plus) - 3376 PDC20376 + 3376 PDC20376 (FastTrak 376) 1043 809e A7V8X motherboard - 4d30 20267 + 4d30 PDC20267 (FastTrak100/Ultra100) 105a 4d33 Ultra100 - 105a 4d39 Fasttrak100 + 105a 4d39 FastTrak100 4d33 20246 105a 4d33 20246 IDE Controller - 4d38 20262 + 4d38 PDC20262 (FastTrak66/Ultra66) 105a 4d30 Ultra Device on SuperTrak 105a 4d33 Ultra66 - 105a 4d39 Fasttrak66 - 4d68 20268 + 105a 4d39 FastTrak66 + 4d68 PDC20268 (Ultra100 TX2) 105a 4d68 Ultra100TX2 4d69 20269 105a 4d68 Ultra133TX2 - 5275 PDC20276 IDE + 5275 PDC20276 (MBFastTrak133 Lite) 105a 0275 SuperTrak SX6000 IDE 105a 1275 MBFastTrak133 Lite (tm) Controller (RAID mode) 1458 b001 MBUltra 133 5300 DC5300 - 6268 20268R - 6269 PDC20271 + 6268 PDC20270 (FastTrak100 LP/TX2/TX4) + 105a 4d68 FastTrak100 TX2 + 6269 PDC20271 (FastTrak TX2000) 105a 6269 FastTrak TX2/TX2000 - 6621 PDC20621 [SX4000] 4 Channel IDE RAID Controller + 6621 PDC20621 (FastTrak S150 SX4/FastTrak SX4000 lite) 6622 PDC20621 [SATA150 SX4] 4 Channel IDE RAID Controller - 6626 PDC20618 Ultra 618 - 6629 PDC20619 FastTrak TX4000 RAID - 7275 PDC20277 + 6626 PDC20618 (Ultra 618) + 6629 PDC20619 (FastTrak TX4000) + 7275 PDC20277 (SBFastTrak133 Lite) 105b Foxconn International, Inc. 105c Wipro Infotech Limited 105d Number 9 Computer Company @@ -2070,6 +2138,8 @@ 1014 0242 iSeries 2872 DASD IOA 1014 0266 Dual Channel PCI-X U320 SCSI Adapter 1014 0278 Dual Channel PCI-X U320 SCSI RAID Adapter + 1014 02D3 Dual Channel PCI-X U320 SCSI Adapter + 1014 02D4 Dual Channel PCI-X U320 SCSI RAID Adapter ba55 eXtremeRAID 1100 support Device ba56 eXtremeRAID 2000/3000 support Device 106a Aten Research Inc @@ -2199,6 +2269,7 @@ 107c LG Electronics [Lucky Goldstar Co. Ltd] 107d LeadTek Research Inc. 0000 P86C850 + 2134 WinFast 3D S320 II 107e Interphase Corporation 0001 5515 ATM Adapter [Flipper] 0002 100 VG AnyLan Controller @@ -2348,10 +2419,10 @@ 0673 USB0673 0680 PCI0680 Ultra ATA-133 Host Controller 1095 3680 Winic W-680 (Silicon Image 680 based) - 3112 Silicon Image Serial ATARaid Controller [ CMD/Sil 3112/3112A ] + 3112 SiI 3112 [SATALink/SATARaid] Serial ATA Controller 1095 6112 Asus A7N8X - 3114 Silicon Image SiI 3114 SATARaid - 3512 Silicon Image Serial ATARaid Controller [ CMD/Sil 3512 ] + 3114 SiI 3114 [SATALink/SATARaid] Serial ATA Controller + 3512 SiI 3512 [SATALink/SATARaid] Serial ATA Controller 1096 Alacron 1097 Appian Technology 1098 Quantum Designs (H.K.) Ltd @@ -2742,6 +2813,7 @@ 10b7 7000 10/100 Mini PCI Ethernet Adapter 10f1 2466 Tiger MPX S2466 (3C920 Integrated Fast Ethernet Controller) 9201 3C920B-EMB Integrated Fast Ethernet Controller [Tornado] + 1043 80ab A7N8X Deluxe onboard 3C920B-EMB Integrated Fast Ethernet Controller 9202 3Com 3C920B-EMB-WNM Integrated Fast Ethernet Controller 9210 3C920B-EMB-WNM Integrated Fast Ethernet Controller 9300 3CSOHO100B-TX 910-A01 [tulip] @@ -2837,6 +2909,7 @@ 5219 M5219 5225 M5225 5229 M5229 IDE + 1014 050f ThinkPad R30 1043 8053 A7A266 Motherboard IDE 5235 M5225 5237 USB 1.1 Controller @@ -2859,8 +2932,8 @@ 545a SmartLink SmartPCI563 56K Modem 5471 M5471 Memory Stick Controller 5473 M5473 SD-MMC Controller - 7101 M7101 PMU - 10b9 7101 ALI M7101 Power Management Controller + 7101 M7101 Power Management Controller [PMU] + 1014 0510 ThinkPad R30 10ba Mitsubishi Electric Corp. 0301 AccelGraphics AccelECLIPSE 0304 AccelGALAXY A2100 [OEM Evans & Sutherland] @@ -3001,6 +3074,7 @@ 1043 0205 PCI-V3800 1043 4000 AGP-V3800PRO 1048 0c21 Synergy II + 107d 2134 WinFast 3D S320 II + TV-Out 1092 4804 Viper V770 1092 4a00 Viper V770 1092 4a02 Viper V770 Ultra @@ -3041,11 +3115,13 @@ 1554 1041 Pixelview RIVA TNT2 M64 002e NV6 [Vanta] 002f NV6 [Vanta] + 0041 NV40 OS1RT00B30 0060 nForce2 ISA Bridge 1043 80ad A7N8X Mainboard 0064 nForce2 SMBus (MCP) 0065 nForce2 IDE 0066 nForce2 Ethernet Controller + 1043 80a7 A7N8X Mainboard onboard nForce2 Ethernet 0067 nForce2 USB Controller 1043 0c11 A7N8X Mainboard 0068 nForce2 USB Controller @@ -3292,6 +3368,7 @@ 1071 8160 MIM2000 10bd 0320 EP-320X-R 10ec 8139 RT8139 + 1113 ec01 FNC-0107TX 1186 1300 DFE-538TX 1186 1320 SN5200 1186 8139 DRN-32TX @@ -3342,7 +3419,7 @@ 10f9 PC Direct 10fa Truevision 000c TARGA 1000 -10fb Thesys Gesellschaft für Mikroelektronik mbH +10fb Thesys Gesellschaft für Mikroelektronik mbH 186f TH 6255 10fc I-O Data Device, Inc. # What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives @@ -3358,6 +3435,7 @@ 9400 INI-940 9401 INI-950 9500 360P + 9502 Initio INI-9100UW Ultra Wide SCSI Controller INIC-950P chip 1102 Creative Labs 0002 SB Live! EMU10k1 1102 0020 CT4850 SBLive! Value @@ -3507,13 +3585,16 @@ 0e11 0097 SoundMax Digital Integrated Audio 0e11 b194 Soundmax integrated digital audio 1019 0985 P6VXA Motherboard + 1043 1106 A7V133/A7V133-C Mainboard 1106 4511 Onboard Audio on EP7KXA 1458 7600 Onboard Audio 1462 3091 MS-6309 Onboard Audio + 1462 3300 MS-6330 Onboard Audio 15dd 7609 Onboard Audio 3059 VT8233/A/8235/8237 AC97 Audio Controller 1019 0a81 L7VTA v1.0 Motherboard (KT400-8235) 1043 8095 A7V8X Motherboard (Realtek ALC650 codec) + 1043 80a1 A7V8X-X Motherboard 1043 80b0 A7V600 motherboard (ADI AD1980 codec [SoundMAX]) 1106 3059 L7VMM2 Motherboard 1297 c160 FX41 motherboard (Realtek ALC650 codec) @@ -3526,6 +3607,7 @@ 1186 1401 DFE-530TX rev B 13b9 1421 LD-10/100AL PCI Fast Ethernet Adapter (rev.B) 3068 Intel 537 [AC97 Modem] + 1462 309e MS-6309 Saturn Motherboard 3074 VT8233 PCI to ISA Bridge 1043 8052 VT8233A 3091 VT8633 [Apollo Pro266] @@ -3906,7 +3988,15 @@ 1133 1c0b Diva Server V-PRI/T1-24 Cornet NQ 3 1133 1c0c Diva Server V-PRI/E1-30 Cornet NQ 3 e01e Diva Server 2PRI + 1133 1e00 Diva Server V-2PRI/E1-60 + 1133 1e01 Diva Server V-2PRI/T1-48 + 1133 1e02 Diva Server 2PRI/E1-60 + 1133 1e03 Diva Server 2PRI/T1-48 e020 Diva Server 4PRI + 1133 2000 Diva Server V-4PRI/E1-120 + 1133 2001 Diva Server V-4PRI/T1-96 + 1133 2002 Diva Server 4PRI/E1-120 + 1133 2003 Diva Server 4PRI/T1-96 e024 Diva Server Analog-4P e028 Diva Server Analog-8P 1134 Mercury Computer Systems @@ -4145,6 +4235,7 @@ 1165 Imagraph Corporation 0001 Motion TPEG Recorder/Player with audio 1166 ServerWorks + 0000 CMIC-LE 0005 CNB20-LE Host Bridge 0006 CNB20HE Host Bridge 0007 CNB20-LE Host Bridge @@ -4152,13 +4243,13 @@ 0009 CNB20LE Host Bridge 0010 CIOB30 0011 CMIC-HE - 0012 CMIC-LE + 0012 CMIC-WS Host Bridge (GC-LE chipset) 0013 CNB20-HE Host Bridge - 0014 CNB20-HE Host Bridge + 0014 CMIC-LE Host Bridge (GC-LE chipset) 0015 CMIC-GC Host Bridge 0016 CMIC-GC Host Bridge 0017 GCNB-LE Host Bridge - 0101 CIOB-X2 + 0101 CIOB-X2 PCI-X I/O Bridge 0110 CIOB-E I/O Bridge with Gigabit Ethernet 0200 OSB4 South Bridge 0201 CSB5 South Bridge @@ -4255,6 +4346,7 @@ 1186 1300 DFE-538TX 10/100 Ethernet Adapter 1186 1301 DFE-530TX+ 10/100 Ethernet Adapter 1340 DFE-690TXD CardBus PC Card + 1541 DFE-680TXD CardBus PC Card 1561 DRP-32TXD Cardbus PC Card 3300 DWL-510 2.4GHz Wireless PCI Adapter 3b05 DWL-G650+ CardBus PC Card @@ -4337,9 +4429,10 @@ 11a9 InnoSys Inc. 4240 AMCC S933Q Intelligent Serial Card 11aa Actel -# (formerly Galileo technologies) -11ab Marvell +# Formerly Galileo Technology, Inc. +11ab Marvell Technology Group Ltd. 0146 GT-64010/64010A System Controller + 1fa6 Marvell W8300 802.11 Adapter 4320 Yukon Gigabit Ethernet 10/100/1000Base-T Adapter 4611 GT-64115 System Controller 4620 GT-64120/64120A/64121A System Controller @@ -4677,6 +4770,7 @@ 6933 OZ6933 Cardbus Controller 1025 1016 Travelmate 612 TX 6972 OZ6912 Cardbus Controller + 1014 020c ThinkPad R30 1179 0001 Magnia Z310 7110 OZ711Mx MultiMediaBay Accelerator 7112 OZ711EC1/M1 SmartCardBus MultiMediaBay Controller @@ -4762,6 +4856,7 @@ 122c Sican GmbH 122d Aztech System Ltd 1206 368DSP + 1400 Trident PCI288-Q3DII (NX) 50dc 3328 Audio 122d 0001 3328 Audio 80da 3328 Audio @@ -4905,11 +5000,15 @@ 3873 Prism 2.5 Wavelan chipset 1186 3501 DWL-520 Wireless PCI Adapter 1186 3700 DWL-520 Wireless PCI Adapter, Rev E1 + 1385 4105 MA311 802.11b wireless adapter 1668 0414 HWP01170-01 802.11b PCI Wireless Adapter 16a5 1601 AIR.mate PC-400 PCI Wireless LAN Adapter 1737 3874 WMP11 Wireless 802.11b PCI Adapter 8086 2513 Wireless 802.11b MiniPCI Adapter + 3886 ISL3886 [Prism Javelin/Prism Xbow] 3890 Intersil ISL3890 [Prism GT/Prism Duette] + 10b8 a835 SMC2835W V2 Wireless Cardbus Adapter + 16a5 1605 ALLNET ALL0271 Wireless PCI Adapter 17cf 0014 Ovislink WL-5400PCM, Prism GT 8130 HMP8130 NTSC/PAL Video Decoder 8131 HMP8131 NTSC/PAL Video Decoder @@ -5155,7 +5254,7 @@ 9132 Ethernet 100/10 MBit 1283 Integrated Technology Express, Inc. 673a IT8330G - 8212 IT/ITE8212 Dual channel ATA RAID + 8212 IT/ITE8212 Dual channel ATA RAID controller 8330 IT8330G 8872 IT8874F PCI Dual Serial Port Controller 8888 IT8888F PCI to ISA Bridge with SMB @@ -5466,7 +5565,8 @@ 0985 NC100 Network Everywhere Fast Ethernet 10/100 1985 21x4x DEC-Tulip compatible 10/100 Ethernet 2850 HSP MicroModem 56 - 8201 [ADMtek] SP906B_V2 Wireless LAN adapter + 8201 ADMtek ADM8211 802.11b Wireless Interface + 10b8 2635 SMC2635W 802.11b (11Mbps) wireless lan pcmcia (cardbus) card 1317 8201 SMC2635W 802.11b (11mbps) wireless lan pcmcia (cardbus) card 9511 21x4x DEC-Tulip compatible 10/100 Ethernet 1318 Packet Engines Inc. @@ -5535,7 +5635,6 @@ 132d Integrated Silicon Solution, Inc. 1330 MMC Networks 1331 Radisys Corp. - 0030 ENP-2611 8200 82600 Host Bridge 8201 82600 IDE 8202 82600 USB @@ -5659,9 +5758,11 @@ 1385 Netgear 4100 802.11b Wireless Adapter (MA301) 4105 MA311 802.11b wireless adapter + 4a00 WAG311 802.11abg Wireless Adapter 620a GA620 Gigabit Ethernet 622a GA622 630a GA630 Gigabit Ethernet + f004 FA310TX 1386 Video Domain Technologies 1387 Systran Corp 1388 Hitachi Information Technology Co Ltd @@ -5720,6 +5821,7 @@ 13a6 Videonics Inc 13a7 Teles AG 13a8 Exar Corp. + 0154 XR17C154 Quad UART 0158 XR17C158 Octal UART 13a9 Siemens Medical Systems, Ultrasound Group 13aa Broadband Networks Inc @@ -5752,6 +5854,7 @@ 13c1 3ware Inc 1000 3ware ATA-RAID 1001 3ware 7000-series ATA-RAID + 13c1 1001 3ware Inc 3ware 7xxx/8xxx-series PATA/SATA-RAID 1002 3ware ATA-RAID 13c2 Technotrend Systemtechnik GmbH 13c3 Janz Computer AG @@ -5884,10 +5987,11 @@ 140f Salient Systems Corp 1410 Midas lab Inc 1411 Ikos Systems Inc -1412 IC Ensemble Inc - 1712 ICE1712 [Envy24] +# formerly IC Ensemble Inc. +1412 VIA Technologies Inc. + 1712 ICE1712 [Envy24] PCI Multi-Channel I/O Controller 1412 d638 M-Audio Delta 410 - 1724 ICE1724 [Envy24HT] + 1724 VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller 1413 Addonics 1414 Microsoft Corporation 1415 Oxford Semiconductor Ltd @@ -5990,6 +6094,7 @@ 1460 DYNARC INC 1461 Avermedia Technologies Inc 1462 Micro-Star International Co., Ltd. + 6825 PCI Card wireless 11g [PC54G] 8725 NVIDIA NV25 [GeForce4 Ti 4600] VGA Adapter # MSI G4Ti4800, 128MB DDR SDRAM, TV-Out, DVI-I 9000 NVIDIA NV28 [GeForce4 Ti 4800] VGA Adapter @@ -6150,8 +6255,9 @@ 14d6 Accusys Inc 14d7 Hirakawa Hewtech Corp 14d8 HOPF Elektronik GmBH -14d9 Alpha Processor Inc - 0010 AP1011 HyperTransport-PCI Bridge [Sturgeon] +# Formerly SiPackets, Inc., formerly API NetWorks, Inc., formerly Alpha Processor, Inc. +14d9 Alliance Semiconductor Corporation + 0010 AP1011/SP1011 HyperTransport-PCI Bridge [Sturgeon] 14da National Aerospace Laboratories 14db AFAVLAB Technology Inc 2120 TK9902 @@ -6175,6 +6281,14 @@ 14e2 INFOLIBRIA 14e3 AMTELCO 14e4 Broadcom Corporation + 0800 Sentry5 Chipcommon I/O Controller + 0804 Sentry5 PCI Bridge + 0805 Sentry5 MIPS32 CPU + 0806 Sentry5 Ethernet Controller + 080b Sentry5 Crypto Accelerator + 080f Sentry5 DDR/SDR RAM Controller + 0811 Sentry5 External Interface Core + 0816 BCM3302 Sentry5 MIPS32 CPU 1644 NetXtreme BCM5700 Gigabit Ethernet 1014 0277 Broadcom Vigil B5700 1000Base-T 1028 00d1 Broadcom BCM5700 @@ -6241,21 +6355,14 @@ 164d NetXtreme BCM5702FE Gigabit Ethernet 1653 NetXtreme BCM5705 Gigabit Ethernet 1654 NetXtreme BCM5705_2 Gigabit Ethernet - 1658 NetXtreme BCM5720 Gigabit Ethernet - 1659 NetXtreme BCM5721 Gigabit Ethernet + 1659 NetXtreme BCM5721 Gigabit Ethernet PCI Express 165d NetXtreme BCM5705M Gigabit Ethernet 165e NetXtreme BCM5705M_2 Gigabit Ethernet - 166e NetXtreme BCM5705F Gigabit Ethernet - 1676 NetXtreme BCM5750 Gigabit Ethernet - 1677 NetXtreme BCM5751 Gigabit Ethernet - 167c NetXtreme BCM5750M Gigabit Ethernet - 167d NetXtreme BCM5751M Gigabit Ethernet - 167e NetXtreme BCM5751F Gigabit Ethernet + 1677 NetXtreme BCM5751 Gigabit Ethernet PCI Express 1696 NetXtreme BCM5782 Gigabit Ethernet 103c 12bc HP d530 CMT (DG746A) 14e4 000d NetXtreme BCM5782 1000Base-T 169c NetXtreme BCM5788 Gigabit Ethernet - 169d NetXtreme BCM5789 Gigabit Ethernet 16a6 NetXtreme BCM5702X Gigabit Ethernet 0e11 00bb NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T) 1028 0126 BCM5702 1000Base-T @@ -6279,13 +6386,17 @@ 103c 12ca HP Combo FC/GigE-T [A9784A] 14e4 0009 NetXtreme BCM5703 1000Base-T 14e4 000a NetXtreme BCM5703 1000Base-SX - 170d NetXtreme BCM5901 Gigabit Ethernet - 170e NetXtreme BCM5901_2 Gigabit Ethernet + 170c BCM4401-B0 100Base-TX + 170d NetXtreme BCM5901 100Base-TX + 170e NetXtreme BCM5901 100Base-TX + 3352 BCM3352 + 3360 BCM3360 4210 BCM4210 iLine10 HomePNA 2.0 4211 BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem 4212 BCM4212 v.90 56k modem 4301 BCM4301 802.11b - 4320 BCM94306 802.11g + 4307 BCM4307 802.11b Wireless LAN Controller + 4320 BCM4306 802.11b/g Wireless LAN Controller 1028 0001 TrueMobile 1300 WLAN Mini-PCI Card 1737 4320 WPC54G 4324 BCM4309 802.11a/b/g @@ -6293,12 +6404,47 @@ 4401 BCM4401 100Base-T 1043 80a8 A7V8X motherboard 4402 BCM4402 Integrated 10/100BaseT + 4403 BCM4402 V.90 56k Modem 4410 BCM4413 iLine32 HomePNA 2.0 4411 BCM4413 V.90 56k modem 4412 BCM4413 10/100BaseT + 4430 BCM44xx CardBus iLine32 HomePNA 2.0 + 4432 BCM44xx CardBus 10/100BaseT + 4610 BCM4610 Sentry5 PCI to SB Bridge + 4611 BCM4610 Sentry5 iLine32 HomePNA 1.0 + 4612 BCM4610 Sentry5 V.90 56k Modem + 4613 BCM4610 Sentry5 Ethernet Controller + 4614 BCM4610 Sentry5 External Interface + 4615 BCM4610 Sentry5 USB Controller + 4704 BCM4704 PCI to SB Bridge + 4708 BCM4708 Sentry5 PCI to SB Bridge + 4710 BCM4710 Sentry5 PCI to SB Bridge + 4711 BCM47xx Sentry5 iLine32 HomePNA 2.0 + 4712 Sentry5 UART + 4713 Sentry5 Ethernet Controller + 4714 BCM47xx Sentry5 External Interface + 4715 Sentry5 USB Controller + 4716 BCM47xx Sentry5 USB Host Controller + 4717 BCM47xx Sentry5 USB Device Controller + 4718 Sentry5 Crypto Accelerator + 5365 BCM5365P Sentry5 Host Bridge + 5600 BCM5600 StrataSwitch 24+2 Ethernet Switch Controller + 5605 BCM5605 StrataSwitch 24+2 Ethernet Switch Controller + 5615 BCM5615 StrataSwitch 24+2 Ethernet Switch Controller + 5625 BCM5625 StrataSwitch 24+2 Ethernet Switch Controller + 5645 BCM5645 StrataSwitch 24+2 Ethernet Switch Controller + 5670 BCM5670 8-Port 10GE Ethernet Switch Fabric + 5680 BCM5680 G-Switch 8 Port Gigabit Ethernet Switch Controller 5690 BCM5690 12-port Multi-Layer Gigabit Ethernet Switch + 5691 BCM5691 GE/10GE 8+2 Gigabit Ethernet Switch Controller 5820 BCM5820 Crypto Accelerator 5821 BCM5821 Crypto Accelerator + 5822 BCM5822 Crypto Accelerator + 5823 BCM5823 Crypto Accelerator + 5824 BCM5824 Crypto Accelerator + 5840 BCM5840 Crypto Accelerator + 5841 BCM5841 Crypto Accelerator + 5850 BCM5850 Crypto Accelerator 14e5 Pixelfusion Ltd 14e6 SHINING Technology Inc 14e7 3CX @@ -6823,11 +6969,16 @@ 1619 FarSite Communications Ltd 0400 FarSync T2P (2 port X.21/V.35/V.24) 0440 FarSync T4P (4 port X.21/V.35/V.24) +# www.rioworks.com +161f Rioworks 1626 TDK Semiconductor Corp. 8410 RTL81xx Fast Ethernet 1629 Kongsberg Spacetec AS 1003 Format synchronizer v3.0 2002 Fast Universal Data Output +# This seems to occur on their 802.11b Wireless card WMP-11 +1637 Linksys + 3874 Linksys 802.11b WMP11 PCI Wireless card 1638 Standard Microsystems Corp [SMC] 1100 SMC2602W EZConnect/Addtron AWA-100/Eumitcom WL11000 163c Smart Link Ltd. @@ -6862,6 +7013,7 @@ 168c 0013 WG511T Wireless CardBus Adapter 168c 1025 DWL-G650B2 Wireless CardBus Adapter 1014 AR5212 802.11abg NIC +16a5 Tekram Technology Co.,Ltd. 16ab Global Sun Technology Inc 1100 GL24110P 1101 PLX9052 PCMCIA-to-PCI Wireless LAN @@ -6874,9 +7026,13 @@ 16cd Densitron Technologies # www.pikatechnologies.com 16df PIKA Technologies Inc. +16e3 European Space Agency + 1e0f LEON2FT Processor 16ec U.S. Robotics 00ff USR997900 10/100 Mbps PCI Network Card 3685 Wireless Access PCI Adapter Model 022415 +16f4 Vweb Corp + 8000 VW2010 16f6 VideoTele.com, Inc. # www.internetmachines.com 1702 Internet Machines Corporation (IMC) @@ -6884,8 +7040,12 @@ 170b NetOctave 0100 NSP2000-SSL crypto accelerator 170c YottaYotta Inc. +# Seems to be a 2nd ID for Vitesse Semiconductor +1725 Vitesse Semiconductor + 7174 VSC7174 PCI/PCI-X Serial ATA Host Bus Controller 172a Accelerated Encryption 1737 Linksys + 0013 WMP54G Wireless Pci Card 1032 Gigabit Network Adapter 1737 0015 EG1032 v2 Instant Gigabit Network Adapter 1064 Gigabit Network Adapter @@ -6914,10 +7074,12 @@ 0004 CAMAC Controller 0005 PROFIBUS 0006 AMCC HOTlink +1797 JumpTec h, GMBH 1799 Belkin 6001 Wireless PCI Card - F5D6001 6020 Wireless PCMCIA Card - F5D6020 6060 Wireless PDA Card - F5D6060 + 7000 Wireless PCI Card - F5D7000 17af Hightech Information System Ltd. 17b3 Hawking Technologies ab08 PN672TX 10/100 Ethernet @@ -6929,6 +7091,9 @@ 2280 USB 2.0 # S2io ships 10Gb PCI-X Ethernet adapters www.s2io.com 17d5 S2io Inc. +# Supplying full name for a currently green entry +17fe Linksys, A Division of Cisco Systems + 2220 [AirConn] INPROCOMM IPN 2220 WLAN Adapter (rev 01) 1813 Ambient Technologies Inc 4000 HaM controllerless modem 16be 0001 V9x HAM Data Fax Modem @@ -6937,6 +7102,8 @@ 1814 RaLink 0101 Wireless PCI Adpator RT2400 / RT2460 0201 Ralink RT2500 802.11 Cardbus Reference Card +1820 InfiniCon Systems Inc. +1822 Twinhan Technology Co. Ltd 1830 Credence Systems Corporation 1851 Microtune, Inc. 1852 Anritsu Corp. @@ -6952,6 +7119,8 @@ # found e.g. on KNC DVB-S card 1894 KNC One 18a1 Astute Networks Inc. +18bc Info-Tek Corp. +18c9 ARVOO Engineering BV 18ca XGI - Xabre Graphics Inc 0040 Volari V8 18e6 MPL AG @@ -7018,6 +7187,7 @@ 0008 GLINT Gamma G1 0009 Permedia II 2D+3D 1040 0011 AccelStar II + 13e9 1000 6221L-4U 3d3d 0100 AccelStar II 3D Accelerator 3d3d 0111 Permedia 3:16 3d3d 0114 Santa Ana @@ -7269,10 +7439,11 @@ 5555 Genroco, Inc 0003 TURBOstor HFP-832 [HiPPI NIC] 5654 VoiceTronix Pty Ltd + 3132 OpenSwitch12 5700 Netpower 5851 Exacq Technologies 6356 UltraStor -6374 c't Magazin für Computertechnik +6374 c't Magazin für Computertechnik 6773 GPPCI 6409 Logitec Corp. 6666 Decision Computer International Co. @@ -7292,6 +7463,8 @@ 0008 1000 WorldMark 4300 INCA ASIC 0039 21145 Fast Ethernet 0122 82437FX + 0309 80303 I/O Processor PCI-to-PCI Bridge + 030d 80312 I/O Companion Chip PCI-to-PCI Bridge 0326 PCI Bridge Hub I/OxAPIC Interrupt Controller A 0327 PCI Bridge Hub I/OxAPIC Interrupt Controller B 0329 PCI Bridge Hub A @@ -7315,13 +7488,38 @@ 0340 41210 [Lanai] Serial to Parallel PCI Bridge # B-segment bridge 0341 41210 [Lanai] Serial to Parallel PCI Bridge - 0482 82375EB - 0483 82424ZX [Saturn] - 0484 82378IB [SIO ISA Bridge] - 0486 82430ZX [Aries] - 04a3 82434LX [Mercury/Neptune] + 0482 82375EB/SB PCI to EISA Bridge + 0483 82424TX/ZX [Saturn] CPU to PCI bridge + 0484 82378ZB/IB, 82379AB (SIO, SIO.A) PCI to ISA Bridge + 0486 82425EX/ZX [Aries] PCIset with ISA bridge + 04a3 82434LX/NX [Mercury/Neptune] Processor to PCI bridge 04d0 82437FX [Triton FX] + 0500 E8870 Processor bus control + 0501 E8870 Memory controller +# and registers common to both SPs + 0502 E8870 Scalability Port 0 +# and global performance monitoring + 0503 E8870 Scalability Port 1 + 0510 E8870IO Hub Interface Port 0 registers (8-bit compatibility port) + 0511 E8870IO Hub Interface Port 1 registers + 0512 E8870IO Hub Interface Port 2 registers + 0513 E8870IO Hub Interface Port 3 registers + 0514 E8870IO Hub Interface Port 4 registers + 0515 E8870IO General SIOH registers + 0516 E8870IO RAS registers + 0530 E8870SP Scalability Port 0 registers + 0531 E8870SP Scalability Port 1 registers + 0532 E8870SP Scalability Port 2 registers + 0533 E8870SP Scalability Port 3 registers + 0534 E8870SP Scalability Port 4 registers + 0535 E8870SP Scalability Port 5 registers +# (bi-interleave 0) and global registers that are neither per-port nor per-interleave + 0536 E8870SP Interleave registers 0 and 1 +# (bi-interleave 1) + 0537 E8870SP Interleave registers 2 and 3 0600 RAID Controller + 8086 01c1 ICP Vortex GDT8546RZ + 8086 01f7 SCRU32 0960 80960RP [i960 RP Microprocessor/Bridge] 0962 80960RM [i960RM Bridge] 0964 80960RP [i960 RP Microprocessor/Bridge] @@ -7406,6 +7604,7 @@ 1019 82547EI Gigabit Ethernet Controller (LOM) 1458 1019 GA-8IPE1000 Pro2 motherboard (865PE) 8086 1019 PRO/1000 CT Desktop Connection + 8086 3427 S875WP1-E mainboard 101d 82546EB Gigabit Ethernet Controller 8086 1000 PRO/1000 MT Quad Port Server Adapter 101e 82540EP Gigabit Ethernet Controller (Mobile) @@ -7453,13 +7652,16 @@ 16be 1040 V.9X DSP Data Fax Modem 1043 PRO/Wireless LAN 2100 3B Mini PCI Adapter 8086 2527 MIM2000/Centrino - 1048 Intel(R) PRO/10GbE LR Server Adapter + 1048 PRO/10GbE LR Server Adapter 8086 a01f PRO/10GbE LR Server Adapter 8086 a11f PRO/10GbE LR Server Adapter 1050 82562EZ 10/100 Ethernet Controller 1462 728c 865PE Neo2 (MS-6728) + 1462 758c MS-6758 (875P Neo) + 8086 3427 S875WP1-E mainboard 1051 82801EB/ER (ICH5/ICH5R) integrated LAN Controller 1059 82551QM Ethernet Controller + 1065 82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller # Updated controller name from 82547EI to 82547GI 1075 82547GI Gigabit Ethernet Controller 8086 0075 PRO/1000 CT Network Connection @@ -7516,8 +7718,8 @@ 4c53 1050 CT7 mainboard 4c53 1051 CE7 mainboard 4c53 1070 PC6 mainboard - 1221 82092AA_0 - 1222 82092AA_1 + 1221 82092AA PCI to PCMCIA Bridge + 1222 82092AA IDE Controller 1223 SAA7116 1225 82452KX/GX [Orion] 1226 82596 PRO/10 PCI @@ -7587,6 +7789,7 @@ 1259 2560 AT-2560 100 1259 2561 AT-2560 100 FX Ethernet Adapter 1266 0001 NE10/100 Adapter + 13e9 1000 6221L-4U 144d 2501 SEM-2000 MiniPCI LAN Adapter 144d 2502 SEM-2100IL MiniPCI LAN Adapter 1668 1100 EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem) @@ -7675,6 +7878,7 @@ 8086 3010 EtherExpress PRO/100 S Network Connection 8086 3011 EtherExpress PRO/100 S Network Connection 8086 3012 EtherExpress PRO/100 Network Connection + 8086 3411 SDS2 Mainboard 122d 430FX - 82437FX TSC [Triton I] 122e 82371FB PIIX ISA [Triton I] 1230 82371FB PIIX IDE [Triton I] @@ -7682,13 +7886,15 @@ 1234 430MX - 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX) 1235 430MX - 82437MX Mob. System Ctrlr (MTSC) & 82438MX Data Path (MTDP) 1237 440FX - 82441FX PMC [Natoma] - 1239 82371FB - 123b 82380PB - 123c 82380AB + 1239 82371FB PIIX IDE Interface + 123b 82380PB PCI to PCI Docking Bridge + 123c 82380AB (MISA) Mobile PCI-to-ISA Bridge 123d 683053 Programmable Interrupt Device +# in" hidden" mode + 123e 82466GX (IHPC) Integrated Hot-Plug Controller 123f 82466GX Integrated Hot-Plug Controller (IHPC) - 1240 752 AGP - 124b 82380FB + 1240 82752 (752) AGP Graphics Accelerator + 124b 82380FB (MPCI2) Mobile Docking Controller 1250 430HX - 82439HX TXC [Triton II] 1360 82806AA PCI64 Hub PCI Bridge 1361 82806AA PCI64 Hub Controller (HRes) @@ -7782,7 +7988,7 @@ 2446 Intel 537 [82801BA/BAM AC'97 Modem] 1025 1016 Travelmate 612 TX 104d 80df Vaio PCG-FX403 - 2448 82801BAM/CAM PCI Bridge + 2448 82801 PCI Bridge 2449 82801BA/BAM/CA/CAM Ethernet Controller 0e11 0012 EtherExpress PRO/100 VM 0e11 0091 EtherExpress PRO/100 VE @@ -7824,7 +8030,7 @@ 8086 4532 D815EEA2 mainboard 8086 4557 D815EGEW Mainboard 244c 82801BAM ISA Bridge (LPC) - 244e 82801BA/CA/DB/EB/ER Hub interface to PCI Bridge + 244e 82801 PCI Bridge 1014 0267 NetVista A30p 2450 82801E ISA Bridge (LPC) 2452 82801E USB @@ -7879,45 +8085,45 @@ 248b 82801CA Ultra ATA Storage Controller 15d9 3480 P4DP6 248c 82801CAM ISA Bridge (LPC) - 24c0 82801DB (ICH4) LPC Bridge + 24c0 82801DB/DBL (ICH4/ICH4-L) LPC Bridge 1014 0267 NetVista A30p 1462 5800 845PE Max (MS-6580) - 24c2 82801DB (ICH4) USB UHCI #1 + 24c2 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 5800 845PE Max (MS-6580) - 24c3 82801DB/DBM (ICH4) SMBus Controller + 24c3 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller 1014 0267 NetVista A30p 1071 8160 MIM2000 1458 24c2 GA-8PE667 Ultra 1462 5800 845PE Max (MS-6580) 4c53 1090 Cx9 / Vx9 mainboard - 24c4 82801DB (ICH4) USB UHCI #2 + 24c4 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 5800 845PE Max (MS-6580) 4c53 1090 Cx9 / Vx9 mainboard - 24c5 82801DB (ICH4) AC'97 Audio Controller + 24c5 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller 0e11 00b8 Analog Devices Inc. codec [SoundMAX] 1014 0267 NetVista A30p 1071 8160 MIM2000 1458 a002 GA-8PE667 Ultra 1462 5800 845PE Max (MS-6580) - 24c6 82801DB (ICH4) AC'97 Modem Controller + 24c6 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller 1071 8160 MIM2000 - 24c7 82801DB (ICH4) USB UHCI #3 + 24c7 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 5800 845PE Max (MS-6580) 24ca 82801DBM (ICH4) Ultra ATA Storage Controller 1071 8160 MIM2000 - 24cb 82801DB (ICH4) Ultra ATA 100 Storage Controller + 24cb 82801DB/DBL (ICH4/ICH4-L) UltraATA-100 IDE Controller 1014 0267 NetVista A30p 1458 24c2 GA-8PE667 Ultra 1462 5800 845PE Max (MS-6580) 4c53 1090 Cx9 / Vx9 mainboard 24cc 82801DBM LPC Interface Controller - 24cd 82801DB (ICH4) USB2 EHCI Controller + 24cd 82801DB/DBM (ICH4/ICH4-M) USB 2.0 EHCI Controller 1014 0267 NetVista A30p 1071 8160 MIM2000 1462 3981 845PE Max (MS-6580) @@ -7927,19 +8133,23 @@ 103c 12bc d530 CMT (DG746A) 1458 24d1 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d2 82801EB/ER (ICH5/ICH5R) USB UHCI #1 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d3 82801EB/ER (ICH5/ICH5R) SMBus Controller 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d4 82801EB/ER (ICH5/ICH5R) USB UHCI #2 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24d5 82801EB/ER (ICH5/ICH5R) AC'97 Audio Controller 103c 12bc Analog Devices codec [SoundMAX Integrated Digital Audio] 1043 80f3 P4P800 Mainboard @@ -7950,22 +8160,26 @@ 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24db 82801EB/ER (ICH5/ICH5R) Ultra ATA 100 Storage Controller 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) 1462 7580 MSI 875P + 8086 3427 S875WP1-E mainboard 24dc 82801EB LPC Interface Controller 24dd 82801EB/ER (ICH5/ICH5R) USB2 EHCI Controller 103c 12bc d530 CMT (DG746A) 1043 80a6 P4P800 Mainboard 1458 5006 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24de 82801EB/ER (ICH5/ICH5R) USB UHCI #4 1043 80a6 P4P800 Mainboard 1458 24d2 GA-8IPE1000 Pro2 motherboard (865PE) 1462 7280 865PE Neo2 (MS-6728) + 8086 3427 S875WP1-E mainboard 24df 82801EB (ICH5R) SATA (cc=RAID) 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1028 0095 Precision Workstation 220 Chipset @@ -7984,23 +8198,23 @@ 2534 82860 860 (Wombat) Chipset PCI Bridge 2540 E7500 Memory Controller Hub 15d9 3480 P4DP6 - 2541 E7000 Series Host RASUM Controller + 2541 E7500/E7501 Host RASUM Controller 15d9 3480 P4DP6 4c53 1090 Cx9 / Vx9 mainboard - 2543 E7000 Series Hub Interface B PCI-to-PCI Bridge - 2544 E7000 Series Hub Interface B RASUM Controller + 2543 E7500/E7501 Hub Interface B PCI-to-PCI Bridge + 2544 E7500/E7501 Hub Interface B RASUM Controller 4c53 1090 Cx9 / Vx9 mainboard - 2545 E7000 Series Hub Interface C PCI-to-PCI Bridge - 2546 E7000 Series Hub Interface C RASUM Controller - 2547 E7000 Series Hub Interface D PCI-to-PCI Bridge - 2548 E7000 Series Hub Interface D RASUM Controller + 2545 E7500/E7501 Hub Interface C PCI-to-PCI Bridge + 2546 E7500/E7501 Hub Interface C RASUM Controller + 2547 E7500/E7501 Hub Interface D PCI-to-PCI Bridge + 2548 E7500/E7501 Hub Interface D RASUM Controller 254c E7501 Memory Controller Hub 4c53 1090 Cx9 / Vx9 mainboard 2550 E7505 Memory Controller Hub - 2551 E7000 Series RAS Controller - 2552 E7000 Series Processor to AGP Controller - 2553 E7000 Series Hub Interface B PCI-to-PCI Bridge - 2554 E7000 Series Hub Interface B PCI-to-PCI Bridge RAS Controller + 2551 E7505/E7205 Series RAS Controller + 2552 E7505/E7205 PCI-to-AGP Bridge + 2553 E7505 Hub Interface B PCI-to-PCI Bridge + 2554 E7505 Hub Interface B PCI-to-PCI Bridge RAS Controller 255d E7205 Memory Controller Hub 2560 82845G/GL[Brookdale-G]/GE/PE DRAM Controller/Host-Hub Interface 1458 2560 GA-8PE667 Ultra @@ -8022,14 +8236,17 @@ 2579 82875P Processor to AGP Controller 257b 82875P Processor to PCI to CSA Bridge 257e 82875P Processor to I/O Memory Interface - 2580 Memory Controller Hub - 2581 Memory Controller Hub PCI Express Port - 2582 Graphics Controller - 2584 Workstation Memory Controller Hub - 2585 Workstation Memory Controller Hub PCI Express Port + 2580 915G/P/GV Processor to I/O Controller + 2581 915G/P/GV PCI Express Root Port + 2582 82915G Express Chipset Family Graphics Controller + 2584 925X Memory Controller Hub + 2585 925X PCI Express Root Port 2588 Server Memory Controller Hub 2589 Server Memory Controller Hub PCI Express Port 258a Graphics Controller + 2590 Mobile Memory Controller Hub + 2591 Mobile Memory Controller Hub PCI Express Port + 2592 Mobile Graphics Controller 25a1 6300ESB LPC Interface Controller 25a2 6300ESB PATA Storage Controller 25a3 6300ESB SATA Storage Controller @@ -8043,26 +8260,63 @@ 25ad 6300ESB USB2 Enhanced Host Controller 25ae 6300ESB 64-bit PCI-X Bridge 25b0 6300ESB SATA RAID Controller - 2640 I/O Controller Hub LPC - 2641 I/O Controller Hub LPC - 2642 I/O Controller Hub LPC - 2651 I/O Controller Hub SATA cc=ide - 2652 I/O Controller Hub SATA cc=raid - 2658 I/O Controller Hub USB - 2659 I/O Controller Hub USB - 265a I/O Controller Hub USB - 265b I/O Controller Hub USB - 265c I/O Controller Hub USB2 - 2660 I/O Controller Hub PCI Express Port 0 - 2662 I/O Controller Hub PCI Express Port 1 - 2664 I/O Controller Hub PCI Express Port 2 - 2666 I/O Controller Hub PCI Express Port 3 - 2668 I/O Controller Hub Audio - 266a I/O Controller Hub SMBus - 266d I/O Controller Hub Modem - 266e I/O Controller Hub Audio - 266f I/O Controller Hub PATA - 2782 Graphics Controller + 2600 Server Hub Interface + 2601 Server Hub PCI Express x4 Port D + 2602 Server Hub PCI Express x4 Port C0 + 2603 Server Hub PCI Express x4 Port C1 + 2604 Server Hub PCI Express x4 Port B0 + 2605 Server Hub PCI Express x4 Port B1 + 2606 Server Hub PCI Express x4 Port A0 + 2607 Server Hub PCI Express x4 Port A1 + 2608 Server Hub PCI Express x8 Port C + 2609 Server Hub PCI Express x8 Port B + 260a Server Hub PCI Express x8 Port A + 260c Server Hub IMI Registers + 2610 Server Hub System Bus, Boot, and Interrupt Registers + 2611 Server Hub Address Mapping Registers + 2612 Server Hub RAS Registers + 2613 Server Hub Performance Monitoring Registers + 2614 Server Hub Performance Monitoring Registers + 2615 Server Hub Performance Monitoring Registers + 2617 Server Hub Debug Registers + 2618 Server Hub Debug Registers + 2619 Server Hub Debug Registers + 261a Server Hub Debug Registers + 261b Server Hub Debug Registers + 261c Server Hub Debug Registers + 261d Server Hub Debug Registers + 261e Server Hub Debug Registers + 2620 External Memory Bridge + 2621 External Memory Bridge Control Registers + 2622 External Memory Bridge Memory Interleaving Registers + 2623 External Memory Bridge DDR Initialization and Calibration + 2624 External Memory Bridge Reserved Registers + 2625 External Memory Bridge Reserved Registers + 2626 External Memory Bridge Reserved Registers + 2627 External Memory Bridge Reserved Registers + 2640 82801FB/FR (ICH6/ICH6R) LPC Interface Bridge + 2641 82801FBM (ICH6M) LPC Interface Bridge + 2642 82801FW/FRW (ICH6W/ICH6RW) LPC Interface Bridge + 2651 82801FB/FW (ICH6/ICH6W) SATA Controller + 2652 82801FR/FRW (ICH6R/ICH6RW) SATA Controller + 2653 82801FBM (ICH6M) SATA Controller + 2658 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1 + 2659 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #2 + 265a 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #3 + 265b 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #4 + 265c 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller + 2660 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 1 + 2662 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 2 + 2664 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 3 + 2666 82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 4 + 2668 82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller + 266a 82801FB/FBM/FR/FW/FRW (ICH6 Family) SMBus Controller + 266c 82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller + 266d 82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Modem Controller + 266e 82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Audio Controller + 266f 82801FB/FBM/FR/FW/FRW (ICH6 Family) IDE Controller + 2782 82915G Express Chipset Family Graphics Controller + 2792 Mobile Graphics Controller 3092 Integrated RAID 3200 GD31244 PCI-X SATA HBA 3340 82855PM Processor to I/O Controller @@ -8092,7 +8346,7 @@ 359a Memory Controller Hub PCI Express Port C1 359b Memory Controller Hub Extended Configuration Registers 359e Workstation Memory Controller Hub - 4220 Intel(R) PRO/Wireless 2200BG + 4220 PRO/Wireless 2200BG 5200 EtherExpress PRO/100 Intelligent Server 5201 EtherExpress PRO/100 Intelligent Server 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter @@ -8155,7 +8409,7 @@ 7601 82372FB PIIX5 IDE 7602 82372FB PIIX5 USB 7603 82372FB PIIX5 SMBus - 7800 i740 + 7800 82740 (i740) AGP Graphics Accelerator 003d 0008 Starfighter AGP 003d 000b Starfighter AGP 1092 0100 Stealth II G460 @@ -8175,7 +8429,9 @@ 84e6 460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB) 84ea 460GX - 84460GX AGP Bridge (GXB function 1) 8500 IXP4xx Family Network Processor (IXP420, 421, 422, 425 and IXC1100) - 9000 Intel IXP2000 Familly Network Processor + 9000 Intel IXP2000 Family Network Processor + 9001 Intel IXP2400 Network Processor + 9004 Intel IXP2800 Network Processor 9621 Integrated RAID 9622 Integrated RAID 9641 Integrated RAID @@ -8184,10 +8440,12 @@ # observed, and documented in Intel revision note; new mask of 1011:0026 b154 21154 PCI-to-PCI Bridge b555 21555 Non transparent PCI-to-PCI Bridge + 1331 0030 Radisys ENP-2611 4c53 1050 CT7 mainboard 4c53 1051 CE7 mainboard e4bf 1000 CC8-1-BLUES ffff 450NX/GX [Orion] - 82453KX/GX Memory controller [BUG] +8401 TRENDware International Inc. 8800 Trigem Computer Inc. 2008 Video assistent component 8866 T-Square Design Inc. @@ -8352,15 +8610,18 @@ 00c1 AIC-7899B U160/m 00c3 AIC-7899D U160/m 00c5 RAID subsystem HBA - 1028 00c5 PowerEdge 2550 + 1028 00c5 PowerEdge 2400,2500,2550,4400 00cf AIC-7899P U160/m 1028 00ce PowerEdge 1400 1028 00d1 PowerEdge 2550 10f1 2462 Thunder K7 S2462 15d9 9005 Onboard SCSI Host Adapter + 8086 3411 SDS2 Mainboard 0250 ServeRAID Controller 1014 0279 ServeRAID-xx 1014 028c ServeRAID-xx +# from kernel sources + 0279 ServeRAID 6M 0283 AAC-RAID 9005 0283 Catapult 0284 AAC-RAID @@ -8429,7 +8690,7 @@ 1000 0012 1P2S 9845 PCI 9845 Multi-I/O Controller 1000 0006 0P6S (6 port 16550a serial card) - 9855 PCI 9855 Multi-I/O Controller 4 Serial 1 Parallel + 9855 PCI 9855 Multi-I/O Controller 1000 0014 1P4S 9902 Stargen Inc. 0001 SG2010 PCI over Starfabric Bridge @@ -8444,6 +8705,7 @@ a304 Sony a727 3Com Corporation aa42 Scitex Digital Video ac1e Digital Receiver Technology Inc +aecb Adrienne Electronics Corporation b1b3 Shiva Europe Limited # Pinnacle should be 11bd, but they got it wrong several times --mj bd11 Pinnacle Systems, Inc. (Wrong ID) @@ -8464,9 +8726,9 @@ d84d Exsys dead Indigita Corporation e000 Winbond e000 W89C940 -# see : http://www.schoenfeld.de/inside/Inside_CWMK3.txt -e159 Individual Computers - Jens Schoenfeld - 0001 Intel 537 +# see also : http://www.schoenfeld.de/inside/Inside_CWMK3.txt maybe a misuse of TJN id or it use the TJN 3XX chip for other applic +e159 Tiger Jet Network Inc. + 0001 Tiger3XX Modem/ISDN interface 0059 0001 128k ISDN-S/T Adapter 0059 0003 128k ISDN-U Adapter 0002 Tiger100APC ISDN chipset diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ee7b9feb6..e88017d6f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -373,7 +373,10 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max child->bridge_ctl = bctl; cmax = pci_scan_child_bus(child); - if (cmax > max) max = cmax; + if (cmax > max) + max = cmax; + if (child->subordinate > max) + max = child->subordinate; } else { /* * We need to assign a number to this bus which we always @@ -571,6 +574,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... @@ -640,7 +648,7 @@ pci_scan_single_device(struct pci_bus *bus, int devfn) return NULL; /* Fix up broken headers */ - pci_fixup_device(PCI_FIXUP_HEADER, dev); + pci_fixup_device(pci_fixup_header, dev); /* * Add the device to our list of discovered devices @@ -772,6 +780,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/quirks.c b/drivers/pci/quirks.c index 6e7c35013..164f738df 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1,10 +1,10 @@ /* - * $Id: quirks.c,v 1.5 1998/05/02 19:24:14 mj Exp $ - * * This file contains work-arounds for many known PCI hardware * bugs. Devices present only on certain architectures (host * bridges et cetera) should be handled in arch-specific code. * + * Note: any quirks for hotpluggable devices must _NOT_ be declared __init. + * * Copyright (c) 1999 Martin Mares * * The bridge optimization stuff has been removed. If you really @@ -39,6 +39,7 @@ static void __devinit quirk_passive_release(struct pci_dev *dev) } } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); /* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround but VIA don't answer queries. If you happen to have good contacts at VIA @@ -46,8 +47,6 @@ static void __devinit quirk_passive_release(struct pci_dev *dev) This appears to be BIOS not version dependent. So presumably there is a chipset level fix */ - - int isa_dma_bridge_buggy; /* Exported */ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) @@ -57,34 +56,47 @@ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) printk(KERN_INFO "Activating ISA DMA hang workarounds.\n"); } } + /* + * Its not totally clear which chipsets are the problematic ones + * We know 82C586 and 82C596 variants are affected. + */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs ); int pci_pci_problems; /* * Chipsets where PCI->PCI transfers vanish or hang */ - static void __devinit quirk_nopcipci(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_FAIL)==0) - { + if ((pci_pci_problems & PCIPCI_FAIL)==0) { printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_FAIL; + pci_pci_problems |= PCIPCI_FAIL; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); /* * Triton requires workarounds to be used by the drivers */ - static void __devinit quirk_triton(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_TRITON)==0) - { + if ((pci_pci_problems&PCIPCI_TRITON)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_TRITON; + pci_pci_problems |= PCIPCI_TRITON; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton ); /* * VIA Apollo KT133 needs PCI latency patch @@ -104,19 +116,16 @@ static void __devinit quirk_vialatency(struct pci_dev *dev) /* Ok we have a potential problem chipset here. Now see if we have a buggy southbridge */ - p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); - if(p!=NULL) - { + p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); + if (p!=NULL) { pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ /* Check for buggy part revisions */ if (rev < 0x40 || rev > 0x42) return; - } - else - { + } else { p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); - if(p==NULL) /* No problem parts */ + if (p==NULL) /* No problem parts */ return; pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* Check for buggy part revisions */ @@ -145,27 +154,30 @@ static void __devinit quirk_vialatency(struct pci_dev *dev) pci_write_config_byte(dev, 0x76, busarb); printk(KERN_INFO "Applying VIA southbridge workaround.\n"); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); /* * VIA Apollo VP3 needs ETBF on BT848/878 */ - static void __devinit quirk_viaetbf(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_VIAETBF)==0) - { + if ((pci_pci_problems&PCIPCI_VIAETBF)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_VIAETBF; + pci_pci_problems |= PCIPCI_VIAETBF; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf ); + static void __devinit quirk_vsfx(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_VSFX)==0) - { + if ((pci_pci_problems&PCIPCI_VSFX)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_VSFX; + pci_pci_problems |= PCIPCI_VSFX; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx ); /* * Ali Magik requires workarounds to be used by the drivers @@ -173,36 +185,38 @@ static void __devinit quirk_vsfx(struct pci_dev *dev) * workaround applied too * [Info kindly provided by ALi] */ - static void __init quirk_alimagik(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_ALIMAGIK)==0) - { + if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_ALIMAGIK|PCIPCI_TRITON; + pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON; } } - +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik ); /* * Natoma has some interesting boundary conditions with Zoran stuff * at least */ - static void __devinit quirk_natoma(struct pci_dev *dev) { - if((pci_pci_problems&PCIPCI_NATOMA)==0) - { + if ((pci_pci_problems&PCIPCI_NATOMA)==0) { printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); - pci_pci_problems|=PCIPCI_NATOMA; + pci_pci_problems |= PCIPCI_NATOMA; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma ); /* * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. * If it's needed, re-allocate the region. */ - static void __devinit quirk_s3_64M(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; @@ -212,6 +226,8 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev) r->end = 0x3ffffff; } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M ); static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr) { @@ -231,7 +247,6 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsi * ATI Northbridge setups MCE the processor if you even * read somewhere between 0x3b0->0x3bb or read 0x3d3 */ - static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) { printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n"); @@ -239,6 +254,7 @@ static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) request_region(0x3b0, 0x0C, "RadeonIGP"); request_region(0x3d3, 0x01, "RadeonIGP"); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce ); /* * Let's make the southbridge information explicit instead @@ -260,6 +276,7 @@ static void __devinit quirk_ali7101_acpi(struct pci_dev *dev) pci_read_config_word(dev, 0xE2, ®ion); quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi ); /* * PIIX4 ACPI: Two IO regions pointed to by longwords at @@ -275,6 +292,7 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x90, ®ion); quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi ); /* * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at @@ -291,6 +309,15 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x58, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); /* * VIA ACPI: One IO region pointed to by longword at @@ -308,6 +335,7 @@ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi ); /* * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at @@ -330,6 +358,7 @@ static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev) smb &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi ); #ifdef CONFIG_X86_IO_APIC @@ -358,6 +387,7 @@ static void __devinit quirk_via_ioapic(struct pci_dev *dev) /* Offset 0x58: External APIC IRQ output control */ pci_write_config_byte (dev, 0x58, tmp); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); /* * The AMD io apic can hang the box when an apic irq is masked. @@ -368,30 +398,29 @@ static void __devinit quirk_via_ioapic(struct pci_dev *dev) * noapic specified. For the moment we assume its the errata. We may be wrong * of course. However the advice is demonstrably good even if so.. */ - static void __devinit quirk_amd_ioapic(struct pci_dev *dev) { u8 rev; pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - if(rev >= 0x02) - { + if (rev >= 0x02) { printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n"); printk(KERN_WARNING " : booting with the \"noapic\" option.\n"); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic ); static void __init quirk_ioapic_rmw(struct pci_dev *dev) { if (dev->devfn == 0 && dev->bus->number == 0) sis_apic_bug = 1; } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw ); #define AMD8131_revA0 0x01 #define AMD8131_revB0 0x11 #define AMD8131_MISC 0x40 #define AMD8131_NIOAMODE_BIT 0 - static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) { unsigned char revid, tmp; @@ -407,6 +436,7 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) pci_write_config_byte( dev, AMD8131_MISC, tmp); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, quirk_amd_8131_ioapic ); #endif /* CONFIG_X86_IO_APIC */ @@ -444,6 +474,8 @@ static void __devinit quirk_via_acpi(struct pci_dev *d) if (irq && (irq != 2)) d->irq = irq; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); static void __devinit quirk_via_irqpic(struct pci_dev *dev) { @@ -459,6 +491,9 @@ static void __devinit quirk_via_irqpic(struct pci_dev *dev) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic ); /* @@ -480,6 +515,8 @@ static void __devinit quirk_piix3_usb(struct pci_dev *dev) legsup &= 0x50ef; pci_write_config_word(dev, 0xc0, legsup); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb ); /* * VIA VT82C598 has its device ID settable and many BIOSes @@ -492,6 +529,7 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev) pci_write_config_byte(dev, 0xfc, 0); pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id ); /* * CardBus controllers have a legacy base address that enables them @@ -505,6 +543,7 @@ static void __devinit quirk_cardbus_legacy(struct pci_dev *dev) return; pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0); } +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy ); /* * Following the PCI ordering rules is optional on the AMD762. I'm not @@ -513,13 +552,11 @@ static void __devinit quirk_cardbus_legacy(struct pci_dev *dev) * To be fair to AMD, it follows the spec by default, its BIOS people * who turn it off! */ - static void __devinit quirk_amd_ordering(struct pci_dev *dev) { u32 pcic; pci_read_config_dword(dev, 0x4C, &pcic); - if((pcic&6)!=6) - { + if ((pcic&6)!=6) { pcic |= 6; printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n"); pci_write_config_dword(dev, 0x4C, pcic); @@ -528,6 +565,7 @@ static void __devinit quirk_amd_ordering(struct pci_dev *dev) pci_write_config_dword(dev, 0x84, pcic); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); /* * DreamWorks provided workaround for Dunord I-3000 problem @@ -536,18 +574,26 @@ static void __devinit quirk_amd_ordering(struct pci_dev *dev) * assigned to it. We force a larger allocation to ensure that * nothing gets put too close to it. */ - static void __devinit quirk_dunord ( struct pci_dev * dev ) { - struct resource * r = & dev -> resource [ 1 ]; - r -> start = 0; - r -> end = 0xffffff; + struct resource *r = &dev->resource [1]; + r->start = 0; + r->end = 0xffffff; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord ); +/* + * i82380FB mobile docking controller: its PCI-to-PCI bridge + * is subtractive decoding (transparent), and does indicate this + * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80 + * instead of 0x01. + */ static void __devinit quirk_transparent_bridge(struct pci_dev *dev) { dev->transparent = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge ); /* * Common misconfiguration of the MediaGX/Geode PCI master that will @@ -555,7 +601,6 @@ static void __devinit quirk_transparent_bridge(struct pci_dev *dev) * datasheets found at http://www.national.com/ds/GX for info on what * these bits do. */ - static void __init quirk_mediagx_master(struct pci_dev *dev) { u8 reg; @@ -566,6 +611,7 @@ static void __init quirk_mediagx_master(struct pci_dev *dev) pci_write_config_byte(dev, 0x41, reg); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); /* * As per PCI spec, ignore base address registers 0-3 of the IDE controllers @@ -584,7 +630,6 @@ static void __init quirk_mediagx_master(struct pci_dev *dev) * we do now ? We don't want is pci_enable_device to come along * and assign new resources. Both approaches work for that. */ - static void __devinit quirk_ide_bases(struct pci_dev *dev) { struct resource *res; @@ -616,34 +661,33 @@ static void __devinit quirk_ide_bases(struct pci_dev *dev) printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n", first_bar, last_bar, pci_name(dev)); } +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases ); /* * Ensure C0 rev restreaming is off. This is normally done by * the BIOS but in the odd case it is not the results are corruption * hence the presence of a Linux check */ - static void __init quirk_disable_pxb(struct pci_dev *pdev) { u16 config; u8 rev; pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - if(rev != 0x04) /* Only C0 requires this */ + if (rev != 0x04) /* Only C0 requires this */ return; pci_read_config_word(pdev, 0x40, &config); - if(config & (1<<6)) - { + if (config & (1<<6)) { config &= ~(1<<6); pci_write_config_word(pdev, 0x40, config); printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n"); } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); /* * VIA northbridges care about PCI_INTERRUPT_LINE */ - int interrupt_line_quirk; static void __devinit quirk_via_bridge(struct pci_dev *pdev) @@ -651,6 +695,7 @@ static void __devinit quirk_via_bridge(struct pci_dev *pdev) if(pdev->devfn == 0) interrupt_line_quirk = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge ); /* * Serverworks CSB5 IDE does not fully support native mode @@ -667,15 +712,16 @@ static void __init quirk_svwks_csb5ide(struct pci_dev *pdev) quirk_ide_bases(pdev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide ); /* This was originally an Alpha specific thing, but it really fits here. * The i82375 PCI/EISA bridge appears as non-classified. Fix that. */ - static void __init quirk_eisa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_EISA << 8; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge @@ -689,7 +735,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev) * becomes necessary to do this tweak in two steps -- I've chosen the Host * bridge as trigger. */ - static int __initdata asus_hides_smbus = 0; static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) @@ -699,6 +744,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) switch(dev->subsystem_device) { case 0x8070: /* P4B */ case 0x8088: /* P4B533 */ + case 0x1626: /* L3C notebook */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) @@ -730,8 +776,20 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x0890: /* HP Compaq nc6000 */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + switch (dev->subsystem_device) { + case 0x12bc: /* HP D330L */ + asus_hides_smbus = 1; + } } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); static void __init asus_hides_smbus_lpc(struct pci_dev *dev) { @@ -744,12 +802,17 @@ static void __init asus_hides_smbus_lpc(struct pci_dev *dev) if (val & 0x8) { pci_write_config_word(dev, 0xF2, val & (~0x8)); pci_read_config_word(dev, 0xF2, &val); - if(val & 0x8) + if (val & 0x8) printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); else printk(KERN_INFO "PCI: Enabled i801 SMBus device\n"); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); /* * SiS 96x south bridge: BIOS typically hides SMBus device... @@ -803,6 +866,19 @@ static void __init quirk_sis_96x_compatible(struct pci_dev *dev) { sis_96x_compatible = 1; } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible ); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); #ifdef CONFIG_X86_IO_APIC static void __init quirk_alder_ioapic(struct pci_dev *pdev) @@ -815,16 +891,17 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev) /* the first BAR is the location of the IO APIC...we must * not touch this (and it's already covered by the fixmap), so * forcibly insert it into the resource tree */ - if(pci_resource_start(pdev, 0) && pci_resource_len(pdev, 0)) + if (pci_resource_start(pdev, 0) && pci_resource_len(pdev, 0)) insert_resource(&iomem_resource, &pdev->resource[0]); /* The next five BARs all seem to be rubbish, so just clean * them out */ - for(i=1; i < 6; i++) { + for (i=1; i < 6; i++) { memset(&pdev->resource[i], 0, sizeof(pdev->resource[i])); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic ); #endif #ifdef CONFIG_SCSI_SATA @@ -898,6 +975,7 @@ static void __init quirk_intel_ide_combined(struct pci_dev *pdev) else request_region(0x170, 8, "libata"); /* port 1 */ } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined ); #endif /* CONFIG_SCSI_SATA */ int pciehp_msi_quirk; @@ -906,163 +984,45 @@ static void __devinit quirk_pciehp_msi(struct pci_dev *pdev) { pciehp_msi_quirk = 1; } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi ); -/* - * The main table of quirks. - * - * Note: any hooks for hotpluggable devices in this table must _NOT_ - * be declared __init. - */ - -static struct pci_fixup pci_fixups[] __devinitdata = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, - /* - * Its not totally clear which chipsets are the problematic ones - * We know 82C586 and 82C596 variants are affected. - */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi }, - - /* Intel LPC interface bridges all have 128 bytes of magic ACPI/TCO regs and 64 bytes of GPIO */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi }, - - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb }, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge }, - { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy }, - -#ifdef CONFIG_X86_IO_APIC - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, - quirk_amd_8131_ioapic }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic }, -#endif - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic }, - - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce }, - /* - * i82380FB mobile docking controller: its PCI-to-PCI bridge - * is subtractive decoding (transparent), and does indicate this - * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80 - * instead of 0x01. - */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge }, - - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master }, - - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide }, - - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge }, - /* - * on Asus P4B boards, the i801SMBus device is disabled at startup. - * this also goes for boards in HP Compaq nc6000 and nc8000 notebooks. - */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc }, - -#ifdef CONFIG_SCSI_SATA - /* Fixup BIOSes that configure Parallel ATA (PATA / IDE) and - * Serial ATA (SATA) into the same PCI ID. - */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, - quirk_intel_ide_combined }, -#endif /* CONFIG_SCSI_SATA */ - - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi }, - - { 0 } -}; - - -static void pci_do_fixups(struct pci_dev *dev, int pass, struct pci_fixup *f) +static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { - while (f->pass) { - if (f->pass == pass && - (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && + while (f < end) { + if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { -#ifdef DEBUG - printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); -#endif + pr_debug(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); f->hook(dev); } f++; } } -void pci_fixup_device(int pass, struct pci_dev *dev) +extern struct pci_fixup __start_pci_fixups_header[]; +extern struct pci_fixup __end_pci_fixups_header[]; +extern struct pci_fixup __start_pci_fixups_final[]; +extern struct pci_fixup __end_pci_fixups_final[]; + +void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) { - pci_do_fixups(dev, pass, pcibios_fixups); - pci_do_fixups(dev, pass, pci_fixups); + struct pci_fixup *start, *end; + + switch(pass) { + case pci_fixup_header: + start = __start_pci_fixups_header; + end = __end_pci_fixups_header; + break; + + case pci_fixup_final: + start = __start_pci_fixups_final; + end = __end_pci_fixups_final; + break; + default: + /* stupid compiler warning, you would think with an enum... */ + return; + } + pci_do_fixups(dev, start, end); } EXPORT_SYMBOL(pciehp_msi_quirk); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 5ef19b175..889b2e3ac 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/pci/setup-bus.c b/drivers/pci/setup-bus.c index 7f0f6c209..e21250c39 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -537,10 +537,11 @@ pci_assign_unassigned_resources(void) /* Depth first, calculate sizes and alignments of all subordinate buses. */ - for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) + list_for_each(ln, &pci_root_buses) { pci_bus_size_bridges(pci_bus_b(ln)); + } /* Depth last, allocate resources and update the hardware. */ - for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) { + list_for_each(ln, &pci_root_buses) { pci_bus_assign_resources(pci_bus_b(ln)); pci_enable_bridges(pci_bus_b(ln)); } diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index bd79f3bd1..124225edc 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/cardbus.c b/drivers/pcmcia/cardbus.c index 4dab2ffc8..1b86c6d3a 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -85,7 +85,7 @@ =====================================================================*/ -static u_int xlate_rom_addr(u_char * b, u_int addr) +static u_int xlate_rom_addr(void __iomem *b, u_int addr) { u_int img = 0, ofs = 0, sz; u_short data; diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index b78d41a3c..317ca50a3 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -103,7 +103,7 @@ void release_cis_mem(struct pcmcia_socket *s) * If flags & MAP_ATTRIB, map the attribute space, otherwise * map the memory space. */ -static unsigned char * +static void __iomem * set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) { pccard_mem_map *mem = &s->cis_mem; @@ -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; } @@ -143,7 +141,8 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr) { - u_char *sys, *end, *buf = ptr; + void __iomem *sys, *end; + unsigned char *buf = ptr; cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len); @@ -206,7 +205,8 @@ int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr) { - u_char *sys, *end, *buf = ptr; + void __iomem *sys, *end; + unsigned char *buf = ptr; cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f796bc99c..c33ac2756 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -427,8 +427,6 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) return ret; } /* send_event */ -#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100) - static void socket_remove_drivers(struct pcmcia_socket *skt) { client_t *client; @@ -448,8 +446,7 @@ static void socket_shutdown(struct pcmcia_socket *skt) socket_remove_drivers(skt); skt->state &= SOCKET_INUSE|SOCKET_PRESENT; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(shutdown_delay)); + msleep(shutdown_delay * 10); skt->state &= SOCKET_INUSE; shutdown_socket(skt); } @@ -467,8 +464,7 @@ static int socket_reset(struct pcmcia_socket *skt) skt->socket.flags &= ~SS_RESET; skt->ops->set_socket(skt, &skt->socket); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(unreset_delay)); + msleep(unreset_delay * 10); for (i = 0; i < unreset_limit; i++) { skt->ops->get_status(skt, &status); @@ -478,8 +474,7 @@ static int socket_reset(struct pcmcia_socket *skt) if (status & SS_READY) return CS_SUCCESS; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(unreset_check)); + msleep(unreset_check * 10); } cs_err(skt, "time out after reset.\n"); @@ -496,8 +491,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) if (!(status & SS_DETECT)) return CS_NO_CARD; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(initial_delay)); + msleep(initial_delay * 10); for (i = 0; i < 100; i++) { skt->ops->get_status(skt, &status); @@ -507,8 +501,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) if (!(status & SS_PENDING)) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(10)); + msleep(100); } if (status & SS_PENDING) { @@ -541,8 +534,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) /* * Wait "vcc_settle" for the supply to stabilise. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(vcc_settle)); + msleep(vcc_settle * 10); skt->ops->get_status(skt, &status); if (!(status & SS_POWERON)) { @@ -659,10 +651,8 @@ static void socket_detect_change(struct pcmcia_socket *skt) if (!(skt->state & SOCKET_SUSPEND)) { int status; - if (!(skt->state & SOCKET_PRESENT)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cs_to_timeout(2)); - } + if (!(skt->state & SOCKET_PRESENT)) + msleep(20); skt->ops->get_status(skt, &status); if ((skt->state & SOCKET_PRESENT) && @@ -1886,11 +1876,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 +1897,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/ds.c b/drivers/pcmcia/ds.c index 71592c71d..b4f741a12 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -133,7 +134,7 @@ static dev_info_t dev_info = "Driver Services"; static int major_dev = -1; -extern struct proc_dir_entry *proc_pccard; +static struct proc_dir_entry *proc_pccard; /*====================================================================*/ @@ -1080,8 +1081,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) * Ugly. But we want to wait for the socket threads to have started up. * We really should let the drivers themselves drive some of this.. */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/4); + msleep(250); init_waitqueue_head(&s->queue); init_waitqueue_head(&s->request); diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index fd08c3a5b..875c9cfae 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 3115eb3bc..eb255238a 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, ®ion, 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 b753c3186..561974efb 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -513,8 +513,7 @@ static u_int __init test_irq(u_short sock, int irq) if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0) return 1; irq_hits = 0; irq_sock = sock; - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); + msleep(10); if (irq_hits) { free_irq(irq, i365_count_irq); debug(2, " spurious hit!\n"); @@ -1159,13 +1158,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 +1172,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 +1186,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 +1308,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 57b1bca00..4f00c9dda 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/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 491d11bc8..2bdf9a004 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -178,39 +179,6 @@ int pxa2xx_drv_pcmcia_probe(struct device *dev) first = ops->first; nr = ops->nr; - /* Setup GPIOs for PCMCIA/CF alternate function mode. - * - * It would be nice if set_GPIO_mode included support - * for driving GPIO outputs to default high/low state - * before programming GPIOs as outputs. Setting GPIO - * outputs to default high/low state via GPSR/GPCR - * before defining them as outputs should reduce - * the possibility of glitching outputs during GPIO - * setup. This of course assumes external terminators - * are present to hold GPIOs in a defined state. - * - * In the meantime, setup default state of GPIO - * outputs before we enable them as outputs. - */ - - GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | - GPIO_bit(GPIO49_nPWE) | - GPIO_bit(GPIO50_nPIOR) | - GPIO_bit(GPIO51_nPIOW) | - GPIO_bit(GPIO52_nPCE_1) | - GPIO_bit(GPIO53_nPCE_2); - - pxa_gpio_mode(GPIO48_nPOE_MD); - pxa_gpio_mode(GPIO49_nPWE_MD); - pxa_gpio_mode(GPIO50_nPIOR_MD); - pxa_gpio_mode(GPIO51_nPIOW_MD); - pxa_gpio_mode(GPIO52_nPCE_1_MD); - pxa_gpio_mode(GPIO53_nPCE_2_MD); - pxa_gpio_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */ - pxa_gpio_mode(GPIO55_nPREG_MD); - pxa_gpio_mode(GPIO56_nPWAIT_MD); - pxa_gpio_mode(GPIO57_nIOIS16_MD); - /* Provide our PXA2xx specific timing routines. */ ops->set_timing = pxa2xx_pcmcia_set_timing; #ifdef CONFIG_CPU_FREQ diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index e22a57a4a..48726e739 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -25,10 +25,40 @@ #include #include #include +#include #include #include "sa1111_generic.h" +static int +lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + /* + * Setup default state of GPIO outputs + * before we enable them as outputs. + */ + GPSR(GPIO48_nPOE) = + GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | + GPIO_bit(GPIO52_nPCE_1) | + GPIO_bit(GPIO53_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO52_nPCE_1_MD); + pxa_gpio_mode(GPIO53_nPCE_2_MD); + pxa_gpio_mode(GPIO54_pSKTSEL_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + + return sa1111_pcmcia_hw_init(skt); +} + static int lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) @@ -201,7 +231,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static struct pcmcia_low_level lubbock_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = sa1111_pcmcia_hw_init, + .hw_init = lubbock_pcmcia_hw_init, .hw_shutdown = sa1111_pcmcia_hw_shutdown, .socket_state = sa1111_pcmcia_socket_state, .configure_socket = lubbock_pcmcia_configure_socket, diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index fe62a597d..5309734e1 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "soc_common.h" @@ -38,6 +39,29 @@ static struct pcmcia_irqs irqs[] = { static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { + /* + * Setup default state of GPIO outputs + * before we enable them as outputs. + */ + GPSR(GPIO48_nPOE) = + GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | + GPIO_bit(GPIO85_nPCE_1) | + GPIO_bit(GPIO54_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO85_nPCE_1_MD); + pxa_gpio_mode(GPIO54_nPCE_2_MD); + pxa_gpio_mode(GPIO79_pSKTSEL_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 6869e209d..620b20f7e 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -88,6 +88,9 @@ static resource_map_t io_db = { }; static DECLARE_MUTEX(rsrc_sem); +static unsigned int rsrc_mem_probe; +#define MEM_PROBE_LOW (1 << 0) +#define MEM_PROBE_HIGH (1 << 1) #ifdef CONFIG_PCMCIA_PROBE @@ -301,8 +304,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 +313,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; @@ -325,15 +324,13 @@ static int checksum(struct pcmcia_socket *s, struct resource *res) { pccard_mem_map map; int i, a = 0, b = -1, d; - void *virt; + void __iomem *virt; virt = ioremap(res->start, s->map_size); if (virt) { 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); @@ -457,24 +454,21 @@ static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s) return do_mem_probe(m->base, m->num, s); } -static void validate_mem(struct pcmcia_socket *s) +static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { resource_map_t *m, mm; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; - static int hi = 0, lo = 0; u_long b, i, ok = 0; - int force_low = !(s->features & SS_CAP_PAGE_REGS); - down(&rsrc_sem); /* We do up to four passes through the list */ - if (!force_low) { - if (hi++ || (inv_probe(mem_db.next, s) > 0)) - goto out; + if (probe_mask & MEM_PROBE_HIGH) { + if (inv_probe(mem_db.next, s) > 0) + return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } - if (lo++) - goto out; + if ((probe_mask & MEM_PROBE_LOW) == 0) + return; for (m = mem_db.next; m != &mem_db; m = mm.next) { mm = *m; /* Only probe < 1 MB */ @@ -494,38 +488,51 @@ static void validate_mem(struct pcmcia_socket *s) } } } - out: - up(&rsrc_sem); } #else /* CONFIG_PCMCIA_PROBE */ -static void validate_mem(struct pcmcia_socket *s) +static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { - resource_map_t *m, mm; - static int done = 0; + resource_map_t *m, mm; - if (done++ == 0) { - down(&rsrc_sem); for (m = mem_db.next; m != &mem_db; m = mm.next) { - mm = *m; - if (do_mem_probe(mm.base, mm.num, s)) - break; + mm = *m; + if (do_mem_probe(mm.base, mm.num, s)) + break; } - up(&rsrc_sem); - } } #endif /* CONFIG_PCMCIA_PROBE */ +/* + * Locking note: this is the only place where we take + * both rsrc_sem and skt_sem. + */ void pcmcia_validate_mem(struct pcmcia_socket *s) { - down(&s->skt_sem); + if (probe_mem) { + unsigned int probe_mask; + + down(&rsrc_sem); + + probe_mask = MEM_PROBE_LOW; + if (s->features & SS_CAP_PAGE_REGS) + probe_mask = MEM_PROBE_HIGH; + + if (probe_mask & ~rsrc_mem_probe) { + rsrc_mem_probe |= probe_mask; - if (probe_mem && s->state & SOCKET_PRESENT) - validate_mem(s); + down(&s->skt_sem); - up(&s->skt_sem); + if (s->state & SOCKET_PRESENT) + validate_mem(s, probe_mask); + + up(&s->skt_sem); + } + + up(&rsrc_sem); + } } EXPORT_SYMBOL(pcmcia_validate_mem); diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index e442953b3..64fd5e37f 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -96,8 +97,7 @@ static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt) set_h3600_egpio(IPAQ_EGPIO_OPT_ON); clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10*HZ / 1000); + msleep(10); soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6d393e739..a45fee3f4 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -49,6 +49,11 @@ #include "soc_common.h" +/* FIXME: platform dependent resource declaration has to move out of this file */ +#ifdef CONFIG_ARCH_PXA +#include +#endif + #ifdef DEBUG static int pc_debug; @@ -448,9 +453,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 +665,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 +683,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 +781,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 f3b38e96d..d986d13f2 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 4c8a7a572..d6974a147 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, ®ion, 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++) { @@ -1088,6 +1091,7 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), diff --git a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h index 7c3bfbfaa..7f04a6b73 100644 --- a/drivers/pcmcia/yenta_socket.h +++ b/drivers/pcmcia/yenta_socket.h @@ -107,7 +107,7 @@ struct cardbus_type { struct yenta_socket { struct pci_dev *dev; int cb_irq, io_irq; - void *base; + void __iomem *base; struct timer_list poll_timer; struct pcmcia_socket socket; diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 781a4c064..f7548c410 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -240,12 +240,14 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); int i, ret; - pnp_info_buffer_t *buffer = (pnp_info_buffer_t *) - pnp_alloc(sizeof(pnp_info_buffer_t)); - if (!buffer) - return -ENOMEM; + pnp_info_buffer_t *buffer; + if (!dev) return -EINVAL; + + buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); + if (!buffer) + return -ENOMEM; buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index ee6d1ed50..bf52990a8 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -655,8 +655,10 @@ static int __init isapnp_create_device(struct pnp_card *card, if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; option = pnp_register_independent_option(dev); - if (!option) + if (!option) { + kfree(dev); return 1; + } pnp_add_card_device(card,dev); while (1) { diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index c224f74fa..ca7996d4b 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -69,14 +69,14 @@ __asm__( #define Q_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(cpu_gdt_table[cpu][(selname) >> 3], __va((u32)(address))); \ -set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ +set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \ +set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ } while(0) #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(cpu_gdt_table[cpu][(selname) >> 3], (u32)(address)); \ -set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ +set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \ +set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ } while(0) static struct desc_struct bad_bios_desc = { 0, 0x00409200 }; @@ -115,8 +115,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, return PNP_FUNCTION_NOT_SUPPORTED; cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc; /* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave(&pnp_bios_lock, flags); @@ -158,7 +158,7 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, ); spin_unlock_irqrestore(&pnp_bios_lock, flags); - cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40; put_cpu(); /* If we get here and this is set then the PnP BIOS faulted on us. */ diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 6c9866346..1a2fe19dd 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -252,8 +252,10 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; - if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) + if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) { + kfree(node); return -ENODEV; + } if(pnpbios_write_resources_to_node(res, node)<0) { kfree(node); return -1; diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index 88fcd1668..2fa4d21c7 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -90,8 +90,10 @@ static int proc_read_escd(char *buf, char **start, off_t pos, tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL); if (!tmpbuf) return -ENOMEM; - if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) + if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) { + kfree(tmpbuf); return -EIO; + } escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256; @@ -168,8 +170,10 @@ static int proc_read_node(char *buf, char **start, off_t pos, node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - if (pnp_bios_get_dev_node(&nodenum, boot, node)) + if (pnp_bios_get_dev_node(&nodenum, boot, node)) { + kfree(node); return -EIO; + } len = node->size - sizeof(struct pnp_bios_node); memcpy(buf, node->data, len); kfree(node); diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index f990065e1..7aafbf80d 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -346,12 +346,12 @@ pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struc { unsigned int len, tag; int priority = 0; - struct pnp_option *option; + struct pnp_option *option, *option_independent; if (!p) return NULL; - option = pnp_register_independent_option(dev); + option_independent = option = pnp_register_independent_option(dev); if (!option) return NULL; @@ -428,9 +428,14 @@ pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struc case SMALL_TAG_ENDDEP: if (len != 0) goto len_err; + if (option_independent == option) + printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n"); + option = option_independent; break; case SMALL_TAG_END: + if (option_independent != option) + printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_ENDDEP tag\n"); p = p + 2; return (unsigned char *)p; break; diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index da52c86dc..d42015c38 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -104,4 +104,8 @@ static int __init pnp_system_init(void) return pnp_register_driver(&system_pnp_driver); } -subsys_initcall(pnp_system_init); +/** + * Reserve motherboard resources after PCI claim BARs, + * but before PCI assign resources for uninitialized PCI devices + */ +fs_initcall(pnp_system_init); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index cc79775b0..deaecd080 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.37 $ + * $Revision: 1.38 $ */ #include @@ -304,8 +304,11 @@ dasd_diag_check_device(struct dasd_device *device) (device->bp_block >> 10), (device->blocks << device->s2b_shift) >> 1); rc = 0; - } else + } else { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "volume has incompatible disk layout"); rc = -EMEDIUMTYPE; + } free_page((long) label); return rc; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 27bf674af..56f471c23 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.57 $ + * $Revision: 1.61 $ */ #include @@ -68,6 +68,10 @@ static struct ccw_device_id dasd_eckd_ids[] = { { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4}, { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5}, { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6}, + { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7}, + { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8}, + { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9}, + { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa}, { /* end of list */ }, }; @@ -274,9 +278,11 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, data->attributes.mode = 0x3; /* ECKD */ - if (private->rdc_data.cu_type == 0x2105 + if ((private->rdc_data.cu_type == 0x2105 || + private->rdc_data.cu_type == 0x2107 || + private->rdc_data.cu_type == 0x1750) && !(private->uses_cdl && trk < 2)) - data->ga_extended |= 0x40; + data->ga_extended |= 0x40; /* Regular Data Format Mode */ geo.cyl = private->rdc_data.no_cyl; geo.head = private->rdc_data.trk_per_cyl; @@ -499,11 +505,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device) "sizes of configuration data mismatch" "%d (read) vs %ld (expected)", conf_len, sizeof (struct dasd_eckd_confdata)); + + kfree(conf_data); /* allocated by read_conf_data() */ return 0; /* no errror */ } memcpy(&private->conf_data, conf_data, sizeof (struct dasd_eckd_confdata)); - + kfree(conf_data); /* allocated by read_conf_data() */ return 0; } @@ -903,6 +911,8 @@ dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb) switch (cdev->id.cu_type) { case 0x3990: case 0x2105: + case 0x2107: + case 0x1750: return dasd_3990_erp_examine(cqr, irb); case 0x9343: return dasd_9343_erp_examine(cqr, irb); @@ -923,6 +933,8 @@ dasd_eckd_erp_action(struct dasd_ccw_req * cqr) switch (cdev->id.cu_type) { case 0x3990: case 0x2105: + case 0x2107: + case 0x1750: return dasd_3990_erp_action; case 0x9343: /* Return dasd_9343_erp_action; */ diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index ca83f9b0a..b7a764ca3 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -19,6 +20,7 @@ //#define DCSSBLK_DEBUG /* Debug messages on/off */ #define DCSSBLK_NAME "dcssblk" #define DCSSBLK_MINORS_PER_DISK 1 +#define DCSSBLK_PARM_LEN 400 #ifdef DCSSBLK_DEBUG #define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x) @@ -34,6 +36,8 @@ static int dcssblk_open(struct inode *inode, struct file *filp); static int dcssblk_release(struct inode *inode, struct file *filp); static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; + static int dcssblk_major; static struct block_device_operations dcssblk_devops = { .owner = THIS_MODULE, @@ -641,6 +645,47 @@ fail: return 0; } +static void +dcssblk_check_params(void) +{ + int rc, i, j, k; + char buf[9]; + struct dcssblk_dev_info *dev_info; + + for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); + i++) { + for (j = i; (dcssblk_segments[j] != ',') && + (dcssblk_segments[j] != '\0') && + (dcssblk_segments[j] != '(') && + (j - i) < 8; j++) + { + buf[j-i] = dcssblk_segments[j]; + } + buf[j-i] = '\0'; + rc = dcssblk_add_store(dcssblk_root_dev, buf, j-i); + if ((rc >= 0) && (dcssblk_segments[j] == '(')) { + for (k = 0; buf[k] != '\0'; k++) + buf[k] = toupper(buf[k]); + if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { + down_read(&dcssblk_devices_sem); + dev_info = dcssblk_get_device_by_name(buf); + up_read(&dcssblk_devices_sem); + if (dev_info) + dcssblk_shared_store(&dev_info->dev, + "0\n", 2); + } + } + while ((dcssblk_segments[j] != ',') && + (dcssblk_segments[j] != '\0')) + { + j++; + } + if (dcssblk_segments[j] == '\0') + break; + i = j; + } +} + /* * The init/exit functions. */ @@ -689,6 +734,9 @@ dcssblk_init(void) } dcssblk_major = rc; init_rwsem(&dcssblk_devices_sem); + + dcssblk_check_params(); + PRINT_DEBUG("...finished!\n"); return 0; } @@ -696,4 +744,12 @@ dcssblk_init(void) module_init(dcssblk_init); module_exit(dcssblk_exit); +module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); +MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " + "comma-separated list, each name max. 8 chars.\n" + "Adding \"(local)\" to segment name equals echoing 0 to " + "/sys/devices/dcssblk//shared after loading " + "the segment - \n" + "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\""); + MODULE_LICENSE("GPL"); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index e92bb9473..9c72ffb65 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -366,10 +366,7 @@ raw3215_tasklet(void *data) tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -1055,10 +1052,7 @@ tty3215_flush_buffer(struct tty_struct *tty) raw = (struct raw3215_info *) tty->driver_data; raw3215_flush_buffer(raw); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 047d305cc..ca0f875bf 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,7 @@ static volatile unsigned long sclp_status = 0; #define SCLP_INIT 0 #define SCLP_RUNNING 1 #define SCLP_READING 2 +#define SCLP_SHUTDOWN 3 #define SCLP_INIT_POLL_INTERVAL 1 #define SCLP_BUSY_POLL_INTERVAL 1 @@ -606,10 +608,12 @@ sclp_init_mask(void) sccb->mask_length = sizeof(sccb_mask_t); /* copy in the sccb mask of the registered event types */ spin_lock_irqsave(&sclp_lock, flags); - list_for_each(l, &sclp_reg_list) { - t = list_entry(l, struct sclp_register, list); - sccb->receive_mask |= t->receive_mask; - sccb->send_mask |= t->send_mask; + if (!test_bit(SCLP_SHUTDOWN, &sclp_status)) { + list_for_each(l, &sclp_reg_list) { + t = list_entry(l, struct sclp_register, list); + sccb->receive_mask |= t->receive_mask; + sccb->send_mask |= t->send_mask; + } } sccb->sclp_receive_mask = 0; sccb->sclp_send_mask = 0; @@ -647,9 +651,10 @@ sclp_init_mask(void) /* WRITEMASK failed - we cannot rely on receiving a state change event, so initially, polling is the only alternative for us to ever become operational. */ - if (!timer_pending(&retry_timer) || - !mod_timer(&retry_timer, - jiffies + SCLP_INIT_POLL_INTERVAL*HZ)) { + if (!test_bit(SCLP_SHUTDOWN, &sclp_status) && + (!timer_pending(&retry_timer) || + !mod_timer(&retry_timer, + jiffies + SCLP_INIT_POLL_INTERVAL*HZ))) { retry_timer.function = sclp_init_mask_retry; retry_timer.data = 0; retry_timer.expires = jiffies + @@ -671,6 +676,26 @@ sclp_init_mask_retry(unsigned long data) sclp_init_mask(); } +/* Reboot event handler - reset send and receive mask to prevent pending SCLP + * events from interfering with rebooted system. */ +static int +sclp_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + unsigned long flags; + + /* Note: need spinlock to maintain atomicity when accessing global + * variables. */ + spin_lock_irqsave(&sclp_lock, flags); + set_bit(SCLP_SHUTDOWN, &sclp_status); + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_init_mask(); + return NOTIFY_DONE; +} + +static struct notifier_block sclp_reboot_notifier = { + .notifier_call = sclp_reboot_event +}; + /* * sclp setup function. Called early (no kmalloc!) from sclp_console_init(). */ @@ -691,6 +716,10 @@ sclp_init(void) list_add(&sclp_state_change_event.list, &sclp_reg_list); list_add(&sclp_quiesce_event.list, &sclp_reg_list); + rc = register_reboot_notifier(&sclp_reboot_notifier); + if (rc) + return rc; + /* * request the 0x2401 external interrupt * The sclp driver is initialized early (before kmalloc works). We diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index a1ad37580..cd11cb171 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -277,10 +277,7 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) wake_up(&sclp_tty_waitq); /* check if the tty needs a wake up call */ if (sclp_tty != NULL) { - if ((sclp_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - sclp_tty->ldisc.write_wakeup) - (sclp_tty->ldisc.write_wakeup)(sclp_tty); - wake_up_interruptible(&sclp_tty->write_wait); + tty_wakeup(sclp_tty); } } diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 22760a120..cc143fa9f 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -139,10 +139,7 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) wake_up(&sclp_vt220_waitq); /* Check if the tty needs a wake up call */ if (sclp_vt220_tty != NULL) { - if ((sclp_vt220_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - (sclp_vt220_tty->ldisc.write_wakeup != NULL)) - (sclp_vt220_tty->ldisc.write_wakeup)(sclp_vt220_tty); - wake_up_interruptible(&sclp_vt220_tty->write_wait); + tty_wakeup(sclp_vt220_tty); } } diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 29000d5e7..4a06c7d0e 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/blacklist.c * S/390 common I/O routines -- blacklisting of specific devices - * $Revision: 1.31 $ + * $Revision: 1.33 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -229,7 +229,7 @@ s390_redo_validation (void) unsigned int irq; CIO_TRACE_EVENT (0, "redoval"); - for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) { + for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { int ret; struct subchannel *sch; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 9b86522fb..21a75ee28 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup - * $Revision: 1.28 $ + * $Revision: 1.29 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -191,14 +191,12 @@ ccwgroup_create(struct device *root, gdev->cdev[i]->dev.driver_data = gdev; del_drvdata = 1; - *gdev = (struct ccwgroup_device) { - .creator_id = creator_id, - .count = argc, - .dev = { - .bus = &ccwgroup_bus_type, - .parent = root, - .release = ccwgroup_release, - }, + gdev->creator_id = creator_id; + gdev->count = argc; + gdev->dev = (struct device ) { + .bus = &ccwgroup_bus_type, + .parent = root, + .release = ccwgroup_release, }; snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s", diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 38e59dd24..fa6f0b105 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.123 $ + * $Revision: 1.128 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -17,8 +17,8 @@ #include #include #include +#include -#include #include #include #include @@ -141,6 +141,7 @@ cio_tpi(void) sch = (struct subchannel *)(unsigned long)tpi_info->intparm; if (!sch) return 1; + local_bh_disable(); irq_enter (); spin_lock(&sch->lock); memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); @@ -148,6 +149,7 @@ cio_tpi(void) sch->driver->irq(&sch->dev); spin_unlock(&sch->lock); irq_exit (); + __local_bh_enable(); return 1; } @@ -409,10 +411,10 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) if (ccode) return -ENODEV; - sch->schib.pmcw.ena = 1; - sch->schib.pmcw.isc = isc; - sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; for (retry = 5, ret = 0; retry > 0; retry--) { + sch->schib.pmcw.ena = 1; + sch->schib.pmcw.isc = isc; + sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; ret = cio_modify(sch); if (ret == -ENODEV) break; @@ -463,9 +465,8 @@ cio_disable_subchannel (struct subchannel *sch) */ return -EBUSY; - - sch->schib.pmcw.ena = 0; for (retry = 5, ret = 0; retry > 0; retry--) { + sch->schib.pmcw.ena = 0; ret = cio_modify(sch); if (ret == -ENODEV) break; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 788ae49c5..1708a16e4 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -1,5 +1,5 @@ /* - * linux/drivers/s390/cio/cmf.c ($Revision: 1.15 $) + * linux/drivers/s390/cio/cmf.c ($Revision: 1.16 $) * * Linux on zSeries Channel Measurement Facility support * @@ -526,29 +526,26 @@ readall_cmb (struct ccw_device *cdev, struct cmbdata *data) time = get_clock() - cdev->private->cmb_start_time; spin_unlock_irqrestore(cdev->ccwlock, flags); - *data = (struct cmbdata) { - /* we only know values before device_busy_time */ - .size = offsetof(struct cmbdata, device_busy_time), - - /* conver to nanoseconds */ - .elapsed_time = (time * 1000) >> 12, - - /* copy data to new structure */ - .ssch_rsch_count = cmb.ssch_rsch_count, - .sample_count = cmb.sample_count, - - /* time fields are converted to nanoseconds while copying */ - .device_connect_time - = time_to_nsec(cmb.device_connect_time), - .function_pending_time - = time_to_nsec(cmb.function_pending_time), - .device_disconnect_time - = time_to_nsec(cmb.device_disconnect_time), - .control_unit_queuing_time - = time_to_nsec(cmb.control_unit_queuing_time), - .device_active_only_time - = time_to_nsec(cmb.device_active_only_time), - }; + memset(data, sizeof(struct cmbdata), 0); + + /* we only know values before device_busy_time */ + data->size = offsetof(struct cmbdata, device_busy_time); + + /* convert to nanoseconds */ + data->elapsed_time = (time * 1000) >> 12; + + /* copy data to new structure */ + data->ssch_rsch_count = cmb.ssch_rsch_count; + data->sample_count = cmb.sample_count; + + /* time fields are converted to nanoseconds while copying */ + data->device_connect_time = time_to_nsec(cmb.device_connect_time); + data->function_pending_time = time_to_nsec(cmb.function_pending_time); + data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time); + data->control_unit_queuing_time + = time_to_nsec(cmb.control_unit_queuing_time); + data->device_active_only_time + = time_to_nsec(cmb.device_active_only_time); return 0; } @@ -739,33 +736,29 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) time = get_clock() - cdev->private->cmb_start_time; spin_unlock_irqrestore(cdev->ccwlock, flags); - *data = (struct cmbdata) { - /* we only know values before device_busy_time */ - .size = offsetof(struct cmbdata, device_busy_time), - - /* conver to nanoseconds */ - .elapsed_time = (time * 1000) >> 12, - - /* copy data to new structure */ - .ssch_rsch_count = cmb.ssch_rsch_count, - .sample_count = cmb.sample_count, - - /* time fields are converted to nanoseconds while copying */ - .device_connect_time - = time_to_nsec(cmb.device_connect_time), - .function_pending_time - = time_to_nsec(cmb.function_pending_time), - .device_disconnect_time - = time_to_nsec(cmb.device_disconnect_time), - .control_unit_queuing_time - = time_to_nsec(cmb.control_unit_queuing_time), - .device_active_only_time - = time_to_nsec(cmb.device_active_only_time), - .device_busy_time - = time_to_nsec(cmb.device_busy_time), - .initial_command_response_time - = time_to_nsec(cmb.initial_command_response_time), - }; + memset (data, sizeof(struct cmbdata), 0); + + /* we only know values before device_busy_time */ + data->size = offsetof(struct cmbdata, device_busy_time); + + /* conver to nanoseconds */ + data->elapsed_time = (time * 1000) >> 12; + + /* copy data to new structure */ + data->ssch_rsch_count = cmb.ssch_rsch_count; + data->sample_count = cmb.sample_count; + + /* time fields are converted to nanoseconds while copying */ + data->device_connect_time = time_to_nsec(cmb.device_connect_time); + data->function_pending_time = time_to_nsec(cmb.function_pending_time); + data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time); + data->control_unit_queuing_time + = time_to_nsec(cmb.control_unit_queuing_time); + data->device_active_only_time + = time_to_nsec(cmb.device_active_only_time); + data->device_busy_time = time_to_nsec(cmb.device_busy_time); + data->initial_command_response_time + = time_to_nsec(cmb.initial_command_response_time); return 0; } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index dba1bfb9a..dd12416e8 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/css.c * driver for channel subsystem - * $Revision: 1.80 $ + * $Revision: 1.82 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -278,7 +278,7 @@ css_rescan_devices(void) { int irq, ret; - for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) { + for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { ret = css_evaluate_subchannel(irq, 1); /* No more memory. It doesn't make sense to continue. No * panic because this can happen in midflight and just @@ -521,6 +521,7 @@ css_enqueue_subchannel_slow(unsigned long schid) new_slow_sch = kmalloc(sizeof(struct slow_subchannel), GFP_ATOMIC); if (!new_slow_sch) return -ENOMEM; + memset(new_slow_sch, sizeof(struct slow_subchannel), 0); new_slow_sch->schid = schid; spin_lock_irqsave(&slow_subchannel_lock, flags); list_add_tail(&new_slow_sch->slow_list, &slow_subchannels_head); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a921b1fea..bf652fa34 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device.c * bus driver for ccw devices - * $Revision: 1.120 $ + * $Revision: 1.124 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -540,6 +540,8 @@ get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) return cdev; } +extern int css_get_ssd_info(struct subchannel *sch); + void ccw_device_do_unreg_rereg(void *data) { @@ -581,6 +583,8 @@ ccw_device_do_unreg_rereg(void *data) device_unregister(&other_sch->dev); } } + /* Update ssd info here. */ + css_get_ssd_info(sch); cdev->private->devno = sch->schib.pmcw.dev; } else need_rename = 0; @@ -633,7 +637,8 @@ io_subchannel_register(void *data) sch->dev.driver_data = 0; kfree (cdev->private); kfree (cdev); - goto out; + put_device(&sch->dev); + return; } ret = subchannel_add_files(cdev->dev.parent); @@ -707,18 +712,19 @@ static int io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) { int rc; + struct ccw_device_private *priv; sch->dev.driver_data = cdev; sch->driver = &io_subchannel_driver; cdev->ccwlock = &sch->lock; - *cdev->private = (struct ccw_device_private) { - .devno = sch->schib.pmcw.dev, - .irq = sch->irq, - .state = DEV_STATE_NOT_OPER, - .cmb_list = LIST_HEAD_INIT(cdev->private->cmb_list), - }; - init_waitqueue_head(&cdev->private->wait_q); - init_timer(&cdev->private->timer); + /* Init private data. */ + priv = cdev->private; + priv->devno = sch->schib.pmcw.dev; + priv->irq = sch->irq; + priv->state = DEV_STATE_NOT_OPER; + INIT_LIST_HEAD(&priv->cmb_list); + init_waitqueue_head(&priv->wait_q); + init_timer(&priv->timer); /* Set an initial name for the device. */ snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 6a8db8450..03b569b4b 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -995,6 +995,7 @@ device_trigger_reprobe(struct subchannel *sch) if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; + /* We should also udate ssd info, but this has to wait. */ ccw_device_start_id(cdev, 0); spin_unlock_irqrestore(&sch->lock, flags); } diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 32365959c..f6cb89728 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -303,10 +303,10 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); irb = (struct irb *) __LC_IRB; - /* Retry sense id for cc=1. */ + /* Retry sense id, if needed. */ if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { - if (irb->scsw.cc == 1) { + if ((irb->scsw.cc == 1) || !irb->scsw.actl) { ret = __ccw_device_sense_id_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_id_done(cdev, ret); diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index bc768b62a..4f7dca3c7 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.84 $" +#define VERSION_QDIO_C "$Revision: 1.86 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -365,7 +365,7 @@ qdio_stop_polling(struct qdio_q *q) * small window we can miss between resetting it and * checking for PRIMED state */ - if (q->is_iqdio_q) + if (q->is_thinint_q) tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind); return 0; diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c index 6290b5c56..2806b2d15 100644 --- a/drivers/s390/net/ctctty.c +++ b/drivers/s390/net/ctctty.c @@ -307,10 +307,7 @@ ctc_tty_tint(ctc_tty_info * info) info->flags &= ~CTC_ASYNC_TX_LINESTAT; if (tty) { - if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } return (skb_queue_empty(&info->tx_queue) ? 0 : 1); @@ -589,9 +586,7 @@ ctc_tty_flush_buffer(struct tty_struct *tty) info->lsr |= UART_LSR_TEMT; spin_unlock_irqrestore(&ctc_tty_lock, flags); wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); ex: DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__); return; @@ -1066,8 +1061,7 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp) skb_queue_purge(&info->tx_queue); info->lsr |= UART_LSR_TEMT; } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); info->tty = 0; tty->closing = 0; if (info->blocked_open) { diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index cac57951a..f78636132 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -11,7 +11,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Martin Schwidefsky * - * $Revision: 1.85 $ $Date: 2004/08/04 11:05:43 $ + * $Revision: 1.92 $ $Date: 2004/09/03 08:06:11 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,7 +59,7 @@ /** * initialization string for output */ -#define VERSION_LCS_C "$Revision: 1.85 $" +#define VERSION_LCS_C "$Revision: 1.92 $" static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char debug_buffer[255]; @@ -70,6 +70,7 @@ static char debug_buffer[255]; static void lcs_tasklet(unsigned long); static void lcs_start_kernel_thread(struct lcs_card *card); static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); +static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); /** * Debug Facility Stuff @@ -100,9 +101,9 @@ lcs_register_debug_facility(void) return -ENOMEM; } debug_register_view(lcs_dbf_setup, &debug_hex_ascii_view); - debug_set_level(lcs_dbf_setup, 2); + debug_set_level(lcs_dbf_setup, 4); debug_register_view(lcs_dbf_trace, &debug_hex_ascii_view); - debug_set_level(lcs_dbf_trace, 2); + debug_set_level(lcs_dbf_trace, 4); return 0; } @@ -316,7 +317,106 @@ lcs_setup_write(struct lcs_card *card) init_waitqueue_head(&card->write.wait_q); } +static void +lcs_set_allowed_threads(struct lcs_card *card, unsigned long threads) +{ + unsigned long flags; + + spin_lock_irqsave(&card->mask_lock, flags); + card->thread_allowed_mask = threads; + spin_unlock_irqrestore(&card->mask_lock, flags); + wake_up(&card->wait_q); +} +static inline int +lcs_threads_running(struct lcs_card *card, unsigned long threads) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&card->mask_lock, flags); + rc = (card->thread_running_mask & threads); + spin_unlock_irqrestore(&card->mask_lock, flags); + return rc; +} + +static int +lcs_wait_for_threads(struct lcs_card *card, unsigned long threads) +{ + return wait_event_interruptible(card->wait_q, + lcs_threads_running(card, threads) == 0); +} + +static inline int +lcs_set_thread_start_bit(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + + spin_lock_irqsave(&card->mask_lock, flags); + if ( !(card->thread_allowed_mask & thread) || + (card->thread_start_mask & thread) ) { + spin_unlock_irqrestore(&card->mask_lock, flags); + return -EPERM; + } + card->thread_start_mask |= thread; + spin_unlock_irqrestore(&card->mask_lock, flags); + return 0; +} + +static void +lcs_clear_thread_running_bit(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + spin_lock_irqsave(&card->mask_lock, flags); + card->thread_running_mask &= ~thread; + spin_unlock_irqrestore(&card->mask_lock, flags); + wake_up(&card->wait_q); +} + +static inline int +__lcs_do_run_thread(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&card->mask_lock, flags); + if (card->thread_start_mask & thread){ + if ((card->thread_allowed_mask & thread) && + !(card->thread_running_mask & thread)){ + rc = 1; + card->thread_start_mask &= ~thread; + card->thread_running_mask |= thread; + } else + rc = -EPERM; + } + spin_unlock_irqrestore(&card->mask_lock, flags); + return rc; +} + +static int +lcs_do_run_thread(struct lcs_card *card, unsigned long thread) +{ + int rc = 0; + wait_event(card->wait_q, + (rc = __lcs_do_run_thread(card, thread)) >= 0); + return rc; +} + +static int +lcs_do_start_thread(struct lcs_card *card, unsigned long thread) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&card->mask_lock, flags); + LCS_DBF_TEXT_(4, trace, " %02x%02x%02x", + (u8) card->thread_start_mask, + (u8) card->thread_allowed_mask, + (u8) card->thread_running_mask); + rc = (card->thread_start_mask & thread); + spin_unlock_irqrestore(&card->mask_lock, flags); + return rc; +} /** * Initialize channels,card and state machines. @@ -337,34 +437,53 @@ lcs_setup_card(struct lcs_card *card) /* Initialize kernel thread task used for LGW commands. */ INIT_WORK(&card->kernel_thread_starter, (void *)lcs_start_kernel_thread,card); - card->thread_mask = 0; + card->thread_start_mask = 0; + card->thread_allowed_mask = 0; + card->thread_running_mask = 0; + init_waitqueue_head(&card->wait_q); spin_lock_init(&card->lock); spin_lock_init(&card->ipm_lock); + spin_lock_init(&card->mask_lock); #ifdef CONFIG_IP_MULTICAST INIT_LIST_HEAD(&card->ipm_list); #endif INIT_LIST_HEAD(&card->lancmd_waiters); } +static inline void +lcs_clear_multicast_list(struct lcs_card *card) +{ +#ifdef CONFIG_IP_MULTICAST + struct lcs_ipm_list *ipm; + unsigned long flags; + + /* Free multicast list. */ + LCS_DBF_TEXT(3, setup, "clmclist"); + spin_lock_irqsave(&card->ipm_lock, flags); + while (!list_empty(&card->ipm_list)){ + ipm = list_entry(card->ipm_list.next, + struct lcs_ipm_list, list); + list_del(&ipm->list); + if (ipm->ipm_state != LCS_IPM_STATE_SET_REQUIRED){ + spin_unlock_irqrestore(&card->ipm_lock, flags); + lcs_send_delipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); + } + kfree(ipm); + } + spin_unlock_irqrestore(&card->ipm_lock, flags); +#endif +} /** * Cleanup channels,card and state machines. */ static void lcs_cleanup_card(struct lcs_card *card) { - struct list_head *l, *n; - struct lcs_ipm_list *ipm_list; LCS_DBF_TEXT(3, setup, "cleancrd"); LCS_DBF_HEX(2,setup,&card,sizeof(void*)); -#ifdef CONFIG_IP_MULTICAST - /* Free multicast list. */ - list_for_each_safe(l, n, &card->ipm_list) { - ipm_list = list_entry(l, struct lcs_ipm_list, list); - list_del(&ipm_list->list); - kfree(ipm_list); - } -#endif + if (card->dev != NULL) free_netdev(card->dev); /* Cleanup channels. */ @@ -651,6 +770,44 @@ lcs_get_lancmd(struct lcs_card *card, int count) return buffer; } + +static void +lcs_get_reply(struct lcs_reply *reply) +{ + WARN_ON(atomic_read(&reply->refcnt) <= 0); + atomic_inc(&reply->refcnt); +} + +static void +lcs_put_reply(struct lcs_reply *reply) +{ + WARN_ON(atomic_read(&reply->refcnt) <= 0); + if (atomic_dec_and_test(&reply->refcnt)) { + kfree(reply); + } + +} + +static struct lcs_reply * +lcs_alloc_reply(struct lcs_cmd *cmd) +{ + struct lcs_reply *reply; + + LCS_DBF_TEXT(4, trace, "getreply"); + + reply = kmalloc(sizeof(struct lcs_reply), GFP_ATOMIC); + if (!reply) + return NULL; + memset(reply,0,sizeof(struct lcs_reply)); + atomic_set(&reply->refcnt,1); + reply->sequence_no = cmd->sequence_no; + reply->received = 0; + reply->rc = 0; + init_waitqueue_head(&reply->wait_q); + + return reply; +} + /** * Notifier function for lancmd replies. Called from read irq. */ @@ -665,12 +822,14 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) list_for_each_safe(l, n, &card->lancmd_waiters) { reply = list_entry(l, struct lcs_reply, list); if (reply->sequence_no == cmd->sequence_no) { - list_del(&reply->list); + lcs_get_reply(reply); + list_del_init(&reply->list); if (reply->callback != NULL) reply->callback(card, cmd); reply->received = 1; reply->rc = cmd->return_code; wake_up(&reply->wait_q); + lcs_put_reply(reply); break; } } @@ -683,50 +842,66 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) void lcs_lancmd_timeout(unsigned long data) { - struct lcs_reply *reply; + struct lcs_reply *reply, *list_reply, *r; + unsigned long flags; LCS_DBF_TEXT(4, trace, "timeout"); reply = (struct lcs_reply *) data; - list_del(&reply->list); - reply->received = 1; - reply->rc = -ETIME; - wake_up(&reply->wait_q); + spin_lock_irqsave(&reply->card->lock, flags); + list_for_each_entry_safe(list_reply, r, + &reply->card->lancmd_waiters,list) { + if (reply == list_reply) { + lcs_get_reply(reply); + list_del_init(&reply->list); + spin_unlock_irqrestore(&reply->card->lock, flags); + reply->received = 1; + reply->rc = -ETIME; + wake_up(&reply->wait_q); + lcs_put_reply(reply); + return; + } + } + spin_unlock_irqrestore(&reply->card->lock, flags); } static int lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer, void (*reply_callback)(struct lcs_card *, struct lcs_cmd *)) { - struct lcs_reply reply; + struct lcs_reply *reply; struct lcs_cmd *cmd; struct timer_list timer; + unsigned long flags; int rc; LCS_DBF_TEXT(4, trace, "sendcmd"); cmd = (struct lcs_cmd *) buffer->data; - cmd->sequence_no = ++card->sequence_no; cmd->return_code = 0; - reply.sequence_no = cmd->sequence_no; - reply.callback = reply_callback; - reply.received = 0; - reply.rc = 0; - init_waitqueue_head(&reply.wait_q); - spin_lock(&card->lock); - list_add_tail(&reply.list, &card->lancmd_waiters); - spin_unlock(&card->lock); + cmd->sequence_no = card->sequence_no++; + reply = lcs_alloc_reply(cmd); + if (!reply) + return -ENOMEM; + reply->callback = reply_callback; + reply->card = card; + spin_lock_irqsave(&card->lock, flags); + list_add_tail(&reply->list, &card->lancmd_waiters); + spin_unlock_irqrestore(&card->lock, flags); + buffer->callback = lcs_release_buffer; rc = lcs_ready_buffer(&card->write, buffer); if (rc) return rc; init_timer(&timer); timer.function = lcs_lancmd_timeout; - timer.data = (unsigned long) &reply; + timer.data = (unsigned long) reply; timer.expires = jiffies + HZ*card->lancmd_timeout; add_timer(&timer); - wait_event(reply.wait_q, reply.received); - del_timer(&timer); - LCS_DBF_TEXT_(4, trace, "rc:%d",reply.rc); - return reply.rc ? -EIO : 0; + wait_event(reply->wait_q, reply->received); + del_timer_sync(&timer); + LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc); + rc = reply->rc; + lcs_put_reply(reply); + return rc ? -EIO : 0; } /** @@ -940,33 +1115,56 @@ lcs_check_multicast_support(struct lcs_card *card) static void lcs_fix_multicast_list(struct lcs_card *card) { - struct list_head *l, *n; - struct lcs_ipm_list *ipm; + struct list_head failed_list; + struct lcs_ipm_list *ipm, *tmp; + unsigned long flags; + int rc; LCS_DBF_TEXT(4,trace, "fixipm"); - spin_lock(&card->ipm_lock); - list_for_each_safe(l, n, &card->ipm_list) { - ipm = list_entry(l, struct lcs_ipm_list, list); + INIT_LIST_HEAD(&failed_list); + spin_lock_irqsave(&card->ipm_lock, flags); +list_modified: + list_for_each_entry_safe(ipm, tmp, &card->ipm_list, list){ switch (ipm->ipm_state) { case LCS_IPM_STATE_SET_REQUIRED: - if (lcs_send_setipm(card, ipm)) + /* del from ipm_list so noone else can tamper with + * this entry */ + list_del_init(&ipm->list); + spin_unlock_irqrestore(&card->ipm_lock, flags); + rc = lcs_send_setipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); + if (rc) { PRINT_INFO("Adding multicast address failed." "Table possibly full!\n"); - else + /* store ipm in failed list -> will be added + * to ipm_list again, so a retry will be done + * during the next call of this function */ + list_add_tail(&ipm->list, &failed_list); + } else { ipm->ipm_state = LCS_IPM_STATE_ON_CARD; - break; + /* re-insert into ipm_list */ + list_add_tail(&ipm->list, &card->ipm_list); + } + goto list_modified; case LCS_IPM_STATE_DEL_REQUIRED: - lcs_send_delipm(card, ipm); list_del(&ipm->list); + spin_unlock_irqrestore(&card->ipm_lock, flags); + lcs_send_delipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); kfree(ipm); - break; + goto list_modified; case LCS_IPM_STATE_ON_CARD: break; } } + /* re-insert all entries from the failed_list into ipm_list */ + list_for_each_entry(ipm, &failed_list, list) { + list_del_init(&ipm->list); + list_add_tail(&ipm->list, &card->ipm_list); + } + spin_unlock_irqrestore(&card->ipm_lock, flags); if (card->state == DEV_STATE_UP) netif_wake_queue(card->dev); - spin_unlock(&card->ipm_lock); } /** @@ -985,51 +1183,67 @@ lcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev) /** * function called by net device to handle multicast address relevant things */ -static int -lcs_register_mc_addresses(void *data) +static inline void +lcs_remove_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) { - struct lcs_card *card; - char buf[MAX_ADDR_LEN]; - struct list_head *l; struct ip_mc_list *im4; - struct in_device *in4_dev; - struct lcs_ipm_list *ipm, *tmp; - - daemonize("regipm"); - LCS_DBF_TEXT(4, trace, "regmulti"); + struct list_head *l; + struct lcs_ipm_list *ipm; + unsigned long flags; + char buf[MAX_ADDR_LEN]; - card = (struct lcs_card *) data; - in4_dev = in_dev_get(card->dev); - if (in4_dev == NULL) - return 0; - read_lock(&in4_dev->lock); - spin_lock(&card->ipm_lock); - /* Check for multicast addresses to be removed. */ + LCS_DBF_TEXT(4, trace, "remmclst"); + spin_lock_irqsave(&card->ipm_lock, flags); list_for_each(l, &card->ipm_list) { ipm = list_entry(l, struct lcs_ipm_list, list); for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) { lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); - if (memcmp(buf, &ipm->ipm.mac_addr, - LCS_MAC_LENGTH) == 0 && - ipm->ipm.ip_addr == im4->multiaddr) + if ( (ipm->ipm.ip_addr == im4->multiaddr) && + (memcmp(buf, &ipm->ipm.mac_addr, + LCS_MAC_LENGTH) == 0) ) break; } if (im4 == NULL) ipm->ipm_state = LCS_IPM_STATE_DEL_REQUIRED; } - /* Check for multicast addresses to be added. */ + spin_unlock_irqrestore(&card->ipm_lock, flags); +} + +static inline struct lcs_ipm_list * +lcs_check_addr_entry(struct lcs_card *card, struct ip_mc_list *im4, char *buf) +{ + struct lcs_ipm_list *tmp, *ipm = NULL; + struct list_head *l; + unsigned long flags; + + LCS_DBF_TEXT(4, trace, "chkmcent"); + spin_lock_irqsave(&card->ipm_lock, flags); + list_for_each(l, &card->ipm_list) { + tmp = list_entry(l, struct lcs_ipm_list, list); + if ( (tmp->ipm.ip_addr == im4->multiaddr) && + (memcmp(buf, &tmp->ipm.mac_addr, + LCS_MAC_LENGTH) == 0) ) { + ipm = tmp; + break; + } + } + spin_unlock_irqrestore(&card->ipm_lock, flags); + return ipm; +} + +static inline void +lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) +{ + + struct ip_mc_list *im4; + struct lcs_ipm_list *ipm; + char buf[MAX_ADDR_LEN]; + unsigned long flags; + + LCS_DBF_TEXT(4, trace, "setmclst"); for (im4 = in4_dev->mc_list; im4; im4 = im4->next) { lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); - ipm = NULL; - list_for_each(l, &card->ipm_list) { - tmp = list_entry(l, struct lcs_ipm_list, list); - if (memcmp(buf, &tmp->ipm.mac_addr, - LCS_MAC_LENGTH) == 0 && - tmp->ipm.ip_addr == im4->multiaddr) { - ipm = tmp; - break; - } - } + ipm = lcs_check_addr_entry(card, im4, buf); if (ipm != NULL) continue; /* Address already in list. */ ipm = (struct lcs_ipm_list *) @@ -1043,12 +1257,37 @@ lcs_register_mc_addresses(void *data) memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); ipm->ipm.ip_addr = im4->multiaddr; ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED; + spin_lock_irqsave(&card->ipm_lock, flags); list_add(&ipm->list, &card->ipm_list); + spin_unlock_irqrestore(&card->ipm_lock, flags); } - spin_unlock(&card->ipm_lock); - read_unlock(&in4_dev->lock); +} + +static int +lcs_register_mc_addresses(void *data) +{ + struct lcs_card *card; + struct in_device *in4_dev; + + card = (struct lcs_card *) data; + daemonize("regipm"); + + if (!lcs_do_run_thread(card, LCS_SET_MC_THREAD)) + return 0; + LCS_DBF_TEXT(4, trace, "regmulti"); + + in4_dev = in_dev_get(card->dev); + if (in4_dev == NULL) + goto out; + read_lock(&in4_dev->mc_list_lock); + lcs_remove_mc_addresses(card,in4_dev); + lcs_set_mc_addresses(card, in4_dev); + read_unlock(&in4_dev->mc_list_lock); in_dev_put(in4_dev); + lcs_fix_multicast_list(card); +out: + lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD); return 0; } /** @@ -1062,8 +1301,10 @@ lcs_set_multicast_list(struct net_device *dev) LCS_DBF_TEXT(4, trace, "setmulti"); card = (struct lcs_card *) dev->priv; - set_bit(3, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + + if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) { + schedule_work(&card->kernel_thread_starter); + } } #endif /* CONFIG_IP_MULTICAST */ @@ -1427,6 +1668,7 @@ lcs_resetcard(struct lcs_card *card) return -EIO; } + /** * LCS Stop card */ @@ -1440,6 +1682,7 @@ lcs_stopcard(struct lcs_card *card) if (card->read.state != CH_STATE_STOPPED && card->write.state != CH_STATE_STOPPED && card->state == DEV_STATE_UP) { + lcs_clear_multicast_list(card); rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); rc = lcs_send_shutdown(card); } @@ -1459,6 +1702,9 @@ lcs_lgw_startlan_thread(void *data) card = (struct lcs_card *) data; daemonize("lgwstpln"); + + if (!lcs_do_run_thread(card, LCS_STARTLAN_THREAD)) + return 0; LCS_DBF_TEXT(4, trace, "lgwstpln"); if (card->dev) netif_stop_queue(card->dev); @@ -1471,6 +1717,7 @@ lcs_lgw_startlan_thread(void *data) } else PRINT_ERR("LCS Startlan for device %s failed!\n", card->dev->name); + lcs_clear_thread_running_bit(card, LCS_STARTLAN_THREAD); return 0; } @@ -1485,8 +1732,11 @@ lcs_lgw_startup_thread(void *data) struct lcs_card *card; card = (struct lcs_card *) data; - daemonize("lgwstpln"); - LCS_DBF_TEXT(4, trace, "lgwstpln"); + daemonize("lgwstaln"); + + if (!lcs_do_run_thread(card, LCS_STARTUP_THREAD)) + return 0; + LCS_DBF_TEXT(4, trace, "lgwstaln"); if (card->dev) netif_stop_queue(card->dev); rc = lcs_send_startup(card, LCS_INITIATOR_LGW); @@ -1511,6 +1761,7 @@ Done: else PRINT_ERR("LCS Startup for device %s failed!\n", card->dev->name); + lcs_clear_thread_running_bit(card, LCS_STARTUP_THREAD); return 0; } @@ -1526,6 +1777,9 @@ lcs_lgw_stoplan_thread(void *data) card = (struct lcs_card *) data; daemonize("lgwstop"); + + if (!lcs_do_run_thread(card, LCS_STOPLAN_THREAD)) + return 0; LCS_DBF_TEXT(4, trace, "lgwstop"); if (card->dev) netif_stop_queue(card->dev); @@ -1539,6 +1793,7 @@ lcs_lgw_stoplan_thread(void *data) rc = lcs_resetcard(card); if (rc != 0) rc = lcs_stopcard(card); + lcs_clear_thread_running_bit(card, LCS_STOPLAN_THREAD); return rc; } @@ -1549,14 +1804,14 @@ static void lcs_start_kernel_thread(struct lcs_card *card) { LCS_DBF_TEXT(5, trace, "krnthrd"); - if (test_and_clear_bit(0, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_STARTUP_THREAD)) kernel_thread(lcs_lgw_startup_thread, (void *) card, SIGCHLD); - if (test_and_clear_bit(1, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_STARTLAN_THREAD)) kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD); - if (test_and_clear_bit(2, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_STOPLAN_THREAD)) kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD); #ifdef CONFIG_IP_MULTICAST - if (test_and_clear_bit(3, &card->thread_mask)) + if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD); #endif } @@ -1571,16 +1826,19 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) if (cmd->initiator == LCS_INITIATOR_LGW) { switch(cmd->cmd_code) { case LCS_CMD_STARTUP: - set_bit(0, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + if (!lcs_set_thread_start_bit(card, + LCS_STARTUP_THREAD)) + schedule_work(&card->kernel_thread_starter); break; case LCS_CMD_STARTLAN: - set_bit(1, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + if (!lcs_set_thread_start_bit(card, + LCS_STARTLAN_THREAD)) + schedule_work(&card->kernel_thread_starter); break; case LCS_CMD_STOPLAN: - set_bit(2, &card->thread_mask); - schedule_work(&card->kernel_thread_starter); + if (!lcs_set_thread_start_bit(card, + LCS_STOPLAN_THREAD)) + schedule_work(&card->kernel_thread_starter); break; default: PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); @@ -1953,7 +2211,9 @@ netdev_out: card->dev->set_multicast_list = lcs_set_multicast_list; #endif netif_stop_queue(card->dev); + lcs_set_allowed_threads(card,0xffffffff); if (recover_state == DEV_STATE_RECOVER) { + lcs_set_multicast_list(card->dev); card->dev->flags |= IFF_UP; netif_wake_queue(card->dev); card->state = DEV_STATE_UP; @@ -1982,7 +2242,9 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return -ENODEV; - + lcs_set_allowed_threads(card, 0); + if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) + return -ERESTARTSYS; LCS_DBF_HEX(3, setup, &card, sizeof(void*)); recover_state = card->state; diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index 44cf99060..bd3fee027 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -6,7 +6,7 @@ #include #include -#define VERSION_LCS_H "$Revision: 1.17 $" +#define VERSION_LCS_H "$Revision: 1.18 $" #define LCS_DBF_TEXT(level, name, text) \ do { \ @@ -152,6 +152,12 @@ enum lcs_dev_states { DEV_STATE_RECOVER, }; +enum lcs_threads { + LCS_SET_MC_THREAD = 1, + LCS_STARTLAN_THREAD = 2, + LCS_STOPLAN_THREAD = 4, + LCS_STARTUP_THREAD = 8, +}; /** * LCS struct declarations */ @@ -247,9 +253,11 @@ struct lcs_buffer { struct lcs_reply { struct list_head list; __u16 sequence_no; + atomic_t refcnt; /* Callback for completion notification. */ void (*callback)(struct lcs_card *, struct lcs_cmd *); wait_queue_head_t wait_q; + struct lcs_card *card; int received; int rc; }; @@ -268,6 +276,7 @@ struct lcs_channel { int buf_idx; }; + /** * definition of the lcs card */ @@ -287,7 +296,11 @@ struct lcs_card { int lancmd_timeout; struct work_struct kernel_thread_starter; - unsigned long thread_mask; + spinlock_t mask_lock; + unsigned long thread_start_mask; + unsigned long thread_running_mask; + unsigned long thread_allowed_mask; + wait_queue_head_t wait_q; #ifdef CONFIG_IP_MULTICAST struct list_head ipm_list; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 17f0f67d8..3e374ddfe 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.130 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.145 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier * - * $Revision: 1.130 $ $Date: 2004/08/05 11:21:50 $ + * $Revision: 1.145 $ $Date: 2004/10/08 15:08:40 $ * * 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 @@ -73,12 +73,13 @@ qeth_eyecatcher(void) #include #include #include +#include #include "qeth.h" #include "qeth_mpc.h" #include "qeth_fs.h" -#define VERSION_QETH_C "$Revision: 1.130 $" +#define VERSION_QETH_C "$Revision: 1.145 $" static const char *version = "qeth S/390 OSA-Express driver"; /** @@ -2147,7 +2148,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) skb->mac.raw = skb->data; skb_pull(skb, ETH_ALEN * 2 + sizeof (short)); - eth = skb->mac.ethernet; + eth = eth_hdr(skb); if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) @@ -3834,6 +3835,7 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, /* return EBUSY because we sent old packet, not * the current one */ rc = -EBUSY; + atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); goto out; } } @@ -4372,12 +4374,13 @@ qeth_snmp_command(struct qeth_card *card, char *udata) /* skip 4 bytes (data_len struct member) to get req_len */ if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int))) return -EFAULT; - ureq = kmalloc(req_len, GFP_KERNEL); + ureq = kmalloc(req_len+sizeof(struct qeth_snmp_ureq_hdr), GFP_KERNEL); if (!ureq) { QETH_DBF_TEXT(trace, 2, "snmpnome"); return -ENOMEM; } - if (copy_from_user(ureq, udata, req_len)){ + if (copy_from_user(ureq, udata, + req_len+sizeof(struct qeth_snmp_ureq_hdr))){ kfree(ureq); return -EFAULT; } @@ -4546,7 +4549,8 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!card) return -ENODEV; - if (card->state != CARD_STATE_UP) + if ((card->state != CARD_STATE_UP) && + (card->state != CARD_STATE_SOFTSETUP)) return -ENODEV; switch (cmd){ @@ -4733,9 +4737,10 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) QETH_DBF_TEXT(trace, 4, "frvaddr4"); if (!card->vlangrp) return; - in_dev = in_dev_get(card->vlangrp->vlan_devices[vid]); + rcu_read_lock(); + in_dev = __in_dev_get(card->vlangrp->vlan_devices[vid]); if (!in_dev) - return; + goto out; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next){ addr = qeth_get_addr_buffer(QETH_PROT_IPV4); if (addr){ @@ -4746,7 +4751,8 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) kfree(addr); } } - in_dev_put(in_dev); +out: + rcu_read_unlock(); } static void @@ -4918,9 +4924,9 @@ qeth_add_vlan_mc(struct qeth_card *card) in_dev = in_dev_get(vg->vlan_devices[i]); if (!in_dev) continue; - read_lock(&in_dev->lock); + read_lock(&in_dev->mc_list_lock); qeth_add_mc(card,in_dev); - read_unlock(&in_dev->lock); + read_unlock(&in_dev->mc_list_lock); in_dev_put(in_dev); } #endif @@ -4935,10 +4941,10 @@ qeth_add_multicast_ipv4(struct qeth_card *card) in4_dev = in_dev_get(card->dev); if (in4_dev == NULL) return; - read_lock(&in4_dev->lock); + read_lock(&in4_dev->mc_list_lock); qeth_add_mc(card, in4_dev); qeth_add_vlan_mc(card); - read_unlock(&in4_dev->lock); + read_unlock(&in4_dev->mc_list_lock); in_dev_put(in4_dev); } @@ -5739,7 +5745,7 @@ qeth_start_ipa_ip_fragmentation(struct qeth_card *card) QETH_DBF_TEXT(trace,3,"ipaipfrg"); if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - PRINT_INFO("IP fragmentation not supported on %s\n", + PRINT_INFO("Hardware IP fragmentation not supported on %s\n", card->info.if_name); return -EOPNOTSUPP; } @@ -5747,11 +5753,11 @@ qeth_start_ipa_ip_fragmentation(struct qeth_card *card) rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start IP fragmentation " + PRINT_WARN("Could not start Hardware IP fragmentation " "assist on %s: 0x%x\n", card->info.if_name, rc); } else - PRINT_INFO("IP fragmentation enabled \n"); + PRINT_INFO("Hardware IP fragmentation enabled \n"); return rc; } @@ -6706,19 +6712,26 @@ static int qeth_arp_constructor(struct neighbour *neigh) { struct net_device *dev = neigh->dev; - struct in_device *in_dev = in_dev_get(dev); + struct in_device *in_dev; + struct neigh_parms *parms; - if (in_dev == NULL) - return -EINVAL; if (!qeth_verify_dev(dev)) { - in_dev_put(in_dev); return qeth_old_arp_constructor(neigh); } + rcu_read_lock(); + in_dev = rcu_dereference(__in_dev_get(dev)); + if (in_dev == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + + parms = in_dev->arp_parms; + __neigh_parms_put(neigh->parms); + neigh->parms = neigh_parms_clone(parms); + rcu_read_unlock(); + neigh->type = inet_addr_type(*(u32 *) neigh->primary_key); - if (in_dev->arp_parms) - neigh->parms = in_dev->arp_parms; - in_dev_put(in_dev); neigh->nud_state = NUD_NOARP; neigh->ops = arp_direct_ops; neigh->output = neigh->ops->queue_xmit; diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 167043492..7e26f0f1b 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -63,10 +63,6 @@ struct crw { #define CRW_ERC_PERRI 0x07 /* perm. error, facility init */ #define CRW_ERC_PMOD 0x08 /* installed parameters modified */ -#define MCHCHK_STATUS_TO_PROCESS 0x00000001 -#define MCHCHK_STATUS_IN_PROGRESS 0x00000002 -#define MCHCHK_STATUS_WAITING 0x00000004 - extern __inline__ int stcrw(struct crw *pcrw ) { int ccode; diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index dad02890e..88414579d 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.129 $" #include "zfcp_ext.h" @@ -47,11 +47,11 @@ static void zfcp_ns_gid_pn_handler(unsigned long); /* miscellaneous */ 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 void zfcp_sg_list_free(struct zfcp_sg_list *); +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, " + "FC ERP QDIO CIO Config FSF SCSI Other, " "levels: 0=none 1=normal 2=devel 3=trace"); #ifdef ZFCP_PRINT_FLAGS @@ -257,24 +257,20 @@ zfcp_device_setup(char *str) static void __init zfcp_init_device_configure(void) { - int found = 0; struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) - if (strcmp(zfcp_data.init_busid, - zfcp_get_busid_by_adapter(adapter)) == 0) { - zfcp_adapter_get(adapter); - found = 1; - break; - } + adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid); + if (adapter) + zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); - if (!found) + + if (adapter == NULL) goto out_adapter; - port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0); + port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); if (!port) goto out_port; unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); @@ -377,12 +373,13 @@ zfcp_module_init(void) * -ENOMEM - Insufficient memory * -EFAULT - User space memory I/O operation fault * -EPERM - Cannot create or queue FSF request or create SBALs + * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) */ 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 +400,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; @@ -467,22 +464,17 @@ zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file, (sense_data.devno >> 16) & 0xFF, (sense_data.devno & 0xFFFF)); - retval = -ENXIO; read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { - if (strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), - BUS_ID_SIZE) == 0) { - zfcp_adapter_get(adapter); - retval = 0; - break; - } - } + adapter = zfcp_get_adapter_by_busid(bus_id); + if (adapter) + zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); kfree(bus_id); - if (retval != 0) { + if (adapter == NULL) { ZFCP_LOG_INFO("invalid adapter\n"); + retval = -ENXIO; goto out; } @@ -520,6 +512,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, @@ -559,13 +557,16 @@ zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file, } -/* - * function: zfcp_sg_list_alloc - * - * purpose: Create a scatter-gather list of the specified size +/** + * zfcp_sg_list_alloc - create a scatter-gather list of the specified size + * @sg_list: structure describing a scatter gather list + * @size: size of scatter-gather list + * Return: 0 on success, else -ENOMEM * - * returns: 0 - Scatter gather list is created - * -ENOMEM - Insufficient memory (*list_ptr is then set to NULL) + * In sg_list->sg a pointer to the created scatter-gather list is returned, + * or NULL if we run out of memory. sg_list->count specifies the number of + * elements of the scatter-gather list. The maximum size of a single element + * in the scatter-gather list is PAGE_SIZE. */ static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) @@ -573,6 +574,9 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) struct scatterlist *sg; unsigned int i; int retval = 0; + void *address; + + BUG_ON(sg_list == NULL); sg_list->count = size >> PAGE_SHIFT; if (size & ~PAGE_MASK) @@ -588,7 +592,8 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { sg->length = min(size, PAGE_SIZE); sg->offset = 0; - sg->page = alloc_pages(GFP_KERNEL, 0); + address = (void *) get_zeroed_page(GFP_KERNEL); + zfcp_address_to_sg(address, sg); if (sg->page == NULL) { sg_list->count = i; zfcp_sg_list_free(sg_list); @@ -603,41 +608,61 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) } -/* - * function: zfcp_sg_list_free - * - * purpose: Destroy a scatter-gather list and release memory +/** + * zfcp_sg_list_free - free memory of a scatter-gather list + * @sg_list: structure describing a scatter-gather list * - * returns: Always 0 + * Memory for each element in the scatter-gather list is freed. + * Finally sg_list->sg is freed itself and sg_list->count is reset. */ -static inline int +static inline void zfcp_sg_list_free(struct zfcp_sg_list *sg_list) { struct scatterlist *sg; unsigned int i; - int retval = 0; BUG_ON(sg_list == NULL); for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) __free_pages(sg->page, 0); + sg_list->count = 0; kfree(sg_list->sg); +} - return retval; +/** + * zfcp_sg_size - determine size of a scatter-gather list + * @sg: array of (struct scatterlist) + * @sg_count: elements in array + * Return: size of entire scatter-gather list + */ +size_t +zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) +{ + unsigned int i; + struct scatterlist *p; + size_t size; + + size = 0; + for (i = 0, p = sg; i < sg_count; i++, p++) { + BUG_ON(p == NULL); + size += p->length; + } + + return size; } -/* - * function: zfcp_sg_list_copy_from_user - * - * purpose: Copy data from user space memory to the scatter-gather list - * - * returns: 0 - The data has been copied from user - * -EFAULT - Memory I/O operation fault +/** + * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list + * @sg_list: structure describing a scatter-gather list + * @user_buffer: pointer to buffer in user space + * @size: number of bytes to be copied + * Return: 0 on success, -EFAULT if copy_from_user fails. */ 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; @@ -645,10 +670,14 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer, void *zfcp_buffer; int retval = 0; + BUG_ON(sg_list == NULL); + + if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) + return -EFAULT; + for (sg = sg_list->sg; size > 0; sg++) { length = min((unsigned int)size, sg->length); - zfcp_buffer = (void*) - ((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset); + zfcp_buffer = zfcp_sg_to_address(sg); if (copy_from_user(zfcp_buffer, user_buffer, length)) { retval = -EFAULT; goto out; @@ -662,16 +691,16 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer, } -/* - * function: zfcp_sg_list_copy_to_user - * - * purpose: Copy data from the scatter-gather list to user space memory - * - * returns: 0 - The data has been copied to user - * -EFAULT - Memory I/O operation fault +/** + * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space + * @user_buffer: pointer to buffer in user space + * @sg_list: structure describing a scatter-gather list + * @size: number of bytes to be copied + * Return: 0 on success, -EFAULT if copy_to_user fails */ 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; @@ -679,10 +708,14 @@ zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list, void *zfcp_buffer; int retval = 0; + BUG_ON(sg_list == NULL); + + if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) + return -EFAULT; + for (sg = sg_list->sg; size > 0; sg++) { - length = min((unsigned int)size, sg->length); - zfcp_buffer = (void*) - ((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset); + length = min((unsigned int) size, sg->length); + zfcp_buffer = zfcp_sg_to_address(sg); if (copy_to_user(user_buffer, zfcp_buffer, length)) { retval = -EFAULT; goto out; @@ -705,13 +738,12 @@ zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list, #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG /** - * zfcp_get_unit_by_lun - find unit in unit list of port by fcp lun + * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN * @port: pointer to port to search for unit - * @fcp_lun: lun to search for - * Traverses list of all units of a port and returns pointer to a unit - * if lun of a unit matches. + * @fcp_lun: FCP LUN to search for + * Traverse list of all units of a port and return pointer to a unit + * with the given FCP LUN. */ - struct zfcp_unit * zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) { @@ -730,13 +762,12 @@ zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) } /** - * zfcp_get_port_by_wwpn - find unit in unit list of port by fcp lun + * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn * @adapter: pointer to adapter to search for port * @wwpn: wwpn to search for - * Traverses list of all ports of an adapter and returns a pointer to a port - * if wwpn of a port matches. + * Traverse list of all ports of an adapter and return pointer to a port + * with the given wwpn. */ - struct zfcp_port * zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) { @@ -745,6 +776,30 @@ zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) list_for_each_entry(port, &adapter->port_list_head, list) { if ((port->wwpn == wwpn) && + !(atomic_read(&port->status) & + (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) { + found = 1; + break; + } + } + return found ? port : NULL; +} + +/** + * zfcp_get_port_by_did - find port in port list of adapter by d_id + * @adapter: pointer to adapter to search for port + * @d_id: d_id to search for + * Traverse list of all ports of an adapter and return pointer to a port + * with the given d_id. + */ +struct zfcp_port * +zfcp_get_port_by_did(struct zfcp_adapter *adapter, u32 d_id) +{ + struct zfcp_port *port; + int found = 0; + + list_for_each_entry(port, &adapter->port_list_head, list) { + if ((port->d_id == d_id) && !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { found = 1; @@ -754,14 +809,38 @@ zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) return found ? port : NULL; } -/* - * Enqueues a logical unit at the end of the unit list associated with the - * specified port. Also sets up some unit internal structures. +/** + * zfcp_get_adapter_by_busid - find adpater in adapter list by bus_id + * @bus_id: bus_id to search for + * Traverse list of all adapters and return pointer to an adapter + * with the given bus_id. + */ +struct zfcp_adapter * +zfcp_get_adapter_by_busid(char *bus_id) +{ + struct zfcp_adapter *adapter; + int found = 0; + + list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { + if ((strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), + BUS_ID_SIZE) == 0) && + !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, + &adapter->status)){ + found = 1; + break; + } + } + return found ? adapter : NULL; +} + +/** + * zfcp_unit_enqueue - enqueue unit to unit list of a port. + * @port: pointer to port where unit is added + * @fcp_lun: FCP LUN of unit to be enqueued + * Return: pointer to enqueued unit on success, NULL on error + * Locks: config_sema must be held to serialize changes to the unit list * - * returns: pointer to unit with a usecount of 1 if a new unit was - * successfully enqueued - * NULL otherwise - * locks: config_sema must be held to serialise changes to the unit list + * Sets up some unit internal structures and creates sysfs entry. */ struct zfcp_unit * zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) @@ -1022,6 +1101,12 @@ zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) debug_unregister(adapter->in_els_dbf); } +void +zfcp_dummy_release(struct device *dev) +{ + return; +} + /* * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. @@ -1113,6 +1198,14 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) goto sysfs_failed; + adapter->generic_services.parent = &adapter->ccw_device->dev; + adapter->generic_services.release = zfcp_dummy_release; + snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE, + "generic_services"); + + if (device_register(&adapter->generic_services)) + goto generic_services_failed; + /* put allocated adapter at list tail */ write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); @@ -1123,6 +1216,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) goto out; + generic_services_failed: + zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); sysfs_failed: dev_set_drvdata(&ccw_device->dev, NULL); failed_low_mem_buffers: @@ -1153,6 +1248,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) int retval = 0; unsigned long flags; + device_unregister(&adapter->generic_services); zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); dev_set_drvdata(&adapter->ccw_device->dev, NULL); /* sanity check: no pending FSF requests */ @@ -1195,15 +1291,22 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) return; } -/* - * Enqueues a remote port to the port list. All port internal structures - * are set up and the sysfs entry is also generated. +/** + * zfcp_port_enqueue - enqueue port to port list of adapter + * @adapter: adapter where remote port is added + * @wwpn: WWPN of the remote port to be enqueued + * @status: initial status for the port + * @d_id: destination id of the remote port to be enqueued + * Return: pointer to enqueued port on success, NULL on error + * Locks: config_sema must be held to serialize changes to the port list * - * returns: pointer to port or NULL - * locks: config_sema must be held to serialise changes to the port list + * All port internal structures are set up and the sysfs entry is generated. + * d_id is used to enqueue ports with a well known address like the Directory + * Service for nameserver lookup. */ struct zfcp_port * -zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status) +zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, + u32 d_id) { struct zfcp_port *port, *tmp_port; int check_wwpn; @@ -1243,12 +1346,39 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status) atomic_set_mask(status, &port->status); /* setup for sysfs registration */ - if (status & ZFCP_STATUS_PORT_NAMESERVER) - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "nameserver"); - else + if (status & ZFCP_STATUS_PORT_WKA) { + switch (d_id) { + case ZFCP_DID_DIRECTORY_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "directory"); + break; + case ZFCP_DID_MANAGEMENT_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "management"); + break; + case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "key_distribution"); + break; + case ZFCP_DID_ALIAS_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "alias"); + break; + case ZFCP_DID_TIME_SERVICE: + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, + "time"); + break; + default: + kfree(port); + return NULL; + } + port->d_id = d_id; + port->sysfs_device.parent = &adapter->generic_services; + } else { snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", wwpn); port->sysfs_device.parent = &adapter->ccw_device->dev; + } port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); @@ -1287,9 +1417,12 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status) list_add_tail(&port->list, &adapter->port_list_head); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); + if (d_id == ZFCP_DID_DIRECTORY_SERVICE) + if (!adapter->nameserver_port) + adapter->nameserver_port = port; + adapter->ports++; write_unlock_irq(&zfcp_data.config_lock); - adapter->ports++; zfcp_adapter_get(adapter); return port; @@ -1301,8 +1434,8 @@ zfcp_port_dequeue(struct zfcp_port *port) zfcp_port_wait(port); write_lock_irq(&zfcp_data.config_lock); list_del(&port->list); - write_unlock_irq(&zfcp_data.config_lock); port->adapter->ports--; + write_unlock_irq(&zfcp_data.config_lock); zfcp_adapter_put(port->adapter); zfcp_sysfs_port_remove_files(&port->sysfs_device, atomic_read(&port->status)); @@ -1315,17 +1448,14 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) { struct zfcp_port *port; - /* generate port structure */ - port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_NAMESERVER); + port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, + ZFCP_DID_DIRECTORY_SERVICE); if (!port) { ZFCP_LOG_INFO("error: enqueue of nameserver port for " "adapter %s failed\n", zfcp_get_busid_by_adapter(adapter)); return -ENXIO; } - /* set special D_ID */ - port->d_id = ZFCP_DID_NAMESERVER; - adapter->nameserver_port = port; zfcp_port_put(port); return 0; @@ -1389,7 +1519,7 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (atomic_test_mask - (ZFCP_STATUS_PORT_NAMESERVER, &port->status)) + (ZFCP_STATUS_PORT_WKA, &port->status)) continue; /* Do we know this port? If not skip it. */ if (!atomic_test_mask @@ -1646,15 +1776,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 ((ct->status != 0) || 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; @@ -1665,7 +1787,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data) "lookup does not match expected wwpn 0x%016Lx " "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, zfcp_get_busid_by_port(port)); - goto failed; + goto mismatch; } /* looks like a valid d_id */ @@ -1675,19 +1797,185 @@ static void zfcp_ns_gid_pn_handler(unsigned long data) zfcp_get_busid_by_port(port), port->wwpn, port->d_id); goto out; -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)); + mismatch: ZFCP_LOG_DEBUG("CT IUs do not match:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, sizeof(struct ct_iu_gid_pn_req)); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, sizeof(struct ct_iu_gid_pn_resp)); + 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)); out: zfcp_gid_pn_buffers_free(gid_pn); 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 dda20bf00..22f69d6bf 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.91 $" /*************************** INCLUDES *****************************************/ @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -72,12 +73,22 @@ /* zfcp version number, it consists of major, minor, and patch-level number */ #define ZFCP_VERSION "4.1.3" +/** + * zfcp_sg_to_address - determine kernel address from struct scatterlist + * @list: struct scatterlist + * Return: kernel address + */ static inline void * zfcp_sg_to_address(struct scatterlist *list) { return (void *) (page_address(list->page) + list->offset); } +/** + * zfcp_address_to_sg - set up struct scatterlist from kernel address + * @address: kernel address + * @list: struct scatterlist + */ static inline void zfcp_address_to_sg(void *address, struct scatterlist *list) { @@ -146,6 +157,9 @@ typedef u32 scsi_lun_t; #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 6 #define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP 50 +/* timeout value for "default timer" for fsf requests */ +#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ); + /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ typedef unsigned long long wwn_t; @@ -158,7 +172,6 @@ typedef unsigned int fcp_dl_t; /* timeout for name-server lookup (in seconds) */ #define ZFCP_NS_GID_PN_TIMEOUT 10 -#define ZFCP_NS_GA_NXT_TIMEOUT 120 /* largest SCSI command we can process */ /* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */ @@ -276,33 +289,17 @@ struct fcp_logo { #define R_A_TOV 10 /* seconds */ #define ZFCP_ELS_TIMEOUT (2 * R_A_TOV) -#define ZFCP_LS_RJT 0x01 -#define ZFCP_LS_ACC 0x02 #define ZFCP_LS_RTV 0x0E #define ZFCP_LS_RLS 0x0F #define ZFCP_LS_PDISC 0x50 #define ZFCP_LS_ADISC 0x52 -#define ZFCP_LS_RSCN 0x61 -#define ZFCP_LS_RNID 0x78 -#define ZFCP_LS_RLIR 0x7A #define ZFCP_LS_RTV_E_D_TOV_FLAG 0x04000000 -/* LS_ACC Reason Codes */ -#define ZFCP_LS_RJT_INVALID_COMMAND_CODE 0x01 -#define ZFCP_LS_RJT_LOGICAL_ERROR 0x03 -#define ZFCP_LS_RJT_LOGICAL_BUSY 0x05 -#define ZFCP_LS_RJT_PROTOCOL_ERROR 0x07 -#define ZFCP_LS_RJT_UNABLE_TO_PERFORM 0x09 -#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 { @@ -383,45 +380,10 @@ struct zfcp_ls_adisc_acc { fc_id_t nport_id; } __attribute__ ((packed)); -struct zfcp_ls_rnid { - u8 code; - u8 field[3]; - u8 node_id_format; - u8 reserved[3]; -} __attribute__((packed)); - -/* common identification data */ -struct zfcp_ls_rnid_common_id { - u64 n_port_name; - u64 node_name; -} __attribute__((packed)); - -/* general topology specific identification data */ -struct zfcp_ls_rnid_general_topology_id { - u8 vendor_unique[16]; - u32 associated_type; - u32 physical_port_number; - u32 nr_attached_nodes; - u8 node_management; - u8 ip_version; - u16 port_number; - u8 ip_address[16]; - u8 reserved[2]; - u16 vendor_specific; -} __attribute__((packed)); - -struct zfcp_ls_rnid_acc { - u8 code; - u8 field[3]; - u8 node_id_format; - u8 common_id_length; - u8 reserved; - u8 specific_id_length; - struct zfcp_ls_rnid_common_id - common_id; - struct zfcp_ls_rnid_general_topology_id - specific_id; -} __attribute__((packed)); +struct zfcp_rc_entry { + u8 code; + const char *description; +}; /* * FC-GS-2 stuff @@ -431,9 +393,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 @@ -530,23 +492,29 @@ struct zfcp_ls_rnid_acc { __LINE__ , ##args); #define ZFCP_LOG(level, fmt, args...) \ +do { \ if (ZFCP_LOG_CHECK(level)) \ - _ZFCP_LOG(fmt , ##args) + _ZFCP_LOG(fmt, ##args); \ +} while (0) #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL # define ZFCP_LOG_NORMAL(fmt, args...) #else # define ZFCP_LOG_NORMAL(fmt, args...) \ +do { \ if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \ - printk(KERN_ERR ZFCP_NAME": " fmt , ##args); + printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ +} while (0) #endif #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO # define ZFCP_LOG_INFO(fmt, args...) #else # define ZFCP_LOG_INFO(fmt, args...) \ +do { \ if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \ - printk(KERN_ERR ZFCP_NAME": " fmt , ##args); + printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ +} while (0) #endif #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG @@ -568,8 +536,10 @@ struct zfcp_ls_rnid_acc { #else extern u32 flags_dump; # define ZFCP_LOG_FLAGS(level, fmt, args...) \ +do { \ if (level <= flags_dump) \ - _ZFCP_LOG(fmt , ##args) + _ZFCP_LOG(fmt, ##args); \ +} while (0) #endif /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ @@ -606,7 +576,12 @@ extern u32 flags_dump; ZFCP_STATUS_ADAPTER_REGISTERED) -#define ZFCP_DID_NAMESERVER 0xFFFFFC +/* FC-PH/FC-GS well-known address identifiers for generic services */ +#define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA +#define ZFCP_DID_TIME_SERVICE 0xFFFFFB +#define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC +#define ZFCP_DID_ALIAS_SERVICE 0xFFFFF8 +#define ZFCP_DID_KEY_DISTRIBUTION_SERVICE 0xFFFFF7 /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 @@ -616,7 +591,8 @@ extern u32 flags_dump; #define ZFCP_STATUS_PORT_NO_SCSI_ID 0x00000010 #define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020 -#define ZFCP_STATUS_PORT_NAMESERVER \ +/* for ports with well known addresses */ +#define ZFCP_STATUS_PORT_WKA \ (ZFCP_STATUS_PORT_NO_WWPN | \ ZFCP_STATUS_PORT_NO_SCSI_ID) @@ -789,43 +765,29 @@ struct ct_iu_gid_pn_req { wwn_t wwpn; } __attribute__ ((packed)); -/* nameserver request CT_IU -- for requests where - * a port identifier is required */ -struct ct_iu_ga_nxt_req { - struct ct_hdr header; - fc_id_t d_id; -} __attribute__ ((packed)); - /* FS_ACC IU and data unit for GID_PN nameserver request */ struct ct_iu_gid_pn_resp { struct ct_hdr header; fc_id_t d_id; } __attribute__ ((packed)); -/* FS_ACC IU and data unit for GA_NXT nameserver request */ -struct ct_iu_ga_nxt_resp { - struct ct_hdr header; - u8 port_type; - u8 port_id[3]; - u64 port_wwn; - u8 port_symbolic_name_length; - u8 port_symbolic_name[255]; - u64 node_wwn; - u8 node_symbolic_name_length; - u8 node_symbolic_name[255]; - u64 initial_process_associator; - u8 node_ip[16]; - u32 cos; - u8 fc4_types[32]; - u8 port_ip[16]; - u64 fabric_wwn; - u8 reserved; - u8 hard_address[3]; -} __attribute__ ((packed)); - typedef void (*zfcp_send_ct_handler_t)(unsigned long); -/* used to pass parameters to zfcp_send_ct() */ +/** + * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct + * @port: port where the request is sent to + * @req: scatter-gather list for request + * @resp: scatter-gather list for response + * @req_count: number of elements in request scatter-gather list + * @resp_count: number of elements in response scatter-gather list + * @handler: handler function (called for response to the request) + * @handler_data: data passed to handler function + * @pool: pointer to memory pool for ct request structure + * @timeout: FSF timeout for this request + * @timer: timer (e.g. for request initiated by erp) + * @completion: completion for synchronization purposes + * @status: used to pass error status to calling function + */ struct zfcp_send_ct { struct zfcp_port *port; struct scatterlist *req; @@ -834,7 +796,7 @@ struct zfcp_send_ct { unsigned int resp_count; zfcp_send_ct_handler_t handler; unsigned long handler_data; - mempool_t *pool; /* mempool for ct not for fsf_req */ + mempool_t *pool; int timeout; struct timer_list *timer; struct completion *completion; @@ -851,10 +813,22 @@ struct zfcp_gid_pn_data { struct zfcp_port *port; }; -typedef int (*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 */ +typedef void (*zfcp_send_els_handler_t)(unsigned long); + +/** + * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els + * @port: port where the request is sent to + * @req: scatter-gather list for request + * @resp: scatter-gather list for response + * @req_count: number of elements in request scatter-gather list + * @resp_count: number of elements in response scatter-gather list + * @handler: handler function (called for response to the request) + * @handler_data: data passed to handler function + * @timer: timer (e.g. for request initiated by erp) + * @completion: completion for synchronization purposes + * @ls_code: hex code of ELS command + * @status: used to pass error status to calling function + */ struct zfcp_send_els { struct zfcp_port *port; struct scatterlist *req; @@ -863,6 +837,7 @@ struct zfcp_send_els { unsigned int resp_count; zfcp_send_els_handler_t handler; unsigned long handler_data; + struct timer_list *timer; struct completion *completion; int ls_code; int status; @@ -892,6 +867,7 @@ union zfcp_req_data { struct zfcp_send_ct *send_ct; struct zfcp_send_els *send_els; struct zfcp_status_read status_read; + struct fsf_qtcb_bottom_port *port_data; }; struct zfcp_qdio_queue { @@ -979,6 +955,7 @@ struct zfcp_adapter { rwlock_t cmd_dbf_lock; struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct qdio_initialize qdio_init_data; /* for qdio_establish */ + struct device generic_services; /* directory for WKA ports */ }; /* @@ -1080,6 +1057,11 @@ struct zfcp_data { fcp_lun_t init_fcp_lun; }; +/** + * struct zfcp_sg_list - struct describing a scatter-gather list + * @sg: pointer to array of (struct scatterlist) + * @count: number of elements in scatter-gather list + */ struct zfcp_sg_list { struct scatterlist *sg; unsigned int count; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e0766777e..55759e83f 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.65 $" #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); @@ -126,6 +126,25 @@ static void zfcp_erp_memwait_handler(unsigned long); static void zfcp_erp_timeout_handler(unsigned long); static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *); +/** + * zfcp_fsf_request_timeout_handler - called if a request timed out + * @data: pointer to adapter for handler function + * + * This function needs to be called if requests (ELS, Generic Service, + * or SCSI commands) exceed a certain time limit. The assumption is + * that after the time limit the adapter get stuck. So we trigger a reopen of + * the adapter. This should not be used for error recovery, SCSI abort + * commands and SCSI requests from SCSI mid-layer. + */ +void +zfcp_fsf_request_timeout_handler(unsigned long data) +{ + struct zfcp_adapter *adapter; + + adapter = (struct zfcp_adapter *) data; + + zfcp_erp_adapter_reopen(adapter, 0); +} /* * function: zfcp_fsf_scsi_er_timeout_handler @@ -324,6 +343,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 +432,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; - 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; + switch (req_code) { - 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); } @@ -735,14 +669,15 @@ zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask) return retval; } -/* - * function: - * - * purpose: Wrappper for zfcp_erp_port_reopen_internal - * used to ensure the correct locking +/** + * zfcp_erp_port_reopen - initiate reopen of a remote port + * @port: port to be reopened + * @clear_mask: specifies flags in port status to be cleared + * Return: 0 on success, < 0 on error * - * returns: 0 - initiated action succesfully - * <0 - failed to initiate action + * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures + * correct locking. An error recovery task is initiated to do the reopen. + * To wait for the completion of the reopen zfcp_erp_wait should be used. */ int zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask) @@ -802,14 +737,15 @@ zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask) return retval; } -/* - * function: - * - * purpose: Wrappper for zfcp_erp_unit_reopen_internal - * used to ensure the correct locking +/** + * zfcp_erp_unit_reopen - initiate reopen of a unit + * @unit: unit to be reopened + * @clear_mask: specifies flags in unit status to be cleared + * Return: 0 on success, < 0 on error * - * returns: 0 - initiated action succesfully - * <0 - failed to initiate action + * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct + * locking. An error recovery task is initiated to do the reopen. + * To wait for the completion of the reopen zfcp_erp_wait should be used. */ int zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask) @@ -1987,12 +1923,10 @@ zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) return retval; } -/* - * function: - * - * purpose: - * - * returns: +/** + * zfcp_erp_wait - wait for completion of error recovery on an adapter + * @adapter: adapter for which to wait for completion of its error recovery + * Return: 0 */ int zfcp_erp_wait(struct zfcp_adapter *adapter) @@ -2130,7 +2064,7 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask) struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) - if (!atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status)) + if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) zfcp_erp_port_reopen_internal(port, clear_mask); return retval; @@ -2725,7 +2659,7 @@ zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action) { int retval; - if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, + if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &erp_action->port->status)) retval = zfcp_erp_port_strategy_open_nameserver(erp_action); else @@ -2863,10 +2797,10 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_PORT_OPENING: if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - ZFCP_LOG_DEBUG("nameserver port is open\n"); + ZFCP_LOG_DEBUG("WKA port is open\n"); retval = ZFCP_ERP_SUCCEEDED; } else { - ZFCP_LOG_DEBUG("open failed for nameserver port\n"); + ZFCP_LOG_DEBUG("open failed for WKA port\n"); retval = ZFCP_ERP_FAILED; } /* this is needed anyway (dont care for retval of wakeup) */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index d99005c01..35c6104ec 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.57 $" #include "zfcp_def.h" @@ -50,15 +50,16 @@ extern void zfcp_sysfs_port_release(struct device *); extern void zfcp_sysfs_unit_release(struct device *); /**************************** CONFIGURATION *********************************/ -extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, - fcp_lun_t fcp_lun); -extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, - wwn_t wwpn); +extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); +extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, wwn_t); +extern struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *, u32); +struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); extern int zfcp_adapter_debug_register(struct zfcp_adapter *); extern void zfcp_adapter_dequeue(struct zfcp_adapter *); extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); -extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32); +extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, + u32, u32); extern void zfcp_port_dequeue(struct zfcp_port *); extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); extern void zfcp_unit_dequeue(struct zfcp_unit *); @@ -94,8 +95,11 @@ extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); +extern int zfcp_fsf_exchange_port_data(struct zfcp_adapter *, + struct fsf_qtcb_bottom_port *); extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, u32, u32, struct zfcp_sg_list *); +extern void zfcp_fsf_request_timeout_handler(unsigned long); extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long); extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); @@ -108,7 +112,7 @@ extern int zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, struct zfcp_unit *, struct scsi_cmnd *, - int); + struct timer_list*, int); extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fsf_req_cleanup(struct zfcp_fsf_req *); @@ -117,9 +121,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 *); @@ -132,10 +138,10 @@ extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *); extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); -extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd); -extern int zfcp_scsi_command_sync(struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd); +extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *, + struct scsi_cmnd *, struct timer_list *); +extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, + struct timer_list *); extern struct scsi_transport_template *zfcp_transport_template; extern struct fc_function_template zfcp_transport_functions; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 79451af65..44c646cca 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -29,11 +29,12 @@ */ /* 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.65 $" #include "zfcp_ext.h" static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *); +static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *); static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *); static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *); static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *); @@ -48,7 +49,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 +80,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 *************************/ /****************************************************************/ @@ -684,13 +684,11 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) break; case FSF_SQ_ULP_PROGRAMMING_ERROR: ZFCP_LOG_FLAGS(0, "FSF_SQ_ULP_PROGRAMMING_ERROR\n"); - ZFCP_LOG_NORMAL("bug: An illegal amount of data was attempted " - "to be sent to the adapter %s " - "Stopping all operations on this adapter. ", + ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " + "(adapter %s)\n", zfcp_get_busid_by_adapter(fsf_req->adapter)); debug_text_exception(fsf_req->adapter->erp_dbf, 0, "fsf_sq_ulp_err"); - zfcp_erp_adapter_shutdown(fsf_req->adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: @@ -785,6 +783,11 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) zfcp_fsf_exchange_config_data_handler(fsf_req); break; + case FSF_QTCB_EXCHANGE_PORT_DATA : + ZFCP_LOG_FLAGS(2, "FSF_QTCB_EXCHANGE_PORT_DATA\n"); + zfcp_fsf_exchange_port_data_handler(fsf_req); + break; + case FSF_QTCB_SEND_ELS : ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_ELS\n"); zfcp_fsf_send_els_handler(fsf_req); @@ -1624,26 +1627,6 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_REQUEST_BUF_NOT_VALID : - ZFCP_LOG_FLAGS(2, "FSF_REQUEST_BUF_NOT_VALID\n"); - ZFCP_LOG_NORMAL("error: The port 0x%016Lx on adapter %s has " - "rejected a generic services command " - "due to invalid request buffer.\n", - port->wwpn, zfcp_get_busid_by_port(port)); - debug_text_event(adapter->erp_dbf, 1, "fsf_s_reqiv"); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_RESPONSE_BUF_NOT_VALID : - ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_BUF_NOT_VALID\n"); - ZFCP_LOG_NORMAL("error: The port 0x%016Lx on adapter %s has " - "rejected a generic services command " - "due to invalid response buffer.\n", - port->wwpn, zfcp_get_busid_by_port(port)); - debug_text_event(adapter->erp_dbf, 1, "fsf_s_resiv"); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_PORT_BOXED : ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n"); ZFCP_LOG_INFO("The remote port 0x%016Lx on adapter %s " @@ -1665,9 +1648,10 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) } skip_fsfstatus: - if (send_ct->handler != NULL) { + send_ct->status = retval; + + if (send_ct->handler != NULL) send_ct->handler(send_ct->handler_data); - } return retval; } @@ -1769,7 +1753,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); /* start QDIO request for this FSF request */ - ret = zfcp_fsf_req_send(fsf_req, NULL); + ret = zfcp_fsf_req_send(fsf_req, els->timer); if (ret) { ZFCP_LOG_DEBUG("error: initiation of ELS request failed " "(adapter %s, port 0x%016Lx)\n", @@ -1863,6 +1847,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"); @@ -1921,15 +1909,6 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) bottom->resp_buf_length); break; - case FSF_UNKNOWN_COMMAND: - ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n"); - ZFCP_LOG_INFO( - "FSF command 0x%x is not supported by FCP adapter " - "(adapter: %s)\n", fsf_req->fsf_command, - zfcp_get_busid_by_port(port)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_ACCESS_DENIED: ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n"); ZFCP_LOG_NORMAL("Access denied, cannot send ELS " @@ -1971,8 +1950,6 @@ skip_fsfstatus: if (send_els->handler != 0) send_els->handler(send_els->handler_data); - kfree(send_els); - return retval; } @@ -2219,6 +2196,111 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) return 0; } +/** + * zfcp_fsf_exchange_port_data - request information about local port + * @adapter: for which port data is requested + * @data: response to exchange port data request + */ +int +zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_port *data) +{ + volatile struct qdio_buffer_element *sbale; + int retval = 0; + unsigned long lock_flags; + struct zfcp_fsf_req *fsf_req; + struct timer_list *timer; + + if(!(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT)){ + ZFCP_LOG_INFO("error: exchange port data " + "command not supported by adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + return -EOPNOTSUPP; + } + + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) + return -ENOMEM; + + /* setup new FSF request */ + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + 0, 0, &lock_flags, &fsf_req); + if (retval < 0) { + ZFCP_LOG_INFO("error: Out of resources. Could not create an " + "exchange port data request for" + "the adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + goto out; + } + + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + + fsf_req->data.port_data = data; + + init_timer(timer); + timer->function = zfcp_fsf_request_timeout_handler; + timer->data = (unsigned long) adapter; + timer->expires = ZFCP_FSF_REQUEST_TIMEOUT; + + retval = zfcp_fsf_req_send(fsf_req, timer); + if (retval) { + ZFCP_LOG_INFO("error: Could not send an exchange port data " + "command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + zfcp_fsf_req_free(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + goto out; + } + + ZFCP_LOG_DEBUG("Exchange Port Data request initiated (adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); + + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + + wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + del_timer_sync(timer); + zfcp_fsf_req_cleanup(fsf_req); + out: + kfree(timer); + return retval; +} + + +/** + * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request + * @fsf_req: pointer to struct zfcp_fsf_req + */ +static void +zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) +{ + struct fsf_qtcb_bottom_port *bottom; + struct fsf_qtcb_bottom_port *data = fsf_req->data.port_data; + + if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) + return; + + switch (fsf_req->qtcb->header.fsf_status) { + case FSF_GOOD : + ZFCP_LOG_FLAGS(2,"FSF_GOOD\n"); + bottom = &fsf_req->qtcb->bottom.port; + memcpy(data, bottom, sizeof(*data)); + break; + + default: + debug_text_event(fsf_req->adapter->erp_dbf, 0, "xchg-port-ng"); + debug_event(fsf_req->adapter->erp_dbf, 0, + &fsf_req->qtcb->header.fsf_status, sizeof(u32)); + } +} + + /* * function: zfcp_fsf_open_port * @@ -3319,19 +3401,19 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) return retval; } -/* - * function: zfcp_fsf_send_fcp_command_task - * - * purpose: - * - * returns: - * - * note: we do not employ linked commands (not supported by HBA anyway) +/** + * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) + * @adapter: adapter where scsi command is issued + * @unit: unit where command is sent to + * @scsi_cmnd: scsi command to be sent + * @timer: timer to be started when request is initiated + * @req_flags: flags for fsf_request */ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, struct zfcp_unit *unit, - struct scsi_cmnd * scsi_cmnd, int req_flags) + struct scsi_cmnd * scsi_cmnd, + struct timer_list *timer, int req_flags) { struct zfcp_fsf_req *fsf_req = NULL; struct fcp_cmnd_iu *fcp_cmnd_iu; @@ -3486,7 +3568,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, * start QDIO request for this FSF request * covered by an SBALE) */ - retval = zfcp_fsf_req_send(fsf_req, NULL); + retval = zfcp_fsf_req_send(fsf_req, timer); if (unlikely(retval < 0)) { ZFCP_LOG_INFO("error: Could not send FCP command request " "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", @@ -3788,44 +3870,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - /* FIXME: this should be obsolete, isn' it? */ - case FSF_INBOUND_DATA_LENGTH_NOT_VALID: - ZFCP_LOG_FLAGS(0, "FSF_INBOUND_DATA_LENGTH_NOT_VALID\n"); - ZFCP_LOG_NORMAL("bug: An invalid inbound data length field " - "was found in a command for unit 0x%016Lx " - "on port 0x%016Lx on adapter %s.\n", - unit->fcp_lun, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); - /* stop operation for this adapter */ - debug_text_event(fsf_req->adapter->erp_dbf, 0, - "fsf_s_in_dl_nv"); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("idleninv", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - /* FIXME: this should be obsolete, isn' it? */ - case FSF_OUTBOUND_DATA_LENGTH_NOT_VALID: - ZFCP_LOG_FLAGS(0, "FSF_OUTBOUND_DATA_LENGTH_NOT_VALID\n"); - ZFCP_LOG_NORMAL("bug: An invalid outbound data length field " - "was found in a command unit 0x%016Lx on port " - "0x%016Lx on adapter %s\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - /* stop operation for this adapter */ - debug_text_event(fsf_req->adapter->erp_dbf, 0, - "fsf_s_out_dl_nv"); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("odleninv", fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_CMND_LENGTH_NOT_VALID: ZFCP_LOG_FLAGS(0, "FSF_CMND_LENGTH_NOT_VALID\n"); ZFCP_LOG_NORMAL @@ -4157,87 +4201,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); @@ -4585,16 +4548,6 @@ zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) retval = -EIO; break; - case FSF_UNKNOWN_COMMAND: - ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n"); - ZFCP_LOG_NORMAL( - "FSF command 0x%x is not supported by the adapter %s\n", - fsf_req->fsf_command, - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EINVAL; - break; - case FSF_UNKNOWN_OP_SUBTYPE: ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n"); ZFCP_LOG_NORMAL( @@ -4682,8 +4635,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)) @@ -4712,30 +4665,25 @@ zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd) * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue * @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 + * @lock_flags: lock_flags if queue_lock is taken + * 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 879313864..3ad0ace82 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -84,19 +84,12 @@ #define FSF_SERVICE_CLASS_NOT_SUPPORTED 0x00000006 #define FSF_FCPLUN_NOT_VALID 0x00000009 #define FSF_ACCESS_DENIED 0x00000010 -#define FSF_ACCESS_TYPE_NOT_VALID 0x00000011 #define FSF_LUN_SHARING_VIOLATION 0x00000012 -#define FSF_COMMAND_ABORTED_ULP 0x00000020 -#define FSF_COMMAND_ABORTED_ADAPTER 0x00000021 #define FSF_FCP_COMMAND_DOES_NOT_EXIST 0x00000022 #define FSF_DIRECTION_INDICATOR_NOT_VALID 0x00000030 -#define FSF_INBOUND_DATA_LENGTH_NOT_VALID 0x00000031 /* FIX: obsolete? */ -#define FSF_OUTBOUND_DATA_LENGTH_NOT_VALID 0x00000032 /* FIX: obsolete? */ #define FSF_CMND_LENGTH_NOT_VALID 0x00000033 #define FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED 0x00000040 #define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED 0x00000041 -#define FSF_REQUEST_BUF_NOT_VALID 0x00000042 -#define FSF_RESPONSE_BUF_NOT_VALID 0x00000043 #define FSF_ELS_COMMAND_REJECTED 0x00000050 #define FSF_GENERIC_COMMAND_REJECTED 0x00000051 #define FSF_OPERATION_PARTIALLY_SUCCESSFUL 0x00000052 @@ -227,6 +220,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 d0a879f0a..6c0808163 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.68 $" #include "zfcp_ext.h" @@ -247,15 +247,16 @@ zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) /** * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and * zfcp_scsi_command_sync - * @adapter: adapter for where scsi command is issued + * @adapter: adapter where scsi command is issued * @unit: unit to which scsi command is sent * @scpnt: scsi command to be sent + * @timer: timer to be started if request is successfully initiated * * Note: In scsi_done function must be set in scpnt. */ int zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, - struct scsi_cmnd *scpnt) + struct scsi_cmnd *scpnt, struct timer_list *timer) { int tmp; int retval; @@ -291,7 +292,7 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, goto out; } - tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, + tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, timer, ZFCP_REQ_AUTO_CLEANUP); if (unlikely(tmp < 0)) { @@ -313,18 +314,28 @@ zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) /** * zfcp_scsi_command_sync - send a SCSI command and wait for completion - * returns 0, errors are indicated by scsi_cmnd->result + * @unit: unit where command is sent to + * @scpnt: scsi command to be sent + * @timer: timer to be started if request is successfully initiated + * Return: 0 + * + * Errors are indicated in scpnt->result */ int -zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt) +zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, + struct timer_list *timer) { + int ret; DECLARE_COMPLETION(wait); scpnt->SCp.ptr = (void *) &wait; /* silent re-use */ - scpnt->done = zfcp_scsi_command_sync_handler; - zfcp_scsi_command_async(unit->port->adapter, unit, scpnt); + scpnt->scsi_done = zfcp_scsi_command_sync_handler; + ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, timer); + if ((ret == 0) && (scpnt->result == 0)) wait_for_completion(&wait); + scpnt->SCp.ptr = NULL; + return 0; } @@ -355,7 +366,7 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; unit = (struct zfcp_unit *) scpnt->device->hostdata; - return zfcp_scsi_command_async(adapter, unit, scpnt); + return zfcp_scsi_command_async(adapter, unit, scpnt, NULL); } /* @@ -430,7 +441,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 d7536a11a..f92ec32d7 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.37 $" #include "zfcp_ext.h" #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG static const char fc_topologies[5][25] = { - {""}, - {"point-to-point"}, - {"fabric"}, - {"arbitrated loop"}, - {"fabric (virt. adapter)"} + "", + "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 @@ -127,7 +106,7 @@ zfcp_sysfs_port_add_store(struct device *dev, const char *buf, size_t count) if ((endp + 1) < (buf + count)) goto out; - port = zfcp_port_enqueue(adapter, wwpn, 0); + port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (!port) goto out; @@ -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 e0d6eecfe..ffd55176f 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 11a27c1ff..10b66cd8c 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.44 $" #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; } /** @@ -232,29 +234,6 @@ zfcp_sysfs_port_failed_show(struct device *dev, char *buf) 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. @@ -300,7 +279,7 @@ zfcp_sysfs_port_create_files(struct device *dev, u32 flags) retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group); - if ((flags & ZFCP_STATUS_PORT_NAMESERVER) || retval) + if ((flags & ZFCP_STATUS_PORT_WKA) || retval) return retval; retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group); @@ -320,7 +299,7 @@ void zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) { sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); - if (!(flags & ZFCP_STATUS_PORT_NAMESERVER)) + if (!(flags & ZFCP_STATUS_PORT_WKA)) sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); } diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c index 904c8aead..bad3b7f2c 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/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index d45619f3b..1ff81bec8 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -1531,8 +1531,7 @@ static void aurora_close(struct tty_struct * tty, struct file * filp) aurora_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; port->tty = 0; @@ -1743,10 +1742,7 @@ static void aurora_flush_buffer(struct tty_struct *tty) port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); #ifdef AURORA_DEBUG printk("aurora_flush_buffer: end\n"); #endif @@ -2223,10 +2219,7 @@ static void do_softint(void *private_) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } #ifdef AURORA_DEBUG printk("do_softint: end\n"); diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 37189ef06..d5259f7fe 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -452,7 +452,7 @@ static void fans_full_blast(void) } } -#define POLL_INTERVAL (5 * HZ) +#define POLL_INTERVAL (5 * 1000) static unsigned long last_warning_jiffies; static struct task_struct *kenvctrld_task; @@ -468,8 +468,7 @@ static int kenvctrld(void *__unused) struct bbc_cpu_temperature *tp; struct bbc_fan_control *fp; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(POLL_INTERVAL); + msleep_interruptible(POLL_INTERVAL); if (signal_pending(current)) break; diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index a489c544f..2dcd3cd87 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -189,13 +189,13 @@ static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) while (limit-- > 0) { u8 val; - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); *status = val = readb(bp->i2c_control_regs + 0); if ((val & I2C_PCF_PIN) == 0) { ret = 0; break; } - schedule_timeout(HZ/4); + msleep_interruptible(250); } remove_wait_queue(&bp->wq, &wait); bp->waiting = 0; diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index ad870a300..9fcf180ba 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -118,40 +118,26 @@ * UNKNOWN, MAGICAL MYSTERY REGISTER * */ -struct wd_timer_regblk { - volatile __u16 dcntr; /* down counter - hw */ - volatile __u16 dcntr_pad; - volatile __u16 limit; /* limit register - hw */ - volatile __u16 limit_pad; - volatile __u8 status; /* status register - b */ - volatile __u8 status_pad; - volatile __u16 status_pad2; - volatile __u32 pad32; /* yet more padding */ -}; +#define WD_TIMER_REGSZ 16 +#define WD0_OFF 0 +#define WD1_OFF (WD_TIMER_REGSZ * 1) +#define WD2_OFF (WD_TIMER_REGSZ * 2) +#define PLD_OFF (WD_TIMER_REGSZ * 3) -struct wd_pld_regblk { - volatile __u8 intr_mask; /* interrupt mask - b */ - volatile __u8 intr_mask_pad; - volatile __u16 intr_mask_pad2; - volatile __u8 status; /* device status - b */ - volatile __u8 status_pad; - volatile __u16 status_pad2; -}; +#define WD_DCNTR 0x00 +#define WD_LIMIT 0x04 +#define WD_STATUS 0x08 -struct wd_regblk { - volatile struct wd_timer_regblk wd0_regs; - volatile struct wd_timer_regblk wd1_regs; - volatile struct wd_timer_regblk wd2_regs; - volatile struct wd_pld_regblk pld_regs; -}; +#define PLD_IMASK (PLD_OFF + 0x00) +#define PLD_STATUS (PLD_OFF + 0x04) /* Individual timer structure */ struct wd_timer { __u16 timeout; __u8 intr_mask; - unsigned char runstatus; - volatile struct wd_timer_regblk* regs; + unsigned char runstatus; + void __iomem *regs; }; /* Device structure @@ -165,7 +151,7 @@ struct wd_device { unsigned short opt_timeout; unsigned char initialized; struct wd_timer watchdog[WD_NUMDEVS]; - volatile struct wd_regblk* regs; + void __iomem *regs; }; static struct wd_device wd_dev = { @@ -495,12 +481,12 @@ static void wd_dumpregs(void) i, wd_getstatus(&wd_dev.watchdog[i])); } - printk("\tintr_mask at 0x%lx: 0x%x\n", - (unsigned long)(&wd_dev.regs->pld_regs.intr_mask), - readb(&wd_dev.regs->pld_regs.intr_mask)); - printk("\tpld_status at 0x%lx: 0x%x\n", - (unsigned long)(&wd_dev.regs->pld_regs.status), - readb(&wd_dev.regs->pld_regs.status)); + printk("\tintr_mask at %p: 0x%x\n", + wd_dev.regs + PLD_IMASK, + readb(wd_dev.regs + PLD_IMASK)); + printk("\tpld_status at %p: 0x%x\n", + wd_dev.regs + PLD_STATUS, + readb(wd_dev.regs + PLD_STATUS)); } #endif @@ -513,7 +499,7 @@ static void wd_dumpregs(void) */ static void wd_toggleintr(struct wd_timer* pTimer, int enable) { - unsigned char curregs = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); unsigned char setregs = (NULL == pTimer) ? (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : @@ -523,7 +509,7 @@ static void wd_toggleintr(struct wd_timer* pTimer, int enable) (curregs &= ~setregs): (curregs |= setregs); - wd_writeb(curregs, &wd_dev.regs->pld_regs.intr_mask); + wd_writeb(curregs, wd_dev.regs + PLD_IMASK); return; } @@ -534,8 +520,8 @@ static void wd_toggleintr(struct wd_timer* pTimer, int enable) */ static void wd_pingtimer(struct wd_timer* pTimer) { - if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { - wd_readw(&pTimer->regs->dcntr); + if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { + wd_readw(pTimer->regs + WD_DCNTR); } } @@ -547,7 +533,7 @@ static void wd_pingtimer(struct wd_timer* pTimer) */ static void wd_stoptimer(struct wd_timer* pTimer) { - if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { + if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { wd_toggleintr(pTimer, WD_INTR_OFF); if(wd_dev.isbaddoggie) { @@ -574,7 +560,7 @@ static void wd_starttimer(struct wd_timer* pTimer) } pTimer->runstatus &= ~WD_STAT_SVCD; - wd_writew(pTimer->timeout, &pTimer->regs->limit); + wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); wd_toggleintr(pTimer, WD_INTR_ON); } @@ -584,7 +570,7 @@ static void wd_starttimer(struct wd_timer* pTimer) static void wd_resetbrokentimer(struct wd_timer* pTimer) { wd_toggleintr(pTimer, WD_INTR_ON); - wd_writew(WD_BLIMIT, &pTimer->regs->limit); + wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); } /* Timer device initialization helper. @@ -593,7 +579,7 @@ static void wd_resetbrokentimer(struct wd_timer* pTimer) static int wd_inittimer(int whichdog) { struct miscdevice *whichmisc; - volatile struct wd_timer_regblk *whichregs; + void __iomem *whichregs; char whichident[8]; int whichmask; __u16 whichlimit; @@ -603,7 +589,7 @@ static int wd_inittimer(int whichdog) case WD0_ID: whichmisc = &wd0_miscdev; strcpy(whichident, "RIC"); - whichregs = &wd_dev.regs->wd0_regs; + whichregs = wd_dev.regs + WD0_OFF; whichmask = WD0_INTR_MASK; whichlimit= (0 == wd0_timeout) ? (wd_dev.opt_timeout): @@ -612,7 +598,7 @@ static int wd_inittimer(int whichdog) case WD1_ID: whichmisc = &wd1_miscdev; strcpy(whichident, "XIR"); - whichregs = &wd_dev.regs->wd1_regs; + whichregs = wd_dev.regs + WD1_OFF; whichmask = WD1_INTR_MASK; whichlimit= (0 == wd1_timeout) ? (wd_dev.opt_timeout): @@ -621,7 +607,7 @@ static int wd_inittimer(int whichdog) case WD2_ID: whichmisc = &wd2_miscdev; strcpy(whichident, "POR"); - whichregs = &wd_dev.regs->wd2_regs; + whichregs = wd_dev.regs + WD2_OFF; whichmask = WD2_INTR_MASK; whichlimit= (0 == wd2_timeout) ? (wd_dev.opt_timeout): @@ -686,8 +672,8 @@ static void wd_brokentimer(unsigned long data) static int wd_getstatus(struct wd_timer* pTimer) { - unsigned char stat = wd_readb(&pTimer->regs->status); - unsigned char intr = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); + unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); unsigned char ret = WD_STOPPED; /* determine STOPPED */ @@ -805,7 +791,7 @@ static void __exit wd_cleanup(void) * also now eventually trip. */ for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(WD_S_RUNNING == wd_readb(&wd_dev.watchdog[id].regs->status)) { + if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { if(wd_dev.opt_enable) { printk(KERN_WARNING "%s%i: timer not stopped at release\n", WD_OBPNAME, id); @@ -818,7 +804,7 @@ static void __exit wd_cleanup(void) "%s%i: defect workaround disabled at release, "\ "timer expires in ~%01i sec\n", WD_OBPNAME, id, - wd_readw(&wd_dev.watchdog[id].regs->limit) / 10); + wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); } } } diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index e8ac0b4d3..adb30d5d3 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -70,7 +70,7 @@ MODULE_SUPPORTED_DEVICE * FLIP - Inverts display for upside-down mounted board * bits 0-4 - 7-segment display contents */ -volatile u8* d7s_regs = NULL; +static void __iomem* d7s_regs; static inline void d7s_free(void) { diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index cd6e2d39f..f6ed35b24 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -130,10 +130,8 @@ static int errno; */ #define ENVCTRL_CPCI_IGNORED_NODE 0x70 -struct pcf8584_reg { - unsigned char data; - unsigned char csr; -}; +#define PCF8584_DATA 0x00 +#define PCF8584_CSR 0x01 /* Each child device can be monitored by up to PCF8584_MAX_CHANNELS. * Property of a port or channel as defined by the firmware. @@ -175,7 +173,7 @@ struct i2c_child_t { char mon_type[PCF8584_MAX_CHANNELS]; }; -volatile static struct pcf8584_reg *i2c = NULL; +static void __iomem *i2c; static struct i2c_child_t i2c_childlist[ENVCTRL_MAX_CPU*2]; static unsigned char chnls_mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static unsigned int warning_temperature = 0; @@ -185,22 +183,6 @@ static char read_cpu; /* Forward declarations. */ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char); -/* Function description: Read a byte from an i2c controller register. - * Return: A byte from the passed in address. - */ -static inline unsigned char envctrl_readb(volatile unsigned char *p) -{ - return readb(p); -} - -/* Function description: Write a byte to an i2c controller register. - * Return: Nothing. - */ -static inline void envctrl_writeb(unsigned char val, volatile unsigned char *p) -{ - writeb(val, p); -} - /* Function Description: Test the PIN bit (Pending Interrupt Not) * to test when serial transmission is completed . * Return : None. @@ -210,7 +192,7 @@ static void envtrl_i2c_test_pin(void) int limit = 1000000; while (--limit > 0) { - if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) + if (!(readb(i2c + PCF8584_CSR) & STATUS_PIN)) break; udelay(1); } @@ -228,7 +210,7 @@ static void envctrl_i2c_test_bb(void) while (--limit > 0) { /* Busy bit 0 means busy. */ - if (envctrl_readb(&i2c->csr) & STATUS_BB) + if (readb(i2c + PCF8584_CSR) & STATUS_BB) break; udelay(1); } @@ -245,20 +227,20 @@ static int envctrl_i2c_read_addr(unsigned char addr) envctrl_i2c_test_bb(); /* Load address. */ - envctrl_writeb(addr + 1, &i2c->data); + writeb(addr + 1, i2c + PCF8584_DATA); envctrl_i2c_test_bb(); - envctrl_writeb(OBD_SEND_START, &i2c->csr); + writeb(OBD_SEND_START, i2c + PCF8584_CSR); /* Wait for PIN. */ envtrl_i2c_test_pin(); /* CSR 0 means acknowledged. */ - if (!(envctrl_readb(&i2c->csr) & STATUS_LRB)) { - return envctrl_readb(&i2c->data); + if (!(readb(i2c + PCF8584_CSR) & STATUS_LRB)) { + return readb(i2c + PCF8584_DATA); } else { - envctrl_writeb(OBD_SEND_STOP, &i2c->csr); + writeb(OBD_SEND_STOP, i2c + PCF8584_CSR); return 0; } } @@ -269,10 +251,10 @@ static int envctrl_i2c_read_addr(unsigned char addr) static void envctrl_i2c_write_addr(unsigned char addr) { envctrl_i2c_test_bb(); - envctrl_writeb(addr, &i2c->data); + writeb(addr, i2c + PCF8584_DATA); /* Generate Start condition. */ - envctrl_writeb(OBD_SEND_START, &i2c->csr); + writeb(OBD_SEND_START, i2c + PCF8584_CSR); } /* Function Description: Read 1 byte of data from addr @@ -282,8 +264,8 @@ static void envctrl_i2c_write_addr(unsigned char addr) static unsigned char envctrl_i2c_read_data(void) { envtrl_i2c_test_pin(); - envctrl_writeb(CONTROL_ES0, &i2c->csr); /* Send neg ack. */ - return envctrl_readb(&i2c->data); + writeb(CONTROL_ES0, i2c + PCF8584_CSR); /* Send neg ack. */ + return readb(i2c + PCF8584_DATA); } /* Function Description: Instruct the device which port to read data from. @@ -292,7 +274,7 @@ static unsigned char envctrl_i2c_read_data(void) static void envctrl_i2c_write_data(unsigned char port) { envtrl_i2c_test_pin(); - envctrl_writeb(port, &i2c->data); + writeb(port, i2c + PCF8584_DATA); } /* Function Description: Generate Stop condition after last byte is sent. @@ -301,7 +283,7 @@ static void envctrl_i2c_write_data(unsigned char port) static void envctrl_i2c_stop(void) { envtrl_i2c_test_pin(); - envctrl_writeb(OBD_SEND_STOP, &i2c->csr); + writeb(OBD_SEND_STOP, i2c + PCF8584_CSR); } /* Function Description: Read adc device. @@ -323,7 +305,7 @@ static unsigned char envctrl_i2c_read_8591(unsigned char addr, unsigned char por envctrl_i2c_read_data(); envctrl_i2c_stop(); - return envctrl_readb(&i2c->data); + return readb(i2c + PCF8584_DATA); } /* Function Description: Read gpio device. @@ -1084,8 +1066,7 @@ static int __init envctrl_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "i2c")) { - i2c = ioremap( edev->resource[0].start, - sizeof(struct pcf8584_reg)); + i2c = ioremap(edev->resource[0].start, 0x2); for_each_edevchild(edev, edev_child) { if (!strcmp("gpio", edev_child->prom_name)) { i2c_childlist[i].i2ctype = I2C_GPIO; @@ -1108,15 +1089,15 @@ done: } /* Set device address. */ - envctrl_writeb(CONTROL_PIN, &i2c->csr); - envctrl_writeb(PCF8584_ADDRESS, &i2c->data); + writeb(CONTROL_PIN, i2c + PCF8584_CSR); + writeb(PCF8584_ADDRESS, i2c + PCF8584_DATA); /* Set system clock and SCL frequencies. */ - envctrl_writeb(CONTROL_PIN | CONTROL_ES1, &i2c->csr); - envctrl_writeb(CLK_4_43 | BUS_CLK_90, &i2c->data); + writeb(CONTROL_PIN | CONTROL_ES1, i2c + PCF8584_CSR); + writeb(CLK_4_43 | BUS_CLK_90, i2c + PCF8584_DATA); /* Enable serial interface. */ - envctrl_writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, &i2c->csr); + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, i2c + PCF8584_CSR); udelay(200); /* Register the device as a minor miscellaneous device. */ diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index f35cb3276..0d4295044 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -22,6 +22,7 @@ #include #include #include +#include static spinlock_t flash_lock = SPIN_LOCK_UNLOCKED; static struct { @@ -115,7 +116,7 @@ flash_read(struct file * file, char __user * buf, count = flash.read_size - p; for (i = 0; i < count; i++) { - u8 data = readb(flash.read_base + p + i); + u8 data = upa_readb(flash.read_base + p + i); if (put_user(data, buf)) return -EFAULT; buf++; diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c index c095308db..378a1d680 100644 --- a/drivers/sbus/dvma.c +++ b/drivers/sbus/dvma.c @@ -17,14 +17,6 @@ struct sbus_dma *dma_chain; -/* Print out the current values in the DMA control registers */ -extern __inline__ void dump_dma_regs(unsigned long dregs) -{ - printk("DMA CONTROL<%08x> ADDR<%08x> CNT<%08x> TEST<%08x>\n", - sbus_readl(dregs + DMA_CSR), sbus_readl(dregs + DMA_ADDR), - sbus_readl(dregs + DMA_COUNT), sbus_readl(dregs + DMA_TEST)); -} - void __init init_one_dvma(struct sbus_dma *dma, int num_dma) { printk("dma%d: ", num_dma); @@ -64,9 +56,6 @@ void __init init_one_dvma(struct sbus_dma *dma, int num_dma) break; } printk("\n"); -#if 0 /* Clutters up the screen */ - dump_dma_regs(dma->regs); -#endif } /* Probe this SBus DMA module(s) */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index b8731f204..68ca37d2d 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -551,7 +551,7 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) /* Now post the command packet */ if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n"); - tw_dev->srb[request_id] = 0; /* Flag internal command */ + tw_dev->srb[request_id] = NULL; /* Flag internal command */ tw_dev->state[request_id] = TW_S_POSTED; outl(command_que_value, command_que_addr); } else { @@ -718,7 +718,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int tw_state_request_start(tw_dev, &request_id); /* Flag internal command */ - tw_dev->srb[request_id] = 0; + tw_dev->srb[request_id] = NULL; /* Flag chrdev ioctl */ tw_dev->chrdev_request_id = request_id; @@ -2692,7 +2692,7 @@ int tw_scsi_release(struct Scsi_Host *tw_host) /* Fake like we just shut down, so notify the card that * we "shut down cleanly". */ - tw_halt(0, 0, 0); // parameters aren't actually used + tw_halt(NULL, 0, NULL); // parameters aren't actually used /* Free up the IO region */ release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index e4d60d1d1..06faeb228 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -142,11 +142,8 @@ static char *BusLogic_CommandFailureReason; static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) { - BusLogic_Announce("***** BusLogic SCSI Driver Version " - BusLogic_DriverVersion " of " - BusLogic_DriverDate " *****\n", HostAdapter); - BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " - "\n", HostAdapter); + BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " BusLogic_DriverDate " *****\n", HostAdapter); + BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " "\n", HostAdapter); } @@ -157,9 +154,8 @@ static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) static const char *BusLogic_DriverInfo(struct Scsi_Host *Host) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Host->hostdata; - return HostAdapter->FullModelName; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; + return HostAdapter->FullModelName; } @@ -170,17 +166,14 @@ static const char *BusLogic_DriverInfo(struct Scsi_Host *Host) static void __init BusLogic_RegisterHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - HostAdapter->Next = NULL; - if (BusLogic_FirstRegisteredHostAdapter == NULL) - { - BusLogic_FirstRegisteredHostAdapter = HostAdapter; - BusLogic_LastRegisteredHostAdapter = HostAdapter; - } - else - { - BusLogic_LastRegisteredHostAdapter->Next = HostAdapter; - BusLogic_LastRegisteredHostAdapter = HostAdapter; - } + HostAdapter->Next = NULL; + if (BusLogic_FirstRegisteredHostAdapter == NULL) { + BusLogic_FirstRegisteredHostAdapter = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } else { + BusLogic_LastRegisteredHostAdapter->Next = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } } @@ -191,24 +184,18 @@ static void __init BusLogic_RegisterHostAdapter(struct BusLogic_HostAdapter *Hos static void BusLogic_UnregisterHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) - { - BusLogic_FirstRegisteredHostAdapter = - BusLogic_FirstRegisteredHostAdapter->Next; - if (HostAdapter == BusLogic_LastRegisteredHostAdapter) - BusLogic_LastRegisteredHostAdapter = NULL; - } - else - { - struct BusLogic_HostAdapter *PreviousHostAdapter = - BusLogic_FirstRegisteredHostAdapter; - while (PreviousHostAdapter != NULL && - PreviousHostAdapter->Next != HostAdapter) - PreviousHostAdapter = PreviousHostAdapter->Next; - if (PreviousHostAdapter != NULL) - PreviousHostAdapter->Next = HostAdapter->Next; - } - HostAdapter->Next = NULL; + if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) { + BusLogic_FirstRegisteredHostAdapter = BusLogic_FirstRegisteredHostAdapter->Next; + if (HostAdapter == BusLogic_LastRegisteredHostAdapter) + BusLogic_LastRegisteredHostAdapter = NULL; + } else { + struct BusLogic_HostAdapter *PreviousHostAdapter = BusLogic_FirstRegisteredHostAdapter; + while (PreviousHostAdapter != NULL && PreviousHostAdapter->Next != HostAdapter) + PreviousHostAdapter = PreviousHostAdapter->Next; + if (PreviousHostAdapter != NULL) + PreviousHostAdapter->Next = HostAdapter->Next; + } + HostAdapter->Next = NULL; } @@ -218,33 +205,29 @@ static void BusLogic_UnregisterHostAdapter(struct BusLogic_HostAdapter *HostAdap created CCBs are added to Host Adapter's free list. */ -static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, - void *BlockPointer, int BlockSize, - dma_addr_t BlockPointerHandle) +static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, void *BlockPointer, int BlockSize, dma_addr_t BlockPointerHandle) { - struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) BlockPointer; - unsigned int offset = 0; - memset(BlockPointer, 0, BlockSize); - CCB->AllocationGroupHead = BlockPointerHandle; - CCB->AllocationGroupSize = BlockSize; - while ((BlockSize -= sizeof(struct BusLogic_CCB)) >= 0) - { - CCB->Status = BusLogic_CCB_Free; - CCB->HostAdapter = HostAdapter; - CCB->DMA_Handle = (u32)BlockPointerHandle + offset; - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - CCB->CallbackFunction = BusLogic_QueueCompletedCCB; - CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; + struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) BlockPointer; + unsigned int offset = 0; + memset(BlockPointer, 0, BlockSize); + CCB->AllocationGroupHead = BlockPointerHandle; + CCB->AllocationGroupSize = BlockSize; + while ((BlockSize -= sizeof(struct BusLogic_CCB)) >= 0) { + CCB->Status = BusLogic_CCB_Free; + CCB->HostAdapter = HostAdapter; + CCB->DMA_Handle = (u32) BlockPointerHandle + offset; + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + CCB->CallbackFunction = BusLogic_QueueCompletedCCB; + CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; + } + CCB->Next = HostAdapter->Free_CCBs; + CCB->NextAll = HostAdapter->All_CCBs; + HostAdapter->Free_CCBs = CCB; + HostAdapter->All_CCBs = CCB; + HostAdapter->AllocatedCCBs++; + CCB++; + offset += sizeof(struct BusLogic_CCB); } - CCB->Next = HostAdapter->Free_CCBs; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->Free_CCBs = CCB; - HostAdapter->All_CCBs = CCB; - HostAdapter->AllocatedCCBs++; - CCB++; - offset += sizeof(struct BusLogic_CCB); - } } @@ -254,23 +237,18 @@ static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, static boolean __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter) { - int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); - void *BlockPointer; - dma_addr_t BlockPointerHandle; - while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) - { - BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, - &BlockPointerHandle); - if (BlockPointer == NULL) - { - BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", - HostAdapter); - return false; + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); + void *BlockPointer; + dma_addr_t BlockPointerHandle; + while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) { + BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle); + if (BlockPointer == NULL) { + BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", HostAdapter); + return false; + } + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle); } - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, - BlockPointerHandle); - } - return true; + return true; } @@ -280,25 +258,19 @@ static boolean __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *Ho static void BusLogic_DestroyCCBs(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_CCB *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL; - HostAdapter->All_CCBs = NULL; - HostAdapter->Free_CCBs = NULL; - while ((CCB = NextCCB) != NULL) - { - NextCCB = CCB->NextAll; - if (CCB->AllocationGroupHead) - { - if (Last_CCB) - pci_free_consistent(HostAdapter->PCI_Device, - Last_CCB->AllocationGroupSize, Last_CCB, - Last_CCB->AllocationGroupHead); - Last_CCB = CCB; + struct BusLogic_CCB *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL; + HostAdapter->All_CCBs = NULL; + HostAdapter->Free_CCBs = NULL; + while ((CCB = NextCCB) != NULL) { + NextCCB = CCB->NextAll; + if (CCB->AllocationGroupHead) { + if (Last_CCB) + pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead); + Last_CCB = CCB; + } } - } - if (Last_CCB) - pci_free_consistent(HostAdapter->PCI_Device, - Last_CCB->AllocationGroupSize, Last_CCB, - Last_CCB->AllocationGroupHead); + if (Last_CCB) + pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead); } @@ -309,40 +281,30 @@ static void BusLogic_DestroyCCBs(struct BusLogic_HostAdapter *HostAdapter) multiple host adapters share the same IRQ Channel. */ -static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, - int AdditionalCCBs, - boolean SuccessMessageP) +static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, boolean SuccessMessageP) { - int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); - int PreviouslyAllocated = HostAdapter->AllocatedCCBs; - void *BlockPointer; - dma_addr_t BlockPointerHandle; - if (AdditionalCCBs <= 0) return; - while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) - { - BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, - &BlockPointerHandle); - if (BlockPointer == NULL) break; - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, - BlockPointerHandle); - } - if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) - { - if (SuccessMessageP) - BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", - HostAdapter, - HostAdapter->AllocatedCCBs - PreviouslyAllocated, - HostAdapter->AllocatedCCBs); - return; - } - BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); - if (HostAdapter->DriverQueueDepth > - HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) - { - HostAdapter->DriverQueueDepth = - HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; - HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; - } + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); + int PreviouslyAllocated = HostAdapter->AllocatedCCBs; + void *BlockPointer; + dma_addr_t BlockPointerHandle; + if (AdditionalCCBs <= 0) + return; + while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) { + BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle); + if (BlockPointer == NULL) + break; + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle); + } + if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) { + if (SuccessMessageP) + BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", HostAdapter, HostAdapter->AllocatedCCBs - PreviouslyAllocated, HostAdapter->AllocatedCCBs); + return; + } + BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); + if (HostAdapter->DriverQueueDepth > HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) { + HostAdapter->DriverQueueDepth = HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; + HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; + } } /* @@ -352,31 +314,27 @@ static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapt */ static struct BusLogic_CCB *BusLogic_AllocateCCB(struct BusLogic_HostAdapter - *HostAdapter) + *HostAdapter) { - static unsigned long SerialNumber = 0; - struct BusLogic_CCB *CCB; - CCB = HostAdapter->Free_CCBs; - if (CCB != NULL) - { - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - if (HostAdapter->Free_CCBs == NULL) - BusLogic_CreateAdditionalCCBs(HostAdapter, - HostAdapter->IncrementalCCBs, - true); - return CCB; - } - BusLogic_CreateAdditionalCCBs(HostAdapter, - HostAdapter->IncrementalCCBs, - true); - CCB = HostAdapter->Free_CCBs; - if (CCB == NULL) return NULL; - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - return CCB; + static unsigned long SerialNumber = 0; + struct BusLogic_CCB *CCB; + CCB = HostAdapter->Free_CCBs; + if (CCB != NULL) { + CCB->SerialNumber = ++SerialNumber; + HostAdapter->Free_CCBs = CCB->Next; + CCB->Next = NULL; + if (HostAdapter->Free_CCBs == NULL) + BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); + return CCB; + } + BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); + CCB = HostAdapter->Free_CCBs; + if (CCB == NULL) + return NULL; + CCB->SerialNumber = ++SerialNumber; + HostAdapter->Free_CCBs = CCB->Next; + CCB->Next = NULL; + return CCB; } @@ -388,26 +346,17 @@ static struct BusLogic_CCB *BusLogic_AllocateCCB(struct BusLogic_HostAdapter static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB) { - struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; - if (CCB->Command->use_sg != 0) - { - pci_unmap_sg(HostAdapter->PCI_Device, - (struct scatterlist *)CCB->Command->request_buffer, - CCB->Command->use_sg, - scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); - } - else if (CCB->Command->request_bufflen != 0) - { - pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer, - CCB->DataLength, - scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); - } - pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer, - CCB->SenseDataLength, PCI_DMA_FROMDEVICE); - CCB->Command = NULL; - CCB->Status = BusLogic_CCB_Free; - CCB->Next = HostAdapter->Free_CCBs; - HostAdapter->Free_CCBs = CCB; + struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; + if (CCB->Command->use_sg != 0) { + pci_unmap_sg(HostAdapter->PCI_Device, (struct scatterlist *) CCB->Command->request_buffer, CCB->Command->use_sg, scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); + } else if (CCB->Command->request_bufflen != 0) { + pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer, CCB->DataLength, scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); + } + pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE); + CCB->Command = NULL; + CCB->Status = BusLogic_CCB_Free; + CCB->Next = HostAdapter->Free_CCBs; + HostAdapter->Free_CCBs = CCB; } @@ -429,228 +378,205 @@ static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB) waiting for the Host Adapter Ready bit to be set in the Status Register. */ -static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, - enum BusLogic_OperationCode OperationCode, - void *ParameterData, - int ParameterLength, - void *ReplyData, - int ReplyLength) +static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_OperationCode OperationCode, void *ParameterData, int ParameterLength, void *ReplyData, int ReplyLength) { - unsigned char *ParameterPointer = (unsigned char *) ParameterData; - unsigned char *ReplyPointer = (unsigned char *) ReplyData; - union BusLogic_StatusRegister StatusRegister; - union BusLogic_InterruptRegister InterruptRegister; - unsigned long ProcessorFlags = 0; - int ReplyBytes = 0, Result; - long TimeoutCounter; - /* - Clear out the Reply Data if provided. - */ - if (ReplyLength > 0) - memset(ReplyData, 0, ReplyLength); - /* - If the IRQ Channel has not yet been acquired, then interrupts must be - disabled while issuing host adapter commands since a Command Complete - interrupt could occur if the IRQ Channel was previously enabled by another - BusLogic Host Adapter or another driver sharing the same IRQ Channel. - */ - if (!HostAdapter->IRQ_ChannelAcquired) - { - local_irq_save(ProcessorFlags); - local_irq_disable(); - } - /* - Wait for the Host Adapter Ready bit to be set and the Command/Parameter - Register Busy bit to be reset in the Status Register. - */ - TimeoutCounter = 10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.HostAdapterReady && - !StatusRegister.sr.CommandParameterRegisterBusy) - break; - udelay(100); - } - if (TimeoutCounter < 0) - { - BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; - Result = -2; - goto Done; - } - /* - Write the OperationCode to the Command/Parameter Register. - */ - HostAdapter->HostAdapterCommandCompleted = false; - BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); - /* - Write any additional Parameter Bytes. - */ - TimeoutCounter = 10000; - while (ParameterLength > 0 && --TimeoutCounter >= 0) - { - /* - Wait 100 microseconds to give the Host Adapter enough time to determine - whether the last value written to the Command/Parameter Register was - valid or not. If the Command Complete bit is set in the Interrupt - Register, then the Command Invalid bit in the Status Register will be - reset if the Operation Code or Parameter was valid and the command - has completed, or set if the Operation Code or Parameter was invalid. - If the Data In Register Ready bit is set in the Status Register, then - the Operation Code was valid, and data is waiting to be read back - from the Host Adapter. Otherwise, wait for the Command/Parameter - Register Busy bit in the Status Register to be reset. - */ - udelay(100); - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister.ir.CommandComplete) break; - if (HostAdapter->HostAdapterCommandCompleted) break; - if (StatusRegister.sr.DataInRegisterReady) break; - if (StatusRegister.sr.CommandParameterRegisterBusy) continue; - BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); - ParameterLength--; - } - if (TimeoutCounter < 0) - { - BusLogic_CommandFailureReason = - "Timeout waiting for Parameter Acceptance"; - Result = -2; - goto Done; - } - /* - The Modify I/O Address command does not cause a Command Complete Interrupt. - */ - if (OperationCode == BusLogic_ModifyIOAddress) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.CommandInvalid) - { - BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; - Result = -1; - goto Done; + unsigned char *ParameterPointer = (unsigned char *) ParameterData; + unsigned char *ReplyPointer = (unsigned char *) ReplyData; + union BusLogic_StatusRegister StatusRegister; + union BusLogic_InterruptRegister InterruptRegister; + unsigned long ProcessorFlags = 0; + int ReplyBytes = 0, Result; + long TimeoutCounter; + /* + Clear out the Reply Data if provided. + */ + if (ReplyLength > 0) + memset(ReplyData, 0, ReplyLength); + /* + If the IRQ Channel has not yet been acquired, then interrupts must be + disabled while issuing host adapter commands since a Command Complete + interrupt could occur if the IRQ Channel was previously enabled by another + BusLogic Host Adapter or another driver sharing the same IRQ Channel. + */ + if (!HostAdapter->IRQ_ChannelAcquired) { + local_irq_save(ProcessorFlags); + local_irq_disable(); + } + /* + Wait for the Host Adapter Ready bit to be set and the Command/Parameter + Register Busy bit to be reset in the Status Register. + */ + TimeoutCounter = 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.HostAdapterReady && !StatusRegister.sr.CommandParameterRegisterBusy) + break; + udelay(100); + } + if (TimeoutCounter < 0) { + BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; + Result = -2; + goto Done; + } + /* + Write the OperationCode to the Command/Parameter Register. + */ + HostAdapter->HostAdapterCommandCompleted = false; + BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); + /* + Write any additional Parameter Bytes. + */ + TimeoutCounter = 10000; + while (ParameterLength > 0 && --TimeoutCounter >= 0) { + /* + Wait 100 microseconds to give the Host Adapter enough time to determine + whether the last value written to the Command/Parameter Register was + valid or not. If the Command Complete bit is set in the Interrupt + Register, then the Command Invalid bit in the Status Register will be + reset if the Operation Code or Parameter was valid and the command + has completed, or set if the Operation Code or Parameter was invalid. + If the Data In Register Ready bit is set in the Status Register, then + the Operation Code was valid, and data is waiting to be read back + from the Host Adapter. Otherwise, wait for the Command/Parameter + Register Busy bit in the Status Register to be reset. + */ + udelay(100); + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (InterruptRegister.ir.CommandComplete) + break; + if (HostAdapter->HostAdapterCommandCompleted) + break; + if (StatusRegister.sr.DataInRegisterReady) + break; + if (StatusRegister.sr.CommandParameterRegisterBusy) + continue; + BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); + ParameterLength--; } - if (BusLogic_GlobalOptions.TraceConfiguration) - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " - "(Modify I/O Address)\n", HostAdapter, - OperationCode, StatusRegister.All); - Result = 0; - goto Done; - } - /* - Select an appropriate timeout value for awaiting command completion. - */ - switch (OperationCode) - { - case BusLogic_InquireInstalledDevicesID0to7: - case BusLogic_InquireInstalledDevicesID8to15: - case BusLogic_InquireTargetDevices: - /* Approximately 60 seconds. */ - TimeoutCounter = 60*10000; - break; - default: - /* Approximately 1 second. */ - TimeoutCounter = 10000; - break; - } - /* - Receive any Reply Bytes, waiting for either the Command Complete bit to - be set in the Interrupt Register, or for the Interrupt Handler to set the - Host Adapter Command Completed bit in the Host Adapter structure. - */ - while (--TimeoutCounter >= 0) - { - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister.ir.CommandComplete) break; - if (HostAdapter->HostAdapterCommandCompleted) break; - if (StatusRegister.sr.DataInRegisterReady) - { - if (++ReplyBytes <= ReplyLength) - *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); - else BusLogic_ReadDataInRegister(HostAdapter); + if (TimeoutCounter < 0) { + BusLogic_CommandFailureReason = "Timeout waiting for Parameter Acceptance"; + Result = -2; + goto Done; } - if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && - StatusRegister.sr.HostAdapterReady) break; - udelay(100); - } - if (TimeoutCounter < 0) - { - BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; - Result = -2; - goto Done; - } - /* - Clear any pending Command Complete Interrupt. - */ - BusLogic_InterruptReset(HostAdapter); - /* - Provide tracing information if requested. - */ - if (BusLogic_GlobalOptions.TraceConfiguration) - { - int i; - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", - HostAdapter, OperationCode, - StatusRegister.All, ReplyLength, ReplyBytes); - if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; - for (i = 0; i < ReplyLength; i++) - BusLogic_Notice(" %02X", HostAdapter, - ((unsigned char *) ReplyData)[i]); - BusLogic_Notice("\n", HostAdapter); - } - /* - Process Command Invalid conditions. - */ - if (StatusRegister.sr.CommandInvalid) - { - /* - Some early BusLogic Host Adapters may not recover properly from - a Command Invalid condition, so if this appears to be the case, - a Soft Reset is issued to the Host Adapter. Potentially invalid - commands are never attempted after Mailbox Initialization is - performed, so there should be no Host Adapter state lost by a - Soft Reset in response to a Command Invalid condition. - */ - udelay(1000); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.CommandInvalid || - StatusRegister.sr.Reserved || - StatusRegister.sr.DataInRegisterReady || - StatusRegister.sr.CommandParameterRegisterBusy || - !StatusRegister.sr.HostAdapterReady || - !StatusRegister.sr.InitializationRequired || - StatusRegister.sr.DiagnosticActive || - StatusRegister.sr.DiagnosticFailure) - { - BusLogic_SoftReset(HostAdapter); - udelay(1000); + /* + The Modify I/O Address command does not cause a Command Complete Interrupt. + */ + if (OperationCode == BusLogic_ModifyIOAddress) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.CommandInvalid) { + BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; + Result = -1; + goto Done; + } + if (BusLogic_GlobalOptions.TraceConfiguration) + BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All); + Result = 0; + goto Done; + } + /* + Select an appropriate timeout value for awaiting command completion. + */ + switch (OperationCode) { + case BusLogic_InquireInstalledDevicesID0to7: + case BusLogic_InquireInstalledDevicesID8to15: + case BusLogic_InquireTargetDevices: + /* Approximately 60 seconds. */ + TimeoutCounter = 60 * 10000; + break; + default: + /* Approximately 1 second. */ + TimeoutCounter = 10000; + break; } - BusLogic_CommandFailureReason = "Command Invalid"; - Result = -1; - goto Done; - } - /* - Handle Excess Parameters Supplied conditions. - */ - if (ParameterLength > 0) - { - BusLogic_CommandFailureReason = "Excess Parameters Supplied"; - Result = -1; - goto Done; - } - /* - Indicate the command completed successfully. - */ - BusLogic_CommandFailureReason = NULL; - Result = ReplyBytes; - /* - Restore the interrupt status if necessary and return. - */ -Done: - if (!HostAdapter->IRQ_ChannelAcquired) - local_irq_restore(ProcessorFlags); - return Result; + /* + Receive any Reply Bytes, waiting for either the Command Complete bit to + be set in the Interrupt Register, or for the Interrupt Handler to set the + Host Adapter Command Completed bit in the Host Adapter structure. + */ + while (--TimeoutCounter >= 0) { + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (InterruptRegister.ir.CommandComplete) + break; + if (HostAdapter->HostAdapterCommandCompleted) + break; + if (StatusRegister.sr.DataInRegisterReady) { + if (++ReplyBytes <= ReplyLength) + *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); + else + BusLogic_ReadDataInRegister(HostAdapter); + } + if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.sr.HostAdapterReady) + break; + udelay(100); + } + if (TimeoutCounter < 0) { + BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; + Result = -2; + goto Done; + } + /* + Clear any pending Command Complete Interrupt. + */ + BusLogic_InterruptReset(HostAdapter); + /* + Provide tracing information if requested. + */ + if (BusLogic_GlobalOptions.TraceConfiguration) { + int i; + BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", HostAdapter, OperationCode, StatusRegister.All, ReplyLength, ReplyBytes); + if (ReplyLength > ReplyBytes) + ReplyLength = ReplyBytes; + for (i = 0; i < ReplyLength; i++) + BusLogic_Notice(" %02X", HostAdapter, ((unsigned char *) ReplyData)[i]); + BusLogic_Notice("\n", HostAdapter); + } + /* + Process Command Invalid conditions. + */ + if (StatusRegister.sr.CommandInvalid) { + /* + Some early BusLogic Host Adapters may not recover properly from + a Command Invalid condition, so if this appears to be the case, + a Soft Reset is issued to the Host Adapter. Potentially invalid + commands are never attempted after Mailbox Initialization is + performed, so there should be no Host Adapter state lost by a + Soft Reset in response to a Command Invalid condition. + */ + udelay(1000); + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.CommandInvalid || + StatusRegister.sr.Reserved || + StatusRegister.sr.DataInRegisterReady || + StatusRegister.sr.CommandParameterRegisterBusy || !StatusRegister.sr.HostAdapterReady || !StatusRegister.sr.InitializationRequired || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.DiagnosticFailure) { + BusLogic_SoftReset(HostAdapter); + udelay(1000); + } + BusLogic_CommandFailureReason = "Command Invalid"; + Result = -1; + goto Done; + } + /* + Handle Excess Parameters Supplied conditions. + */ + if (ParameterLength > 0) { + BusLogic_CommandFailureReason = "Excess Parameters Supplied"; + Result = -1; + goto Done; + } + /* + Indicate the command completed successfully. + */ + BusLogic_CommandFailureReason = NULL; + Result = ReplyBytes; + /* + Restore the interrupt status if necessary and return. + */ + Done: + if (!HostAdapter->IRQ_ChannelAcquired) + local_irq_restore(ProcessorFlags); + return Result; } @@ -662,13 +588,14 @@ Done: static void __init BusLogic_AppendProbeAddressISA(unsigned long IO_Address) { - struct BusLogic_ProbeInfo *ProbeInfo; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return; - ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Device = NULL; + struct BusLogic_ProbeInfo *ProbeInfo; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) + return; + ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_MultiMaster; + ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Device = NULL; } @@ -681,38 +608,27 @@ static void __init BusLogic_AppendProbeAddressISA(unsigned long IO_Address) static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - /* - If BusLogic Driver Options specifications requested that ISA Bus Probes - be inhibited, do not proceed further. - */ - if (BusLogic_ProbeOptions.NoProbeISA) return; - /* - Append the list of standard BusLogic MultiMaster ISA I/O Addresses. - */ - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe330 - : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x330); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe334 - : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x334); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe230 - : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x230); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe234 - : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x234); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe130 - : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x130); - if (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe134 - : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) - BusLogic_AppendProbeAddressISA(0x134); + /* + If BusLogic Driver Options specifications requested that ISA Bus Probes + be inhibited, do not proceed further. + */ + if (BusLogic_ProbeOptions.NoProbeISA) + return; + /* + Append the list of standard BusLogic MultiMaster ISA I/O Addresses. + */ + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x330); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x334); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x230); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x234); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x130); + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x134); } @@ -724,30 +640,24 @@ static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapt of increasing PCI Bus and Device Number. */ -static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, - int ProbeInfoCount) +static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, int ProbeInfoCount) { - int LastInterchange = ProbeInfoCount-1, Bound, j; - while (LastInterchange > 0) - { - Bound = LastInterchange; - LastInterchange = 0; - for (j = 0; j < Bound; j++) - { - struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j]; - struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j+1]; - if (ProbeInfo1->Bus > ProbeInfo2->Bus || - (ProbeInfo1->Bus == ProbeInfo2->Bus && - (ProbeInfo1->Device > ProbeInfo2->Device))) - { - struct BusLogic_ProbeInfo TempProbeInfo; - memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo)); - memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo)); - memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo)); - LastInterchange = j; - } + int LastInterchange = ProbeInfoCount - 1, Bound, j; + while (LastInterchange > 0) { + Bound = LastInterchange; + LastInterchange = 0; + for (j = 0; j < Bound; j++) { + struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j]; + struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j + 1]; + if (ProbeInfo1->Bus > ProbeInfo2->Bus || (ProbeInfo1->Bus == ProbeInfo2->Bus && (ProbeInfo1->Device > ProbeInfo2->Device))) { + struct BusLogic_ProbeInfo TempProbeInfo; + memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo)); + memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo)); + memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo)); + LastInterchange = j; + } + } } - } } @@ -762,292 +672,226 @@ static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoLi static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - struct BusLogic_ProbeInfo *PrimaryProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; - int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; - int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; - boolean ForceBusDeviceScanningOrder = false; - boolean ForceBusDeviceScanningOrderChecked = false; - boolean StandardAddressSeen[6]; - struct pci_dev *PCI_Device = NULL; - int i; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0; - BusLogic_ProbeInfoCount++; - for (i = 0; i < 6; i++) - StandardAddressSeen[i] = false; - /* - Iterate over the MultiMaster PCI Host Adapters. For each enumerated host - adapter, determine whether its ISA Compatible I/O Port is enabled and if - so, whether it is assigned the Primary I/O Address. A host adapter that is - assigned the Primary I/O Address will always be the preferred boot device. - The MultiMaster BIOS will first recognize a host adapter at the Primary I/O - Address, then any other PCI host adapters, and finally any host adapters - located at the remaining standard ISA I/O Addresses. When a PCI host - adapter is found with its ISA Compatible I/O Port enabled, a command is - issued to disable the ISA Compatible I/O Port, and it is noted that the - particular standard ISA I/O Address need not be probed. - */ - PrimaryProbeInfo->IO_Address = 0; - while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, - PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, - PCI_Device)) != NULL) - { - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; - enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest; - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long BaseAddress0; - unsigned long BaseAddress1; - unsigned long IO_Address; - unsigned long PCI_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); - PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); - - if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) - { - BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " - "MultiMaster Host Adapter\n", NULL, BaseAddress0); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (pci_resource_flags(PCI_Device,1) & IORESOURCE_IO) - { - BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " - "MultiMaster Host Adapter\n", NULL, BaseAddress1); - BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", - NULL, Bus, Device, PCI_Address); - continue; - } - if (IRQ_Channel == 0) - { - BusLogic_Error("BusLogic: IRQ Channel %d invalid for " - "MultiMaster Host Adapter\n", NULL, IRQ_Channel); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (BusLogic_GlobalOptions.TraceProbe) - { - BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " - "detected at\n", NULL); - BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " - "0x%X PCI Address 0x%X\n", NULL, - Bus, Device, IO_Address, PCI_Address); - } - /* - Issue the Inquire PCI Host Adapter Information command to determine - the ISA Compatible I/O Port. If the ISA Compatible I/O Port is - known and enabled, note that the particular Standard ISA I/O - Address should not be probed. - */ - HostAdapter->IO_Address = IO_Address; - BusLogic_InterruptReset(HostAdapter); - if (BusLogic_Command(HostAdapter, - BusLogic_InquirePCIHostAdapterInformation, - NULL, 0, &PCIHostAdapterInformation, - sizeof(PCIHostAdapterInformation)) - == sizeof(PCIHostAdapterInformation)) - { - if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) - StandardAddressSeen[PCIHostAdapterInformation - .ISACompatibleIOPort] = true; - } - else PCIHostAdapterInformation.ISACompatibleIOPort = - BusLogic_IO_Disable; - /* - * Issue the Modify I/O Address command to disable the ISA Compatible - * I/O Port. On PCI Host Adapters, the Modify I/O Address command - * allows modification of the ISA compatible I/O Address that the Host - * Adapter responds to; it does not affect the PCI compliant I/O Address - * assigned at system initialization. - */ - ModifyIOAddressRequest = BusLogic_IO_Disable; - BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, - &ModifyIOAddressRequest, - sizeof(ModifyIOAddressRequest), NULL, 0); - /* - For the first MultiMaster Host Adapter enumerated, issue the Fetch - Host Adapter Local RAM command to read byte 45 of the AutoSCSI area, - for the setting of the "Use Bus And Device # For PCI Scanning Seq." - option. Issue the Inquire Board ID command since this option is - only valid for the BT-948/958/958D. - */ - if (!ForceBusDeviceScanningOrderChecked) - { - struct BusLogic_FetchHostAdapterLocalRAMRequest - FetchHostAdapterLocalRAMRequest; - struct BusLogic_AutoSCSIByte45 AutoSCSIByte45; - struct BusLogic_BoardID BoardID; - FetchHostAdapterLocalRAMRequest.ByteOffset = - BusLogic_AutoSCSI_BaseOffset + 45; - FetchHostAdapterLocalRAMRequest.ByteCount = - sizeof(AutoSCSIByte45); - BusLogic_Command(HostAdapter, - BusLogic_FetchHostAdapterLocalRAM, - &FetchHostAdapterLocalRAMRequest, - sizeof(FetchHostAdapterLocalRAMRequest), - &AutoSCSIByte45, sizeof(AutoSCSIByte45)); - BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, - NULL, 0, &BoardID, sizeof(BoardID)); - if (BoardID.FirmwareVersion1stDigit == '5') - ForceBusDeviceScanningOrder = - AutoSCSIByte45.ForceBusDeviceScanningOrder; - ForceBusDeviceScanningOrderChecked = true; - } - /* - Determine whether this MultiMaster Host Adapter has its ISA - Compatible I/O Port enabled and is assigned the Primary I/O Address. - If it does, then it is the Primary MultiMaster Host Adapter and must - be recognized first. If it does not, then it is added to the list - for probing after any Primary MultiMaster Host Adapter is probed. - */ - if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) - { - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - PrimaryProbeInfo->IO_Address = IO_Address; - PrimaryProbeInfo->PCI_Address = PCI_Address; - PrimaryProbeInfo->Bus = Bus; - PrimaryProbeInfo->Device = Device; - PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; - PrimaryProbeInfo->PCI_Device = PCI_Device; - PCIMultiMasterCount++; + struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; + int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; + int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; + boolean ForceBusDeviceScanningOrder = false; + boolean ForceBusDeviceScanningOrderChecked = false; + boolean StandardAddressSeen[6]; + struct pci_dev *PCI_Device = NULL; + int i; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) + return 0; + BusLogic_ProbeInfoCount++; + for (i = 0; i < 6; i++) + StandardAddressSeen[i] = false; + /* + Iterate over the MultiMaster PCI Host Adapters. For each enumerated host + adapter, determine whether its ISA Compatible I/O Port is enabled and if + so, whether it is assigned the Primary I/O Address. A host adapter that is + assigned the Primary I/O Address will always be the preferred boot device. + The MultiMaster BIOS will first recognize a host adapter at the Primary I/O + Address, then any other PCI host adapters, and finally any host adapters + located at the remaining standard ISA I/O Addresses. When a PCI host + adapter is found with its ISA Compatible I/O Port enabled, a command is + issued to disable the ISA Compatible I/O Port, and it is noted that the + particular standard ISA I/O Address need not be probed. + */ + PrimaryProbeInfo->IO_Address = 0; + while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) { + struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; + struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; + enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest; + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + unsigned long IO_Address; + unsigned long PCI_Address; + + if (pci_enable_device(PCI_Device)) + continue; + + if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); + + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { + BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, BaseAddress0); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { + BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, BaseAddress1); + BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address); + continue; + } + if (IRQ_Channel == 0) { + BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, IRQ_Channel); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (BusLogic_GlobalOptions.TraceProbe) { + BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL); + BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address); + } + /* + Issue the Inquire PCI Host Adapter Information command to determine + the ISA Compatible I/O Port. If the ISA Compatible I/O Port is + known and enabled, note that the particular Standard ISA I/O + Address should not be probed. + */ + HostAdapter->IO_Address = IO_Address; + BusLogic_InterruptReset(HostAdapter); + if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation)) + == sizeof(PCIHostAdapterInformation)) { + if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) + StandardAddressSeen[PCIHostAdapterInformation.ISACompatibleIOPort] = true; + } else + PCIHostAdapterInformation.ISACompatibleIOPort = BusLogic_IO_Disable; + /* + * Issue the Modify I/O Address command to disable the ISA Compatible + * I/O Port. On PCI Host Adapters, the Modify I/O Address command + * allows modification of the ISA compatible I/O Address that the Host + * Adapter responds to; it does not affect the PCI compliant I/O Address + * assigned at system initialization. + */ + ModifyIOAddressRequest = BusLogic_IO_Disable; + BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, &ModifyIOAddressRequest, sizeof(ModifyIOAddressRequest), NULL, 0); + /* + For the first MultiMaster Host Adapter enumerated, issue the Fetch + Host Adapter Local RAM command to read byte 45 of the AutoSCSI area, + for the setting of the "Use Bus And Device # For PCI Scanning Seq." + option. Issue the Inquire Board ID command since this option is + only valid for the BT-948/958/958D. + */ + if (!ForceBusDeviceScanningOrderChecked) { + struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; + struct BusLogic_AutoSCSIByte45 AutoSCSIByte45; + struct BusLogic_BoardID BoardID; + FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset + 45; + FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte45); + BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIByte45, sizeof(AutoSCSIByte45)); + BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)); + if (BoardID.FirmwareVersion1stDigit == '5') + ForceBusDeviceScanningOrder = AutoSCSIByte45.ForceBusDeviceScanningOrder; + ForceBusDeviceScanningOrderChecked = true; + } + /* + Determine whether this MultiMaster Host Adapter has its ISA + Compatible I/O Port enabled and is assigned the Primary I/O Address. + If it does, then it is the Primary MultiMaster Host Adapter and must + be recognized first. If it does not, then it is added to the list + for probing after any Primary MultiMaster Host Adapter is probed. + */ + if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) { + PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; + PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + PrimaryProbeInfo->IO_Address = IO_Address; + PrimaryProbeInfo->PCI_Address = PCI_Address; + PrimaryProbeInfo->Bus = Bus; + PrimaryProbeInfo->Device = Device; + PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; + PrimaryProbeInfo->PCI_Device = PCI_Device; + PCIMultiMasterCount++; + } else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_MultiMaster; + ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; + ProbeInfo->Bus = Bus; + ProbeInfo->Device = Device; + ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; + NonPrimaryPCIMultiMasterCount++; + PCIMultiMasterCount++; + } else + BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL); } - else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) - { - struct BusLogic_ProbeInfo *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = PCI_Device; - NonPrimaryPCIMultiMasterCount++; - PCIMultiMasterCount++; + /* + If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON + for the first enumerated MultiMaster Host Adapter, and if that host adapter + is a BT-948/958/958D, then the MultiMaster BIOS will recognize MultiMaster + Host Adapters in the order of increasing PCI Bus and Device Number. In + that case, sort the probe information into the same order the BIOS uses. + If this option is OFF, then the MultiMaster BIOS will recognize MultiMaster + Host Adapters in the order they are enumerated by the PCI BIOS, and hence + no sorting is necessary. + */ + if (ForceBusDeviceScanningOrder) + BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[NonPrimaryPCIMultiMasterIndex], NonPrimaryPCIMultiMasterCount); + /* + If no PCI MultiMaster Host Adapter is assigned the Primary I/O Address, + then the Primary I/O Address must be probed explicitly before any PCI + host adapters are probed. + */ + if (!BusLogic_ProbeOptions.NoProbeISA) + if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) { + PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; + PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + PrimaryProbeInfo->IO_Address = 0x330; + } + /* + Append the list of standard BusLogic MultiMaster ISA I/O Addresses, + omitting the Primary I/O Address which has already been handled. + */ + if (!BusLogic_ProbeOptions.NoProbeISA) { + if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x334); + if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x230); + if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x234); + if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x130); + if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x134); } - else BusLogic_Warning("BusLogic: Too many Host Adapters " - "detected\n", NULL); - } - /* - If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON - for the first enumerated MultiMaster Host Adapter, and if that host adapter - is a BT-948/958/958D, then the MultiMaster BIOS will recognize MultiMaster - Host Adapters in the order of increasing PCI Bus and Device Number. In - that case, sort the probe information into the same order the BIOS uses. - If this option is OFF, then the MultiMaster BIOS will recognize MultiMaster - Host Adapters in the order they are enumerated by the PCI BIOS, and hence - no sorting is necessary. - */ - if (ForceBusDeviceScanningOrder) - BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[ - NonPrimaryPCIMultiMasterIndex], - NonPrimaryPCIMultiMasterCount); - /* - If no PCI MultiMaster Host Adapter is assigned the Primary I/O Address, - then the Primary I/O Address must be probed explicitly before any PCI - host adapters are probed. - */ - if (!BusLogic_ProbeOptions.NoProbeISA) - if (PrimaryProbeInfo->IO_Address == 0 && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe330 - : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) - { - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - PrimaryProbeInfo->IO_Address = 0x330; - } - /* - Append the list of standard BusLogic MultiMaster ISA I/O Addresses, - omitting the Primary I/O Address which has already been handled. - */ - if (!BusLogic_ProbeOptions.NoProbeISA) - { - if (!StandardAddressSeen[1] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe334 - : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x334); - if (!StandardAddressSeen[2] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe230 - : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x230); - if (!StandardAddressSeen[3] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe234 - : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x234); - if (!StandardAddressSeen[4] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe130 - : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x130); - if (!StandardAddressSeen[5] && - (BusLogic_ProbeOptions.LimitedProbeISA - ? BusLogic_ProbeOptions.Probe134 - : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) - BusLogic_AppendProbeAddressISA(0x134); - } - /* - Iterate over the older non-compliant MultiMaster PCI Host Adapters, - noting the PCI bus location and assigned IRQ Channel. - */ - PCI_Device = NULL; - while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, - PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, - PCI_Device)) != NULL) - { - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long IO_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = pci_resource_start(PCI_Device, 0); - - if (IO_Address == 0 || IRQ_Channel == 0) continue; - for (i = 0; i < BusLogic_ProbeInfoCount; i++) - { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[i]; - if (ProbeInfo->IO_Address == IO_Address && - ProbeInfo->HostAdapterType == BusLogic_MultiMaster) - { - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->PCI_Address = 0; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = PCI_Device; - break; - } + /* + Iterate over the older non-compliant MultiMaster PCI Host Adapters, + noting the PCI bus location and assigned IRQ Channel. + */ + PCI_Device = NULL; + while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) { + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long IO_Address; + + if (pci_enable_device(PCI_Device)) + continue; + + if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = pci_resource_start(PCI_Device, 0); + + if (IO_Address == 0 || IRQ_Channel == 0) + continue; + for (i = 0; i < BusLogic_ProbeInfoCount; i++) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[i]; + if (ProbeInfo->IO_Address == IO_Address && ProbeInfo->HostAdapterType == BusLogic_MultiMaster) { + ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->PCI_Address = 0; + ProbeInfo->Bus = Bus; + ProbeInfo->Device = Device; + ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; + break; + } + } } - } - return PCIMultiMasterCount; + return PCIMultiMasterCount; } @@ -1061,100 +905,77 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; - struct pci_dev *PCI_Device = NULL; - /* - Interrogate PCI Configuration Space for any FlashPoint Host Adapters. - */ - while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, - PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, - PCI_Device)) != NULL) - { - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long BaseAddress0; - unsigned long BaseAddress1; - unsigned long IO_Address; - unsigned long PCI_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); - PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); + int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; + struct pci_dev *PCI_Device = NULL; + /* + Interrogate PCI Configuration Space for any FlashPoint Host Adapters. + */ + while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) { + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + unsigned long IO_Address; + unsigned long PCI_Address; + + if (pci_enable_device(PCI_Device)) + continue; + + if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); #ifndef CONFIG_SCSI_OMIT_FLASHPOINT - if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) - { - BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " - "FlashPoint Host Adapter\n", NULL, BaseAddress0); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) - { - BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " - "FlashPoint Host Adapter\n", NULL, BaseAddress1); - BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", - NULL, Bus, Device, PCI_Address); - continue; - } - if (IRQ_Channel == 0) - { - BusLogic_Error("BusLogic: IRQ Channel %d invalid for " - "FlashPoint Host Adapter\n", NULL, IRQ_Channel); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", - NULL, Bus, Device, IO_Address); - continue; - } - if (BusLogic_GlobalOptions.TraceProbe) - { - BusLogic_Notice("BusLogic: FlashPoint Host Adapter " - "detected at\n", NULL); - BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " - "0x%X PCI Address 0x%X\n", NULL, - Bus, Device, IO_Address, PCI_Address); - } - if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) - { - struct BusLogic_ProbeInfo *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_FlashPoint; - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = PCI_Device; - FlashPointCount++; - } - else BusLogic_Warning("BusLogic: Too many Host Adapters " - "detected\n", NULL); + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { + BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, BaseAddress0); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { + BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, BaseAddress1); + BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address); + continue; + } + if (IRQ_Channel == 0) { + BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, IRQ_Channel); + BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); + continue; + } + if (BusLogic_GlobalOptions.TraceProbe) { + BusLogic_Notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL); + BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address); + } + if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_FlashPoint; + ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; + ProbeInfo->Bus = Bus; + ProbeInfo->Device = Device; + ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; + FlashPointCount++; + } else + BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL); #else - BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " - "PCI Bus %d Device %d\n", NULL, Bus, Device); - BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " - "but FlashPoint\n", NULL, IO_Address, PCI_Address, IRQ_Channel); - BusLogic_Error("BusLogic: support was omitted in this kernel " - "configuration.\n", NULL); + BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, Bus, Device); + BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " "but FlashPoint\n", NULL, IO_Address, PCI_Address, IRQ_Channel); + BusLogic_Error("BusLogic: support was omitted in this kernel " "configuration.\n", NULL); #endif - } - /* - The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of - increasing PCI Bus and Device Number, so sort the probe information into - the same order the BIOS uses. - */ - BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[FlashPointIndex], - FlashPointCount); - return FlashPointCount; + } + /* + The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of + increasing PCI Bus and Device Number, so sort the probe information into + the same order the BIOS uses. + */ + BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[FlashPointIndex], FlashPointCount); + return FlashPointCount; } @@ -1174,106 +995,70 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAda static void __init BusLogic_InitializeProbeInfoList(struct BusLogic_HostAdapter *PrototypeHostAdapter) { - /* - If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint - Host Adapters; otherwise, default to the standard ISA MultiMaster probe. - */ - if (!BusLogic_ProbeOptions.NoProbePCI) - { - if (BusLogic_ProbeOptions.MultiMasterFirst) - { - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - } - else if (BusLogic_ProbeOptions.FlashPointFirst) - { - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - } - else - { - int FlashPointCount = - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - int PCIMultiMasterCount = - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - if (FlashPointCount > 0 && PCIMultiMasterCount > 0) - { - struct BusLogic_ProbeInfo *ProbeInfo = - &BusLogic_ProbeInfoList[FlashPointCount]; - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct BusLogic_FetchHostAdapterLocalRAMRequest - FetchHostAdapterLocalRAMRequest; - struct BusLogic_BIOSDriveMapByte Drive0MapByte; - while (ProbeInfo->HostAdapterBusType != BusLogic_PCI_Bus) - ProbeInfo++; - HostAdapter->IO_Address = ProbeInfo->IO_Address; - FetchHostAdapterLocalRAMRequest.ByteOffset = - BusLogic_BIOS_BaseOffset + BusLogic_BIOS_DriveMapOffset + 0; - FetchHostAdapterLocalRAMRequest.ByteCount = - sizeof(Drive0MapByte); - BusLogic_Command(HostAdapter, - BusLogic_FetchHostAdapterLocalRAM, - &FetchHostAdapterLocalRAMRequest, - sizeof(FetchHostAdapterLocalRAMRequest), - &Drive0MapByte, sizeof(Drive0MapByte)); - /* - If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0 - is controlled by this PCI MultiMaster Host Adapter, then - reverse the probe order so that MultiMaster Host Adapters are - probed before FlashPoint Host Adapters. - */ - if (Drive0MapByte.DiskGeometry != - BusLogic_BIOS_Disk_Not_Installed) - { - struct BusLogic_ProbeInfo - SavedProbeInfo[BusLogic_MaxHostAdapters]; - int MultiMasterCount = - BusLogic_ProbeInfoCount - FlashPointCount; - memcpy(SavedProbeInfo, - BusLogic_ProbeInfoList, - BusLogic_ProbeInfoCount - * sizeof(struct BusLogic_ProbeInfo)); - memcpy(&BusLogic_ProbeInfoList[0], - &SavedProbeInfo[FlashPointCount], - MultiMasterCount * sizeof(struct BusLogic_ProbeInfo)); - memcpy(&BusLogic_ProbeInfoList[MultiMasterCount], - &SavedProbeInfo[0], - FlashPointCount * sizeof(struct BusLogic_ProbeInfo)); + /* + If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint + Host Adapters; otherwise, default to the standard ISA MultiMaster probe. + */ + if (!BusLogic_ProbeOptions.NoProbePCI) { + if (BusLogic_ProbeOptions.MultiMasterFirst) { + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + } else if (BusLogic_ProbeOptions.FlashPointFirst) { + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + } else { + int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + if (FlashPointCount > 0 && PCIMultiMasterCount > 0) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[FlashPointCount]; + struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; + struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; + struct BusLogic_BIOSDriveMapByte Drive0MapByte; + while (ProbeInfo->HostAdapterBusType != BusLogic_PCI_Bus) + ProbeInfo++; + HostAdapter->IO_Address = ProbeInfo->IO_Address; + FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_BIOS_BaseOffset + BusLogic_BIOS_DriveMapOffset + 0; + FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(Drive0MapByte); + BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &Drive0MapByte, sizeof(Drive0MapByte)); + /* + If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0 + is controlled by this PCI MultiMaster Host Adapter, then + reverse the probe order so that MultiMaster Host Adapters are + probed before FlashPoint Host Adapters. + */ + if (Drive0MapByte.DiskGeometry != BusLogic_BIOS_Disk_Not_Installed) { + struct BusLogic_ProbeInfo SavedProbeInfo[BusLogic_MaxHostAdapters]; + int MultiMasterCount = BusLogic_ProbeInfoCount - FlashPointCount; + memcpy(SavedProbeInfo, BusLogic_ProbeInfoList, BusLogic_ProbeInfoCount * sizeof(struct BusLogic_ProbeInfo)); + memcpy(&BusLogic_ProbeInfoList[0], &SavedProbeInfo[FlashPointCount], MultiMasterCount * sizeof(struct BusLogic_ProbeInfo)); + memcpy(&BusLogic_ProbeInfoList[MultiMasterCount], &SavedProbeInfo[0], FlashPointCount * sizeof(struct BusLogic_ProbeInfo)); + } + } } - } - } - } - else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); + } else + BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); } -#endif /* CONFIG_PCI */ +#endif /* CONFIG_PCI */ /* BusLogic_Failure prints a standardized error message, and then returns false. */ -static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, - char *ErrorMessage) +static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage) { - BusLogic_AnnounceDriver(HostAdapter); - if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) - { - BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", - HostAdapter); - BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", - HostAdapter, HostAdapter->Bus, HostAdapter->Device, - HostAdapter->IO_Address, HostAdapter->PCI_Address); - } - else BusLogic_Error("While configuring BusLogic Host Adapter at " - "I/O Address 0x%X:\n", HostAdapter, - HostAdapter->IO_Address); - BusLogic_Error("%s FAILED - DETACHING\n", HostAdapter, ErrorMessage); - if (BusLogic_CommandFailureReason != NULL) - BusLogic_Error("ADDITIONAL FAILURE INFO - %s\n", HostAdapter, - BusLogic_CommandFailureReason); - return false; + BusLogic_AnnounceDriver(HostAdapter); + if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) { + BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", HostAdapter); + BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device, HostAdapter->IO_Address, HostAdapter->PCI_Address); + } else + BusLogic_Error("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", HostAdapter, HostAdapter->IO_Address); + BusLogic_Error("%s FAILED - DETACHING\n", HostAdapter, ErrorMessage); + if (BusLogic_CommandFailureReason != NULL) + BusLogic_Error("ADDITIONAL FAILURE INFO - %s\n", HostAdapter, BusLogic_CommandFailureReason); + return false; } @@ -1283,81 +1068,64 @@ static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_StatusRegister StatusRegister; - union BusLogic_InterruptRegister InterruptRegister; - union BusLogic_GeometryRegister GeometryRegister; - /* - FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - FlashPointInfo->BaseAddress = - (u32) HostAdapter->IO_Address; - FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; - FlashPointInfo->Present = false; - if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && - FlashPointInfo->Present)) - { - BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " - "PCI Bus %d Device %d\n", HostAdapter, - HostAdapter->Bus, HostAdapter->Device); - BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, " - "but FlashPoint\n", HostAdapter, - HostAdapter->IO_Address, HostAdapter->PCI_Address); - BusLogic_Error("BusLogic: Probe Function failed to validate it.\n", - HostAdapter); - return false; + union BusLogic_StatusRegister StatusRegister; + union BusLogic_InterruptRegister InterruptRegister; + union BusLogic_GeometryRegister GeometryRegister; + /* + FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->BaseAddress = (u32) HostAdapter->IO_Address; + FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; + FlashPointInfo->Present = false; + if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && FlashPointInfo->Present)) { + BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device); + BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, " "but FlashPoint\n", HostAdapter, HostAdapter->IO_Address, HostAdapter->PCI_Address); + BusLogic_Error("BusLogic: Probe Function failed to validate it.\n", HostAdapter); + return false; + } + if (BusLogic_GlobalOptions.TraceProbe) + BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", HostAdapter, HostAdapter->IO_Address); + /* + Indicate the Host Adapter Probe completed successfully. + */ + return true; } - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", - HostAdapter, HostAdapter->IO_Address); - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; - } - /* - Read the Status, Interrupt, and Geometry Registers to test if there are I/O - ports that respond, and to check the values to determine if they are from a - BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which - case there is definitely no BusLogic Host Adapter at this base I/O Address. - The test here is a subset of that used by the BusLogic Host Adapter BIOS. - */ - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " - "Geometry 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All, - InterruptRegister.All, GeometryRegister.All); - if (StatusRegister.All == 0 || - StatusRegister.sr.DiagnosticActive || - StatusRegister.sr.CommandParameterRegisterBusy || - StatusRegister.sr.Reserved || - StatusRegister.sr.CommandInvalid || - InterruptRegister.ir.Reserved != 0) - return false; - /* - Check the undocumented Geometry Register to test if there is an I/O port - that responded. Adaptec Host Adapters do not implement the Geometry - Register, so this test helps serve to avoid incorrectly recognizing an - Adaptec 1542A or 1542B as a BusLogic. Unfortunately, the Adaptec 1542C - series does respond to the Geometry Register I/O port, but it will be - rejected later when the Inquire Extended Setup Information command is - issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a - BusLogic clone that implements the same interface as earlier BusLogic - Host Adapters, including the undocumented commands, and is therefore - supported by this driver. However, the AMI FastDisk always returns 0x00 - upon reading the Geometry Register, so the extended translation option - should always be left disabled on the AMI FastDisk. - */ - if (GeometryRegister.All == 0xFF) return false; - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; + /* + Read the Status, Interrupt, and Geometry Registers to test if there are I/O + ports that respond, and to check the values to determine if they are from a + BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which + case there is definitely no BusLogic Host Adapter at this base I/O Address. + The test here is a subset of that used by the BusLogic Host Adapter BIOS. + */ + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); + if (BusLogic_GlobalOptions.TraceProbe) + BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All, InterruptRegister.All, GeometryRegister.All); + if (StatusRegister.All == 0 || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.CommandParameterRegisterBusy || StatusRegister.sr.Reserved || StatusRegister.sr.CommandInvalid || InterruptRegister.ir.Reserved != 0) + return false; + /* + Check the undocumented Geometry Register to test if there is an I/O port + that responded. Adaptec Host Adapters do not implement the Geometry + Register, so this test helps serve to avoid incorrectly recognizing an + Adaptec 1542A or 1542B as a BusLogic. Unfortunately, the Adaptec 1542C + series does respond to the Geometry Register I/O port, but it will be + rejected later when the Inquire Extended Setup Information command is + issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a + BusLogic clone that implements the same interface as earlier BusLogic + Host Adapters, including the undocumented commands, and is therefore + supported by this driver. However, the AMI FastDisk always returns 0x00 + upon reading the Geometry Register, so the extended translation option + should always be left disabled on the AMI FastDisk. + */ + if (GeometryRegister.All == 0xFF) + return false; + /* + Indicate the Host Adapter Probe completed successfully. + */ + return true; } @@ -1370,113 +1138,101 @@ static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *Hos */ static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter - *HostAdapter, - boolean HardReset) + *HostAdapter, boolean HardReset) { - union BusLogic_StatusRegister StatusRegister; - int TimeoutCounter; - /* - FlashPoint Host Adapters are Hard Reset by the FlashPoint SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - FlashPointInfo->HostSoftReset = !HardReset; - FlashPointInfo->ReportDataUnderrun = true; - HostAdapter->CardHandle = - FlashPoint_HardwareResetHostAdapter(FlashPointInfo); - if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false; - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; - } - /* - Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host - Adapter should respond by setting Diagnostic Active in the Status Register. - */ - if (HardReset) - BusLogic_HardReset(HostAdapter); - else BusLogic_SoftReset(HostAdapter); - /* - Wait until Diagnostic Active is set in the Status Register. - */ - TimeoutCounter = 5*10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.DiagnosticActive) break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " - "Status 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) return false; - /* - Wait 100 microseconds to allow completion of any initial diagnostic - activity which might leave the contents of the Status Register - unpredictable. - */ - udelay(100); - /* - Wait until Diagnostic Active is reset in the Status Register. - */ - TimeoutCounter = 10*10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (!StatusRegister.sr.DiagnosticActive) break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " - "Status 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) return false; - /* - Wait until at least one of the Diagnostic Failure, Host Adapter Ready, - or Data In Register Ready bits is set in the Status Register. - */ - TimeoutCounter = 10000; - while (--TimeoutCounter >= 0) - { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.DiagnosticFailure || - StatusRegister.sr.HostAdapterReady || - StatusRegister.sr.DataInRegisterReady) - break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " - "Status 0x%02X\n", HostAdapter, - HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) return false; - /* - If Diagnostic Failure is set or Host Adapter Ready is reset, then an - error occurred during the Host Adapter diagnostics. If Data In Register - Ready is set, then there is an Error Code available. - */ - if (StatusRegister.sr.DiagnosticFailure || - !StatusRegister.sr.HostAdapterReady) - { - BusLogic_CommandFailureReason = NULL; - BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS"); - BusLogic_Error("HOST ADAPTER STATUS REGISTER = %02X\n", - HostAdapter, StatusRegister.All); - if (StatusRegister.sr.DataInRegisterReady) - { - unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter); - BusLogic_Error("HOST ADAPTER ERROR CODE = %d\n", - HostAdapter, ErrorCode); + union BusLogic_StatusRegister StatusRegister; + int TimeoutCounter; + /* + FlashPoint Host Adapters are Hard Reset by the FlashPoint SCCB Manager. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->HostSoftReset = !HardReset; + FlashPointInfo->ReportDataUnderrun = true; + HostAdapter->CardHandle = FlashPoint_HardwareResetHostAdapter(FlashPointInfo); + if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) + return false; + /* + Indicate the Host Adapter Hard Reset completed successfully. + */ + return true; + } + /* + Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host + Adapter should respond by setting Diagnostic Active in the Status Register. + */ + if (HardReset) + BusLogic_HardReset(HostAdapter); + else + BusLogic_SoftReset(HostAdapter); + /* + Wait until Diagnostic Active is set in the Status Register. + */ + TimeoutCounter = 5 * 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.DiagnosticActive) + break; + udelay(100); } - return false; - } - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); + if (TimeoutCounter < 0) + return false; + /* + Wait 100 microseconds to allow completion of any initial diagnostic + activity which might leave the contents of the Status Register + unpredictable. + */ + udelay(100); + /* + Wait until Diagnostic Active is reset in the Status Register. + */ + TimeoutCounter = 10 * 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (!StatusRegister.sr.DiagnosticActive) + break; + udelay(100); + } + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); + if (TimeoutCounter < 0) + return false; + /* + Wait until at least one of the Diagnostic Failure, Host Adapter Ready, + or Data In Register Ready bits is set in the Status Register. + */ + TimeoutCounter = 10000; + while (--TimeoutCounter >= 0) { + StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); + if (StatusRegister.sr.DiagnosticFailure || StatusRegister.sr.HostAdapterReady || StatusRegister.sr.DataInRegisterReady) + break; + udelay(100); + } + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); + if (TimeoutCounter < 0) + return false; + /* + If Diagnostic Failure is set or Host Adapter Ready is reset, then an + error occurred during the Host Adapter diagnostics. If Data In Register + Ready is set, then there is an Error Code available. + */ + if (StatusRegister.sr.DiagnosticFailure || !StatusRegister.sr.HostAdapterReady) { + BusLogic_CommandFailureReason = NULL; + BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS"); + BusLogic_Error("HOST ADAPTER STATUS REGISTER = %02X\n", HostAdapter, StatusRegister.All); + if (StatusRegister.sr.DataInRegisterReady) { + unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter); + BusLogic_Error("HOST ADAPTER ERROR CODE = %d\n", HostAdapter, ErrorCode); + } + return false; + } + /* + Indicate the Host Adapter Hard Reset completed successfully. + */ + return true; } @@ -1487,35 +1243,30 @@ static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; - unsigned char RequestedReplyLength; - boolean Result = true; - /* - FlashPoint Host Adapters do not require this protection. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Issue the Inquire Extended Setup Information command. Only genuine - BusLogic Host Adapters and true clones support this command. Adaptec 1542C - series Host Adapters that respond to the Geometry Register I/O port will - fail this command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, - BusLogic_InquireExtendedSetupInformation, - &RequestedReplyLength, - sizeof(RequestedReplyLength), - &ExtendedSetupInformation, - sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - Result = false; - /* - Provide tracing information if requested and return. - */ - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, - HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); - return Result; + struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; + unsigned char RequestedReplyLength; + boolean Result = true; + /* + FlashPoint Host Adapters do not require this protection. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + return true; + /* + Issue the Inquire Extended Setup Information command. Only genuine + BusLogic Host Adapters and true clones support this command. Adaptec 1542C + series Host Adapters that respond to the Geometry Register I/O port will + fail this command. + */ + RequestedReplyLength = sizeof(ExtendedSetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation)) + != sizeof(ExtendedSetupInformation)) + Result = false; + /* + Provide tracing information if requested and return. + */ + if (BusLogic_GlobalOptions.TraceProbe) + BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); + return Result; } @@ -1527,513 +1278,442 @@ static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *Hos static boolean __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_BoardID BoardID; - struct BusLogic_Configuration Configuration; - struct BusLogic_SetupInformation SetupInformation; - struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; - unsigned char HostAdapterModelNumber[5]; - unsigned char FirmwareVersion3rdDigit; - unsigned char FirmwareVersionLetter; - struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; - struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; - struct BusLogic_AutoSCSIData AutoSCSIData; - union BusLogic_GeometryRegister GeometryRegister; - unsigned char RequestedReplyLength; - unsigned char *TargetPointer, Character; - int TargetID, i; - /* - Configuration Information for FlashPoint Host Adapters is provided in the - FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. - Initialize fields in the Host Adapter structure from the FlashPoint_Info - structure. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(FlashPointInfo->ModelNumber); i++) - *TargetPointer++ = FlashPointInfo->ModelNumber[i]; - *TargetPointer++ = '\0'; - strcpy(HostAdapter->FirmwareVersion, FlashPoint_FirmwareVersion); - HostAdapter->SCSI_ID = FlashPointInfo->SCSI_ID; - HostAdapter->ExtendedTranslationEnabled = - FlashPointInfo->ExtendedTranslationEnabled; - HostAdapter->ParityCheckingEnabled = - FlashPointInfo->ParityCheckingEnabled; - HostAdapter->BusResetEnabled = !FlashPointInfo->HostSoftReset; - HostAdapter->LevelSensitiveInterrupt = true; - HostAdapter->HostWideSCSI = FlashPointInfo->HostWideSCSI; - HostAdapter->HostDifferentialSCSI = false; - HostAdapter->HostSupportsSCAM = true; - HostAdapter->HostUltraSCSI = true; - HostAdapter->ExtendedLUNSupport = true; - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = FlashPointInfo->LowByteTerminated; - HostAdapter->HighByteTerminated = FlashPointInfo->HighByteTerminated; - HostAdapter->SCAM_Enabled = FlashPointInfo->SCAM_Enabled; - HostAdapter->SCAM_Level2 = FlashPointInfo->SCAM_Level2; - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); - HostAdapter->MaxLogicalUnits = 32; - HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; - HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; - HostAdapter->DriverQueueDepth = 255; - HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; - HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; - HostAdapter->FastPermitted = FlashPointInfo->FastPermitted; - HostAdapter->UltraPermitted = FlashPointInfo->UltraPermitted; - HostAdapter->WidePermitted = FlashPointInfo->WidePermitted; - HostAdapter->DisconnectPermitted = FlashPointInfo->DisconnectPermitted; - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - goto Common; - } - /* - Issue the Inquire Board ID command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, - &BoardID, sizeof(BoardID)) != sizeof(BoardID)) - return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID"); - /* - Issue the Inquire Configuration command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, - &Configuration, sizeof(Configuration)) - != sizeof(Configuration)) - return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION"); - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - /* - Issue the Inquire Extended Setup Information command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &ExtendedSetupInformation, - sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); - /* - Issue the Inquire Firmware Version 3rd Digit command. - */ - FirmwareVersion3rdDigit = '\0'; - if (BoardID.FirmwareVersion1stDigit > '0') - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, - NULL, 0, &FirmwareVersion3rdDigit, - sizeof(FirmwareVersion3rdDigit)) - != sizeof(FirmwareVersion3rdDigit)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); - /* - Issue the Inquire Host Adapter Model Number command. - */ - if (ExtendedSetupInformation.BusType == 'A' && - BoardID.FirmwareVersion1stDigit == '2') - /* BusLogic BT-542B ISA 2.xx */ - strcpy(HostAdapterModelNumber, "542B"); - else if (ExtendedSetupInformation.BusType == 'E' && - BoardID.FirmwareVersion1stDigit == '2' && - (BoardID.FirmwareVersion2ndDigit <= '1' || - (BoardID.FirmwareVersion2ndDigit == '2' && - FirmwareVersion3rdDigit == '0'))) - /* BusLogic BT-742A EISA 2.1x or 2.20 */ - strcpy(HostAdapterModelNumber, "742A"); - else if (ExtendedSetupInformation.BusType == 'E' && - BoardID.FirmwareVersion1stDigit == '0') - /* AMI FastDisk EISA Series 441 0.x */ - strcpy(HostAdapterModelNumber, "747A"); - else - { - RequestedReplyLength = sizeof(HostAdapterModelNumber); - if (BusLogic_Command(HostAdapter, BusLogic_InquireHostAdapterModelNumber, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &HostAdapterModelNumber, - sizeof(HostAdapterModelNumber)) - != sizeof(HostAdapterModelNumber)) - return BusLogic_Failure(HostAdapter, - "INQUIRE HOST ADAPTER MODEL NUMBER"); - } - /* - BusLogic MultiMaster Host Adapters can be identified by their model number - and the major version number of their firmware as follows: - - 5.xx BusLogic "W" Series Host Adapters: - BT-948/958/958D - 4.xx BusLogic "C" Series Host Adapters: - BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF - 3.xx BusLogic "S" Series Host Adapters: - BT-747S/747D/757S/757D/445S/545S/542D - BT-542B/742A (revision H) - 2.xx BusLogic "A" Series Host Adapters: - BT-542B/742A (revision G and below) - 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter - */ - /* - Save the Model Name and Host Adapter Name in the Host Adapter structure. - */ - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(HostAdapterModelNumber); i++) - { - Character = HostAdapterModelNumber[i]; - if (Character == ' ' || Character == '\0') break; - *TargetPointer++ = Character; - } - *TargetPointer++ = '\0'; - /* - Save the Firmware Version in the Host Adapter structure. - */ - TargetPointer = HostAdapter->FirmwareVersion; - *TargetPointer++ = BoardID.FirmwareVersion1stDigit; - *TargetPointer++ = '.'; - *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; - if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') - *TargetPointer++ = FirmwareVersion3rdDigit; - *TargetPointer = '\0'; - /* - Issue the Inquire Firmware Version Letter command. - */ - if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) - { - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, - NULL, 0, &FirmwareVersionLetter, - sizeof(FirmwareVersionLetter)) - != sizeof(FirmwareVersionLetter)) - return BusLogic_Failure(HostAdapter, - "INQUIRE FIRMWARE VERSION LETTER"); - if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') - *TargetPointer++ = FirmwareVersionLetter; - *TargetPointer = '\0'; - } - /* - Save the Host Adapter SCSI ID in the Host Adapter structure. - */ - HostAdapter->SCSI_ID = Configuration.HostAdapterID; - /* - Determine the Bus Type and save it in the Host Adapter structure, determine - and save the IRQ Channel if necessary, and determine and save the DMA - Channel for ISA Host Adapters. - */ - HostAdapter->HostAdapterBusType = - BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; - if (HostAdapter->IRQ_Channel == 0) - { - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - } - if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) - { - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; - } - /* - Determine whether Extended Translation is enabled and save it in - the Host Adapter structure. - */ - GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - HostAdapter->ExtendedTranslationEnabled = - GeometryRegister.gr.ExtendedTranslationEnabled; - /* - Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide - SCSI flag, Differential SCSI flag, SCAM Supported flag, and - Ultra SCSI flag in the Host Adapter structure. - */ - HostAdapter->HostAdapterScatterGatherLimit = - ExtendedSetupInformation.ScatterGatherLimit; - HostAdapter->DriverScatterGatherLimit = - HostAdapter->HostAdapterScatterGatherLimit; - if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit) - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupt) - HostAdapter->LevelSensitiveInterrupt = true; - HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI; - HostAdapter->HostDifferentialSCSI = - ExtendedSetupInformation.HostDifferentialSCSI; - HostAdapter->HostSupportsSCAM = ExtendedSetupInformation.HostSupportsSCAM; - HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI; - /* - Determine whether Extended LUN Format CCBs are supported and save the - information in the Host Adapter structure. - */ - if (HostAdapter->FirmwareVersion[0] == '5' || - (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI)) - HostAdapter->ExtendedLUNSupport = true; - /* - Issue the Inquire PCI Host Adapter Information command to read the - Termination Information from "W" series MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] == '5') - { - if (BusLogic_Command(HostAdapter, - BusLogic_InquirePCIHostAdapterInformation, - NULL, 0, &PCIHostAdapterInformation, - sizeof(PCIHostAdapterInformation)) - != sizeof(PCIHostAdapterInformation)) - return BusLogic_Failure(HostAdapter, - "INQUIRE PCI HOST ADAPTER INFORMATION"); - /* - Save the Termination Information in the Host Adapter structure. - */ - if (PCIHostAdapterInformation.GenericInfoValid) - { - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = - PCIHostAdapterInformation.LowByteTerminated; - HostAdapter->HighByteTerminated = - PCIHostAdapterInformation.HighByteTerminated; + struct BusLogic_BoardID BoardID; + struct BusLogic_Configuration Configuration; + struct BusLogic_SetupInformation SetupInformation; + struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; + unsigned char HostAdapterModelNumber[5]; + unsigned char FirmwareVersion3rdDigit; + unsigned char FirmwareVersionLetter; + struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; + struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; + struct BusLogic_AutoSCSIData AutoSCSIData; + union BusLogic_GeometryRegister GeometryRegister; + unsigned char RequestedReplyLength; + unsigned char *TargetPointer, Character; + int TargetID, i; + /* + Configuration Information for FlashPoint Host Adapters is provided in the + FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. + Initialize fields in the Host Adapter structure from the FlashPoint_Info + structure. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { + struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; + TargetPointer = HostAdapter->ModelName; + *TargetPointer++ = 'B'; + *TargetPointer++ = 'T'; + *TargetPointer++ = '-'; + for (i = 0; i < sizeof(FlashPointInfo->ModelNumber); i++) + *TargetPointer++ = FlashPointInfo->ModelNumber[i]; + *TargetPointer++ = '\0'; + strcpy(HostAdapter->FirmwareVersion, FlashPoint_FirmwareVersion); + HostAdapter->SCSI_ID = FlashPointInfo->SCSI_ID; + HostAdapter->ExtendedTranslationEnabled = FlashPointInfo->ExtendedTranslationEnabled; + HostAdapter->ParityCheckingEnabled = FlashPointInfo->ParityCheckingEnabled; + HostAdapter->BusResetEnabled = !FlashPointInfo->HostSoftReset; + HostAdapter->LevelSensitiveInterrupt = true; + HostAdapter->HostWideSCSI = FlashPointInfo->HostWideSCSI; + HostAdapter->HostDifferentialSCSI = false; + HostAdapter->HostSupportsSCAM = true; + HostAdapter->HostUltraSCSI = true; + HostAdapter->ExtendedLUNSupport = true; + HostAdapter->TerminationInfoValid = true; + HostAdapter->LowByteTerminated = FlashPointInfo->LowByteTerminated; + HostAdapter->HighByteTerminated = FlashPointInfo->HighByteTerminated; + HostAdapter->SCAM_Enabled = FlashPointInfo->SCAM_Enabled; + HostAdapter->SCAM_Level2 = FlashPointInfo->SCAM_Level2; + HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; + HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); + HostAdapter->MaxLogicalUnits = 32; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; + HostAdapter->DriverQueueDepth = 255; + HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; + HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; + HostAdapter->FastPermitted = FlashPointInfo->FastPermitted; + HostAdapter->UltraPermitted = FlashPointInfo->UltraPermitted; + HostAdapter->WidePermitted = FlashPointInfo->WidePermitted; + HostAdapter->DisconnectPermitted = FlashPointInfo->DisconnectPermitted; + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + goto Common; + } + /* + Issue the Inquire Board ID command. + */ + if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)) != sizeof(BoardID)) + return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID"); + /* + Issue the Inquire Configuration command. + */ + if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, &Configuration, sizeof(Configuration)) + != sizeof(Configuration)) + return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION"); + /* + Issue the Inquire Setup Information command. + */ + RequestedReplyLength = sizeof(SetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation)) + != sizeof(SetupInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); + /* + Issue the Inquire Extended Setup Information command. + */ + RequestedReplyLength = sizeof(ExtendedSetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation)) + != sizeof(ExtendedSetupInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); + /* + Issue the Inquire Firmware Version 3rd Digit command. + */ + FirmwareVersion3rdDigit = '\0'; + if (BoardID.FirmwareVersion1stDigit > '0') + if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, NULL, 0, &FirmwareVersion3rdDigit, sizeof(FirmwareVersion3rdDigit)) + != sizeof(FirmwareVersion3rdDigit)) + return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); + /* + Issue the Inquire Host Adapter Model Number command. + */ + if (ExtendedSetupInformation.BusType == 'A' && BoardID.FirmwareVersion1stDigit == '2') + /* BusLogic BT-542B ISA 2.xx */ + strcpy(HostAdapterModelNumber, "542B"); + else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '2' && (BoardID.FirmwareVersion2ndDigit <= '1' || (BoardID.FirmwareVersion2ndDigit == '2' && FirmwareVersion3rdDigit == '0'))) + /* BusLogic BT-742A EISA 2.1x or 2.20 */ + strcpy(HostAdapterModelNumber, "742A"); + else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '0') + /* AMI FastDisk EISA Series 441 0.x */ + strcpy(HostAdapterModelNumber, "747A"); + else { + RequestedReplyLength = sizeof(HostAdapterModelNumber); + if (BusLogic_Command(HostAdapter, BusLogic_InquireHostAdapterModelNumber, &RequestedReplyLength, sizeof(RequestedReplyLength), &HostAdapterModelNumber, sizeof(HostAdapterModelNumber)) + != sizeof(HostAdapterModelNumber)) + return BusLogic_Failure(HostAdapter, "INQUIRE HOST ADAPTER MODEL NUMBER"); } - } - /* - Issue the Fetch Host Adapter Local RAM command to read the AutoSCSI data - from "W" and "C" series MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] >= '4') - { - FetchHostAdapterLocalRAMRequest.ByteOffset = - BusLogic_AutoSCSI_BaseOffset; - FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIData); - if (BusLogic_Command(HostAdapter, - BusLogic_FetchHostAdapterLocalRAM, - &FetchHostAdapterLocalRAMRequest, - sizeof(FetchHostAdapterLocalRAMRequest), - &AutoSCSIData, sizeof(AutoSCSIData)) - != sizeof(AutoSCSIData)) - return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM"); - /* - Save the Parity Checking Enabled, Bus Reset Enabled, and Termination - Information in the Host Adapter structure. - */ - HostAdapter->ParityCheckingEnabled = AutoSCSIData.ParityCheckingEnabled; - HostAdapter->BusResetEnabled = AutoSCSIData.BusResetEnabled; - if (HostAdapter->FirmwareVersion[0] == '4') - { - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = AutoSCSIData.LowByteTerminated; - HostAdapter->HighByteTerminated = AutoSCSIData.HighByteTerminated; + /* + BusLogic MultiMaster Host Adapters can be identified by their model number + and the major version number of their firmware as follows: + + 5.xx BusLogic "W" Series Host Adapters: + BT-948/958/958D + 4.xx BusLogic "C" Series Host Adapters: + BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF + 3.xx BusLogic "S" Series Host Adapters: + BT-747S/747D/757S/757D/445S/545S/542D + BT-542B/742A (revision H) + 2.xx BusLogic "A" Series Host Adapters: + BT-542B/742A (revision G and below) + 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter + */ + /* + Save the Model Name and Host Adapter Name in the Host Adapter structure. + */ + TargetPointer = HostAdapter->ModelName; + *TargetPointer++ = 'B'; + *TargetPointer++ = 'T'; + *TargetPointer++ = '-'; + for (i = 0; i < sizeof(HostAdapterModelNumber); i++) { + Character = HostAdapterModelNumber[i]; + if (Character == ' ' || Character == '\0') + break; + *TargetPointer++ = Character; + } + *TargetPointer++ = '\0'; + /* + Save the Firmware Version in the Host Adapter structure. + */ + TargetPointer = HostAdapter->FirmwareVersion; + *TargetPointer++ = BoardID.FirmwareVersion1stDigit; + *TargetPointer++ = '.'; + *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; + if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') + *TargetPointer++ = FirmwareVersion3rdDigit; + *TargetPointer = '\0'; + /* + Issue the Inquire Firmware Version Letter command. + */ + if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) { + if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, NULL, 0, &FirmwareVersionLetter, sizeof(FirmwareVersionLetter)) + != sizeof(FirmwareVersionLetter)) + return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER"); + if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') + *TargetPointer++ = FirmwareVersionLetter; + *TargetPointer = '\0'; } - /* - Save the Wide Permitted, Fast Permitted, Synchronous Permitted, - Disconnect Permitted, Ultra Permitted, and SCAM Information in the - Host Adapter structure. - */ - HostAdapter->WidePermitted = AutoSCSIData.WidePermitted; - HostAdapter->FastPermitted = AutoSCSIData.FastPermitted; - HostAdapter->SynchronousPermitted = - AutoSCSIData.SynchronousPermitted; - HostAdapter->DisconnectPermitted = - AutoSCSIData.DisconnectPermitted; - if (HostAdapter->HostUltraSCSI) - HostAdapter->UltraPermitted = AutoSCSIData.UltraPermitted; - if (HostAdapter->HostSupportsSCAM) - { - HostAdapter->SCAM_Enabled = AutoSCSIData.SCAM_Enabled; - HostAdapter->SCAM_Level2 = AutoSCSIData.SCAM_Level2; + /* + Save the Host Adapter SCSI ID in the Host Adapter structure. + */ + HostAdapter->SCSI_ID = Configuration.HostAdapterID; + /* + Determine the Bus Type and save it in the Host Adapter structure, determine + and save the IRQ Channel if necessary, and determine and save the DMA + Channel for ISA Host Adapters. + */ + HostAdapter->HostAdapterBusType = BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; + if (HostAdapter->IRQ_Channel == 0) { + if (Configuration.IRQ_Channel9) + HostAdapter->IRQ_Channel = 9; + else if (Configuration.IRQ_Channel10) + HostAdapter->IRQ_Channel = 10; + else if (Configuration.IRQ_Channel11) + HostAdapter->IRQ_Channel = 11; + else if (Configuration.IRQ_Channel12) + HostAdapter->IRQ_Channel = 12; + else if (Configuration.IRQ_Channel14) + HostAdapter->IRQ_Channel = 14; + else if (Configuration.IRQ_Channel15) + HostAdapter->IRQ_Channel = 15; + } + if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) { + if (Configuration.DMA_Channel5) + HostAdapter->DMA_Channel = 5; + else if (Configuration.DMA_Channel6) + HostAdapter->DMA_Channel = 6; + else if (Configuration.DMA_Channel7) + HostAdapter->DMA_Channel = 7; } - } - /* - Initialize fields in the Host Adapter structure for "S" and "A" series - MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] < '4') - { - if (SetupInformation.SynchronousInitiationEnabled) - { - HostAdapter->SynchronousPermitted = 0xFF; - if (HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus) - { - if (ExtendedSetupInformation.Misc.FastOnEISA) - HostAdapter->FastPermitted = 0xFF; - if (strcmp(HostAdapter->ModelName, "BT-757") == 0) - HostAdapter->WidePermitted = 0xFF; - } + /* + Determine whether Extended Translation is enabled and save it in + the Host Adapter structure. + */ + GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); + HostAdapter->ExtendedTranslationEnabled = GeometryRegister.gr.ExtendedTranslationEnabled; + /* + Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide + SCSI flag, Differential SCSI flag, SCAM Supported flag, and + Ultra SCSI flag in the Host Adapter structure. + */ + HostAdapter->HostAdapterScatterGatherLimit = ExtendedSetupInformation.ScatterGatherLimit; + HostAdapter->DriverScatterGatherLimit = HostAdapter->HostAdapterScatterGatherLimit; + if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit) + HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; + if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupt) + HostAdapter->LevelSensitiveInterrupt = true; + HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI; + HostAdapter->HostDifferentialSCSI = ExtendedSetupInformation.HostDifferentialSCSI; + HostAdapter->HostSupportsSCAM = ExtendedSetupInformation.HostSupportsSCAM; + HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI; + /* + Determine whether Extended LUN Format CCBs are supported and save the + information in the Host Adapter structure. + */ + if (HostAdapter->FirmwareVersion[0] == '5' || (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI)) + HostAdapter->ExtendedLUNSupport = true; + /* + Issue the Inquire PCI Host Adapter Information command to read the + Termination Information from "W" series MultiMaster Host Adapters. + */ + if (HostAdapter->FirmwareVersion[0] == '5') { + if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation)) + != sizeof(PCIHostAdapterInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE PCI HOST ADAPTER INFORMATION"); + /* + Save the Termination Information in the Host Adapter structure. + */ + if (PCIHostAdapterInformation.GenericInfoValid) { + HostAdapter->TerminationInfoValid = true; + HostAdapter->LowByteTerminated = PCIHostAdapterInformation.LowByteTerminated; + HostAdapter->HighByteTerminated = PCIHostAdapterInformation.HighByteTerminated; + } + } + /* + Issue the Fetch Host Adapter Local RAM command to read the AutoSCSI data + from "W" and "C" series MultiMaster Host Adapters. + */ + if (HostAdapter->FirmwareVersion[0] >= '4') { + FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset; + FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIData); + if (BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIData, sizeof(AutoSCSIData)) + != sizeof(AutoSCSIData)) + return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM"); + /* + Save the Parity Checking Enabled, Bus Reset Enabled, and Termination + Information in the Host Adapter structure. + */ + HostAdapter->ParityCheckingEnabled = AutoSCSIData.ParityCheckingEnabled; + HostAdapter->BusResetEnabled = AutoSCSIData.BusResetEnabled; + if (HostAdapter->FirmwareVersion[0] == '4') { + HostAdapter->TerminationInfoValid = true; + HostAdapter->LowByteTerminated = AutoSCSIData.LowByteTerminated; + HostAdapter->HighByteTerminated = AutoSCSIData.HighByteTerminated; + } + /* + Save the Wide Permitted, Fast Permitted, Synchronous Permitted, + Disconnect Permitted, Ultra Permitted, and SCAM Information in the + Host Adapter structure. + */ + HostAdapter->WidePermitted = AutoSCSIData.WidePermitted; + HostAdapter->FastPermitted = AutoSCSIData.FastPermitted; + HostAdapter->SynchronousPermitted = AutoSCSIData.SynchronousPermitted; + HostAdapter->DisconnectPermitted = AutoSCSIData.DisconnectPermitted; + if (HostAdapter->HostUltraSCSI) + HostAdapter->UltraPermitted = AutoSCSIData.UltraPermitted; + if (HostAdapter->HostSupportsSCAM) { + HostAdapter->SCAM_Enabled = AutoSCSIData.SCAM_Enabled; + HostAdapter->SCAM_Level2 = AutoSCSIData.SCAM_Level2; + } + } + /* + Initialize fields in the Host Adapter structure for "S" and "A" series + MultiMaster Host Adapters. + */ + if (HostAdapter->FirmwareVersion[0] < '4') { + if (SetupInformation.SynchronousInitiationEnabled) { + HostAdapter->SynchronousPermitted = 0xFF; + if (HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus) { + if (ExtendedSetupInformation.Misc.FastOnEISA) + HostAdapter->FastPermitted = 0xFF; + if (strcmp(HostAdapter->ModelName, "BT-757") == 0) + HostAdapter->WidePermitted = 0xFF; + } + } + HostAdapter->DisconnectPermitted = 0xFF; + HostAdapter->ParityCheckingEnabled = SetupInformation.ParityCheckingEnabled; + HostAdapter->BusResetEnabled = true; + } + /* + Determine the maximum number of Target IDs and Logical Units supported by + this driver for Wide and Narrow Host Adapters. + */ + HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); + HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); + /* + Select appropriate values for the Mailbox Count, Driver Queue Depth, + Initial CCBs, and Incremental CCBs variables based on whether or not Strict + Round Robin Mode is supported. If Strict Round Robin Mode is supported, + then there is no performance degradation in using the maximum possible + number of Outgoing and Incoming Mailboxes and allowing the Tagged and + Untagged Queue Depths to determine the actual utilization. If Strict Round + Robin Mode is not supported, then the Host Adapter must scan all the + Outgoing Mailboxes whenever an Outgoing Mailbox entry is made, which can + cause a substantial performance penalty. The host adapters actually have + room to store the following number of CCBs internally; that is, they can + internally queue and manage this many active commands on the SCSI bus + simultaneously. Performance measurements demonstrate that the Driver Queue + Depth should be set to the Mailbox Count, rather than the Host Adapter + Queue Depth (internal CCB capacity), as it is more efficient to have the + queued commands waiting in Outgoing Mailboxes if necessary than to block + the process in the higher levels of the SCSI Subsystem. + + 192 BT-948/958/958D + 100 BT-946C/956C/956CD/747C/757C/757CD/445C + 50 BT-545C/540CF + 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A + */ + if (HostAdapter->FirmwareVersion[0] == '5') + HostAdapter->HostAdapterQueueDepth = 192; + else if (HostAdapter->FirmwareVersion[0] == '4') + HostAdapter->HostAdapterQueueDepth = (HostAdapter->HostAdapterBusType != BusLogic_ISA_Bus ? 100 : 50); + else + HostAdapter->HostAdapterQueueDepth = 30; + if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) { + HostAdapter->StrictRoundRobinModeSupport = true; + HostAdapter->MailboxCount = BusLogic_MaxMailboxes; + } else { + HostAdapter->StrictRoundRobinModeSupport = false; + HostAdapter->MailboxCount = 32; + } + HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; + /* + Tagged Queuing support is available and operates properly on all "W" series + MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with + firmware version 4.22 and above, and on "S" series MultiMaster Host + Adapters with firmware version 3.35 and above. + */ + HostAdapter->TaggedQueuingPermitted = 0; + switch (HostAdapter->FirmwareVersion[0]) { + case '5': + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + break; + case '4': + if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0) + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + break; + case '3': + if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0) + HostAdapter->TaggedQueuingPermitted = 0xFFFF; + break; } - HostAdapter->DisconnectPermitted = 0xFF; - HostAdapter->ParityCheckingEnabled = - SetupInformation.ParityCheckingEnabled; - HostAdapter->BusResetEnabled = true; - } - /* - Determine the maximum number of Target IDs and Logical Units supported by - this driver for Wide and Narrow Host Adapters. - */ - HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); - HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); - /* - Select appropriate values for the Mailbox Count, Driver Queue Depth, - Initial CCBs, and Incremental CCBs variables based on whether or not Strict - Round Robin Mode is supported. If Strict Round Robin Mode is supported, - then there is no performance degradation in using the maximum possible - number of Outgoing and Incoming Mailboxes and allowing the Tagged and - Untagged Queue Depths to determine the actual utilization. If Strict Round - Robin Mode is not supported, then the Host Adapter must scan all the - Outgoing Mailboxes whenever an Outgoing Mailbox entry is made, which can - cause a substantial performance penalty. The host adapters actually have - room to store the following number of CCBs internally; that is, they can - internally queue and manage this many active commands on the SCSI bus - simultaneously. Performance measurements demonstrate that the Driver Queue - Depth should be set to the Mailbox Count, rather than the Host Adapter - Queue Depth (internal CCB capacity), as it is more efficient to have the - queued commands waiting in Outgoing Mailboxes if necessary than to block - the process in the higher levels of the SCSI Subsystem. - - 192 BT-948/958/958D - 100 BT-946C/956C/956CD/747C/757C/757CD/445C - 50 BT-545C/540CF - 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A - */ - if (HostAdapter->FirmwareVersion[0] == '5') - HostAdapter->HostAdapterQueueDepth = 192; - else if (HostAdapter->FirmwareVersion[0] == '4') - HostAdapter->HostAdapterQueueDepth = - (HostAdapter->HostAdapterBusType != BusLogic_ISA_Bus ? 100 : 50); - else HostAdapter->HostAdapterQueueDepth = 30; - if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) - { - HostAdapter->StrictRoundRobinModeSupport = true; - HostAdapter->MailboxCount = BusLogic_MaxMailboxes; - } - else - { - HostAdapter->StrictRoundRobinModeSupport = false; - HostAdapter->MailboxCount = 32; - } - HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; - HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; - HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; - /* - Tagged Queuing support is available and operates properly on all "W" series - MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with - firmware version 4.22 and above, and on "S" series MultiMaster Host - Adapters with firmware version 3.35 and above. - */ - HostAdapter->TaggedQueuingPermitted = 0; - switch (HostAdapter->FirmwareVersion[0]) - { - case '5': - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - case '4': - if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0) - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - case '3': - if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0) - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - } - /* - Determine the Host Adapter BIOS Address if the BIOS is enabled and - save it in the Host Adapter structure. The BIOS is disabled if the - BIOS_Address is 0. - */ - HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12; - /* - ISA Host Adapters require Bounce Buffers if there is more than 16MB memory. - */ - if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus && - (void *) high_memory > (void *) MAX_DMA_ADDRESS) - HostAdapter->BounceBuffersRequired = true; - /* - BusLogic BT-445S Host Adapters prior to board revision E have a hardware - bug whereby when the BIOS is enabled, transfers to/from the same address - range the BIOS occupies modulo 16MB are handled incorrectly. Only properly - functioning BT-445S Host Adapters have firmware version 3.37, so require - that ISA Bounce Buffers be used for the buggy BT-445S models if there is - more than 16MB memory. - */ - if (HostAdapter->BIOS_Address > 0 && - strcmp(HostAdapter->ModelName, "BT-445S") == 0 && - strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 && - (void *) high_memory > (void *) MAX_DMA_ADDRESS) - HostAdapter->BounceBuffersRequired = true; - /* - Initialize parameters common to MultiMaster and FlashPoint Host Adapters. - */ -Common: - /* - Initialize the Host Adapter Full Model Name from the Model Name. - */ - strcpy(HostAdapter->FullModelName, "BusLogic "); - strcat(HostAdapter->FullModelName, HostAdapter->ModelName); - /* - Select an appropriate value for the Tagged Queue Depth either from a - BusLogic Driver Options specification, or based on whether this Host - Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth - is left at 0 for automatic determination in BusLogic_SelectQueueDepths. - Initialize the Untagged Queue Depth. - */ - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - { - unsigned char QueueDepth = 0; - if (HostAdapter->DriverOptions != NULL && - HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) - QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; - else if (HostAdapter->BounceBuffersRequired) - QueueDepth = BusLogic_TaggedQueueDepthBB; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - } - if (HostAdapter->BounceBuffersRequired) - HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; - else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; - if (HostAdapter->DriverOptions != NULL) - HostAdapter->CommonQueueDepth = - HostAdapter->DriverOptions->CommonQueueDepth; - if (HostAdapter->CommonQueueDepth > 0 && - HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth) - HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth; - /* - Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. - Therefore, mask the Tagged Queuing Permitted Default bits with the - Disconnect/Reconnect Permitted bits. - */ - HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; - /* - Combine the default Tagged Queuing Permitted bits with any BusLogic Driver - Options Tagged Queuing specification. - */ - if (HostAdapter->DriverOptions != NULL) - HostAdapter->TaggedQueuingPermitted = - (HostAdapter->DriverOptions->TaggedQueuingPermitted & - HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | - (HostAdapter->TaggedQueuingPermitted & - ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); - - /* - Select an appropriate value for Bus Settle Time either from a BusLogic - Driver Options specification, or from BusLogic_DefaultBusSettleTime. - */ - if (HostAdapter->DriverOptions != NULL && - HostAdapter->DriverOptions->BusSettleTime > 0) - HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; - else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; - /* - Indicate reading the Host Adapter Configuration completed successfully. - */ - return true; + /* + Determine the Host Adapter BIOS Address if the BIOS is enabled and + save it in the Host Adapter structure. The BIOS is disabled if the + BIOS_Address is 0. + */ + HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12; + /* + ISA Host Adapters require Bounce Buffers if there is more than 16MB memory. + */ + if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus && (void *) high_memory > (void *) MAX_DMA_ADDRESS) + HostAdapter->BounceBuffersRequired = true; + /* + BusLogic BT-445S Host Adapters prior to board revision E have a hardware + bug whereby when the BIOS is enabled, transfers to/from the same address + range the BIOS occupies modulo 16MB are handled incorrectly. Only properly + functioning BT-445S Host Adapters have firmware version 3.37, so require + that ISA Bounce Buffers be used for the buggy BT-445S models if there is + more than 16MB memory. + */ + if (HostAdapter->BIOS_Address > 0 && strcmp(HostAdapter->ModelName, "BT-445S") == 0 && strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 && (void *) high_memory > (void *) MAX_DMA_ADDRESS) + HostAdapter->BounceBuffersRequired = true; + /* + Initialize parameters common to MultiMaster and FlashPoint Host Adapters. + */ + Common: + /* + Initialize the Host Adapter Full Model Name from the Model Name. + */ + strcpy(HostAdapter->FullModelName, "BusLogic "); + strcat(HostAdapter->FullModelName, HostAdapter->ModelName); + /* + Select an appropriate value for the Tagged Queue Depth either from a + BusLogic Driver Options specification, or based on whether this Host + Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth + is left at 0 for automatic determination in BusLogic_SelectQueueDepths. + Initialize the Untagged Queue Depth. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) { + unsigned char QueueDepth = 0; + if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) + QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; + else if (HostAdapter->BounceBuffersRequired) + QueueDepth = BusLogic_TaggedQueueDepthBB; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + } + if (HostAdapter->BounceBuffersRequired) + HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; + else + HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; + if (HostAdapter->DriverOptions != NULL) + HostAdapter->CommonQueueDepth = HostAdapter->DriverOptions->CommonQueueDepth; + if (HostAdapter->CommonQueueDepth > 0 && HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth) + HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth; + /* + Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. + Therefore, mask the Tagged Queuing Permitted Default bits with the + Disconnect/Reconnect Permitted bits. + */ + HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; + /* + Combine the default Tagged Queuing Permitted bits with any BusLogic Driver + Options Tagged Queuing specification. + */ + if (HostAdapter->DriverOptions != NULL) + HostAdapter->TaggedQueuingPermitted = + (HostAdapter->DriverOptions->TaggedQueuingPermitted & HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | (HostAdapter->TaggedQueuingPermitted & ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); + + /* + Select an appropriate value for Bus Settle Time either from a BusLogic + Driver Options specification, or from BusLogic_DefaultBusSettleTime. + */ + if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->BusSettleTime > 0) + HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; + else + HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; + /* + Indicate reading the Host Adapter Configuration completed successfully. + */ + return true; } @@ -2045,210 +1725,144 @@ Common: static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter *HostAdapter) { - unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1; - unsigned short SynchronousPermitted, FastPermitted; - unsigned short UltraPermitted, WidePermitted; - unsigned short DisconnectPermitted, TaggedQueuingPermitted; - boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; - char SynchronousString[BusLogic_MaxTargetDevices+1]; - char WideString[BusLogic_MaxTargetDevices+1]; - char DisconnectString[BusLogic_MaxTargetDevices+1]; - char TaggedQueuingString[BusLogic_MaxTargetDevices+1]; - char *SynchronousMessage = SynchronousString; - char *WideMessage = WideString; - char *DisconnectMessage = DisconnectString; - char *TaggedQueuingMessage = TaggedQueuingString; - int TargetID; - BusLogic_Info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", - HostAdapter, HostAdapter->ModelName, - BusLogic_HostAdapterBusNames[HostAdapter->HostAdapterBusType], - (HostAdapter->HostWideSCSI ? " Wide" : ""), - (HostAdapter->HostDifferentialSCSI ? " Differential" : ""), - (HostAdapter->HostUltraSCSI ? " Ultra" : "")); - BusLogic_Info(" Firmware Version: %s, I/O Address: 0x%X, " - "IRQ Channel: %d/%s\n", HostAdapter, - HostAdapter->FirmwareVersion, - HostAdapter->IO_Address, HostAdapter->IRQ_Channel, - (HostAdapter->LevelSensitiveInterrupt ? "Level" : "Edge")); - if (HostAdapter->HostAdapterBusType != BusLogic_PCI_Bus) - { - BusLogic_Info(" DMA Channel: ", HostAdapter); - if (HostAdapter->DMA_Channel > 0) - BusLogic_Info("%d, ", HostAdapter, HostAdapter->DMA_Channel); - else BusLogic_Info("None, ", HostAdapter); - if (HostAdapter->BIOS_Address > 0) - BusLogic_Info("BIOS Address: 0x%X, ", HostAdapter, - HostAdapter->BIOS_Address); - else BusLogic_Info("BIOS Address: None, ", HostAdapter); - } - else - { - BusLogic_Info(" PCI Bus: %d, Device: %d, Address: ", - HostAdapter, HostAdapter->Bus, HostAdapter->Device); - if (HostAdapter->PCI_Address > 0) - BusLogic_Info("0x%X, ", HostAdapter, HostAdapter->PCI_Address); - else BusLogic_Info("Unassigned, ", HostAdapter); - } - BusLogic_Info("Host Adapter SCSI ID: %d\n", HostAdapter, - HostAdapter->SCSI_ID); - BusLogic_Info(" Parity Checking: %s, Extended Translation: %s\n", - HostAdapter, - (HostAdapter->ParityCheckingEnabled - ? "Enabled" : "Disabled"), - (HostAdapter->ExtendedTranslationEnabled - ? "Enabled" : "Disabled")); - AllTargetsMask &= ~(1 << HostAdapter->SCSI_ID); - SynchronousPermitted = HostAdapter->SynchronousPermitted & AllTargetsMask; - FastPermitted = HostAdapter->FastPermitted & AllTargetsMask; - UltraPermitted = HostAdapter->UltraPermitted & AllTargetsMask; - if ((BusLogic_MultiMasterHostAdapterP(HostAdapter) && - (HostAdapter->FirmwareVersion[0] >= '4' || - HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus)) || - BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - CommonSynchronousNegotiation = false; - if (SynchronousPermitted == 0) - { - SynchronousMessage = "Disabled"; - CommonSynchronousNegotiation = true; - } - else if (SynchronousPermitted == AllTargetsMask) - { - if (FastPermitted == 0) - { - SynchronousMessage = "Slow"; - CommonSynchronousNegotiation = true; - } - else if (FastPermitted == AllTargetsMask) - { - if (UltraPermitted == 0) - { - SynchronousMessage = "Fast"; - CommonSynchronousNegotiation = true; + unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1; + unsigned short SynchronousPermitted, FastPermitted; + unsigned short UltraPermitted, WidePermitted; + unsigned short DisconnectPermitted, TaggedQueuingPermitted; + boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; + char SynchronousString[BusLogic_MaxTargetDevices + 1]; + char WideString[BusLogic_MaxTargetDevices + 1]; + char DisconnectString[BusLogic_MaxTargetDevices + 1]; + char TaggedQueuingString[BusLogic_MaxTargetDevices + 1]; + char *SynchronousMessage = SynchronousString; + char *WideMessage = WideString; + char *DisconnectMessage = DisconnectString; + char *TaggedQueuingMessage = TaggedQueuingString; + int TargetID; + BusLogic_Info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", + HostAdapter, HostAdapter->ModelName, + BusLogic_HostAdapterBusNames[HostAdapter->HostAdapterBusType], (HostAdapter->HostWideSCSI ? " Wide" : ""), (HostAdapter->HostDifferentialSCSI ? " Differential" : ""), (HostAdapter->HostUltraSCSI ? " Ultra" : "")); + BusLogic_Info(" Firmware Version: %s, I/O Address: 0x%X, " "IRQ Channel: %d/%s\n", HostAdapter, HostAdapter->FirmwareVersion, HostAdapter->IO_Address, HostAdapter->IRQ_Channel, (HostAdapter->LevelSensitiveInterrupt ? "Level" : "Edge")); + if (HostAdapter->HostAdapterBusType != BusLogic_PCI_Bus) { + BusLogic_Info(" DMA Channel: ", HostAdapter); + if (HostAdapter->DMA_Channel > 0) + BusLogic_Info("%d, ", HostAdapter, HostAdapter->DMA_Channel); + else + BusLogic_Info("None, ", HostAdapter); + if (HostAdapter->BIOS_Address > 0) + BusLogic_Info("BIOS Address: 0x%X, ", HostAdapter, HostAdapter->BIOS_Address); + else + BusLogic_Info("BIOS Address: None, ", HostAdapter); + } else { + BusLogic_Info(" PCI Bus: %d, Device: %d, Address: ", HostAdapter, HostAdapter->Bus, HostAdapter->Device); + if (HostAdapter->PCI_Address > 0) + BusLogic_Info("0x%X, ", HostAdapter, HostAdapter->PCI_Address); + else + BusLogic_Info("Unassigned, ", HostAdapter); + } + BusLogic_Info("Host Adapter SCSI ID: %d\n", HostAdapter, HostAdapter->SCSI_ID); + BusLogic_Info(" Parity Checking: %s, Extended Translation: %s\n", HostAdapter, (HostAdapter->ParityCheckingEnabled ? "Enabled" : "Disabled"), (HostAdapter->ExtendedTranslationEnabled ? "Enabled" : "Disabled")); + AllTargetsMask &= ~(1 << HostAdapter->SCSI_ID); + SynchronousPermitted = HostAdapter->SynchronousPermitted & AllTargetsMask; + FastPermitted = HostAdapter->FastPermitted & AllTargetsMask; + UltraPermitted = HostAdapter->UltraPermitted & AllTargetsMask; + if ((BusLogic_MultiMasterHostAdapterP(HostAdapter) && (HostAdapter->FirmwareVersion[0] >= '4' || HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus)) || BusLogic_FlashPointHostAdapterP(HostAdapter)) { + CommonSynchronousNegotiation = false; + if (SynchronousPermitted == 0) { + SynchronousMessage = "Disabled"; + CommonSynchronousNegotiation = true; + } else if (SynchronousPermitted == AllTargetsMask) { + if (FastPermitted == 0) { + SynchronousMessage = "Slow"; + CommonSynchronousNegotiation = true; + } else if (FastPermitted == AllTargetsMask) { + if (UltraPermitted == 0) { + SynchronousMessage = "Fast"; + CommonSynchronousNegotiation = true; + } else if (UltraPermitted == AllTargetsMask) { + SynchronousMessage = "Ultra"; + CommonSynchronousNegotiation = true; + } + } } - else if (UltraPermitted == AllTargetsMask) - { - SynchronousMessage = "Ultra"; - CommonSynchronousNegotiation = true; + if (!CommonSynchronousNegotiation) { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + SynchronousString[TargetID] = ((!(SynchronousPermitted & (1 << TargetID))) ? 'N' : (!(FastPermitted & (1 << TargetID)) ? 'S' : (!(UltraPermitted & (1 << TargetID)) ? 'F' : 'U'))); + SynchronousString[HostAdapter->SCSI_ID] = '#'; + SynchronousString[HostAdapter->MaxTargetDevices] = '\0'; } - } - } - if (!CommonSynchronousNegotiation) - { - for (TargetID = 0; - TargetID < HostAdapter->MaxTargetDevices; - TargetID++) - SynchronousString[TargetID] = - ((!(SynchronousPermitted & (1 << TargetID))) ? 'N' : - (!(FastPermitted & (1 << TargetID)) ? 'S' : - (!(UltraPermitted & (1 << TargetID)) ? 'F' : 'U'))); - SynchronousString[HostAdapter->SCSI_ID] = '#'; - SynchronousString[HostAdapter->MaxTargetDevices] = '\0'; + } else + SynchronousMessage = (SynchronousPermitted == 0 ? "Disabled" : "Enabled"); + WidePermitted = HostAdapter->WidePermitted & AllTargetsMask; + if (WidePermitted == 0) + WideMessage = "Disabled"; + else if (WidePermitted == AllTargetsMask) + WideMessage = "Enabled"; + else { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + WideString[TargetID] = ((WidePermitted & (1 << TargetID)) ? 'Y' : 'N'); + WideString[HostAdapter->SCSI_ID] = '#'; + WideString[HostAdapter->MaxTargetDevices] = '\0'; + } + DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask; + if (DisconnectPermitted == 0) + DisconnectMessage = "Disabled"; + else if (DisconnectPermitted == AllTargetsMask) + DisconnectMessage = "Enabled"; + else { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + DisconnectString[TargetID] = ((DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N'); + DisconnectString[HostAdapter->SCSI_ID] = '#'; + DisconnectString[HostAdapter->MaxTargetDevices] = '\0'; + } + TaggedQueuingPermitted = HostAdapter->TaggedQueuingPermitted & AllTargetsMask; + if (TaggedQueuingPermitted == 0) + TaggedQueuingMessage = "Disabled"; + else if (TaggedQueuingPermitted == AllTargetsMask) + TaggedQueuingMessage = "Enabled"; + else { + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + TaggedQueuingString[TargetID] = ((TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N'); + TaggedQueuingString[HostAdapter->SCSI_ID] = '#'; + TaggedQueuingString[HostAdapter->MaxTargetDevices] = '\0'; + } + BusLogic_Info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n", HostAdapter, SynchronousMessage, WideMessage); + BusLogic_Info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", HostAdapter, DisconnectMessage, TaggedQueuingMessage); + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + BusLogic_Info(" Scatter/Gather Limit: %d of %d segments, " "Mailboxes: %d\n", HostAdapter, HostAdapter->DriverScatterGatherLimit, HostAdapter->HostAdapterScatterGatherLimit, HostAdapter->MailboxCount); + BusLogic_Info(" Driver Queue Depth: %d, " "Host Adapter Queue Depth: %d\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->HostAdapterQueueDepth); + } else + BusLogic_Info(" Driver Queue Depth: %d, " "Scatter/Gather Limit: %d segments\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->DriverScatterGatherLimit); + BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); + CommonTaggedQueueDepth = true; + for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) { + CommonTaggedQueueDepth = false; + break; + } + if (CommonTaggedQueueDepth) { + if (HostAdapter->QueueDepth[0] > 0) + BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); + else + BusLogic_Info("Automatic", HostAdapter); + } else + BusLogic_Info("Individual", HostAdapter); + BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, HostAdapter->UntaggedQueueDepth); + if (HostAdapter->TerminationInfoValid) { + if (HostAdapter->HostWideSCSI) + BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? (HostAdapter->HighByteTerminated ? "Both Enabled" : "Low Enabled") + : (HostAdapter->HighByteTerminated ? "High Enabled" : "Both Disabled"))); + else + BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled")); + if (HostAdapter->HostSupportsSCAM) + BusLogic_Info(", SCAM: %s", HostAdapter, (HostAdapter->SCAM_Enabled ? (HostAdapter->SCAM_Level2 ? "Enabled, Level 2" : "Enabled, Level 1") + : "Disabled")); + BusLogic_Info("\n", HostAdapter); } - } - else SynchronousMessage = - (SynchronousPermitted == 0 ? "Disabled" : "Enabled"); - WidePermitted = HostAdapter->WidePermitted & AllTargetsMask; - if (WidePermitted == 0) - WideMessage = "Disabled"; - else if (WidePermitted == AllTargetsMask) - WideMessage = "Enabled"; - else - { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - WideString[TargetID] = - ((WidePermitted & (1 << TargetID)) ? 'Y' : 'N'); - WideString[HostAdapter->SCSI_ID] = '#'; - WideString[HostAdapter->MaxTargetDevices] = '\0'; - } - DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask; - if (DisconnectPermitted == 0) - DisconnectMessage = "Disabled"; - else if (DisconnectPermitted == AllTargetsMask) - DisconnectMessage = "Enabled"; - else - { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - DisconnectString[TargetID] = - ((DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N'); - DisconnectString[HostAdapter->SCSI_ID] = '#'; - DisconnectString[HostAdapter->MaxTargetDevices] = '\0'; - } - TaggedQueuingPermitted = - HostAdapter->TaggedQueuingPermitted & AllTargetsMask; - if (TaggedQueuingPermitted == 0) - TaggedQueuingMessage = "Disabled"; - else if (TaggedQueuingPermitted == AllTargetsMask) - TaggedQueuingMessage = "Enabled"; - else - { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - TaggedQueuingString[TargetID] = - ((TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N'); - TaggedQueuingString[HostAdapter->SCSI_ID] = '#'; - TaggedQueuingString[HostAdapter->MaxTargetDevices] = '\0'; - } - BusLogic_Info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n", - HostAdapter, SynchronousMessage, WideMessage); - BusLogic_Info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", - HostAdapter, DisconnectMessage, TaggedQueuingMessage); - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - BusLogic_Info(" Scatter/Gather Limit: %d of %d segments, " - "Mailboxes: %d\n", HostAdapter, - HostAdapter->DriverScatterGatherLimit, - HostAdapter->HostAdapterScatterGatherLimit, - HostAdapter->MailboxCount); - BusLogic_Info(" Driver Queue Depth: %d, " - "Host Adapter Queue Depth: %d\n", - HostAdapter, HostAdapter->DriverQueueDepth, - HostAdapter->HostAdapterQueueDepth); - } - else BusLogic_Info(" Driver Queue Depth: %d, " - "Scatter/Gather Limit: %d segments\n", - HostAdapter, HostAdapter->DriverQueueDepth, - HostAdapter->DriverScatterGatherLimit); - BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); - CommonTaggedQueueDepth = true; - for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) - { - CommonTaggedQueueDepth = false; - break; - } - if (CommonTaggedQueueDepth) - { - if (HostAdapter->QueueDepth[0] > 0) - BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); - else BusLogic_Info("Automatic", HostAdapter); - } - else BusLogic_Info("Individual", HostAdapter); - BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, - HostAdapter->UntaggedQueueDepth); - if (HostAdapter->TerminationInfoValid) - { - if (HostAdapter->HostWideSCSI) - BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, - (HostAdapter->LowByteTerminated - ? (HostAdapter->HighByteTerminated - ? "Both Enabled" : "Low Enabled") - : (HostAdapter->HighByteTerminated - ? "High Enabled" : "Both Disabled"))); - else BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, - (HostAdapter->LowByteTerminated ? - "Enabled" : "Disabled")); - if (HostAdapter->HostSupportsSCAM) - BusLogic_Info(", SCAM: %s", HostAdapter, - (HostAdapter->SCAM_Enabled - ? (HostAdapter->SCAM_Level2 - ? "Enabled, Level 2" : "Enabled, Level 1") - : "Disabled")); - BusLogic_Info("\n", HostAdapter); - } - /* - Indicate reporting the Host Adapter configuration completed successfully. - */ - return true; + /* + Indicate reporting the Host Adapter configuration completed successfully. + */ + return true; } @@ -2259,43 +1873,34 @@ static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_Ho static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter) { - if (HostAdapter->IRQ_Channel == 0) - { - BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", - HostAdapter); - return false; - } - /* - Acquire shared access to the IRQ Channel. - */ - if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, - SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) - { - BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", - HostAdapter, HostAdapter->IRQ_Channel); - return false; - } - HostAdapter->IRQ_ChannelAcquired = true; - /* - Acquire exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_Channel > 0) - { - if (request_dma(HostAdapter->DMA_Channel, - HostAdapter->FullModelName) < 0) - { - BusLogic_Error("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", - HostAdapter, HostAdapter->DMA_Channel); - return false; + if (HostAdapter->IRQ_Channel == 0) { + BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", HostAdapter); + return false; } - set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE); - enable_dma(HostAdapter->DMA_Channel); - HostAdapter->DMA_ChannelAcquired = true; - } - /* - Indicate the System Resource Acquisition completed successfully, - */ - return true; + /* + Acquire shared access to the IRQ Channel. + */ + if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) { + BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->IRQ_Channel); + return false; + } + HostAdapter->IRQ_ChannelAcquired = true; + /* + Acquire exclusive access to the DMA Channel. + */ + if (HostAdapter->DMA_Channel > 0) { + if (request_dma(HostAdapter->DMA_Channel, HostAdapter->FullModelName) < 0) { + BusLogic_Error("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->DMA_Channel); + return false; + } + set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE); + enable_dma(HostAdapter->DMA_Channel); + HostAdapter->DMA_ChannelAcquired = true; + } + /* + Indicate the System Resource Acquisition completed successfully, + */ + return true; } @@ -2306,26 +1911,24 @@ static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *Hos static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter) { - /* - Release shared access to the IRQ Channel. - */ - if (HostAdapter->IRQ_ChannelAcquired) - free_irq(HostAdapter->IRQ_Channel, HostAdapter); - /* - Release exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_ChannelAcquired) - free_dma(HostAdapter->DMA_Channel); - /* - Release any allocated memory structs not released elsewhere - */ - if (HostAdapter->MailboxSpace) - pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, - HostAdapter->MailboxSpace, - HostAdapter->MailboxSpaceHandle); - HostAdapter->MailboxSpace = NULL; - HostAdapter->MailboxSpaceHandle = 0; - HostAdapter->MailboxSize = 0; + /* + Release shared access to the IRQ Channel. + */ + if (HostAdapter->IRQ_ChannelAcquired) + free_irq(HostAdapter->IRQ_Channel, HostAdapter); + /* + Release exclusive access to the DMA Channel. + */ + if (HostAdapter->DMA_ChannelAcquired) + free_dma(HostAdapter->DMA_Channel); + /* + Release any allocated memory structs not released elsewhere + */ + if (HostAdapter->MailboxSpace) + pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle); + HostAdapter->MailboxSpace = NULL; + HostAdapter->MailboxSpaceHandle = 0; + HostAdapter->MailboxSize = 0; } @@ -2338,114 +1941,94 @@ static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter) static boolean BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { - struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest; - enum BusLogic_RoundRobinModeRequest RoundRobinModeRequest; - enum BusLogic_SetCCBFormatRequest SetCCBFormatRequest; - int TargetID; - /* - Initialize the pointers to the first and last CCBs that are queued for - completion processing. - */ - HostAdapter->FirstCompletedCCB = NULL; - HostAdapter->LastCompletedCCB = NULL; - /* - Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active, - Command Successful Flag, Active Commands, and Commands Since Reset - for each Target Device. - */ - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; - HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; - HostAdapter->ActiveCommands[TargetID] = 0; - HostAdapter->CommandsSinceReset[TargetID] = 0; - } - /* - FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done; - /* - Initialize the Outgoing and Incoming Mailbox pointers. - */ - HostAdapter->MailboxSize = HostAdapter->MailboxCount * - (sizeof(struct BusLogic_OutgoingMailbox) + sizeof(struct BusLogic_IncomingMailbox)); - HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, - HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle); - if (HostAdapter->MailboxSpace == NULL) - return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION"); - HostAdapter->FirstOutgoingMailbox = - (struct BusLogic_OutgoingMailbox *) HostAdapter->MailboxSpace; - HostAdapter->LastOutgoingMailbox = - HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->FirstIncomingMailbox = - (struct BusLogic_IncomingMailbox *) (HostAdapter->LastOutgoingMailbox + 1); - HostAdapter->LastIncomingMailbox = - HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - - /* - Initialize the Outgoing and Incoming Mailbox structures. - */ - memset(HostAdapter->FirstOutgoingMailbox, 0, - HostAdapter->MailboxCount * sizeof(struct BusLogic_OutgoingMailbox)); - memset(HostAdapter->FirstIncomingMailbox, 0, - HostAdapter->MailboxCount * sizeof(struct BusLogic_IncomingMailbox)); - /* - Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. - */ - ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; - ExtendedMailboxRequest.BaseMailboxAddress = - (u32) HostAdapter->MailboxSpaceHandle; - if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, - &ExtendedMailboxRequest, - sizeof(ExtendedMailboxRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION"); - /* - Enable Strict Round Robin Mode if supported by the Host Adapter. In - Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing - Mailbox for each new command, rather than scanning through all the - Outgoing Mailboxes to find any that have new commands in them. Strict - Round Robin Mode is significantly more efficient. - */ - if (HostAdapter->StrictRoundRobinModeSupport) - { - RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; - if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, - &RoundRobinModeRequest, - sizeof(RoundRobinModeRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); - } - /* - For Host Adapters that support Extended LUN Format CCBs, issue the Set CCB - Format command to allow 32 Logical Units per Target Device. - */ - if (HostAdapter->ExtendedLUNSupport) - { - SetCCBFormatRequest = BusLogic_ExtendedLUNFormatCCB; - if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, - &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), - NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "SET CCB FORMAT"); - } - /* - Announce Successful Initialization. - */ -Done: - if (!HostAdapter->HostAdapterInitialized) - { - BusLogic_Info("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); - BusLogic_Info("\n", HostAdapter); - } - else BusLogic_Warning("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); - HostAdapter->HostAdapterInitialized = true; - /* - Indicate the Host Adapter Initialization completed successfully. - */ - return true; + struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest; + enum BusLogic_RoundRobinModeRequest RoundRobinModeRequest; + enum BusLogic_SetCCBFormatRequest SetCCBFormatRequest; + int TargetID; + /* + Initialize the pointers to the first and last CCBs that are queued for + completion processing. + */ + HostAdapter->FirstCompletedCCB = NULL; + HostAdapter->LastCompletedCCB = NULL; + /* + Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active, + Command Successful Flag, Active Commands, and Commands Since Reset + for each Target Device. + */ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; + HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; + HostAdapter->ActiveCommands[TargetID] = 0; + HostAdapter->CommandsSinceReset[TargetID] = 0; + } + /* + FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + goto Done; + /* + Initialize the Outgoing and Incoming Mailbox pointers. + */ + HostAdapter->MailboxSize = HostAdapter->MailboxCount * (sizeof(struct BusLogic_OutgoingMailbox) + sizeof(struct BusLogic_IncomingMailbox)); + HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle); + if (HostAdapter->MailboxSpace == NULL) + return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION"); + HostAdapter->FirstOutgoingMailbox = (struct BusLogic_OutgoingMailbox *) HostAdapter->MailboxSpace; + HostAdapter->LastOutgoingMailbox = HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; + HostAdapter->FirstIncomingMailbox = (struct BusLogic_IncomingMailbox *) (HostAdapter->LastOutgoingMailbox + 1); + HostAdapter->LastIncomingMailbox = HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; + + /* + Initialize the Outgoing and Incoming Mailbox structures. + */ + memset(HostAdapter->FirstOutgoingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_OutgoingMailbox)); + memset(HostAdapter->FirstIncomingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_IncomingMailbox)); + /* + Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. + */ + ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; + ExtendedMailboxRequest.BaseMailboxAddress = (u32) HostAdapter->MailboxSpaceHandle; + if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, &ExtendedMailboxRequest, sizeof(ExtendedMailboxRequest), NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION"); + /* + Enable Strict Round Robin Mode if supported by the Host Adapter. In + Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing + Mailbox for each new command, rather than scanning through all the + Outgoing Mailboxes to find any that have new commands in them. Strict + Round Robin Mode is significantly more efficient. + */ + if (HostAdapter->StrictRoundRobinModeSupport) { + RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; + if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, &RoundRobinModeRequest, sizeof(RoundRobinModeRequest), NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); + } + /* + For Host Adapters that support Extended LUN Format CCBs, issue the Set CCB + Format command to allow 32 Logical Units per Target Device. + */ + if (HostAdapter->ExtendedLUNSupport) { + SetCCBFormatRequest = BusLogic_ExtendedLUNFormatCCB; + if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "SET CCB FORMAT"); + } + /* + Announce Successful Initialization. + */ + Done: + if (!HostAdapter->HostAdapterInitialized) { + BusLogic_Info("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName); + BusLogic_Info("\n", HostAdapter); + } else + BusLogic_Warning("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName); + HostAdapter->HostAdapterInitialized = true; + /* + Indicate the Host Adapter Initialization completed successfully. + */ + return true; } @@ -2457,127 +2040,106 @@ Done: static boolean __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter *HostAdapter) { - u16 InstalledDevices; - u8 InstalledDevicesID0to7[8]; - struct BusLogic_SetupInformation SetupInformation; - u8 SynchronousPeriod[BusLogic_MaxTargetDevices]; - unsigned char RequestedReplyLength; - int TargetID; - /* - Wait a few seconds between the Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get - confused if they receive SCSI Commands too soon after a SCSI Bus Reset. - */ - BusLogic_Delay(HostAdapter->BusSettleTime); - /* - FlashPoint Host Adapters do not provide for Target Device Inquiry. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Inhibit the Target Device Inquiry if requested. - */ - if (HostAdapter->DriverOptions != NULL && - HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) - return true; - /* - Issue the Inquire Target Devices command for host adapters with firmware - version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command - for older host adapters. This is necessary to force Synchronous Transfer - Negotiation so that the Inquire Setup Information and Inquire Synchronous - Period commands will return valid data. The Inquire Target Devices command - is preferable to Inquire Installed Devices ID 0 to 7 since it only probes - Logical Unit 0 of each Target Device. - */ - if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) - { - - /* - * Issue a Inquire Target Devices command. Inquire Target Devices only - * tests Logical Unit 0 of each Target Device unlike the Inquire Installed - * Devices commands which test Logical Units 0 - 7. Two bytes are - * returned, where byte 0 bit 0 set indicates that Target Device 0 exists, - * and so on. - */ - - if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, - &InstalledDevices, sizeof(InstalledDevices)) - != sizeof(InstalledDevices)) - return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->TargetFlags[TargetID].TargetExists = - (InstalledDevices & (1 << TargetID) ? true : false); - } - else - { - - /* - * Issue an Inquire Installed Devices command. For each Target Device, - * a byte is returned where bit 0 set indicates that Logical Unit 0 - * exists, bit 1 set indicates that Logical Unit 1 exists, and so on. - */ - - if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, - NULL, 0, &InstalledDevicesID0to7, - sizeof(InstalledDevicesID0to7)) - != sizeof(InstalledDevicesID0to7)) - return BusLogic_Failure(HostAdapter, - "INQUIRE INSTALLED DEVICES ID 0 TO 7"); - for (TargetID = 0; TargetID < 8; TargetID++) - HostAdapter->TargetFlags[TargetID].TargetExists = - (InstalledDevicesID0to7[TargetID] != 0 ? true : false); - } - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->SynchronousOffset[TargetID] = - (TargetID < 8 - ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset - : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset); - if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->TargetFlags[TargetID].WideTransfersActive = - (TargetID < 8 - ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) - ? true : false) - : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8)) - ? true : false)); - /* - Issue the Inquire Synchronous Period command. - */ - if (HostAdapter->FirmwareVersion[0] >= '3') - { - - /* Issue a Inquire Synchronous Period command. For each Target Device, - * a byte is returned which represents the Synchronous Transfer Period - * in units of 10 nanoseconds. - */ - - RequestedReplyLength = sizeof(SynchronousPeriod); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SynchronousPeriod, sizeof(SynchronousPeriod)) - != sizeof(SynchronousPeriod)) - return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; - } - else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) - HostAdapter->SynchronousPeriod[TargetID] = - 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] - .TransferPeriod; - /* - Indicate the Target Device Inquiry completed successfully. - */ - return true; + u16 InstalledDevices; + u8 InstalledDevicesID0to7[8]; + struct BusLogic_SetupInformation SetupInformation; + u8 SynchronousPeriod[BusLogic_MaxTargetDevices]; + unsigned char RequestedReplyLength; + int TargetID; + /* + Wait a few seconds between the Host Adapter Hard Reset which initiates + a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get + confused if they receive SCSI Commands too soon after a SCSI Bus Reset. + */ + BusLogic_Delay(HostAdapter->BusSettleTime); + /* + FlashPoint Host Adapters do not provide for Target Device Inquiry. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + return true; + /* + Inhibit the Target Device Inquiry if requested. + */ + if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) + return true; + /* + Issue the Inquire Target Devices command for host adapters with firmware + version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command + for older host adapters. This is necessary to force Synchronous Transfer + Negotiation so that the Inquire Setup Information and Inquire Synchronous + Period commands will return valid data. The Inquire Target Devices command + is preferable to Inquire Installed Devices ID 0 to 7 since it only probes + Logical Unit 0 of each Target Device. + */ + if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) { + + /* + * Issue a Inquire Target Devices command. Inquire Target Devices only + * tests Logical Unit 0 of each Target Device unlike the Inquire Installed + * Devices commands which test Logical Units 0 - 7. Two bytes are + * returned, where byte 0 bit 0 set indicates that Target Device 0 exists, + * and so on. + */ + + if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, &InstalledDevices, sizeof(InstalledDevices)) + != sizeof(InstalledDevices)) + return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevices & (1 << TargetID) ? true : false); + } else { + + /* + * Issue an Inquire Installed Devices command. For each Target Device, + * a byte is returned where bit 0 set indicates that Logical Unit 0 + * exists, bit 1 set indicates that Logical Unit 1 exists, and so on. + */ + + if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, NULL, 0, &InstalledDevicesID0to7, sizeof(InstalledDevicesID0to7)) + != sizeof(InstalledDevicesID0to7)) + return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7"); + for (TargetID = 0; TargetID < 8; TargetID++) + HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevicesID0to7[TargetID] != 0 ? true : false); + } + /* + Issue the Inquire Setup Information command. + */ + RequestedReplyLength = sizeof(SetupInformation); + if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation)) + != sizeof(SetupInformation)) + return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousOffset[TargetID] = (TargetID < 8 ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset : SetupInformation.SynchronousValuesID8to15[TargetID - 8].Offset); + if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].WideTransfersActive = (TargetID < 8 ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) + ? true : false) + : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID - 8)) + ? true : false)); + /* + Issue the Inquire Synchronous Period command. + */ + if (HostAdapter->FirmwareVersion[0] >= '3') { + + /* Issue a Inquire Synchronous Period command. For each Target Device, + * a byte is returned which represents the Synchronous Transfer Period + * in units of 10 nanoseconds. + */ + + RequestedReplyLength = sizeof(SynchronousPeriod); + if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, &RequestedReplyLength, sizeof(RequestedReplyLength), &SynchronousPeriod, sizeof(SynchronousPeriod)) + != sizeof(SynchronousPeriod)) + return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; + } else + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) + HostAdapter->SynchronousPeriod[TargetID] = 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] + .TransferPeriod; + /* + Indicate the Target Device Inquiry completed successfully. + */ + return true; } /* @@ -2590,18 +2152,17 @@ static boolean __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter */ static void __init BusLogic_InitializeHostStructure(struct BusLogic_HostAdapter - *HostAdapter, - struct Scsi_Host *Host) + *HostAdapter, struct Scsi_Host *Host) { - Host->max_id = HostAdapter->MaxTargetDevices; - Host->max_lun = HostAdapter->MaxLogicalUnits; - Host->max_channel = 0; - Host->unique_id = HostAdapter->IO_Address; - Host->this_id = HostAdapter->SCSI_ID; - Host->can_queue = HostAdapter->DriverQueueDepth; - Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit; - Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired; - Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth; + Host->max_id = HostAdapter->MaxTargetDevices; + Host->max_lun = HostAdapter->MaxLogicalUnits; + Host->max_channel = 0; + Host->unique_id = HostAdapter->IO_Address; + Host->this_id = HostAdapter->SCSI_ID; + Host->can_queue = HostAdapter->DriverQueueDepth; + Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit; + Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired; + Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth; } /* @@ -2614,38 +2175,29 @@ static void __init BusLogic_InitializeHostStructure(struct BusLogic_HostAdapter */ static int BusLogic_SlaveConfigure(struct scsi_device *Device) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Device->host->hostdata; - int TargetID = Device->id; - int QueueDepth = HostAdapter->QueueDepth[TargetID]; - - if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && - (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) - { - if (QueueDepth == 0) - QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth); - } - else - { - HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); - QueueDepth = HostAdapter->UntaggedQueueDepth; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - scsi_adjust_queue_depth(Device, 0, QueueDepth); - } - QueueDepth = 0; - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->TargetFlags[TargetID].TargetExists) - { - QueueDepth += HostAdapter->QueueDepth[TargetID]; - } - if (QueueDepth > HostAdapter->AllocatedCCBs) - BusLogic_CreateAdditionalCCBs(HostAdapter, - QueueDepth - - HostAdapter->AllocatedCCBs, - false); - return 0; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Device->host->hostdata; + int TargetID = Device->id; + int QueueDepth = HostAdapter->QueueDepth[TargetID]; + + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { + if (QueueDepth == 0) + QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth); + } else { + HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); + QueueDepth = HostAdapter->UntaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + scsi_adjust_queue_depth(Device, 0, QueueDepth); + } + QueueDepth = 0; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists) { + QueueDepth += HostAdapter->QueueDepth[TargetID]; + } + if (QueueDepth > HostAdapter->AllocatedCCBs) + BusLogic_CreateAdditionalCCBs(HostAdapter, QueueDepth - HostAdapter->AllocatedCCBs, false); + return 0; } /* @@ -2658,162 +2210,145 @@ static int BusLogic_SlaveConfigure(struct scsi_device *Device) static int __init BusLogic_DetectHostAdapter(struct scsi_host_template *HostTemplate) { - int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; - struct BusLogic_HostAdapter *PrototypeHostAdapter; - if (BusLogic_ProbeOptions.NoProbe) return 0; - BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *) - kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), - GFP_ATOMIC); - if (BusLogic_ProbeInfoList == NULL) - { - BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); - return 0; - } - memset(BusLogic_ProbeInfoList, 0, - BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo)); - PrototypeHostAdapter = (struct BusLogic_HostAdapter *) - kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC); - if (PrototypeHostAdapter == NULL) - { - kfree(BusLogic_ProbeInfoList); - BusLogic_Error("BusLogic: Unable to allocate Prototype " - "Host Adapter\n", NULL); - return 0; - } - memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); + int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; + struct BusLogic_HostAdapter *PrototypeHostAdapter; + if (BusLogic_ProbeOptions.NoProbe) + return 0; + BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *) + kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_ATOMIC); + if (BusLogic_ProbeInfoList == NULL) { + BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); + return 0; + } + memset(BusLogic_ProbeInfoList, 0, BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo)); + PrototypeHostAdapter = (struct BusLogic_HostAdapter *) + kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC); + if (PrototypeHostAdapter == NULL) { + kfree(BusLogic_ProbeInfoList); + BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL); + return 0; + } + memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); #ifdef MODULE - if (BusLogic != NULL) - BusLogic_Setup(BusLogic); + if (BusLogic != NULL) + BusLogic_Setup(BusLogic); #endif - BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); - for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) - { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct Scsi_Host *Host; - if (ProbeInfo->IO_Address == 0) continue; - memset(HostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); - HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; - HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; - HostAdapter->IO_Address = ProbeInfo->IO_Address; - HostAdapter->PCI_Address = ProbeInfo->PCI_Address; - HostAdapter->Bus = ProbeInfo->Bus; - HostAdapter->Device = ProbeInfo->Device; - HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; - HostAdapter->AddressCount = - BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; - /* - Probe the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_ProbeHostAdapter(HostAdapter)) continue; - /* - Hard Reset the Host Adapter. If unsuccessful, abort further - initialization. - */ - if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue; - /* - Check the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_CheckHostAdapter(HostAdapter)) continue; - /* - Initialize the Driver Options field if provided. - */ - if (DriverOptionsIndex < BusLogic_DriverOptionsCount) - HostAdapter->DriverOptions = - &BusLogic_DriverOptions[DriverOptionsIndex++]; - /* - Announce the Driver Version and Date, Author's Name, Copyright Notice, - and Electronic Mail Address. - */ - BusLogic_AnnounceDriver(HostAdapter); - /* - Register usage of the I/O Address range. From this point onward, any - failure will be assumed to be due to a problem with the Host Adapter, - rather than due to having mistakenly identified this port as belonging - to a BusLogic Host Adapter. The I/O Address range will not be - released, thereby preventing it from being incorrectly identified as - any other type of Host Adapter. - */ - if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, - "BusLogic")) continue; - /* - Register the SCSI Host structure. - */ - - Host = scsi_host_alloc(HostTemplate, sizeof(struct BusLogic_HostAdapter)); - if(Host==NULL) - { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - continue; - } - HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; - memcpy(HostAdapter, PrototypeHostAdapter, sizeof(struct BusLogic_HostAdapter)); - HostAdapter->SCSI_Host = Host; - HostAdapter->HostNumber = Host->host_no; - /* - Add Host Adapter to the end of the list of registered BusLogic - Host Adapters. - */ - BusLogic_RegisterHostAdapter(HostAdapter); - /* - Read the Host Adapter Configuration, Configure the Host Adapter, - Acquire the System Resources necessary to use the Host Adapter, then - Create the Initial CCBs, Initialize the Host Adapter, and finally - perform Target Device Inquiry. - */ - if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && - BusLogic_ReportHostAdapterConfiguration(HostAdapter) && - BusLogic_AcquireResources(HostAdapter) && - BusLogic_CreateInitialCCBs(HostAdapter) && - BusLogic_InitializeHostAdapter(HostAdapter) && - BusLogic_TargetDeviceInquiry(HostAdapter)) - { - /* - Initialization has been completed successfully. Release and - re-register usage of the I/O Address range so that the Model - Name of the Host Adapter will appear, and initialize the SCSI - Host structure. - */ - release_region(HostAdapter->IO_Address, - HostAdapter->AddressCount); - if(!request_region(HostAdapter->IO_Address, - HostAdapter->AddressCount, - HostAdapter->FullModelName)) { - printk(KERN_WARNING "BusLogic: Release and re-register of " - "port 0x%04lx failed \n", - (unsigned long)HostAdapter->IO_Address); - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - BusLogic_UnregisterHostAdapter(HostAdapter); - scsi_host_put(Host); - } - else { - BusLogic_InitializeHostStructure(HostAdapter, Host); - scsi_add_host(Host, NULL); - scsi_scan_host(Host); - BusLogicHostAdapterCount++; - } - } - else - { - /* - An error occurred during Host Adapter Configuration Querying, Host - Adapter Configuration, Resource Acquisition, CCB Creation, Host - Adapter Initialization, or Target Device Inquiry, so remove Host - Adapter from the list of registered BusLogic Host Adapters, destroy - the CCBs, Release the System Resources, and Unregister the SCSI - Host. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - BusLogic_UnregisterHostAdapter(HostAdapter); - scsi_host_put(Host); + BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); + for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) { + struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; + struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; + struct Scsi_Host *Host; + if (ProbeInfo->IO_Address == 0) + continue; + memset(HostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); + HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; + HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; + HostAdapter->IO_Address = ProbeInfo->IO_Address; + HostAdapter->PCI_Address = ProbeInfo->PCI_Address; + HostAdapter->Bus = ProbeInfo->Bus; + HostAdapter->Device = ProbeInfo->Device; + HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; + HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; + /* + Probe the Host Adapter. If unsuccessful, abort further initialization. + */ + if (!BusLogic_ProbeHostAdapter(HostAdapter)) + continue; + /* + Hard Reset the Host Adapter. If unsuccessful, abort further + initialization. + */ + if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) + continue; + /* + Check the Host Adapter. If unsuccessful, abort further initialization. + */ + if (!BusLogic_CheckHostAdapter(HostAdapter)) + continue; + /* + Initialize the Driver Options field if provided. + */ + if (DriverOptionsIndex < BusLogic_DriverOptionsCount) + HostAdapter->DriverOptions = &BusLogic_DriverOptions[DriverOptionsIndex++]; + /* + Announce the Driver Version and Date, Author's Name, Copyright Notice, + and Electronic Mail Address. + */ + BusLogic_AnnounceDriver(HostAdapter); + /* + Register usage of the I/O Address range. From this point onward, any + failure will be assumed to be due to a problem with the Host Adapter, + rather than due to having mistakenly identified this port as belonging + to a BusLogic Host Adapter. The I/O Address range will not be + released, thereby preventing it from being incorrectly identified as + any other type of Host Adapter. + */ + if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic")) + continue; + /* + Register the SCSI Host structure. + */ + + Host = scsi_host_alloc(HostTemplate, sizeof(struct BusLogic_HostAdapter)); + if (Host == NULL) { + release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + continue; + } + HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; + memcpy(HostAdapter, PrototypeHostAdapter, sizeof(struct BusLogic_HostAdapter)); + HostAdapter->SCSI_Host = Host; + HostAdapter->HostNumber = Host->host_no; + /* + Add Host Adapter to the end of the list of registered BusLogic + Host Adapters. + */ + BusLogic_RegisterHostAdapter(HostAdapter); + /* + Read the Host Adapter Configuration, Configure the Host Adapter, + Acquire the System Resources necessary to use the Host Adapter, then + Create the Initial CCBs, Initialize the Host Adapter, and finally + perform Target Device Inquiry. + */ + if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && + BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) { + /* + Initialization has been completed successfully. Release and + re-register usage of the I/O Address range so that the Model + Name of the Host Adapter will appear, and initialize the SCSI + Host structure. + */ + release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) { + printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address); + BusLogic_DestroyCCBs(HostAdapter); + BusLogic_ReleaseResources(HostAdapter); + BusLogic_UnregisterHostAdapter(HostAdapter); + scsi_host_put(Host); + } else { + BusLogic_InitializeHostStructure(HostAdapter, Host); + scsi_add_host(Host, NULL); + scsi_scan_host(Host); + BusLogicHostAdapterCount++; + } + } else { + /* + An error occurred during Host Adapter Configuration Querying, Host + Adapter Configuration, Resource Acquisition, CCB Creation, Host + Adapter Initialization, or Target Device Inquiry, so remove Host + Adapter from the list of registered BusLogic Host Adapters, destroy + the CCBs, Release the System Resources, and Unregister the SCSI + Host. + */ + BusLogic_DestroyCCBs(HostAdapter); + BusLogic_ReleaseResources(HostAdapter); + BusLogic_UnregisterHostAdapter(HostAdapter); + scsi_host_put(Host); + } } - } - kfree(PrototypeHostAdapter); - kfree(BusLogic_ProbeInfoList); - BusLogic_ProbeInfoList = NULL; - return BusLogicHostAdapterCount; + kfree(PrototypeHostAdapter); + kfree(BusLogic_ProbeInfoList); + BusLogic_ProbeInfoList = NULL; + return BusLogicHostAdapterCount; } @@ -2825,29 +2360,28 @@ static int __init BusLogic_DetectHostAdapter(struct scsi_host_template *HostTemp static int __exit BusLogic_ReleaseHostAdapter(struct Scsi_Host *Host) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Host->hostdata; - /* - FlashPoint Host Adapters must first be released by the FlashPoint - SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); - /* - Destroy the CCBs and release any system resources acquired to - support Host Adapter. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - /* - Release usage of the I/O Address range. - */ - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - /* - Remove Host Adapter from the list of registered BusLogic Host Adapters. - */ - BusLogic_UnregisterHostAdapter(HostAdapter); - return 0; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; + /* + FlashPoint Host Adapters must first be released by the FlashPoint + SCCB Manager. + */ + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); + /* + Destroy the CCBs and release any system resources acquired to + support Host Adapter. + */ + BusLogic_DestroyCCBs(HostAdapter); + BusLogic_ReleaseResources(HostAdapter); + /* + Release usage of the I/O Address range. + */ + release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + /* + Remove Host Adapter from the list of registered BusLogic Host Adapters. + */ + BusLogic_UnregisterHostAdapter(HostAdapter); + return 0; } @@ -2857,20 +2391,17 @@ static int __exit BusLogic_ReleaseHostAdapter(struct Scsi_Host *Host) static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *CCB) { - struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; - CCB->Status = BusLogic_CCB_Completed; - CCB->Next = NULL; - if (HostAdapter->FirstCompletedCCB == NULL) - { - HostAdapter->FirstCompletedCCB = CCB; - HostAdapter->LastCompletedCCB = CCB; - } - else - { - HostAdapter->LastCompletedCCB->Next = CCB; - HostAdapter->LastCompletedCCB = CCB; - } - HostAdapter->ActiveCommands[CCB->TargetID]--; + struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; + CCB->Status = BusLogic_CCB_Completed; + CCB->Next = NULL; + if (HostAdapter->FirstCompletedCCB == NULL) { + HostAdapter->FirstCompletedCCB = CCB; + HostAdapter->LastCompletedCCB = CCB; + } else { + HostAdapter->LastCompletedCCB->Next = CCB; + HostAdapter->LastCompletedCCB = CCB; + } + HostAdapter->ActiveCommands[CCB->TargetID]--; } @@ -2879,57 +2410,50 @@ static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *CCB) the Host Adapter Status and Target Device Status. */ -static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, - enum BusLogic_HostAdapterStatus - HostAdapterStatus, - enum BusLogic_TargetDeviceStatus - TargetDeviceStatus) +static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_HostAdapterStatus HostAdapterStatus, enum BusLogic_TargetDeviceStatus TargetDeviceStatus) { - int HostStatus; - switch (HostAdapterStatus) - { - case BusLogic_CommandCompletedNormally: - case BusLogic_LinkedCommandCompleted: - case BusLogic_LinkedCommandCompletedWithFlag: - HostStatus = DID_OK; - break; - case BusLogic_SCSISelectionTimeout: - HostStatus = DID_TIME_OUT; - break; - case BusLogic_InvalidOutgoingMailboxActionCode: - case BusLogic_InvalidCommandOperationCode: - case BusLogic_InvalidCommandParameter: - BusLogic_Warning("BusLogic Driver Protocol Error 0x%02X\n", - HostAdapter, HostAdapterStatus); - case BusLogic_DataUnderRun: - case BusLogic_DataOverRun: - case BusLogic_UnexpectedBusFree: - case BusLogic_LinkedCCBhasInvalidLUN: - case BusLogic_AutoRequestSenseFailed: - case BusLogic_TaggedQueuingMessageRejected: - case BusLogic_UnsupportedMessageReceived: - case BusLogic_HostAdapterHardwareFailed: - case BusLogic_TargetDeviceReconnectedImproperly: - case BusLogic_AbortQueueGenerated: - case BusLogic_HostAdapterSoftwareError: - case BusLogic_HostAdapterHardwareTimeoutError: - case BusLogic_SCSIParityErrorDetected: - HostStatus = DID_ERROR; - break; - case BusLogic_InvalidBusPhaseRequested: - case BusLogic_TargetFailedResponseToATN: - case BusLogic_HostAdapterAssertedRST: - case BusLogic_OtherDeviceAssertedRST: - case BusLogic_HostAdapterAssertedBusDeviceReset: - HostStatus = DID_RESET; - break; - default: - BusLogic_Warning("Unknown Host Adapter Status 0x%02X\n", - HostAdapter, HostAdapterStatus); - HostStatus = DID_ERROR; - break; - } - return (HostStatus << 16) | TargetDeviceStatus; + int HostStatus; + switch (HostAdapterStatus) { + case BusLogic_CommandCompletedNormally: + case BusLogic_LinkedCommandCompleted: + case BusLogic_LinkedCommandCompletedWithFlag: + HostStatus = DID_OK; + break; + case BusLogic_SCSISelectionTimeout: + HostStatus = DID_TIME_OUT; + break; + case BusLogic_InvalidOutgoingMailboxActionCode: + case BusLogic_InvalidCommandOperationCode: + case BusLogic_InvalidCommandParameter: + BusLogic_Warning("BusLogic Driver Protocol Error 0x%02X\n", HostAdapter, HostAdapterStatus); + case BusLogic_DataUnderRun: + case BusLogic_DataOverRun: + case BusLogic_UnexpectedBusFree: + case BusLogic_LinkedCCBhasInvalidLUN: + case BusLogic_AutoRequestSenseFailed: + case BusLogic_TaggedQueuingMessageRejected: + case BusLogic_UnsupportedMessageReceived: + case BusLogic_HostAdapterHardwareFailed: + case BusLogic_TargetDeviceReconnectedImproperly: + case BusLogic_AbortQueueGenerated: + case BusLogic_HostAdapterSoftwareError: + case BusLogic_HostAdapterHardwareTimeoutError: + case BusLogic_SCSIParityErrorDetected: + HostStatus = DID_ERROR; + break; + case BusLogic_InvalidBusPhaseRequested: + case BusLogic_TargetFailedResponseToATN: + case BusLogic_HostAdapterAssertedRST: + case BusLogic_OtherDeviceAssertedRST: + case BusLogic_HostAdapterAssertedBusDeviceReset: + HostStatus = DID_RESET; + break; + default: + BusLogic_Warning("Unknown Host Adapter Status 0x%02X\n", HostAdapter, HostAdapterStatus); + HostStatus = DID_ERROR; + break; + } + return (HostStatus << 16) | TargetDeviceStatus; } @@ -2940,62 +2464,51 @@ static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, static void BusLogic_ScanIncomingMailboxes(struct BusLogic_HostAdapter *HostAdapter) { - /* - Scan through the Incoming Mailboxes in Strict Round Robin fashion, saving - any completed CCBs for further processing. It is essential that for each - CCB and SCSI Command issued, command completion processing is performed - exactly once. Therefore, only Incoming Mailboxes with completion code - Command Completed Without Error, Command Completed With Error, or Command - Aborted At Host Request are saved for completion processing. When an - Incoming Mailbox has a completion code of Aborted Command Not Found, the - CCB had already completed or been aborted before the current Abort request - was processed, and so completion processing has already occurred and no - further action should be taken. - */ - struct BusLogic_IncomingMailbox *NextIncomingMailbox = - HostAdapter->NextIncomingMailbox; - enum BusLogic_CompletionCode CompletionCode; - while ((CompletionCode = NextIncomingMailbox->CompletionCode) != - BusLogic_IncomingMailboxFree) - { - /* - We are only allowed to do this because we limit our architectures we - run on to machines where bus_to_virt() actually works. There *needs* - to be a dma_addr_to_virt() in the new PCI DMA mapping interface to - replace bus_to_virt() or else this code is going to become very - innefficient. - */ - struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) - Bus_to_Virtual(NextIncomingMailbox->CCB); - if (CompletionCode != BusLogic_AbortedCommandNotFound) - { - if (CCB->Status == BusLogic_CCB_Active || - CCB->Status == BusLogic_CCB_Reset) - { - /* - Save the Completion Code for this CCB and queue the CCB - for completion processing. - */ - CCB->CompletionCode = CompletionCode; - BusLogic_QueueCompletedCCB(CCB); - } - else - { - /* - If a CCB ever appears in an Incoming Mailbox and is not marked - as status Active or Reset, then there is most likely a bug in - the Host Adapter firmware. - */ - BusLogic_Warning("Illegal CCB #%ld status %d in " - "Incoming Mailbox\n", HostAdapter, - CCB->SerialNumber, CCB->Status); - } + /* + Scan through the Incoming Mailboxes in Strict Round Robin fashion, saving + any completed CCBs for further processing. It is essential that for each + CCB and SCSI Command issued, command completion processing is performed + exactly once. Therefore, only Incoming Mailboxes with completion code + Command Completed Without Error, Command Completed With Error, or Command + Aborted At Host Request are saved for completion processing. When an + Incoming Mailbox has a completion code of Aborted Command Not Found, the + CCB had already completed or been aborted before the current Abort request + was processed, and so completion processing has already occurred and no + further action should be taken. + */ + struct BusLogic_IncomingMailbox *NextIncomingMailbox = HostAdapter->NextIncomingMailbox; + enum BusLogic_CompletionCode CompletionCode; + while ((CompletionCode = NextIncomingMailbox->CompletionCode) != BusLogic_IncomingMailboxFree) { + /* + We are only allowed to do this because we limit our architectures we + run on to machines where bus_to_virt() actually works. There *needs* + to be a dma_addr_to_virt() in the new PCI DMA mapping interface to + replace bus_to_virt() or else this code is going to become very + innefficient. + */ + struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) Bus_to_Virtual(NextIncomingMailbox->CCB); + if (CompletionCode != BusLogic_AbortedCommandNotFound) { + if (CCB->Status == BusLogic_CCB_Active || CCB->Status == BusLogic_CCB_Reset) { + /* + Save the Completion Code for this CCB and queue the CCB + for completion processing. + */ + CCB->CompletionCode = CompletionCode; + BusLogic_QueueCompletedCCB(CCB); + } else { + /* + If a CCB ever appears in an Incoming Mailbox and is not marked + as status Active or Reset, then there is most likely a bug in + the Host Adapter firmware. + */ + BusLogic_Warning("Illegal CCB #%ld status %d in " "Incoming Mailbox\n", HostAdapter, CCB->SerialNumber, CCB->Status); + } + } + NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; + if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) + NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; } - NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; - if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) - NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - } - HostAdapter->NextIncomingMailbox = NextIncomingMailbox; + HostAdapter->NextIncomingMailbox = NextIncomingMailbox; } @@ -3008,153 +2521,126 @@ static void BusLogic_ScanIncomingMailboxes(struct BusLogic_HostAdapter *HostAdap static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapter) { - if (HostAdapter->ProcessCompletedCCBsActive) return; - HostAdapter->ProcessCompletedCCBsActive = true; - while (HostAdapter->FirstCompletedCCB != NULL) - { - struct BusLogic_CCB *CCB = HostAdapter->FirstCompletedCCB; - struct scsi_cmnd *Command = CCB->Command; - HostAdapter->FirstCompletedCCB = CCB->Next; - if (HostAdapter->FirstCompletedCCB == NULL) - HostAdapter->LastCompletedCCB = NULL; - /* - Process the Completed CCB. - */ - if (CCB->Opcode == BusLogic_BusDeviceReset) - { - int TargetID = CCB->TargetID; - BusLogic_Warning("Bus Device Reset CCB #%ld to Target " - "%d Completed\n", HostAdapter, - CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); - HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; - HostAdapter->CommandsSinceReset[TargetID] = 0; - HostAdapter->LastResetCompleted[TargetID] = jiffies; - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); -#if 0 /* this needs to be redone different for new EH */ - /* - Bus Device Reset CCBs have the Command field non-NULL only when a - Bus Device Reset was requested for a Command that did not have a - currently active CCB in the Host Adapter (i.e., a Synchronous - Bus Device Reset), and hence would not have its Completion Routine - called otherwise. - */ - while (Command != NULL) - { - struct scsi_cmnd *NextCommand = Command->reset_chain; - Command->reset_chain = NULL; - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - Command = NextCommand; - } + if (HostAdapter->ProcessCompletedCCBsActive) + return; + HostAdapter->ProcessCompletedCCBsActive = true; + while (HostAdapter->FirstCompletedCCB != NULL) { + struct BusLogic_CCB *CCB = HostAdapter->FirstCompletedCCB; + struct scsi_cmnd *Command = CCB->Command; + HostAdapter->FirstCompletedCCB = CCB->Next; + if (HostAdapter->FirstCompletedCCB == NULL) + HostAdapter->LastCompletedCCB = NULL; + /* + Process the Completed CCB. + */ + if (CCB->Opcode == BusLogic_BusDeviceReset) { + int TargetID = CCB->TargetID; + BusLogic_Warning("Bus Device Reset CCB #%ld to Target " "%d Completed\n", HostAdapter, CCB->SerialNumber, TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; + HostAdapter->CommandsSinceReset[TargetID] = 0; + HostAdapter->LastResetCompleted[TargetID] = jiffies; + /* + Place CCB back on the Host Adapter's free list. + */ + BusLogic_DeallocateCCB(CCB); +#if 0 /* this needs to be redone different for new EH */ + /* + Bus Device Reset CCBs have the Command field non-NULL only when a + Bus Device Reset was requested for a Command that did not have a + currently active CCB in the Host Adapter (i.e., a Synchronous + Bus Device Reset), and hence would not have its Completion Routine + called otherwise. + */ + while (Command != NULL) { + struct scsi_cmnd *NextCommand = Command->reset_chain; + Command->reset_chain = NULL; + Command->result = DID_RESET << 16; + Command->scsi_done(Command); + Command = NextCommand; + } #endif - /* - Iterate over the CCBs for this Host Adapter performing completion - processing for any CCBs marked as Reset for this Target. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID) - { - Command = CCB->Command; - BusLogic_DeallocateCCB(CCB); - HostAdapter->ActiveCommands[TargetID]--; - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - } - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - } - else - { - /* - Translate the Completion Code, Host Adapter Status, and Target - Device Status into a SCSI Subsystem Result Code. - */ - switch (CCB->CompletionCode) - { - case BusLogic_IncomingMailboxFree: - case BusLogic_AbortedCommandNotFound: - case BusLogic_InvalidCCB: - BusLogic_Warning("CCB #%ld to Target %d Impossible State\n", - HostAdapter, CCB->SerialNumber, CCB->TargetID); - break; - case BusLogic_CommandCompletedWithoutError: - HostAdapter->TargetStatistics[CCB->TargetID] - .CommandsCompleted++; - HostAdapter->TargetFlags[CCB->TargetID] - .CommandSuccessfulFlag = true; - Command->result = DID_OK << 16; - break; - case BusLogic_CommandAbortedAtHostRequest: - BusLogic_Warning("CCB #%ld to Target %d Aborted\n", - HostAdapter, CCB->SerialNumber, CCB->TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[CCB->TargetID] - .CommandAbortsCompleted); - Command->result = DID_ABORT << 16; - break; - case BusLogic_CommandCompletedWithError: - Command->result = - BusLogic_ComputeResultCode(HostAdapter, - CCB->HostAdapterStatus, - CCB->TargetDeviceStatus); - if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) - { - HostAdapter->TargetStatistics[CCB->TargetID] - .CommandsCompleted++; - if (BusLogic_GlobalOptions.TraceErrors) - { - int i; - BusLogic_Notice("CCB #%ld Target %d: Result %X Host " - "Adapter Status %02X " - "Target Status %02X\n", - HostAdapter, CCB->SerialNumber, - CCB->TargetID, Command->result, - CCB->HostAdapterStatus, - CCB->TargetDeviceStatus); - BusLogic_Notice("CDB ", HostAdapter); - for (i = 0; i < CCB->CDB_Length; i++) - BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]); - BusLogic_Notice("\n", HostAdapter); - BusLogic_Notice("Sense ", HostAdapter); - for (i = 0; i < CCB->SenseDataLength; i++) - BusLogic_Notice(" %02X", HostAdapter, - Command->sense_buffer[i]); - BusLogic_Notice("\n", HostAdapter); - } + /* + Iterate over the CCBs for this Host Adapter performing completion + processing for any CCBs marked as Reset for this Target. + */ + for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) + if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID) { + Command = CCB->Command; + BusLogic_DeallocateCCB(CCB); + HostAdapter->ActiveCommands[TargetID]--; + Command->result = DID_RESET << 16; + Command->scsi_done(Command); + } + HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; + } else { + /* + Translate the Completion Code, Host Adapter Status, and Target + Device Status into a SCSI Subsystem Result Code. + */ + switch (CCB->CompletionCode) { + case BusLogic_IncomingMailboxFree: + case BusLogic_AbortedCommandNotFound: + case BusLogic_InvalidCCB: + BusLogic_Warning("CCB #%ld to Target %d Impossible State\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); + break; + case BusLogic_CommandCompletedWithoutError: + HostAdapter->TargetStatistics[CCB->TargetID] + .CommandsCompleted++; + HostAdapter->TargetFlags[CCB->TargetID] + .CommandSuccessfulFlag = true; + Command->result = DID_OK << 16; + break; + case BusLogic_CommandAbortedAtHostRequest: + BusLogic_Warning("CCB #%ld to Target %d Aborted\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[CCB->TargetID] + .CommandAbortsCompleted); + Command->result = DID_ABORT << 16; + break; + case BusLogic_CommandCompletedWithError: + Command->result = BusLogic_ComputeResultCode(HostAdapter, CCB->HostAdapterStatus, CCB->TargetDeviceStatus); + if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) { + HostAdapter->TargetStatistics[CCB->TargetID] + .CommandsCompleted++; + if (BusLogic_GlobalOptions.TraceErrors) { + int i; + BusLogic_Notice("CCB #%ld Target %d: Result %X Host " + "Adapter Status %02X " "Target Status %02X\n", HostAdapter, CCB->SerialNumber, CCB->TargetID, Command->result, CCB->HostAdapterStatus, CCB->TargetDeviceStatus); + BusLogic_Notice("CDB ", HostAdapter); + for (i = 0; i < CCB->CDB_Length; i++) + BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]); + BusLogic_Notice("\n", HostAdapter); + BusLogic_Notice("Sense ", HostAdapter); + for (i = 0; i < CCB->SenseDataLength; i++) + BusLogic_Notice(" %02X", HostAdapter, Command->sense_buffer[i]); + BusLogic_Notice("\n", HostAdapter); + } + } + break; + } + /* + When an INQUIRY command completes normally, save the + CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit + Wide Data Transfers Supported) bits. + */ + if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[CCB->TargetID]; + struct SCSI_Inquiry *InquiryResult = (struct SCSI_Inquiry *) Command->request_buffer; + TargetFlags->TargetExists = true; + TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; + TargetFlags->WideTransfersSupported = InquiryResult->WBus16; + } + /* + Place CCB back on the Host Adapter's free list. + */ + BusLogic_DeallocateCCB(CCB); + /* + Call the SCSI Command Completion Routine. + */ + Command->scsi_done(Command); } - break; - } - /* - When an INQUIRY command completes normally, save the - CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit - Wide Data Transfers Supported) bits. - */ - if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && - CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) - { - struct BusLogic_TargetFlags *TargetFlags = - &HostAdapter->TargetFlags[CCB->TargetID]; - struct SCSI_Inquiry *InquiryResult = - (struct SCSI_Inquiry *) Command->request_buffer; - TargetFlags->TargetExists = true; - TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; - TargetFlags->WideTransfersSupported = InquiryResult->WBus16; - } - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); - /* - Call the SCSI Command Completion Routine. - */ - Command->scsi_done(Command); } - } - HostAdapter->ProcessCompletedCCBsActive = false; + HostAdapter->ProcessCompletedCCBsActive = false; } @@ -3163,97 +2649,83 @@ static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapt Adapters. */ -static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) +static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier, struct pt_regs *InterruptRegisters) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) DeviceIdentifier; - unsigned long ProcessorFlags; - /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags); - /* - Handle Interrupts appropriately for each Host Adapter type. - */ - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - union BusLogic_InterruptRegister InterruptRegister; - /* - Read the Host Adapter Interrupt Register. - */ - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - if (InterruptRegister.ir.InterruptValid) - { - /* - Acknowledge the interrupt and reset the Host Adapter - Interrupt Register. - */ - BusLogic_InterruptReset(HostAdapter); - /* - Process valid External SCSI Bus Reset and Incoming Mailbox - Loaded Interrupts. Command Complete Interrupts are noted, - and Outgoing Mailbox Available Interrupts are ignored, as - they are never enabled. - */ - if (InterruptRegister.ir.ExternalBusReset) - HostAdapter->HostAdapterExternalReset = true; - else if (InterruptRegister.ir.IncomingMailboxLoaded) - BusLogic_ScanIncomingMailboxes(HostAdapter); - else if (InterruptRegister.ir.CommandComplete) - HostAdapter->HostAdapterCommandCompleted = true; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier; + unsigned long ProcessorFlags; + /* + Acquire exclusive access to Host Adapter. + */ + BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags); + /* + Handle Interrupts appropriately for each Host Adapter type. + */ + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + union BusLogic_InterruptRegister InterruptRegister; + /* + Read the Host Adapter Interrupt Register. + */ + InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); + if (InterruptRegister.ir.InterruptValid) { + /* + Acknowledge the interrupt and reset the Host Adapter + Interrupt Register. + */ + BusLogic_InterruptReset(HostAdapter); + /* + Process valid External SCSI Bus Reset and Incoming Mailbox + Loaded Interrupts. Command Complete Interrupts are noted, + and Outgoing Mailbox Available Interrupts are ignored, as + they are never enabled. + */ + if (InterruptRegister.ir.ExternalBusReset) + HostAdapter->HostAdapterExternalReset = true; + else if (InterruptRegister.ir.IncomingMailboxLoaded) + BusLogic_ScanIncomingMailboxes(HostAdapter); + else if (InterruptRegister.ir.CommandComplete) + HostAdapter->HostAdapterCommandCompleted = true; + } + } else { + /* + Check if there is a pending interrupt for this Host Adapter. + */ + if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) + switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) { + case FlashPoint_NormalInterrupt: + break; + case FlashPoint_ExternalBusReset: + HostAdapter->HostAdapterExternalReset = true; + break; + case FlashPoint_InternalError: + BusLogic_Warning("Internal FlashPoint Error detected" " - Resetting Host Adapter\n", HostAdapter); + HostAdapter->HostAdapterInternalError = true; + break; + } + } + /* + Process any completed CCBs. + */ + if (HostAdapter->FirstCompletedCCB != NULL) + BusLogic_ProcessCompletedCCBs(HostAdapter); + /* + Reset the Host Adapter if requested. + */ + if (HostAdapter->HostAdapterExternalReset) { + BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", HostAdapter, HostAdapter->FullModelName); + BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); + BusLogic_ResetHostAdapter(HostAdapter, false); + HostAdapter->HostAdapterExternalReset = false; + } else if (HostAdapter->HostAdapterInternalError) { + BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", HostAdapter, HostAdapter->FullModelName); + BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); + BusLogic_ResetHostAdapter(HostAdapter, true); + HostAdapter->HostAdapterInternalError = false; } - } - else - { - /* - Check if there is a pending interrupt for this Host Adapter. - */ - if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) - switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) - { - case FlashPoint_NormalInterrupt: - break; - case FlashPoint_ExternalBusReset: - HostAdapter->HostAdapterExternalReset = true; - break; - case FlashPoint_InternalError: - BusLogic_Warning("Internal FlashPoint Error detected" - " - Resetting Host Adapter\n", HostAdapter); - HostAdapter->HostAdapterInternalError = true; - break; - } - } - /* - Process any completed CCBs. - */ - if (HostAdapter->FirstCompletedCCB != NULL) - BusLogic_ProcessCompletedCCBs(HostAdapter); - /* - Reset the Host Adapter if requested. - */ - if (HostAdapter->HostAdapterExternalReset) - { - BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", - HostAdapter, HostAdapter->FullModelName); - BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); - BusLogic_ResetHostAdapter(HostAdapter, false); - HostAdapter->HostAdapterExternalReset = false; - } - else if (HostAdapter->HostAdapterInternalError) - { - BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", - HostAdapter, HostAdapter->FullModelName); - BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); - BusLogic_ResetHostAdapter(HostAdapter, true); - HostAdapter->HostAdapterInternalError = false; - } - /* - Release exclusive access to Host Adapter. - */ - BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags); - return IRQ_HANDLED; + /* + Release exclusive access to Host Adapter. + */ + BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags); + return IRQ_HANDLED; } @@ -3264,43 +2736,38 @@ static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, */ static boolean BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter - *HostAdapter, - enum BusLogic_ActionCode ActionCode, - struct BusLogic_CCB *CCB) + *HostAdapter, enum BusLogic_ActionCode ActionCode, struct BusLogic_CCB *CCB) { - struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; - NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox; - if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) - { - CCB->Status = BusLogic_CCB_Active; - /* - The CCB field must be written before the Action Code field since - the Host Adapter is operating asynchronously and the locking code - does not protect against simultaneous access by the Host Adapter. - */ - NextOutgoingMailbox->CCB = CCB->DMA_Handle; - NextOutgoingMailbox->ActionCode = ActionCode; - BusLogic_StartMailboxCommand(HostAdapter); - if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) - NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox; - if (ActionCode == BusLogic_MailboxStartCommand) - { - HostAdapter->ActiveCommands[CCB->TargetID]++; - if (CCB->Opcode != BusLogic_BusDeviceReset) - HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; + struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; + NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox; + if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) { + CCB->Status = BusLogic_CCB_Active; + /* + The CCB field must be written before the Action Code field since + the Host Adapter is operating asynchronously and the locking code + does not protect against simultaneous access by the Host Adapter. + */ + NextOutgoingMailbox->CCB = CCB->DMA_Handle; + NextOutgoingMailbox->ActionCode = ActionCode; + BusLogic_StartMailboxCommand(HostAdapter); + if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) + NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; + HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox; + if (ActionCode == BusLogic_MailboxStartCommand) { + HostAdapter->ActiveCommands[CCB->TargetID]++; + if (CCB->Opcode != BusLogic_BusDeviceReset) + HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; + } + return true; } - return true; - } - return false; + return false; } /* Error Handling (EH) support */ -static int BusLogic_host_reset(Scsi_Cmnd *SCpnt) +static int BusLogic_host_reset(Scsi_Cmnd * SCpnt) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) SCpnt->device->host->hostdata; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) SCpnt->device->host->hostdata; unsigned int id = SCpnt->device->id; struct BusLogic_TargetStatistics *stats = &HostAdapter->TargetStatistics[id]; @@ -3314,237 +2781,190 @@ static int BusLogic_host_reset(Scsi_Cmnd *SCpnt) Outgoing Mailbox for execution by the associated Host Adapter. */ -static int BusLogic_QueueCommand(struct scsi_cmnd *Command, - void (*CompletionRoutine)(struct scsi_cmnd *)) +static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *)) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Command->device->host->hostdata; - struct BusLogic_TargetFlags *TargetFlags = - &HostAdapter->TargetFlags[Command->device->id]; - struct BusLogic_TargetStatistics *TargetStatistics = - HostAdapter->TargetStatistics; - unsigned char *CDB = Command->cmnd; - int CDB_Length = Command->cmd_len; - int TargetID = Command->device->id; - int LogicalUnit = Command->device->lun; - void *BufferPointer = Command->request_buffer; - int BufferLength = Command->request_bufflen; - int SegmentCount = Command->use_sg; - struct BusLogic_CCB *CCB; - /* - SCSI REQUEST_SENSE commands will be executed automatically by the Host - Adapter for any errors, so they should not be executed explicitly unless - the Sense Data is zero indicating that no error occurred. - */ - if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) - { - Command->result = DID_OK << 16; - CompletionRoutine(Command); - return 0; - } - /* - Allocate a CCB from the Host Adapter's free list. In the unlikely event - that there are none available and memory allocation fails, wait 1 second - and try again. If that fails, the Host Adapter is probably hung so signal - an error as a Host Adapter Hard Reset should be initiated soon. - */ - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) - { - BusLogic_ReleaseHostAdapterLock(HostAdapter); - BusLogic_Delay(1); - BusLogic_AcquireHostAdapterLock(HostAdapter); - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) - { - Command->result = DID_ERROR << 16; - CompletionRoutine(Command); - return 0; - } - } - /* - Initialize the fields in the BusLogic Command Control Block (CCB). - */ - if (SegmentCount == 0 && BufferLength != 0) - { - CCB->Opcode = BusLogic_InitiatorCCB; - CCB->DataLength = BufferLength; - CCB->DataPointer = - pci_map_single(HostAdapter->PCI_Device, BufferPointer, BufferLength, - scsi_to_pci_dma_dir(Command->sc_data_direction)); - } - else if (SegmentCount != 0) - { - struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer; - int Segment, Count; - - Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount, - scsi_to_pci_dma_dir(Command->sc_data_direction)); - CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; - CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment); - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - CCB->DataPointer = (unsigned int)CCB->DMA_Handle + - ((unsigned long)&CCB->ScatterGatherList - - (unsigned long)CCB); - else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); - for (Segment = 0; Segment < Count; Segment++) - { - CCB->ScatterGatherList[Segment].SegmentByteCount = - sg_dma_len(ScatterList+Segment); - CCB->ScatterGatherList[Segment].SegmentDataPointer = - sg_dma_address(ScatterList+Segment); - } - } - else - { - CCB->Opcode = BusLogic_InitiatorCCB; - CCB->DataLength = BufferLength; - CCB->DataPointer = 0; - } - switch (CDB[0]) - { - case READ_6: - case READ_10: - CCB->DataDirection = BusLogic_DataInLengthChecked; - TargetStatistics[TargetID].ReadCommands++; - BusLogic_IncrementByteCounter( - &TargetStatistics[TargetID].TotalBytesRead, BufferLength); - BusLogic_IncrementSizeBucket( - TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); - break; - case WRITE_6: - case WRITE_10: - CCB->DataDirection = BusLogic_DataOutLengthChecked; - TargetStatistics[TargetID].WriteCommands++; - BusLogic_IncrementByteCounter( - &TargetStatistics[TargetID].TotalBytesWritten, BufferLength); - BusLogic_IncrementSizeBucket( - TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); - break; - default: - CCB->DataDirection = BusLogic_UncheckedDataTransfer; - break; - } - CCB->CDB_Length = CDB_Length; - CCB->HostAdapterStatus = 0; - CCB->TargetDeviceStatus = 0; - CCB->TargetID = TargetID; - CCB->LogicalUnit = LogicalUnit; - CCB->TagEnable = false; - CCB->LegacyTagEnable = false; - /* - BusLogic recommends that after a Reset the first couple of commands that - are sent to a Target Device be sent in a non Tagged Queue fashion so that - the Host Adapter and Target Device can establish Synchronous and Wide - Transfer before Queue Tag messages can interfere with the Synchronous and - Wide Negotiation messages. By waiting to enable Tagged Queuing until after - the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is - assured that after a Reset any pending commands are requeued before Tagged - Queuing is enabled and that the Tagged Queuing message will not occur while - the partition table is being printed. In addition, some devices do not - properly handle the transition from non-tagged to tagged commands, so it is - necessary to wait until there are no pending commands for a target device - before queuing tagged commands. - */ - if (HostAdapter->CommandsSinceReset[TargetID]++ >= - BusLogic_MaxTaggedQueueDepth && - !TargetFlags->TaggedQueuingActive && - HostAdapter->ActiveCommands[TargetID] == 0 && - TargetFlags->TaggedQueuingSupported && - (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) - { - TargetFlags->TaggedQueuingActive = true; - BusLogic_Notice("Tagged Queuing now active for Target %d\n", - HostAdapter, TargetID); - } - if (TargetFlags->TaggedQueuingActive) - { - enum BusLogic_QueueTag QueueTag = BusLogic_SimpleQueueTag; - /* - When using Tagged Queuing with Simple Queue Tags, it appears that disk - drive controllers do not guarantee that a queued command will not - remain in a disconnected state indefinitely if commands that read or - write nearer the head position continue to arrive without interruption. - Therefore, for each Target Device this driver keeps track of the last - time either the queue was empty or an Ordered Queue Tag was issued. If - more than 4 seconds (one fifth of the 20 second disk timeout) have - elapsed since this last sequence point, this command will be issued - with an Ordered Queue Tag rather than a Simple Queue Tag, which forces - the Target Device to complete all previously queued commands before - this command may be executed. - */ - if (HostAdapter->ActiveCommands[TargetID] == 0) - HostAdapter->LastSequencePoint[TargetID] = jiffies; - else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ) - { - HostAdapter->LastSequencePoint[TargetID] = jiffies; - QueueTag = BusLogic_OrderedQueueTag; - } - if (HostAdapter->ExtendedLUNSupport) - { - CCB->TagEnable = true; - CCB->QueueTag = QueueTag; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata; + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id]; + struct BusLogic_TargetStatistics *TargetStatistics = HostAdapter->TargetStatistics; + unsigned char *CDB = Command->cmnd; + int CDB_Length = Command->cmd_len; + int TargetID = Command->device->id; + int LogicalUnit = Command->device->lun; + void *BufferPointer = Command->request_buffer; + int BufferLength = Command->request_bufflen; + int SegmentCount = Command->use_sg; + struct BusLogic_CCB *CCB; + /* + SCSI REQUEST_SENSE commands will be executed automatically by the Host + Adapter for any errors, so they should not be executed explicitly unless + the Sense Data is zero indicating that no error occurred. + */ + if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) { + Command->result = DID_OK << 16; + CompletionRoutine(Command); + return 0; } - else - { - CCB->LegacyTagEnable = true; - CCB->LegacyQueueTag = QueueTag; + /* + Allocate a CCB from the Host Adapter's free list. In the unlikely event + that there are none available and memory allocation fails, wait 1 second + and try again. If that fails, the Host Adapter is probably hung so signal + an error as a Host Adapter Hard Reset should be initiated soon. + */ + CCB = BusLogic_AllocateCCB(HostAdapter); + if (CCB == NULL) { + BusLogic_ReleaseHostAdapterLock(HostAdapter); + BusLogic_Delay(1); + BusLogic_AcquireHostAdapterLock(HostAdapter); + CCB = BusLogic_AllocateCCB(HostAdapter); + if (CCB == NULL) { + Command->result = DID_ERROR << 16; + CompletionRoutine(Command); + return 0; + } } - } - memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataLength = sizeof(Command->sense_buffer); - CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, - Command->sense_buffer, - CCB->SenseDataLength, - PCI_DMA_FROMDEVICE); - CCB->Command = Command; - Command->scsi_done = CompletionRoutine; - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - /* - Place the CCB in an Outgoing Mailbox. The higher levels of the SCSI - Subsystem should not attempt to queue more commands than can be placed - in Outgoing Mailboxes, so there should always be one free. In the - unlikely event that there are none available, wait 1 second and try - again. If that fails, the Host Adapter is probably hung so signal an - error as a Host Adapter Hard Reset should be initiated soon. - */ - if (!BusLogic_WriteOutgoingMailbox( - HostAdapter, BusLogic_MailboxStartCommand, CCB)) - { - BusLogic_ReleaseHostAdapterLock(HostAdapter); - BusLogic_Warning("Unable to write Outgoing Mailbox - " - "Pausing for 1 second\n", HostAdapter); - BusLogic_Delay(1); - BusLogic_AcquireHostAdapterLock(HostAdapter); - if (!BusLogic_WriteOutgoingMailbox( - HostAdapter, BusLogic_MailboxStartCommand, CCB)) - { - BusLogic_Warning("Still unable to write Outgoing Mailbox - " - "Host Adapter Dead?\n", HostAdapter); - BusLogic_DeallocateCCB(CCB); - Command->result = DID_ERROR << 16; - Command->scsi_done(Command); - } + /* + Initialize the fields in the BusLogic Command Control Block (CCB). + */ + if (SegmentCount == 0 && BufferLength != 0) { + CCB->Opcode = BusLogic_InitiatorCCB; + CCB->DataLength = BufferLength; + CCB->DataPointer = pci_map_single(HostAdapter->PCI_Device, BufferPointer, BufferLength, scsi_to_pci_dma_dir(Command->sc_data_direction)); + } else if (SegmentCount != 0) { + struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer; + int Segment, Count; + + Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount, scsi_to_pci_dma_dir(Command->sc_data_direction)); + CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; + CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment); + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) + CCB->DataPointer = (unsigned int) CCB->DMA_Handle + ((unsigned long) &CCB->ScatterGatherList - (unsigned long) CCB); + else + CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); + for (Segment = 0; Segment < Count; Segment++) { + CCB->ScatterGatherList[Segment].SegmentByteCount = sg_dma_len(ScatterList + Segment); + CCB->ScatterGatherList[Segment].SegmentDataPointer = sg_dma_address(ScatterList + Segment); + } + } else { + CCB->Opcode = BusLogic_InitiatorCCB; + CCB->DataLength = BufferLength; + CCB->DataPointer = 0; + } + switch (CDB[0]) { + case READ_6: + case READ_10: + CCB->DataDirection = BusLogic_DataInLengthChecked; + TargetStatistics[TargetID].ReadCommands++; + BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesRead, BufferLength); + BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); + break; + case WRITE_6: + case WRITE_10: + CCB->DataDirection = BusLogic_DataOutLengthChecked; + TargetStatistics[TargetID].WriteCommands++; + BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesWritten, BufferLength); + BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); + break; + default: + CCB->DataDirection = BusLogic_UncheckedDataTransfer; + break; + } + CCB->CDB_Length = CDB_Length; + CCB->HostAdapterStatus = 0; + CCB->TargetDeviceStatus = 0; + CCB->TargetID = TargetID; + CCB->LogicalUnit = LogicalUnit; + CCB->TagEnable = false; + CCB->LegacyTagEnable = false; + /* + BusLogic recommends that after a Reset the first couple of commands that + are sent to a Target Device be sent in a non Tagged Queue fashion so that + the Host Adapter and Target Device can establish Synchronous and Wide + Transfer before Queue Tag messages can interfere with the Synchronous and + Wide Negotiation messages. By waiting to enable Tagged Queuing until after + the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is + assured that after a Reset any pending commands are requeued before Tagged + Queuing is enabled and that the Tagged Queuing message will not occur while + the partition table is being printed. In addition, some devices do not + properly handle the transition from non-tagged to tagged commands, so it is + necessary to wait until there are no pending commands for a target device + before queuing tagged commands. + */ + if (HostAdapter->CommandsSinceReset[TargetID]++ >= + BusLogic_MaxTaggedQueueDepth && !TargetFlags->TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] == 0 && TargetFlags->TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { + TargetFlags->TaggedQueuingActive = true; + BusLogic_Notice("Tagged Queuing now active for Target %d\n", HostAdapter, TargetID); + } + if (TargetFlags->TaggedQueuingActive) { + enum BusLogic_QueueTag QueueTag = BusLogic_SimpleQueueTag; + /* + When using Tagged Queuing with Simple Queue Tags, it appears that disk + drive controllers do not guarantee that a queued command will not + remain in a disconnected state indefinitely if commands that read or + write nearer the head position continue to arrive without interruption. + Therefore, for each Target Device this driver keeps track of the last + time either the queue was empty or an Ordered Queue Tag was issued. If + more than 4 seconds (one fifth of the 20 second disk timeout) have + elapsed since this last sequence point, this command will be issued + with an Ordered Queue Tag rather than a Simple Queue Tag, which forces + the Target Device to complete all previously queued commands before + this command may be executed. + */ + if (HostAdapter->ActiveCommands[TargetID] == 0) + HostAdapter->LastSequencePoint[TargetID] = jiffies; + else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4 * HZ) { + HostAdapter->LastSequencePoint[TargetID] = jiffies; + QueueTag = BusLogic_OrderedQueueTag; + } + if (HostAdapter->ExtendedLUNSupport) { + CCB->TagEnable = true; + CCB->QueueTag = QueueTag; + } else { + CCB->LegacyTagEnable = true; + CCB->LegacyQueueTag = QueueTag; + } } - } - else - { - /* - Call the FlashPoint SCCB Manager to start execution of the CCB. - */ - CCB->Status = BusLogic_CCB_Active; - HostAdapter->ActiveCommands[TargetID]++; - TargetStatistics[TargetID].CommandsAttempted++; - FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); - /* - The Command may have already completed and BusLogic_QueueCompletedCCB - been called, or it may still be pending. - */ - if (CCB->Status == BusLogic_CCB_Completed) - BusLogic_ProcessCompletedCCBs(HostAdapter); - } - return 0; + memcpy(CCB->CDB, CDB, CDB_Length); + CCB->SenseDataLength = sizeof(Command->sense_buffer); + CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE); + CCB->Command = Command; + Command->scsi_done = CompletionRoutine; + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + /* + Place the CCB in an Outgoing Mailbox. The higher levels of the SCSI + Subsystem should not attempt to queue more commands than can be placed + in Outgoing Mailboxes, so there should always be one free. In the + unlikely event that there are none available, wait 1 second and try + again. If that fails, the Host Adapter is probably hung so signal an + error as a Host Adapter Hard Reset should be initiated soon. + */ + if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) { + BusLogic_ReleaseHostAdapterLock(HostAdapter); + BusLogic_Warning("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", HostAdapter); + BusLogic_Delay(1); + BusLogic_AcquireHostAdapterLock(HostAdapter); + if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) { + BusLogic_Warning("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", HostAdapter); + BusLogic_DeallocateCCB(CCB); + Command->result = DID_ERROR << 16; + Command->scsi_done(Command); + } + } + } else { + /* + Call the FlashPoint SCCB Manager to start execution of the CCB. + */ + CCB->Status = BusLogic_CCB_Active; + HostAdapter->ActiveCommands[TargetID]++; + TargetStatistics[TargetID].CommandsAttempted++; + FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); + /* + The Command may have already completed and BusLogic_QueueCompletedCCB + been called, or it may still be pending. + */ + if (CCB->Status == BusLogic_CCB_Completed) + BusLogic_ProcessCompletedCCBs(HostAdapter); + } + return 0; } @@ -3554,105 +2974,75 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, static int BusLogic_AbortCommand(struct scsi_cmnd *Command) { - struct BusLogic_HostAdapter *HostAdapter = - (struct BusLogic_HostAdapter *) Command->device->host->hostdata; - - int TargetID = Command->device->id; - struct BusLogic_CCB *CCB; - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); - /* - If this Command has already completed, then no Abort is necessary. - */ - if (Command->serial_number != Command->serial_number_at_timeout) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "Already Completed\n", HostAdapter, TargetID); - return SUCCESS; - } - /* - Attempt to find an Active CCB for this Command. If no Active CCB for this - Command is found, then no Abort is necessary. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Command == Command) break; - if (CCB == NULL) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "No CCB Found\n", HostAdapter, TargetID); - return SUCCESS; - } - else if (CCB->Status == BusLogic_CCB_Completed) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "CCB Completed\n", HostAdapter, TargetID); - return SUCCESS; - } - else if (CCB->Status == BusLogic_CCB_Reset) - { - BusLogic_Warning("Unable to Abort Command to Target %d - " - "CCB Reset\n", HostAdapter, TargetID); - return SUCCESS; - } - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - { - /* - Attempt to Abort this CCB. MultiMaster Firmware versions prior to 5.xx - do not generate Abort Tag messages, but only generate the non-tagged - Abort message. Since non-tagged commands are not sent by the Host - Adapter until the queue of outstanding tagged commands has completed, - and the Abort message is treated as a non-tagged command, it is - effectively impossible to abort commands when Tagged Queuing is active. - Firmware version 5.xx does generate Abort Tag messages, so it is - possible to abort commands when Tagged Queuing is active. - */ - if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && - HostAdapter->FirmwareVersion[0] < '5') - { - BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " - "Abort Tag Not Supported\n", - HostAdapter, CCB->SerialNumber, TargetID); - return FAILURE; - } - else if (BusLogic_WriteOutgoingMailbox( - HostAdapter, BusLogic_MailboxAbortCommand, CCB)) - { - BusLogic_Warning("Aborting CCB #%ld to Target %d\n", - HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); - return SUCCESS; - } - else - { - BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " - "No Outgoing Mailboxes\n", - HostAdapter, CCB->SerialNumber, TargetID); - return FAILURE; + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata; + + int TargetID = Command->device->id; + struct BusLogic_CCB *CCB; + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); + /* + If this Command has already completed, then no Abort is necessary. + */ + if (Command->serial_number != Command->serial_number_at_timeout) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "Already Completed\n", HostAdapter, TargetID); + return SUCCESS; } - } - else - { - /* - Call the FlashPoint SCCB Manager to abort execution of the CCB. - */ - BusLogic_Warning("Aborting CCB #%ld to Target %d\n", - HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter( - &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); - FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); - /* - The Abort may have already been completed and - BusLogic_QueueCompletedCCB been called, or it - may still be pending. - */ - if (CCB->Status == BusLogic_CCB_Completed) - { - BusLogic_ProcessCompletedCCBs(HostAdapter); + /* + Attempt to find an Active CCB for this Command. If no Active CCB for this + Command is found, then no Abort is necessary. + */ + for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) + if (CCB->Command == Command) + break; + if (CCB == NULL) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "No CCB Found\n", HostAdapter, TargetID); + return SUCCESS; + } else if (CCB->Status == BusLogic_CCB_Completed) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Completed\n", HostAdapter, TargetID); + return SUCCESS; + } else if (CCB->Status == BusLogic_CCB_Reset) { + BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Reset\n", HostAdapter, TargetID); + return SUCCESS; + } + if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { + /* + Attempt to Abort this CCB. MultiMaster Firmware versions prior to 5.xx + do not generate Abort Tag messages, but only generate the non-tagged + Abort message. Since non-tagged commands are not sent by the Host + Adapter until the queue of outstanding tagged commands has completed, + and the Abort message is treated as a non-tagged command, it is + effectively impossible to abort commands when Tagged Queuing is active. + Firmware version 5.xx does generate Abort Tag messages, so it is + possible to abort commands when Tagged Queuing is active. + */ + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->FirmwareVersion[0] < '5') { + BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "Abort Tag Not Supported\n", HostAdapter, CCB->SerialNumber, TargetID); + return FAILURE; + } else if (BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxAbortCommand, CCB)) { + BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); + return SUCCESS; + } else { + BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "No Outgoing Mailboxes\n", HostAdapter, CCB->SerialNumber, TargetID); + return FAILURE; + } + } else { + /* + Call the FlashPoint SCCB Manager to abort execution of the CCB. + */ + BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); + BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); + FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); + /* + The Abort may have already been completed and + BusLogic_QueueCompletedCCB been called, or it + may still be pending. + */ + if (CCB->Status == BusLogic_CCB_Completed) { + BusLogic_ProcessCompletedCCBs(HostAdapter); + } + return SUCCESS; } - return SUCCESS; - } - return SUCCESS; + return SUCCESS; } /* @@ -3660,8 +3050,7 @@ static int BusLogic_AbortCommand(struct scsi_cmnd *Command) currently executing SCSI Commands as having been Reset. */ -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, - boolean HardReset) +static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, boolean HardReset) { struct BusLogic_CCB *CCB; int TargetID; @@ -3670,10 +3059,8 @@ static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, * Attempt to Reset and Reinitialize the Host Adapter. */ - if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && - BusLogic_InitializeHostAdapter(HostAdapter))) { - BusLogic_Error("Resetting %s Failed\n", HostAdapter, - HostAdapter->FullModelName); + if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && BusLogic_InitializeHostAdapter(HostAdapter))) { + BusLogic_Error("Resetting %s Failed\n", HostAdapter, HostAdapter->FullModelName); return FAILURE; } @@ -3721,98 +3108,70 @@ static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, the BIOS, and a warning may be displayed. */ -static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_device *Device, - sector_t capacity, int *Parameters) +static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_device *Device, sector_t capacity, int *Parameters) { - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) sdev->host->hostdata; - struct BIOS_DiskParameters *DiskParameters = (struct BIOS_DiskParameters *) Parameters; - unsigned char *buf; - if (HostAdapter->ExtendedTranslationEnabled && - capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */) - { - if (capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - } - else - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - } - } - else - { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - } - DiskParameters->Cylinders = - (unsigned long)capacity / (DiskParameters->Heads * DiskParameters->Sectors); - buf = scsi_bios_ptable(Device); - if (buf == NULL) return 0; - /* - If the boot sector partition table flag is valid, search for a partition - table entry whose end_head matches one of the standard BusLogic geometry - translations (64/32, 128/32, or 255/63). - */ - if (*(unsigned short *) (buf+64) == 0xAA55) - { - struct partition *FirstPartitionEntry = (struct partition *) buf; - struct partition *PartitionEntry = FirstPartitionEntry; - int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; - unsigned char PartitionEntryEndHead=0, PartitionEntryEndSector=0; - for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) - { - PartitionEntryEndHead = PartitionEntry->end_head; - PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; - if (PartitionEntryEndHead == 64-1) - { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - break; - } - else if (PartitionEntryEndHead == 128-1) - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - break; - } - else if (PartitionEntryEndHead == 255-1) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - break; - } - PartitionEntry++; - } - if (PartitionNumber == 4) - { - PartitionEntryEndHead = FirstPartitionEntry->end_head; - PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; - } - DiskParameters->Cylinders = - (unsigned long)capacity / (DiskParameters->Heads * DiskParameters->Sectors); - if (PartitionNumber < 4 && - PartitionEntryEndSector == DiskParameters->Sectors) - { - if (DiskParameters->Cylinders != SavedCylinders) - BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", - HostAdapter, - DiskParameters->Heads, DiskParameters->Sectors); + struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) sdev->host->hostdata; + struct BIOS_DiskParameters *DiskParameters = (struct BIOS_DiskParameters *) Parameters; + unsigned char *buf; + if (HostAdapter->ExtendedTranslationEnabled && capacity >= 2 * 1024 * 1024 /* 1 GB in 512 byte sectors */ ) { + if (capacity >= 4 * 1024 * 1024 /* 2 GB in 512 byte sectors */ ) { + DiskParameters->Heads = 255; + DiskParameters->Sectors = 63; + } else { + DiskParameters->Heads = 128; + DiskParameters->Sectors = 32; + } + } else { + DiskParameters->Heads = 64; + DiskParameters->Sectors = 32; } - else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) - { - BusLogic_Warning("Warning: Partition Table appears to " - "have Geometry %d/%d which is\n", HostAdapter, - PartitionEntryEndHead + 1, - PartitionEntryEndSector); - BusLogic_Warning("not compatible with current BusLogic " - "Host Adapter Geometry %d/%d\n", HostAdapter, - DiskParameters->Heads, DiskParameters->Sectors); + DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors); + buf = scsi_bios_ptable(Device); + if (buf == NULL) + return 0; + /* + If the boot sector partition table flag is valid, search for a partition + table entry whose end_head matches one of the standard BusLogic geometry + translations (64/32, 128/32, or 255/63). + */ + if (*(unsigned short *) (buf + 64) == 0xAA55) { + struct partition *FirstPartitionEntry = (struct partition *) buf; + struct partition *PartitionEntry = FirstPartitionEntry; + int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; + unsigned char PartitionEntryEndHead = 0, PartitionEntryEndSector = 0; + for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) { + PartitionEntryEndHead = PartitionEntry->end_head; + PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; + if (PartitionEntryEndHead == 64 - 1) { + DiskParameters->Heads = 64; + DiskParameters->Sectors = 32; + break; + } else if (PartitionEntryEndHead == 128 - 1) { + DiskParameters->Heads = 128; + DiskParameters->Sectors = 32; + break; + } else if (PartitionEntryEndHead == 255 - 1) { + DiskParameters->Heads = 255; + DiskParameters->Sectors = 63; + break; + } + PartitionEntry++; + } + if (PartitionNumber == 4) { + PartitionEntryEndHead = FirstPartitionEntry->end_head; + PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; + } + DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors); + if (PartitionNumber < 4 && PartitionEntryEndSector == DiskParameters->Sectors) { + if (DiskParameters->Cylinders != SavedCylinders) + BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); + } else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) { + BusLogic_Warning("Warning: Partition Table appears to " "have Geometry %d/%d which is\n", HostAdapter, PartitionEntryEndHead + 1, PartitionEntryEndSector); + BusLogic_Warning("not compatible with current BusLogic " "Host Adapter Geometry %d/%d\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); + } } - } - kfree(buf); - return 0; + kfree(buf); + return 0; } @@ -3820,178 +3179,124 @@ static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_de BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/. */ -static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, - char **StartPointer, off_t Offset, - int BytesAvailable, int WriteFlag) +static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer, off_t Offset, int BytesAvailable, int WriteFlag) { - struct BusLogic_HostAdapter *HostAdapter; - struct BusLogic_TargetStatistics *TargetStatistics; - int TargetID, Length; - char *Buffer; - for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; - HostAdapter != NULL; - HostAdapter = HostAdapter->Next) - if (HostAdapter->HostNumber == shost->host_no) break; - if (HostAdapter == NULL) - { - BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", - NULL, shost->host_no); - return 0; - } - TargetStatistics = HostAdapter->TargetStatistics; - if (WriteFlag) - { - HostAdapter->ExternalHostAdapterResets = 0; - HostAdapter->HostAdapterInternalErrors = 0; - memset(TargetStatistics, 0, - BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics)); - return 0; - } - Buffer = HostAdapter->MessageBuffer; - Length = HostAdapter->MessageBufferLength; - Length += sprintf(&Buffer[Length], "\n\ + struct BusLogic_HostAdapter *HostAdapter; + struct BusLogic_TargetStatistics *TargetStatistics; + int TargetID, Length; + char *Buffer; + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) + if (HostAdapter->HostNumber == shost->host_no) + break; + if (HostAdapter == NULL) { + BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", NULL, shost->host_no); + return 0; + } + TargetStatistics = HostAdapter->TargetStatistics; + if (WriteFlag) { + HostAdapter->ExternalHostAdapterResets = 0; + HostAdapter->HostAdapterInternalErrors = 0; + memset(TargetStatistics, 0, BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics)); + return 0; + } + Buffer = HostAdapter->MessageBuffer; + Length = HostAdapter->MessageBufferLength; + Length += sprintf(&Buffer[Length], "\n\ Current Driver Queue Depth: %d\n\ -Currently Allocated CCBs: %d\n", - HostAdapter->DriverQueueDepth, - HostAdapter->AllocatedCCBs); - Length += sprintf(&Buffer[Length], "\n\n\ +Currently Allocated CCBs: %d\n", HostAdapter->DriverQueueDepth, HostAdapter->AllocatedCCBs); + Length += sprintf(&Buffer[Length], "\n\n\ DATA TRANSFER STATISTICS\n\ \n\ Target Tagged Queuing Queue Depth Active Attempted Completed\n\ ====== ============== =========== ====== ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], " %2d %s", TargetID, - (TargetFlags->TaggedQueuingSupported - ? (TargetFlags->TaggedQueuingActive - ? " Active" - : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) - ? " Permitted" : " Disabled")) - : "Not Supported")); - Length += sprintf(&Buffer[Length], - " %3d %3u %9u %9u\n", - HostAdapter->QueueDepth[TargetID], - HostAdapter->ActiveCommands[TargetID], - TargetStatistics[TargetID].CommandsAttempted, - TargetStatistics[TargetID].CommandsCompleted); - } - Length += sprintf(&Buffer[Length], "\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += sprintf(&Buffer[Length], " %2d %s", TargetID, (TargetFlags->TaggedQueuingSupported ? (TargetFlags->TaggedQueuingActive ? " Active" : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) + ? " Permitted" : " Disabled")) + : "Not Supported")); + Length += sprintf(&Buffer[Length], + " %3d %3u %9u %9u\n", HostAdapter->QueueDepth[TargetID], HostAdapter->ActiveCommands[TargetID], TargetStatistics[TargetID].CommandsAttempted, TargetStatistics[TargetID].CommandsCompleted); + } + Length += sprintf(&Buffer[Length], "\n\ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ ====== ============= ============== =================== ===================\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, - TargetStatistics[TargetID].ReadCommands, - TargetStatistics[TargetID].WriteCommands); - if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u", - TargetStatistics[TargetID].TotalBytesRead.Billions, - TargetStatistics[TargetID].TotalBytesRead.Units); - else - Length += - sprintf(&Buffer[Length], " %9u", - TargetStatistics[TargetID].TotalBytesRead.Units); - if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u\n", - TargetStatistics[TargetID].TotalBytesWritten.Billions, - TargetStatistics[TargetID].TotalBytesWritten.Units); - else - Length += - sprintf(&Buffer[Length], " %9u\n", - TargetStatistics[TargetID].TotalBytesWritten.Units); - } - Length += sprintf(&Buffer[Length], "\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, TargetStatistics[TargetID].ReadCommands, TargetStatistics[TargetID].WriteCommands); + if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) + Length += sprintf(&Buffer[Length], " %9u%09u", TargetStatistics[TargetID].TotalBytesRead.Billions, TargetStatistics[TargetID].TotalBytesRead.Units); + else + Length += sprintf(&Buffer[Length], " %9u", TargetStatistics[TargetID].TotalBytesRead.Units); + if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) + Length += sprintf(&Buffer[Length], " %9u%09u\n", TargetStatistics[TargetID].TotalBytesWritten.Billions, TargetStatistics[TargetID].TotalBytesWritten.Units); + else + Length += sprintf(&Buffer[Length], " %9u\n", TargetStatistics[TargetID].TotalBytesWritten.Units); + } + Length += sprintf(&Buffer[Length], "\n\ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ ====== ======= ========= ========= ========= ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].ReadCommandSizeBuckets[0], - TargetStatistics[TargetID].ReadCommandSizeBuckets[1], - TargetStatistics[TargetID].ReadCommandSizeBuckets[2], - TargetStatistics[TargetID].ReadCommandSizeBuckets[3], - TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].WriteCommandSizeBuckets[0], - TargetStatistics[TargetID].WriteCommandSizeBuckets[1], - TargetStatistics[TargetID].WriteCommandSizeBuckets[2], - TargetStatistics[TargetID].WriteCommandSizeBuckets[3], - TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); - } - Length += sprintf(&Buffer[Length], "\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[0], + TargetStatistics[TargetID].ReadCommandSizeBuckets[1], TargetStatistics[TargetID].ReadCommandSizeBuckets[2], TargetStatistics[TargetID].ReadCommandSizeBuckets[3], TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[0], + TargetStatistics[TargetID].WriteCommandSizeBuckets[1], TargetStatistics[TargetID].WriteCommandSizeBuckets[2], TargetStatistics[TargetID].WriteCommandSizeBuckets[3], TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); + } + Length += sprintf(&Buffer[Length], "\n\ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ ====== ======= ========= ========= ========= ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].ReadCommandSizeBuckets[5], - TargetStatistics[TargetID].ReadCommandSizeBuckets[6], - TargetStatistics[TargetID].ReadCommandSizeBuckets[7], - TargetStatistics[TargetID].ReadCommandSizeBuckets[8], - TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].WriteCommandSizeBuckets[5], - TargetStatistics[TargetID].WriteCommandSizeBuckets[6], - TargetStatistics[TargetID].WriteCommandSizeBuckets[7], - TargetStatistics[TargetID].WriteCommandSizeBuckets[8], - TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); - } - Length += sprintf(&Buffer[Length], "\n\n\ + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[5], + TargetStatistics[TargetID].ReadCommandSizeBuckets[6], TargetStatistics[TargetID].ReadCommandSizeBuckets[7], TargetStatistics[TargetID].ReadCommandSizeBuckets[8], TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[5], + TargetStatistics[TargetID].WriteCommandSizeBuckets[6], TargetStatistics[TargetID].WriteCommandSizeBuckets[7], TargetStatistics[TargetID].WriteCommandSizeBuckets[8], TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); + } + Length += sprintf(&Buffer[Length], "\n\n\ ERROR RECOVERY STATISTICS\n\ \n\ Command Aborts Bus Device Resets Host Adapter Resets\n\ Target Requested Completed Requested Completed Requested Completed\n\ ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\ ====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) continue; - Length += - sprintf(&Buffer[Length], "\ - %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, - TargetStatistics[TargetID].CommandAbortsRequested, - TargetStatistics[TargetID].CommandAbortsAttempted, - TargetStatistics[TargetID].CommandAbortsCompleted, - TargetStatistics[TargetID].BusDeviceResetsRequested, - TargetStatistics[TargetID].BusDeviceResetsAttempted, - TargetStatistics[TargetID].BusDeviceResetsCompleted, - TargetStatistics[TargetID].HostAdapterResetsRequested, - TargetStatistics[TargetID].HostAdapterResetsAttempted, - TargetStatistics[TargetID].HostAdapterResetsCompleted); - } - Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", - HostAdapter->ExternalHostAdapterResets); - Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", - HostAdapter->HostAdapterInternalErrors); - if (Length >= BusLogic_MessageBufferSize) - BusLogic_Error("Message Buffer length %d exceeds size %d\n", - HostAdapter, Length, BusLogic_MessageBufferSize); - if ((Length -= Offset) <= 0) return 0; - if (Length >= BytesAvailable) Length = BytesAvailable; - memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length); - *StartPointer = ProcBuffer; - return Length; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { + struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) + continue; + Length += sprintf(&Buffer[Length], "\ + %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, TargetStatistics[TargetID].CommandAbortsRequested, TargetStatistics[TargetID].CommandAbortsAttempted, TargetStatistics[TargetID].CommandAbortsCompleted, TargetStatistics[TargetID].BusDeviceResetsRequested, TargetStatistics[TargetID].BusDeviceResetsAttempted, TargetStatistics[TargetID].BusDeviceResetsCompleted, TargetStatistics[TargetID].HostAdapterResetsRequested, TargetStatistics[TargetID].HostAdapterResetsAttempted, TargetStatistics[TargetID].HostAdapterResetsCompleted); + } + Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets); + Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", HostAdapter->HostAdapterInternalErrors); + if (Length >= BusLogic_MessageBufferSize) + BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize); + if ((Length -= Offset) <= 0) + return 0; + if (Length >= BytesAvailable) + Length = BytesAvailable; + memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length); + *StartPointer = ProcBuffer; + return Length; } @@ -3999,52 +3304,39 @@ Target Requested Completed Requested Completed Requested Completed\n\ BusLogic_Message prints Driver Messages. */ -static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, - char *Format, - struct BusLogic_HostAdapter *HostAdapter, - ...) +static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Format, struct BusLogic_HostAdapter *HostAdapter, ...) { - static char Buffer[BusLogic_LineBufferSize]; - static boolean BeginningOfLine = true; - va_list Arguments; - int Length = 0; - va_start(Arguments, HostAdapter); - Length = vsprintf(Buffer, Format, Arguments); - va_end(Arguments); - if (MessageLevel == BusLogic_AnnounceLevel) - { - static int AnnouncementLines = 0; - strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], - Buffer); - HostAdapter->MessageBufferLength += Length; - if (++AnnouncementLines <= 2) - printk("%sscsi: %s", BusLogic_MessageLevelMap[MessageLevel], Buffer); - } - else if (MessageLevel == BusLogic_InfoLevel) - { - strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], - Buffer); - HostAdapter->MessageBufferLength += Length; - if (BeginningOfLine) - { - if (Buffer[0] != '\n' || Length > 1) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); - } - else printk("%s", Buffer); - } - else - { - if (BeginningOfLine) - { - if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); - else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); - } - else printk("%s", Buffer); - } - BeginningOfLine = (Buffer[Length-1] == '\n'); + static char Buffer[BusLogic_LineBufferSize]; + static boolean BeginningOfLine = true; + va_list Arguments; + int Length = 0; + va_start(Arguments, HostAdapter); + Length = vsprintf(Buffer, Format, Arguments); + va_end(Arguments); + if (MessageLevel == BusLogic_AnnounceLevel) { + static int AnnouncementLines = 0; + strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer); + HostAdapter->MessageBufferLength += Length; + if (++AnnouncementLines <= 2) + printk("%sscsi: %s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + } else if (MessageLevel == BusLogic_InfoLevel) { + strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer); + HostAdapter->MessageBufferLength += Length; + if (BeginningOfLine) { + if (Buffer[0] != '\n' || Length > 1) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer); + } else + printk("%s", Buffer); + } else { + if (BeginningOfLine) { + if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer); + else + printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + } else + printk("%s", Buffer); + } + BeginningOfLine = (Buffer[Length - 1] == '\n'); } @@ -4055,19 +3347,19 @@ static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, static boolean __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword) { - char *Pointer = *StringPointer; - while (*Keyword != '\0') - { - char StringChar = *Pointer++; - char KeywordChar = *Keyword++; - if (StringChar >= 'A' && StringChar <= 'Z') - StringChar += 'a' - 'Z'; - if (KeywordChar >= 'A' && KeywordChar <= 'Z') - KeywordChar += 'a' - 'Z'; - if (StringChar != KeywordChar) return false; - } - *StringPointer = Pointer; - return true; + char *Pointer = *StringPointer; + while (*Keyword != '\0') { + char StringChar = *Pointer++; + char KeywordChar = *Keyword++; + if (StringChar >= 'A' && StringChar <= 'Z') + StringChar += 'a' - 'Z'; + if (KeywordChar >= 'A' && KeywordChar <= 'Z') + KeywordChar += 'a' - 'Z'; + if (StringChar != KeywordChar) + return false; + } + *StringPointer = Pointer; + return true; } @@ -4090,225 +3382,165 @@ static boolean __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword) static int __init BusLogic_ParseDriverOptions(char *OptionsString) { - while (true) - { - struct BusLogic_DriverOptions *DriverOptions = - &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; - int TargetID; - memset(DriverOptions, 0, sizeof(struct BusLogic_DriverOptions)); - while (*OptionsString != '\0' && *OptionsString != ';') - { - /* Probing Options. */ - if (BusLogic_ParseKeyword(&OptionsString, "IO:")) - { - unsigned long IO_Address = - simple_strtoul(OptionsString, &OptionsString, 0); - BusLogic_ProbeOptions.LimitedProbeISA = true; - switch (IO_Address) - { - case 0x330: - BusLogic_ProbeOptions.Probe330 = true; - break; - case 0x334: - BusLogic_ProbeOptions.Probe334 = true; - break; - case 0x230: - BusLogic_ProbeOptions.Probe230 = true; - break; - case 0x234: - BusLogic_ProbeOptions.Probe234 = true; - break; - case 0x130: - BusLogic_ProbeOptions.Probe130 = true; - break; - case 0x134: - BusLogic_ProbeOptions.Probe134 = true; - break; - default: - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid I/O Address 0x%X)\n", - NULL, IO_Address); - return 0; - } - } - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) - BusLogic_ProbeOptions.NoProbeISA = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) - BusLogic_ProbeOptions.NoProbePCI = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) - BusLogic_ProbeOptions.NoProbe = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) - BusLogic_ProbeOptions.NoSortPCI = true; - else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) - BusLogic_ProbeOptions.MultiMasterFirst = true; - else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) - BusLogic_ProbeOptions.FlashPointFirst = true; - /* Tagged Queuing Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || - BusLogic_ParseKeyword(&OptionsString, "QD:[")) - { - for (TargetID = 0; - TargetID < BusLogic_MaxTargetDevices; - TargetID++) - { - unsigned short QueueDepth = - simple_strtoul(OptionsString, &OptionsString, 0); - if (QueueDepth > BusLogic_MaxTaggedQueueDepth) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid Queue Depth %d)\n", - NULL, QueueDepth); - return 0; - } - DriverOptions->QueueDepth[TargetID] = QueueDepth; - if (*OptionsString == ',') - OptionsString++; - else if (*OptionsString == ']') - break; - else - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(',' or ']' expected at '%s')\n", - NULL, OptionsString); - return 0; - } - } - if (*OptionsString != ']') - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(']' expected at '%s')\n", - NULL, OptionsString); - return 0; - } - else OptionsString++; - } - else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || - BusLogic_ParseKeyword(&OptionsString, "QD:")) - { - unsigned short QueueDepth = - simple_strtoul(OptionsString, &OptionsString, 0); - if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid Queue Depth %d)\n", - NULL, QueueDepth); - return 0; + while (true) { + struct BusLogic_DriverOptions *DriverOptions = &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; + int TargetID; + memset(DriverOptions, 0, sizeof(struct BusLogic_DriverOptions)); + while (*OptionsString != '\0' && *OptionsString != ';') { + /* Probing Options. */ + if (BusLogic_ParseKeyword(&OptionsString, "IO:")) { + unsigned long IO_Address = simple_strtoul(OptionsString, &OptionsString, 0); + BusLogic_ProbeOptions.LimitedProbeISA = true; + switch (IO_Address) { + case 0x330: + BusLogic_ProbeOptions.Probe330 = true; + break; + case 0x334: + BusLogic_ProbeOptions.Probe334 = true; + break; + case 0x230: + BusLogic_ProbeOptions.Probe230 = true; + break; + case 0x234: + BusLogic_ProbeOptions.Probe234 = true; + break; + case 0x130: + BusLogic_ProbeOptions.Probe130 = true; + break; + case 0x134: + BusLogic_ProbeOptions.Probe134 = true; + break; + default: + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid I/O Address 0x%X)\n", NULL, IO_Address); + return 0; + } + } else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) + BusLogic_ProbeOptions.NoProbeISA = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) + BusLogic_ProbeOptions.NoProbePCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) + BusLogic_ProbeOptions.NoProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) + BusLogic_ProbeOptions.NoSortPCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) + BusLogic_ProbeOptions.MultiMasterFirst = true; + else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) + BusLogic_ProbeOptions.FlashPointFirst = true; + /* Tagged Queuing Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || BusLogic_ParseKeyword(&OptionsString, "QD:[")) { + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) { + unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth > BusLogic_MaxTaggedQueueDepth) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth); + return 0; + } + DriverOptions->QueueDepth[TargetID] = QueueDepth; + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString == ']') + break; + else { + BusLogic_Error("BusLogic: Invalid Driver Options " "(',' or ']' expected at '%s')\n", NULL, OptionsString); + return 0; + } + } + if (*OptionsString != ']') { + BusLogic_Error("BusLogic: Invalid Driver Options " "(']' expected at '%s')\n", NULL, OptionsString); + return 0; + } else + OptionsString++; + } else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || BusLogic_ParseKeyword(&OptionsString, "QD:")) { + unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth); + return 0; + } + DriverOptions->CommonQueueDepth = QueueDepth; + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + DriverOptions->QueueDepth[TargetID] = QueueDepth; + } else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || BusLogic_ParseKeyword(&OptionsString, "TQ:")) { + if (BusLogic_ParseKeyword(&OptionsString, "Default")) { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0x0000; + } else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) { + DriverOptions->TaggedQueuingPermitted = 0xFFFF; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } else { + unsigned short TargetBit; + for (TargetID = 0, TargetBit = 1; TargetID < BusLogic_MaxTargetDevices; TargetID++, TargetBit <<= 1) + switch (*OptionsString++) { + case 'Y': + DriverOptions->TaggedQueuingPermitted |= TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'N': + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'X': + break; + default: + OptionsString--; + TargetID = BusLogic_MaxTargetDevices; + break; + } + } + } + /* Miscellaneous Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || BusLogic_ParseKeyword(&OptionsString, "BST:")) { + unsigned short BusSettleTime = simple_strtoul(OptionsString, &OptionsString, 0); + if (BusSettleTime > 5 * 60) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Bus Settle Time %d)\n", NULL, BusSettleTime); + return 0; + } + DriverOptions->BusSettleTime = BusSettleTime; + } else if (BusLogic_ParseKeyword(&OptionsString, "InhibitTargetInquiry")) + DriverOptions->LocalOptions.InhibitTargetInquiry = true; + /* Debugging Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) + BusLogic_GlobalOptions.TraceProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) + BusLogic_GlobalOptions.TraceHardwareReset = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) + BusLogic_GlobalOptions.TraceConfiguration = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) + BusLogic_GlobalOptions.TraceErrors = true; + else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) { + BusLogic_GlobalOptions.TraceProbe = true; + BusLogic_GlobalOptions.TraceHardwareReset = true; + BusLogic_GlobalOptions.TraceConfiguration = true; + BusLogic_GlobalOptions.TraceErrors = true; + } + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString != ';' && *OptionsString != '\0') { + BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " "ignored\n", NULL, OptionsString); + *OptionsString = '\0'; + } } - DriverOptions->CommonQueueDepth = QueueDepth; - for (TargetID = 0; - TargetID < BusLogic_MaxTargetDevices; - TargetID++) - DriverOptions->QueueDepth[TargetID] = QueueDepth; - } - else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || - BusLogic_ParseKeyword(&OptionsString, "TQ:")) - { - if (BusLogic_ParseKeyword(&OptionsString, "Default")) - { - DriverOptions->TaggedQueuingPermitted = 0x0000; - DriverOptions->TaggedQueuingPermittedMask = 0x0000; + if (!(BusLogic_DriverOptionsCount == 0 || BusLogic_ProbeInfoCount == 0 || BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) { + BusLogic_Error("BusLogic: Invalid Driver Options " "(all or no I/O Addresses must be specified)\n", NULL); + return 0; } - else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) - { - DriverOptions->TaggedQueuingPermitted = 0xFFFF; - DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; - } - else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) - { - DriverOptions->TaggedQueuingPermitted = 0x0000; - DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; - } - else - { - unsigned short TargetBit; - for (TargetID = 0, TargetBit = 1; - TargetID < BusLogic_MaxTargetDevices; - TargetID++, TargetBit <<= 1) - switch (*OptionsString++) - { - case 'Y': - DriverOptions->TaggedQueuingPermitted |= TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - break; - case 'N': - DriverOptions->TaggedQueuingPermitted &= ~TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - break; - case 'X': - break; - default: - OptionsString--; - TargetID = BusLogic_MaxTargetDevices; - break; - } - } - } - /* Miscellaneous Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || - BusLogic_ParseKeyword(&OptionsString, "BST:")) - { - unsigned short BusSettleTime = - simple_strtoul(OptionsString, &OptionsString, 0); - if (BusSettleTime > 5 * 60) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(invalid Bus Settle Time %d)\n", - NULL, BusSettleTime); - return 0; - } - DriverOptions->BusSettleTime = BusSettleTime; - } - else if (BusLogic_ParseKeyword(&OptionsString, - "InhibitTargetInquiry")) - DriverOptions->LocalOptions.InhibitTargetInquiry = true; - /* Debugging Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) - BusLogic_GlobalOptions.TraceProbe = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) - BusLogic_GlobalOptions.TraceHardwareReset = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) - BusLogic_GlobalOptions.TraceConfiguration = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) - BusLogic_GlobalOptions.TraceErrors = true; - else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) - { - BusLogic_GlobalOptions.TraceProbe = true; - BusLogic_GlobalOptions.TraceHardwareReset = true; - BusLogic_GlobalOptions.TraceConfiguration = true; - BusLogic_GlobalOptions.TraceErrors = true; - } - if (*OptionsString == ',') - OptionsString++; - else if (*OptionsString != ';' && *OptionsString != '\0') - { - BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " - "ignored\n", NULL, OptionsString); - *OptionsString = '\0'; - } - } - if (!(BusLogic_DriverOptionsCount == 0 || - BusLogic_ProbeInfoCount == 0 || - BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) - { - BusLogic_Error("BusLogic: Invalid Driver Options " - "(all or no I/O Addresses must be specified)\n", NULL); - return 0; - } - /* - Tagged Queuing is disabled when the Queue Depth is 1 since queuing - multiple commands is not possible. - */ - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - if (DriverOptions->QueueDepth[TargetID] == 1) - { - unsigned short TargetBit = 1 << TargetID; - DriverOptions->TaggedQueuingPermitted &= ~TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - } - if (*OptionsString == ';') OptionsString++; - if (*OptionsString == '\0') return 0; - } - return 1; + /* + Tagged Queuing is disabled when the Queue Depth is 1 since queuing + multiple commands is not possible. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + if (DriverOptions->QueueDepth[TargetID] == 1) { + unsigned short TargetBit = 1 << TargetID; + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + } + if (*OptionsString == ';') + OptionsString++; + if (*OptionsString == '\0') + return 0; + } + return 1; } /* @@ -4316,21 +3548,21 @@ static int __init BusLogic_ParseDriverOptions(char *OptionsString) */ static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .proc_name = "BusLogic", - .proc_info = BusLogic_ProcDirectoryInfo, - .name = "BusLogic", - .info = BusLogic_DriverInfo, - .queuecommand = BusLogic_QueueCommand, - .slave_configure = BusLogic_SlaveConfigure, - .bios_param = BusLogic_BIOSDiskParameters, - .eh_host_reset_handler = BusLogic_host_reset, + .module = THIS_MODULE, + .proc_name = "BusLogic", + .proc_info = BusLogic_ProcDirectoryInfo, + .name = "BusLogic", + .info = BusLogic_DriverInfo, + .queuecommand = BusLogic_QueueCommand, + .slave_configure = BusLogic_SlaveConfigure, + .bios_param = BusLogic_BIOSDiskParameters, + .eh_host_reset_handler = BusLogic_host_reset, #if 0 - .eh_abort_handler = BusLogic_AbortCommand, + .eh_abort_handler = BusLogic_AbortCommand, #endif - .unchecked_isa_dma = 1, - .max_sectors = 128, - .use_clustering = ENABLE_CLUSTERING, + .unchecked_isa_dma = 1, + .max_sectors = 128, + .use_clustering = ENABLE_CLUSTERING, }; /* @@ -4341,11 +3573,10 @@ static int __init BusLogic_Setup(char *str) { int ints[3]; - (void)get_options(str, ARRAY_SIZE(ints), ints); + (void) get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] != 0) { - BusLogic_Error("BusLogic: Obsolete Command Line Entry " - "Format Ignored\n", NULL); + BusLogic_Error("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL); return 0; } if (str == NULL || *str == '\0') @@ -4357,13 +3588,14 @@ static int __init BusLogic_Setup(char *str) * Initialization function */ -static int __init BusLogic_init(void) { +static int __init BusLogic_init(void) +{ #ifdef MODULE if (BusLogic) BusLogic_Setup(BusLogic); #endif - + return BusLogic_DetectHostAdapter(&driver_template) ? 0 : -ENODEV; } @@ -4374,14 +3606,12 @@ static int __init BusLogic_init(void) { static void __exit BusLogic_exit(void) { struct BusLogic_HostAdapter *HostAdapter; - for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; - HostAdapter != NULL; HostAdapter = HostAdapter->Next) { + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) { struct Scsi_Host *host = HostAdapter->SCSI_Host; scsi_remove_host(host); } - for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; - HostAdapter != NULL; HostAdapter = HostAdapter->Next) { + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) { struct Scsi_Host *host = HostAdapter->SCSI_Host; BusLogic_ReleaseHostAdapter(host); } diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 2dd778f57..facbce6da 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -128,17 +128,15 @@ Define the Driver Message Levels. */ -enum BusLogic_MessageLevel -{ - BusLogic_AnnounceLevel = 0, - BusLogic_InfoLevel = 1, - BusLogic_NoticeLevel = 2, - BusLogic_WarningLevel = 3, - BusLogic_ErrorLevel = 4 +enum BusLogic_MessageLevel { + BusLogic_AnnounceLevel = 0, + BusLogic_InfoLevel = 1, + BusLogic_NoticeLevel = 2, + BusLogic_WarningLevel = 3, + BusLogic_ErrorLevel = 4 }; -static char *BusLogic_MessageLevelMap[] = - { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; +static char *BusLogic_MessageLevelMap[] = { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; /* @@ -166,17 +164,15 @@ static char *BusLogic_MessageLevelMap[] = of I/O Addresses required by each type. */ -enum BusLogic_HostAdapterType -{ - BusLogic_MultiMaster = 1, - BusLogic_FlashPoint = 2 +enum BusLogic_HostAdapterType { + BusLogic_MultiMaster = 1, + BusLogic_FlashPoint = 2 } PACKED; #define BusLogic_MultiMasterAddressCount 4 #define BusLogic_FlashPointAddressCount 256 -static int BusLogic_HostAdapterAddressCount[3] = - { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; +static int BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; /* @@ -206,39 +202,35 @@ static int BusLogic_HostAdapterAddressCount[3] = Define the possible Host Adapter Bus Types. */ -enum BusLogic_HostAdapterBusType -{ - BusLogic_Unknown_Bus = 0, - BusLogic_ISA_Bus = 1, - BusLogic_EISA_Bus = 2, - BusLogic_PCI_Bus = 3, - BusLogic_VESA_Bus = 4, - BusLogic_MCA_Bus = 5 +enum BusLogic_HostAdapterBusType { + BusLogic_Unknown_Bus = 0, + BusLogic_ISA_Bus = 1, + BusLogic_EISA_Bus = 2, + BusLogic_PCI_Bus = 3, + BusLogic_VESA_Bus = 4, + BusLogic_MCA_Bus = 5 } PACKED; -static char *BusLogic_HostAdapterBusNames[] = - { "Unknown", "ISA", "EISA", "PCI", "VESA", "MCA" }; +static char *BusLogic_HostAdapterBusNames[] = { "Unknown", "ISA", "EISA", "PCI", "VESA", "MCA" }; -static enum BusLogic_HostAdapterBusType BusLogic_HostAdapterBusTypes[] = -{ - BusLogic_VESA_Bus, /* BT-4xx */ - BusLogic_ISA_Bus, /* BT-5xx */ - BusLogic_MCA_Bus, /* BT-6xx */ - BusLogic_EISA_Bus, /* BT-7xx */ - BusLogic_Unknown_Bus, /* BT-8xx */ - BusLogic_PCI_Bus /* BT-9xx */ +static enum BusLogic_HostAdapterBusType BusLogic_HostAdapterBusTypes[] = { + BusLogic_VESA_Bus, /* BT-4xx */ + BusLogic_ISA_Bus, /* BT-5xx */ + BusLogic_MCA_Bus, /* BT-6xx */ + BusLogic_EISA_Bus, /* BT-7xx */ + BusLogic_Unknown_Bus, /* BT-8xx */ + BusLogic_PCI_Bus /* BT-9xx */ }; /* Define the possible Host Adapter BIOS Disk Geometry Translations. */ -enum BusLogic_BIOS_DiskGeometryTranslation -{ - BusLogic_BIOS_Disk_Not_Installed = 0, - BusLogic_BIOS_Disk_Installed_64x32 = 1, - BusLogic_BIOS_Disk_Installed_128x32 = 2, - BusLogic_BIOS_Disk_Installed_255x63 = 3 +enum BusLogic_BIOS_DiskGeometryTranslation { + BusLogic_BIOS_Disk_Not_Installed = 0, + BusLogic_BIOS_Disk_Installed_64x32 = 1, + BusLogic_BIOS_Disk_Installed_128x32 = 2, + BusLogic_BIOS_Disk_Installed_255x63 = 3 } PACKED; @@ -247,18 +239,17 @@ enum BusLogic_BIOS_DiskGeometryTranslation */ typedef enum { - false, - true + false, + true } PACKED boolean; /* Define a 10^18 Statistics Byte Counter data type. */ -struct BusLogic_ByteCounter -{ - unsigned int Units; - unsigned int Billions; +struct BusLogic_ByteCounter { + unsigned int Units; + unsigned int Billions; }; @@ -266,58 +257,54 @@ struct BusLogic_ByteCounter Define the structure for I/O Address and Bus Probing Information. */ -struct BusLogic_ProbeInfo -{ - enum BusLogic_HostAdapterType HostAdapterType; - enum BusLogic_HostAdapterBusType HostAdapterBusType; - unsigned long IO_Address; - unsigned long PCI_Address; - struct pci_dev *PCI_Device; - unsigned char Bus; - unsigned char Device; - unsigned char IRQ_Channel; +struct BusLogic_ProbeInfo { + enum BusLogic_HostAdapterType HostAdapterType; + enum BusLogic_HostAdapterBusType HostAdapterBusType; + unsigned long IO_Address; + unsigned long PCI_Address; + struct pci_dev *PCI_Device; + unsigned char Bus; + unsigned char Device; + unsigned char IRQ_Channel; }; /* Define the Probe Options. */ -struct BusLogic_ProbeOptions -{ - boolean NoProbe:1; /* Bit 0 */ - boolean NoProbeISA:1; /* Bit 1 */ - boolean NoProbePCI:1; /* Bit 2 */ - boolean NoSortPCI:1; /* Bit 3 */ - boolean MultiMasterFirst:1; /* Bit 4 */ - boolean FlashPointFirst:1; /* Bit 5 */ - boolean LimitedProbeISA:1; /* Bit 6 */ - boolean Probe330:1; /* Bit 7 */ - boolean Probe334:1; /* Bit 8 */ - boolean Probe230:1; /* Bit 9 */ - boolean Probe234:1; /* Bit 10 */ - boolean Probe130:1; /* Bit 11 */ - boolean Probe134:1; /* Bit 12 */ +struct BusLogic_ProbeOptions { + boolean NoProbe:1; /* Bit 0 */ + boolean NoProbeISA:1; /* Bit 1 */ + boolean NoProbePCI:1; /* Bit 2 */ + boolean NoSortPCI:1; /* Bit 3 */ + boolean MultiMasterFirst:1; /* Bit 4 */ + boolean FlashPointFirst:1; /* Bit 5 */ + boolean LimitedProbeISA:1; /* Bit 6 */ + boolean Probe330:1; /* Bit 7 */ + boolean Probe334:1; /* Bit 8 */ + boolean Probe230:1; /* Bit 9 */ + boolean Probe234:1; /* Bit 10 */ + boolean Probe130:1; /* Bit 11 */ + boolean Probe134:1; /* Bit 12 */ }; /* Define the Global Options. */ -struct BusLogic_GlobalOptions -{ - boolean TraceProbe:1; /* Bit 0 */ - boolean TraceHardwareReset:1; /* Bit 1 */ - boolean TraceConfiguration:1; /* Bit 2 */ - boolean TraceErrors:1; /* Bit 3 */ +struct BusLogic_GlobalOptions { + boolean TraceProbe:1; /* Bit 0 */ + boolean TraceHardwareReset:1; /* Bit 1 */ + boolean TraceConfiguration:1; /* Bit 2 */ + boolean TraceErrors:1; /* Bit 3 */ }; /* Define the Local Options. */ -struct BusLogic_LocalOptions -{ - boolean InhibitTargetInquiry:1; /* Bit 0 */ +struct BusLogic_LocalOptions { + boolean InhibitTargetInquiry:1; /* Bit 0 */ }; /* @@ -335,198 +322,188 @@ struct BusLogic_LocalOptions Define the structure of the write-only Control Register. */ -union BusLogic_ControlRegister -{ - unsigned char All; - struct { - unsigned char :4; /* Bits 0-3 */ - boolean SCSIBusReset:1; /* Bit 4 */ - boolean InterruptReset:1; /* Bit 5 */ - boolean SoftReset:1; /* Bit 6 */ - boolean HardReset:1; /* Bit 7 */ - } cr; +union BusLogic_ControlRegister { + unsigned char All; + struct { + unsigned char:4; /* Bits 0-3 */ + boolean SCSIBusReset:1; /* Bit 4 */ + boolean InterruptReset:1; /* Bit 5 */ + boolean SoftReset:1; /* Bit 6 */ + boolean HardReset:1; /* Bit 7 */ + } cr; }; /* Define the structure of the read-only Status Register. */ -union BusLogic_StatusRegister -{ - unsigned char All; - struct { - boolean CommandInvalid:1; /* Bit 0 */ - boolean Reserved:1; /* Bit 1 */ - boolean DataInRegisterReady:1; /* Bit 2 */ - boolean CommandParameterRegisterBusy:1; /* Bit 3 */ - boolean HostAdapterReady:1; /* Bit 4 */ - boolean InitializationRequired:1; /* Bit 5 */ - boolean DiagnosticFailure:1; /* Bit 6 */ - boolean DiagnosticActive:1; /* Bit 7 */ - } sr; +union BusLogic_StatusRegister { + unsigned char All; + struct { + boolean CommandInvalid:1; /* Bit 0 */ + boolean Reserved:1; /* Bit 1 */ + boolean DataInRegisterReady:1; /* Bit 2 */ + boolean CommandParameterRegisterBusy:1; /* Bit 3 */ + boolean HostAdapterReady:1; /* Bit 4 */ + boolean InitializationRequired:1; /* Bit 5 */ + boolean DiagnosticFailure:1; /* Bit 6 */ + boolean DiagnosticActive:1; /* Bit 7 */ + } sr; }; /* Define the structure of the read-only Interrupt Register. */ -union BusLogic_InterruptRegister -{ - unsigned char All; - struct { - boolean IncomingMailboxLoaded:1; /* Bit 0 */ - boolean OutgoingMailboxAvailable:1; /* Bit 1 */ - boolean CommandComplete:1; /* Bit 2 */ - boolean ExternalBusReset:1; /* Bit 3 */ - unsigned char Reserved:3; /* Bits 4-6 */ - boolean InterruptValid:1; /* Bit 7 */ - } ir; +union BusLogic_InterruptRegister { + unsigned char All; + struct { + boolean IncomingMailboxLoaded:1; /* Bit 0 */ + boolean OutgoingMailboxAvailable:1; /* Bit 1 */ + boolean CommandComplete:1; /* Bit 2 */ + boolean ExternalBusReset:1; /* Bit 3 */ + unsigned char Reserved:3; /* Bits 4-6 */ + boolean InterruptValid:1; /* Bit 7 */ + } ir; }; /* Define the structure of the read-only Geometry Register. */ -union BusLogic_GeometryRegister -{ - unsigned char All; - struct { - enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2;/* Bits 0-1 */ - enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2;/* Bits 2-3 */ - unsigned char :3; /* Bits 4-6 */ - boolean ExtendedTranslationEnabled:1; /* Bit 7 */ - } gr; +union BusLogic_GeometryRegister { + unsigned char All; + struct { + enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2; /* Bits 0-1 */ + enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2; /* Bits 2-3 */ + unsigned char:3; /* Bits 4-6 */ + boolean ExtendedTranslationEnabled:1; /* Bit 7 */ + } gr; }; /* Define the BusLogic SCSI Host Adapter Command Register Operation Codes. */ -enum BusLogic_OperationCode -{ - BusLogic_TestCommandCompleteInterrupt = 0x00, - BusLogic_InitializeMailbox = 0x01, - BusLogic_ExecuteMailboxCommand = 0x02, - BusLogic_ExecuteBIOSCommand = 0x03, - BusLogic_InquireBoardID = 0x04, - BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, - BusLogic_SetSCSISelectionTimeout = 0x06, - BusLogic_SetPreemptTimeOnBus = 0x07, - BusLogic_SetTimeOffBus = 0x08, - BusLogic_SetBusTransferRate = 0x09, - BusLogic_InquireInstalledDevicesID0to7 = 0x0A, - BusLogic_InquireConfiguration = 0x0B, - BusLogic_EnableTargetMode = 0x0C, - BusLogic_InquireSetupInformation = 0x0D, - BusLogic_WriteAdapterLocalRAM = 0x1A, - BusLogic_ReadAdapterLocalRAM = 0x1B, - BusLogic_WriteBusMasterChipFIFO = 0x1C, - BusLogic_ReadBusMasterChipFIFO = 0x1D, - BusLogic_EchoCommandData = 0x1F, - BusLogic_HostAdapterDiagnostic = 0x20, - BusLogic_SetAdapterOptions = 0x21, - BusLogic_InquireInstalledDevicesID8to15 = 0x23, - BusLogic_InquireTargetDevices = 0x24, - BusLogic_DisableHostAdapterInterrupt = 0x25, - BusLogic_InitializeExtendedMailbox = 0x81, - BusLogic_ExecuteSCSICommand = 0x83, - BusLogic_InquireFirmwareVersion3rdDigit = 0x84, - BusLogic_InquireFirmwareVersionLetter = 0x85, - BusLogic_InquirePCIHostAdapterInformation = 0x86, - BusLogic_InquireHostAdapterModelNumber = 0x8B, - BusLogic_InquireSynchronousPeriod = 0x8C, - BusLogic_InquireExtendedSetupInformation = 0x8D, - BusLogic_EnableStrictRoundRobinMode = 0x8F, - BusLogic_StoreHostAdapterLocalRAM = 0x90, - BusLogic_FetchHostAdapterLocalRAM = 0x91, - BusLogic_StoreLocalDataInEEPROM = 0x92, - BusLogic_UploadAutoSCSICode = 0x94, - BusLogic_ModifyIOAddress = 0x95, - BusLogic_SetCCBFormat = 0x96, - BusLogic_WriteInquiryBuffer = 0x9A, - BusLogic_ReadInquiryBuffer = 0x9B, - BusLogic_FlashROMUploadDownload = 0xA7, - BusLogic_ReadSCAMData = 0xA8, - BusLogic_WriteSCAMData = 0xA9 +enum BusLogic_OperationCode { + BusLogic_TestCommandCompleteInterrupt = 0x00, + BusLogic_InitializeMailbox = 0x01, + BusLogic_ExecuteMailboxCommand = 0x02, + BusLogic_ExecuteBIOSCommand = 0x03, + BusLogic_InquireBoardID = 0x04, + BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, + BusLogic_SetSCSISelectionTimeout = 0x06, + BusLogic_SetPreemptTimeOnBus = 0x07, + BusLogic_SetTimeOffBus = 0x08, + BusLogic_SetBusTransferRate = 0x09, + BusLogic_InquireInstalledDevicesID0to7 = 0x0A, + BusLogic_InquireConfiguration = 0x0B, + BusLogic_EnableTargetMode = 0x0C, + BusLogic_InquireSetupInformation = 0x0D, + BusLogic_WriteAdapterLocalRAM = 0x1A, + BusLogic_ReadAdapterLocalRAM = 0x1B, + BusLogic_WriteBusMasterChipFIFO = 0x1C, + BusLogic_ReadBusMasterChipFIFO = 0x1D, + BusLogic_EchoCommandData = 0x1F, + BusLogic_HostAdapterDiagnostic = 0x20, + BusLogic_SetAdapterOptions = 0x21, + BusLogic_InquireInstalledDevicesID8to15 = 0x23, + BusLogic_InquireTargetDevices = 0x24, + BusLogic_DisableHostAdapterInterrupt = 0x25, + BusLogic_InitializeExtendedMailbox = 0x81, + BusLogic_ExecuteSCSICommand = 0x83, + BusLogic_InquireFirmwareVersion3rdDigit = 0x84, + BusLogic_InquireFirmwareVersionLetter = 0x85, + BusLogic_InquirePCIHostAdapterInformation = 0x86, + BusLogic_InquireHostAdapterModelNumber = 0x8B, + BusLogic_InquireSynchronousPeriod = 0x8C, + BusLogic_InquireExtendedSetupInformation = 0x8D, + BusLogic_EnableStrictRoundRobinMode = 0x8F, + BusLogic_StoreHostAdapterLocalRAM = 0x90, + BusLogic_FetchHostAdapterLocalRAM = 0x91, + BusLogic_StoreLocalDataInEEPROM = 0x92, + BusLogic_UploadAutoSCSICode = 0x94, + BusLogic_ModifyIOAddress = 0x95, + BusLogic_SetCCBFormat = 0x96, + BusLogic_WriteInquiryBuffer = 0x9A, + BusLogic_ReadInquiryBuffer = 0x9B, + BusLogic_FlashROMUploadDownload = 0xA7, + BusLogic_ReadSCAMData = 0xA8, + BusLogic_WriteSCAMData = 0xA9 }; /* Define the Inquire Board ID reply structure. */ -struct BusLogic_BoardID -{ - unsigned char BoardType; /* Byte 0 */ - unsigned char CustomFeatures; /* Byte 1 */ - unsigned char FirmwareVersion1stDigit; /* Byte 2 */ - unsigned char FirmwareVersion2ndDigit; /* Byte 3 */ +struct BusLogic_BoardID { + unsigned char BoardType; /* Byte 0 */ + unsigned char CustomFeatures; /* Byte 1 */ + unsigned char FirmwareVersion1stDigit; /* Byte 2 */ + unsigned char FirmwareVersion2ndDigit; /* Byte 3 */ }; /* Define the Inquire Configuration reply structure. */ -struct BusLogic_Configuration -{ - unsigned char :5; /* Byte 0 Bits 0-4 */ - boolean DMA_Channel5:1; /* Byte 0 Bit 5 */ - boolean DMA_Channel6:1; /* Byte 0 Bit 6 */ - boolean DMA_Channel7:1; /* Byte 0 Bit 7 */ - boolean IRQ_Channel9:1; /* Byte 1 Bit 0 */ - boolean IRQ_Channel10:1; /* Byte 1 Bit 1 */ - boolean IRQ_Channel11:1; /* Byte 1 Bit 2 */ - boolean IRQ_Channel12:1; /* Byte 1 Bit 3 */ - unsigned char :1; /* Byte 1 Bit 4 */ - boolean IRQ_Channel14:1; /* Byte 1 Bit 5 */ - boolean IRQ_Channel15:1; /* Byte 1 Bit 6 */ - unsigned char :1; /* Byte 1 Bit 7 */ - unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */ - unsigned char :4; /* Byte 2 Bits 4-7 */ +struct BusLogic_Configuration { + unsigned char:5; /* Byte 0 Bits 0-4 */ + boolean DMA_Channel5:1; /* Byte 0 Bit 5 */ + boolean DMA_Channel6:1; /* Byte 0 Bit 6 */ + boolean DMA_Channel7:1; /* Byte 0 Bit 7 */ + boolean IRQ_Channel9:1; /* Byte 1 Bit 0 */ + boolean IRQ_Channel10:1; /* Byte 1 Bit 1 */ + boolean IRQ_Channel11:1; /* Byte 1 Bit 2 */ + boolean IRQ_Channel12:1; /* Byte 1 Bit 3 */ + unsigned char:1; /* Byte 1 Bit 4 */ + boolean IRQ_Channel14:1; /* Byte 1 Bit 5 */ + boolean IRQ_Channel15:1; /* Byte 1 Bit 6 */ + unsigned char:1; /* Byte 1 Bit 7 */ + unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */ + unsigned char:4; /* Byte 2 Bits 4-7 */ }; /* Define the Inquire Setup Information reply structure. */ -struct BusLogic_SynchronousValue -{ - unsigned char Offset:4; /* Bits 0-3 */ - unsigned char TransferPeriod:3; /* Bits 4-6 */ - boolean Synchronous:1; /* Bit 7 */ +struct BusLogic_SynchronousValue { + unsigned char Offset:4; /* Bits 0-3 */ + unsigned char TransferPeriod:3; /* Bits 4-6 */ + boolean Synchronous:1; /* Bit 7 */ }; -struct BusLogic_SetupInformation -{ - boolean SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ - boolean ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ - unsigned char :6; /* Byte 0 Bits 2-7 */ - unsigned char BusTransferRate; /* Byte 1 */ - unsigned char PreemptTimeOnBus; /* Byte 2 */ - unsigned char TimeOffBus; /* Byte 3 */ - unsigned char MailboxCount; /* Byte 4 */ - unsigned char MailboxAddress[3]; /* Bytes 5-7 */ - struct BusLogic_SynchronousValue SynchronousValuesID0to7[8];/* Bytes 8-15 */ - unsigned char DisconnectPermittedID0to7; /* Byte 16 */ - unsigned char Signature; /* Byte 17 */ - unsigned char CharacterD; /* Byte 18 */ - unsigned char HostBusType; /* Byte 19 */ - unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ - unsigned char WideTransfersActiveID0to7; /* Byte 21 */ - struct BusLogic_SynchronousValue SynchronousValuesID8to15[8]; /* Bytes 22-29 */ - unsigned char DisconnectPermittedID8to15; /* Byte 30 */ - unsigned char :8; /* Byte 31 */ - unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ - unsigned char WideTransfersActiveID8to15; /* Byte 33 */ +struct BusLogic_SetupInformation { + boolean SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ + boolean ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ + unsigned char:6; /* Byte 0 Bits 2-7 */ + unsigned char BusTransferRate; /* Byte 1 */ + unsigned char PreemptTimeOnBus; /* Byte 2 */ + unsigned char TimeOffBus; /* Byte 3 */ + unsigned char MailboxCount; /* Byte 4 */ + unsigned char MailboxAddress[3]; /* Bytes 5-7 */ + struct BusLogic_SynchronousValue SynchronousValuesID0to7[8]; /* Bytes 8-15 */ + unsigned char DisconnectPermittedID0to7; /* Byte 16 */ + unsigned char Signature; /* Byte 17 */ + unsigned char CharacterD; /* Byte 18 */ + unsigned char HostBusType; /* Byte 19 */ + unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ + unsigned char WideTransfersActiveID0to7; /* Byte 21 */ + struct BusLogic_SynchronousValue SynchronousValuesID8to15[8]; /* Bytes 22-29 */ + unsigned char DisconnectPermittedID8to15; /* Byte 30 */ + unsigned char:8; /* Byte 31 */ + unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ + unsigned char WideTransfersActiveID8to15; /* Byte 33 */ }; /* Define the Initialize Extended Mailbox request structure. */ -struct BusLogic_ExtendedMailboxRequest -{ - unsigned char MailboxCount; /* Byte 0 */ - u32 BaseMailboxAddress; /* Bytes 1-4 */ +struct BusLogic_ExtendedMailboxRequest { + unsigned char MailboxCount; /* Byte 0 */ + u32 BaseMailboxAddress; /* Bytes 1-4 */ } PACKED; @@ -536,67 +513,63 @@ struct BusLogic_ExtendedMailboxRequest the Modify I/O Address command. */ -enum BusLogic_ISACompatibleIOPort -{ - BusLogic_IO_330 = 0, - BusLogic_IO_334 = 1, - BusLogic_IO_230 = 2, - BusLogic_IO_234 = 3, - BusLogic_IO_130 = 4, - BusLogic_IO_134 = 5, - BusLogic_IO_Disable = 6, - BusLogic_IO_Disable2 = 7 +enum BusLogic_ISACompatibleIOPort { + BusLogic_IO_330 = 0, + BusLogic_IO_334 = 1, + BusLogic_IO_230 = 2, + BusLogic_IO_234 = 3, + BusLogic_IO_130 = 4, + BusLogic_IO_134 = 5, + BusLogic_IO_Disable = 6, + BusLogic_IO_Disable2 = 7 } PACKED; -struct BusLogic_PCIHostAdapterInformation -{ - enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort;/* Byte 0 */ - unsigned char PCIAssignedIRQChannel; /* Byte 1 */ - boolean LowByteTerminated:1; /* Byte 2 Bit 0 */ - boolean HighByteTerminated:1; /* Byte 2 Bit 1 */ - unsigned char :2; /* Byte 2 Bits 2-3 */ - boolean JP1:1; /* Byte 2 Bit 4 */ - boolean JP2:1; /* Byte 2 Bit 5 */ - boolean JP3:1; /* Byte 2 Bit 6 */ - boolean GenericInfoValid:1; /* Byte 2 Bit 7 */ - unsigned char :8; /* Byte 3 */ +struct BusLogic_PCIHostAdapterInformation { + enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort; /* Byte 0 */ + unsigned char PCIAssignedIRQChannel; /* Byte 1 */ + boolean LowByteTerminated:1; /* Byte 2 Bit 0 */ + boolean HighByteTerminated:1; /* Byte 2 Bit 1 */ + unsigned char:2; /* Byte 2 Bits 2-3 */ + boolean JP1:1; /* Byte 2 Bit 4 */ + boolean JP2:1; /* Byte 2 Bit 5 */ + boolean JP3:1; /* Byte 2 Bit 6 */ + boolean GenericInfoValid:1; /* Byte 2 Bit 7 */ + unsigned char:8; /* Byte 3 */ }; /* Define the Inquire Extended Setup Information reply structure. */ -struct BusLogic_ExtendedSetupInformation -{ - unsigned char BusType; /* Byte 0 */ - unsigned char BIOS_Address; /* Byte 1 */ - unsigned short ScatterGatherLimit; /* Bytes 2-3 */ - unsigned char MailboxCount; /* Byte 4 */ - u32 BaseMailboxAddress; /* Bytes 5-8 */ - struct { - unsigned char :2; /* Byte 9 Bits 0-1 */ - boolean FastOnEISA:1; /* Byte 9 Bit 2 */ - unsigned char :3; /* Byte 9 Bits 3-5 */ - boolean LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ - unsigned char :1; /* Byte 9 Bit 7 */ - } Misc; - unsigned char FirmwareRevision[3]; /* Bytes 10-12 */ - boolean HostWideSCSI:1; /* Byte 13 Bit 0 */ - boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ - boolean HostSupportsSCAM:1; /* Byte 13 Bit 2 */ - boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */ - boolean HostSmartTermination:1; /* Byte 13 Bit 4 */ - unsigned char :3; /* Byte 13 Bits 5-7 */ +struct BusLogic_ExtendedSetupInformation { + unsigned char BusType; /* Byte 0 */ + unsigned char BIOS_Address; /* Byte 1 */ + unsigned short ScatterGatherLimit; /* Bytes 2-3 */ + unsigned char MailboxCount; /* Byte 4 */ + u32 BaseMailboxAddress; /* Bytes 5-8 */ + struct { + unsigned char:2; /* Byte 9 Bits 0-1 */ + boolean FastOnEISA:1; /* Byte 9 Bit 2 */ + unsigned char:3; /* Byte 9 Bits 3-5 */ + boolean LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ + unsigned char:1; /* Byte 9 Bit 7 */ + } Misc; + unsigned char FirmwareRevision[3]; /* Bytes 10-12 */ + boolean HostWideSCSI:1; /* Byte 13 Bit 0 */ + boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ + boolean HostSupportsSCAM:1; /* Byte 13 Bit 2 */ + boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */ + boolean HostSmartTermination:1; /* Byte 13 Bit 4 */ + unsigned char:3; /* Byte 13 Bits 5-7 */ } PACKED; /* Define the Enable Strict Round Robin Mode request type. */ -enum BusLogic_RoundRobinModeRequest -{ - BusLogic_AggressiveRoundRobinMode = 0, - BusLogic_StrictRoundRobinMode = 1 +enum BusLogic_RoundRobinModeRequest { + BusLogic_AggressiveRoundRobinMode = 0, + BusLogic_StrictRoundRobinMode = 1 } PACKED; @@ -607,96 +580,93 @@ enum BusLogic_RoundRobinModeRequest #define BusLogic_BIOS_BaseOffset 0 #define BusLogic_AutoSCSI_BaseOffset 64 -struct BusLogic_FetchHostAdapterLocalRAMRequest -{ - unsigned char ByteOffset; /* Byte 0 */ - unsigned char ByteCount; /* Byte 1 */ +struct BusLogic_FetchHostAdapterLocalRAMRequest { + unsigned char ByteOffset; /* Byte 0 */ + unsigned char ByteCount; /* Byte 1 */ }; /* Define the Host Adapter Local RAM AutoSCSI structure. */ -struct BusLogic_AutoSCSIData -{ - unsigned char InternalFactorySignature[2]; /* Bytes 0-1 */ - unsigned char InformationByteCount; /* Byte 2 */ - unsigned char HostAdapterType[6]; /* Bytes 3-8 */ - unsigned char :8; /* Byte 9 */ - boolean FloppyEnabled:1; /* Byte 10 Bit 0 */ - boolean FloppySecondary:1; /* Byte 10 Bit 1 */ - boolean LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ - unsigned char :2; /* Byte 10 Bits 3-4 */ - unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */ - unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */ - boolean DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ - unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */ - boolean IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ - unsigned char DMA_TransferRate; /* Byte 13 */ - unsigned char SCSI_ID; /* Byte 14 */ - boolean LowByteTerminated:1; /* Byte 15 Bit 0 */ - boolean ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ - boolean HighByteTerminated:1; /* Byte 15 Bit 2 */ - boolean NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ - boolean FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ - boolean BusResetEnabled:1; /* Byte 15 Bit 5 */ - boolean :1; /* Byte 15 Bit 6 */ - boolean ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ - unsigned char BusOnDelay; /* Byte 16 */ - unsigned char BusOffDelay; /* Byte 17 */ - boolean HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ - boolean BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ - boolean ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ - boolean MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ - boolean :1; /* Byte 18 Bit 4 */ - boolean BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ - boolean BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ - boolean FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ - unsigned short DeviceEnabled; /* Bytes 19-20 */ - unsigned short WidePermitted; /* Bytes 21-22 */ - unsigned short FastPermitted; /* Bytes 23-24 */ - unsigned short SynchronousPermitted; /* Bytes 25-26 */ - unsigned short DisconnectPermitted; /* Bytes 27-28 */ - unsigned short SendStartUnitCommand; /* Bytes 29-30 */ - unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */ - unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */ - unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */ - boolean StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ - boolean VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ - boolean VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ - boolean VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ - unsigned short UltraPermitted; /* Bytes 34-35 */ - unsigned int :32; /* Bytes 36-39 */ - unsigned char :8; /* Byte 40 */ - unsigned char AutoSCSIMaximumLUN; /* Byte 41 */ - boolean :1; /* Byte 42 Bit 0 */ - boolean SCAM_Dominant:1; /* Byte 42 Bit 1 */ - boolean SCAM_Enabled:1; /* Byte 42 Bit 2 */ - boolean SCAM_Level2:1; /* Byte 42 Bit 3 */ - unsigned char :4; /* Byte 42 Bits 4-7 */ - boolean INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ - boolean :1; /* Byte 43 Bit 1 */ - boolean CDROMBootEnabled:1; /* Byte 43 Bit 2 */ - unsigned char :5; /* Byte 43 Bits 3-7 */ - unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */ - unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */ - unsigned char ForceBusDeviceScanningOrder:1; /* Byte 45 Bit 0 */ - unsigned char :7; /* Byte 45 Bits 1-7 */ - unsigned short NonTaggedToAlternateLUNPermitted; /* Bytes 46-47 */ - unsigned short RenegotiateSyncAfterCheckCondition; /* Bytes 48-49 */ - unsigned char Reserved[10]; /* Bytes 50-59 */ - unsigned char ManufacturingDiagnostic[2]; /* Bytes 60-61 */ - unsigned short Checksum; /* Bytes 62-63 */ +struct BusLogic_AutoSCSIData { + unsigned char InternalFactorySignature[2]; /* Bytes 0-1 */ + unsigned char InformationByteCount; /* Byte 2 */ + unsigned char HostAdapterType[6]; /* Bytes 3-8 */ + unsigned char:8; /* Byte 9 */ + boolean FloppyEnabled:1; /* Byte 10 Bit 0 */ + boolean FloppySecondary:1; /* Byte 10 Bit 1 */ + boolean LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ + unsigned char:2; /* Byte 10 Bits 3-4 */ + unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */ + unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */ + boolean DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ + unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */ + boolean IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ + unsigned char DMA_TransferRate; /* Byte 13 */ + unsigned char SCSI_ID; /* Byte 14 */ + boolean LowByteTerminated:1; /* Byte 15 Bit 0 */ + boolean ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ + boolean HighByteTerminated:1; /* Byte 15 Bit 2 */ + boolean NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ + boolean FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ + boolean BusResetEnabled:1; /* Byte 15 Bit 5 */ + boolean:1; /* Byte 15 Bit 6 */ + boolean ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ + unsigned char BusOnDelay; /* Byte 16 */ + unsigned char BusOffDelay; /* Byte 17 */ + boolean HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ + boolean BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ + boolean ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ + boolean MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ + boolean:1; /* Byte 18 Bit 4 */ + boolean BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ + boolean BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ + boolean FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ + unsigned short DeviceEnabled; /* Bytes 19-20 */ + unsigned short WidePermitted; /* Bytes 21-22 */ + unsigned short FastPermitted; /* Bytes 23-24 */ + unsigned short SynchronousPermitted; /* Bytes 25-26 */ + unsigned short DisconnectPermitted; /* Bytes 27-28 */ + unsigned short SendStartUnitCommand; /* Bytes 29-30 */ + unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */ + unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */ + unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */ + boolean StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ + boolean VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ + boolean VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ + boolean VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ + unsigned short UltraPermitted; /* Bytes 34-35 */ + unsigned int:32; /* Bytes 36-39 */ + unsigned char:8; /* Byte 40 */ + unsigned char AutoSCSIMaximumLUN; /* Byte 41 */ + boolean:1; /* Byte 42 Bit 0 */ + boolean SCAM_Dominant:1; /* Byte 42 Bit 1 */ + boolean SCAM_Enabled:1; /* Byte 42 Bit 2 */ + boolean SCAM_Level2:1; /* Byte 42 Bit 3 */ + unsigned char:4; /* Byte 42 Bits 4-7 */ + boolean INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ + boolean:1; /* Byte 43 Bit 1 */ + boolean CDROMBootEnabled:1; /* Byte 43 Bit 2 */ + unsigned char:5; /* Byte 43 Bits 3-7 */ + unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */ + unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */ + unsigned char ForceBusDeviceScanningOrder:1; /* Byte 45 Bit 0 */ + unsigned char:7; /* Byte 45 Bits 1-7 */ + unsigned short NonTaggedToAlternateLUNPermitted; /* Bytes 46-47 */ + unsigned short RenegotiateSyncAfterCheckCondition; /* Bytes 48-49 */ + unsigned char Reserved[10]; /* Bytes 50-59 */ + unsigned char ManufacturingDiagnostic[2]; /* Bytes 60-61 */ + unsigned short Checksum; /* Bytes 62-63 */ } PACKED; /* Define the Host Adapter Local RAM Auto SCSI Byte 45 structure. */ -struct BusLogic_AutoSCSIByte45 -{ - unsigned char ForceBusDeviceScanningOrder:1; /* Bit 0 */ - unsigned char :7; /* Bits 1-7 */ +struct BusLogic_AutoSCSIByte45 { + unsigned char ForceBusDeviceScanningOrder:1; /* Bit 0 */ + unsigned char:7; /* Bits 1-7 */ }; /* @@ -705,12 +675,11 @@ struct BusLogic_AutoSCSIByte45 #define BusLogic_BIOS_DriveMapOffset 17 -struct BusLogic_BIOSDriveMapByte -{ - unsigned char TargetIDBit3:1; /* Bit 0 */ - unsigned char :2; /* Bits 1-2 */ - enum BusLogic_BIOS_DiskGeometryTranslation DiskGeometry:2; /* Bits 3-4 */ - unsigned char TargetID:3; /* Bits 5-7 */ +struct BusLogic_BIOSDriveMapByte { + unsigned char TargetIDBit3:1; /* Bit 0 */ + unsigned char:2; /* Bits 1-2 */ + enum BusLogic_BIOS_DiskGeometryTranslation DiskGeometry:2; /* Bits 3-4 */ + unsigned char TargetID:3; /* Bits 5-7 */ }; /* @@ -718,21 +687,19 @@ struct BusLogic_BIOSDriveMapByte necessary to support more than 8 Logical Units per Target Device. */ -enum BusLogic_SetCCBFormatRequest -{ - BusLogic_LegacyLUNFormatCCB = 0, - BusLogic_ExtendedLUNFormatCCB = 1 +enum BusLogic_SetCCBFormatRequest { + BusLogic_LegacyLUNFormatCCB = 0, + BusLogic_ExtendedLUNFormatCCB = 1 } PACKED; /* Define the Outgoing Mailbox Action Codes. */ -enum BusLogic_ActionCode -{ - BusLogic_OutgoingMailboxFree = 0x00, - BusLogic_MailboxStartCommand = 0x01, - BusLogic_MailboxAbortCommand = 0x02 +enum BusLogic_ActionCode { + BusLogic_OutgoingMailboxFree = 0x00, + BusLogic_MailboxStartCommand = 0x01, + BusLogic_MailboxAbortCommand = 0x02 } PACKED; @@ -742,28 +709,26 @@ enum BusLogic_ActionCode completion codes are stored in the CCB; it only uses codes 1, 2, 4, and 5. */ -enum BusLogic_CompletionCode -{ - BusLogic_IncomingMailboxFree = 0x00, - BusLogic_CommandCompletedWithoutError = 0x01, - BusLogic_CommandAbortedAtHostRequest = 0x02, - BusLogic_AbortedCommandNotFound = 0x03, - BusLogic_CommandCompletedWithError = 0x04, - BusLogic_InvalidCCB = 0x05 +enum BusLogic_CompletionCode { + BusLogic_IncomingMailboxFree = 0x00, + BusLogic_CommandCompletedWithoutError = 0x01, + BusLogic_CommandAbortedAtHostRequest = 0x02, + BusLogic_AbortedCommandNotFound = 0x03, + BusLogic_CommandCompletedWithError = 0x04, + BusLogic_InvalidCCB = 0x05 } PACKED; /* Define the Command Control Block (CCB) Opcodes. */ -enum BusLogic_CCB_Opcode -{ - BusLogic_InitiatorCCB = 0x00, - BusLogic_TargetCCB = 0x01, - BusLogic_InitiatorCCB_ScatterGather = 0x02, - BusLogic_InitiatorCCB_ResidualDataLength = 0x03, - BusLogic_InitiatorCCB_ScatterGatherResidual = 0x04, - BusLogic_BusDeviceReset = 0x81 +enum BusLogic_CCB_Opcode { + BusLogic_InitiatorCCB = 0x00, + BusLogic_TargetCCB = 0x01, + BusLogic_InitiatorCCB_ScatterGather = 0x02, + BusLogic_InitiatorCCB_ResidualDataLength = 0x03, + BusLogic_InitiatorCCB_ScatterGatherResidual = 0x04, + BusLogic_BusDeviceReset = 0x81 } PACKED; @@ -771,12 +736,11 @@ enum BusLogic_CCB_Opcode Define the CCB Data Direction Codes. */ -enum BusLogic_DataDirection -{ - BusLogic_UncheckedDataTransfer = 0, - BusLogic_DataInLengthChecked = 1, - BusLogic_DataOutLengthChecked = 2, - BusLogic_NoDataTransfer = 3 +enum BusLogic_DataDirection { + BusLogic_UncheckedDataTransfer = 0, + BusLogic_DataInLengthChecked = 1, + BusLogic_DataOutLengthChecked = 2, + BusLogic_NoDataTransfer = 3 }; @@ -785,33 +749,32 @@ enum BusLogic_DataDirection return status code 0x0C; it uses 0x12 for both overruns and underruns. */ -enum BusLogic_HostAdapterStatus -{ - BusLogic_CommandCompletedNormally = 0x00, - BusLogic_LinkedCommandCompleted = 0x0A, - BusLogic_LinkedCommandCompletedWithFlag = 0x0B, - BusLogic_DataUnderRun = 0x0C, - BusLogic_SCSISelectionTimeout = 0x11, - BusLogic_DataOverRun = 0x12, - BusLogic_UnexpectedBusFree = 0x13, - BusLogic_InvalidBusPhaseRequested = 0x14, - BusLogic_InvalidOutgoingMailboxActionCode = 0x15, - BusLogic_InvalidCommandOperationCode = 0x16, - BusLogic_LinkedCCBhasInvalidLUN = 0x17, - BusLogic_InvalidCommandParameter = 0x1A, - BusLogic_AutoRequestSenseFailed = 0x1B, - BusLogic_TaggedQueuingMessageRejected = 0x1C, - BusLogic_UnsupportedMessageReceived = 0x1D, - BusLogic_HostAdapterHardwareFailed = 0x20, - BusLogic_TargetFailedResponseToATN = 0x21, - BusLogic_HostAdapterAssertedRST = 0x22, - BusLogic_OtherDeviceAssertedRST = 0x23, - BusLogic_TargetDeviceReconnectedImproperly = 0x24, - BusLogic_HostAdapterAssertedBusDeviceReset = 0x25, - BusLogic_AbortQueueGenerated = 0x26, - BusLogic_HostAdapterSoftwareError = 0x27, - BusLogic_HostAdapterHardwareTimeoutError = 0x30, - BusLogic_SCSIParityErrorDetected = 0x34 +enum BusLogic_HostAdapterStatus { + BusLogic_CommandCompletedNormally = 0x00, + BusLogic_LinkedCommandCompleted = 0x0A, + BusLogic_LinkedCommandCompletedWithFlag = 0x0B, + BusLogic_DataUnderRun = 0x0C, + BusLogic_SCSISelectionTimeout = 0x11, + BusLogic_DataOverRun = 0x12, + BusLogic_UnexpectedBusFree = 0x13, + BusLogic_InvalidBusPhaseRequested = 0x14, + BusLogic_InvalidOutgoingMailboxActionCode = 0x15, + BusLogic_InvalidCommandOperationCode = 0x16, + BusLogic_LinkedCCBhasInvalidLUN = 0x17, + BusLogic_InvalidCommandParameter = 0x1A, + BusLogic_AutoRequestSenseFailed = 0x1B, + BusLogic_TaggedQueuingMessageRejected = 0x1C, + BusLogic_UnsupportedMessageReceived = 0x1D, + BusLogic_HostAdapterHardwareFailed = 0x20, + BusLogic_TargetFailedResponseToATN = 0x21, + BusLogic_HostAdapterAssertedRST = 0x22, + BusLogic_OtherDeviceAssertedRST = 0x23, + BusLogic_TargetDeviceReconnectedImproperly = 0x24, + BusLogic_HostAdapterAssertedBusDeviceReset = 0x25, + BusLogic_AbortQueueGenerated = 0x26, + BusLogic_HostAdapterSoftwareError = 0x27, + BusLogic_HostAdapterHardwareTimeoutError = 0x30, + BusLogic_SCSIParityErrorDetected = 0x34 } PACKED; @@ -819,23 +782,21 @@ enum BusLogic_HostAdapterStatus Define the SCSI Target Device Status Codes. */ -enum BusLogic_TargetDeviceStatus -{ - BusLogic_OperationGood = 0x00, - BusLogic_CheckCondition = 0x02, - BusLogic_DeviceBusy = 0x08 +enum BusLogic_TargetDeviceStatus { + BusLogic_OperationGood = 0x00, + BusLogic_CheckCondition = 0x02, + BusLogic_DeviceBusy = 0x08 } PACKED; /* Define the Queue Tag Codes. */ -enum BusLogic_QueueTag -{ - BusLogic_SimpleQueueTag = 0, - BusLogic_HeadOfQueueTag = 1, - BusLogic_OrderedQueueTag = 2, - BusLogic_ReservedQT = 3 +enum BusLogic_QueueTag { + BusLogic_SimpleQueueTag = 0, + BusLogic_HeadOfQueueTag = 1, + BusLogic_OrderedQueueTag = 2, + BusLogic_ReservedQT = 3 }; /* @@ -852,22 +813,20 @@ typedef unsigned char SCSI_CDB_T[BusLogic_CDB_MaxLength]; Firmware Interface and the FlashPoint SCCB Manager. */ -struct BusLogic_ScatterGatherSegment -{ - u32 SegmentByteCount; /* Bytes 0-3 */ - u32 SegmentDataPointer; /* Bytes 4-7 */ +struct BusLogic_ScatterGatherSegment { + u32 SegmentByteCount; /* Bytes 0-3 */ + u32 SegmentDataPointer; /* Bytes 4-7 */ }; /* Define the Driver CCB Status Codes. */ -enum BusLogic_CCB_Status -{ - BusLogic_CCB_Free = 0, - BusLogic_CCB_Active = 1, - BusLogic_CCB_Completed = 2, - BusLogic_CCB_Reset = 3 +enum BusLogic_CCB_Status { + BusLogic_CCB_Free = 0, + BusLogic_CCB_Active = 1, + BusLogic_CCB_Completed = 2, + BusLogic_CCB_Reset = 3 } PACKED; @@ -890,82 +849,79 @@ enum BusLogic_CCB_Status 32 Logical Units per Target Device. */ -struct BusLogic_CCB -{ - /* - MultiMaster Firmware and FlashPoint SCCB Manager Common Portion. - */ - enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */ - unsigned char :3; /* Byte 1 Bits 0-2 */ - enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */ - boolean TagEnable:1; /* Byte 1 Bit 5 */ - enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */ - unsigned char CDB_Length; /* Byte 2 */ - unsigned char SenseDataLength; /* Byte 3 */ - u32 DataLength; /* Bytes 4-7 */ - u32 DataPointer; /* Bytes 8-11 */ - unsigned char :8; /* Byte 12 */ - unsigned char :8; /* Byte 13 */ - enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 14 */ - enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */ - unsigned char TargetID; /* Byte 16 */ - unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */ - boolean LegacyTagEnable:1; /* Byte 17 Bit 5 */ - enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */ - SCSI_CDB_T CDB; /* Bytes 18-29 */ - unsigned char :8; /* Byte 30 */ - unsigned char :8; /* Byte 31 */ - unsigned int :32; /* Bytes 32-35 */ - u32 SenseDataPointer; /* Bytes 36-39 */ - /* - FlashPoint SCCB Manager Defined Portion. - */ - void (*CallbackFunction)(struct BusLogic_CCB *); /* Bytes 40-43 */ - u32 BaseAddress; /* Bytes 44-47 */ - enum BusLogic_CompletionCode CompletionCode; /* Byte 48 */ +struct BusLogic_CCB { + /* + MultiMaster Firmware and FlashPoint SCCB Manager Common Portion. + */ + enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */ + unsigned char:3; /* Byte 1 Bits 0-2 */ + enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */ + boolean TagEnable:1; /* Byte 1 Bit 5 */ + enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */ + unsigned char CDB_Length; /* Byte 2 */ + unsigned char SenseDataLength; /* Byte 3 */ + u32 DataLength; /* Bytes 4-7 */ + u32 DataPointer; /* Bytes 8-11 */ + unsigned char:8; /* Byte 12 */ + unsigned char:8; /* Byte 13 */ + enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 14 */ + enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */ + unsigned char TargetID; /* Byte 16 */ + unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */ + boolean LegacyTagEnable:1; /* Byte 17 Bit 5 */ + enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */ + SCSI_CDB_T CDB; /* Bytes 18-29 */ + unsigned char:8; /* Byte 30 */ + unsigned char:8; /* Byte 31 */ + unsigned int:32; /* Bytes 32-35 */ + u32 SenseDataPointer; /* Bytes 36-39 */ + /* + FlashPoint SCCB Manager Defined Portion. + */ + void (*CallbackFunction) (struct BusLogic_CCB *); /* Bytes 40-43 */ + u32 BaseAddress; /* Bytes 44-47 */ + enum BusLogic_CompletionCode CompletionCode; /* Byte 48 */ #ifndef CONFIG_SCSI_OMIT_FLASHPOINT - unsigned char :8; /* Byte 49 */ - unsigned short OS_Flags; /* Bytes 50-51 */ - unsigned char Private[48]; /* Bytes 52-99 */ + unsigned char:8; /* Byte 49 */ + unsigned short OS_Flags; /* Bytes 50-51 */ + unsigned char Private[48]; /* Bytes 52-99 */ #endif - /* - BusLogic Linux Driver Defined Portion. - */ - dma_addr_t AllocationGroupHead; - unsigned int AllocationGroupSize; - u32 DMA_Handle; - enum BusLogic_CCB_Status Status; - unsigned long SerialNumber; - struct scsi_cmnd *Command; - struct BusLogic_HostAdapter *HostAdapter; - struct BusLogic_CCB *Next; - struct BusLogic_CCB *NextAll; - struct BusLogic_ScatterGatherSegment - ScatterGatherList[BusLogic_ScatterGatherLimit]; + /* + BusLogic Linux Driver Defined Portion. + */ + dma_addr_t AllocationGroupHead; + unsigned int AllocationGroupSize; + u32 DMA_Handle; + enum BusLogic_CCB_Status Status; + unsigned long SerialNumber; + struct scsi_cmnd *Command; + struct BusLogic_HostAdapter *HostAdapter; + struct BusLogic_CCB *Next; + struct BusLogic_CCB *NextAll; + struct BusLogic_ScatterGatherSegment + ScatterGatherList[BusLogic_ScatterGatherLimit]; }; /* Define the 32 Bit Mode Outgoing Mailbox structure. */ -struct BusLogic_OutgoingMailbox -{ - u32 CCB; /* Bytes 0-3 */ - unsigned int :24; /* Bytes 4-6 */ - enum BusLogic_ActionCode ActionCode; /* Byte 7 */ +struct BusLogic_OutgoingMailbox { + u32 CCB; /* Bytes 0-3 */ + unsigned int:24; /* Bytes 4-6 */ + enum BusLogic_ActionCode ActionCode; /* Byte 7 */ }; /* Define the 32 Bit Mode Incoming Mailbox structure. */ -struct BusLogic_IncomingMailbox -{ - u32 CCB; /* Bytes 0-3 */ - enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 4 */ - enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 5 */ - unsigned char :8; /* Byte 6 */ - enum BusLogic_CompletionCode CompletionCode; /* Byte 7 */ +struct BusLogic_IncomingMailbox { + u32 CCB; /* Bytes 0-3 */ + enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 4 */ + enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 5 */ + unsigned char:8; /* Byte 6 */ + enum BusLogic_CompletionCode CompletionCode; /* Byte 7 */ }; @@ -973,29 +929,27 @@ struct BusLogic_IncomingMailbox Define the BusLogic Driver Options structure. */ -struct BusLogic_DriverOptions -{ - unsigned short TaggedQueuingPermitted; - unsigned short TaggedQueuingPermittedMask; - unsigned short BusSettleTime; - struct BusLogic_LocalOptions LocalOptions; - unsigned char CommonQueueDepth; - unsigned char QueueDepth[BusLogic_MaxTargetDevices]; +struct BusLogic_DriverOptions { + unsigned short TaggedQueuingPermitted; + unsigned short TaggedQueuingPermittedMask; + unsigned short BusSettleTime; + struct BusLogic_LocalOptions LocalOptions; + unsigned char CommonQueueDepth; + unsigned char QueueDepth[BusLogic_MaxTargetDevices]; }; /* Define the Host Adapter Target Flags structure. */ -struct BusLogic_TargetFlags -{ - boolean TargetExists:1; - boolean TaggedQueuingSupported:1; - boolean WideTransfersSupported:1; - boolean TaggedQueuingActive:1; - boolean WideTransfersActive:1; - boolean CommandSuccessfulFlag:1; - boolean TargetInfoReported:1; +struct BusLogic_TargetFlags { + boolean TargetExists:1; + boolean TaggedQueuingSupported:1; + boolean WideTransfersSupported:1; + boolean TaggedQueuingActive:1; + boolean WideTransfersActive:1; + boolean CommandSuccessfulFlag:1; + boolean TargetInfoReported:1; }; /* @@ -1006,25 +960,24 @@ struct BusLogic_TargetFlags typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets]; -struct BusLogic_TargetStatistics -{ - unsigned int CommandsAttempted; - unsigned int CommandsCompleted; - unsigned int ReadCommands; - unsigned int WriteCommands; - struct BusLogic_ByteCounter TotalBytesRead; - struct BusLogic_ByteCounter TotalBytesWritten; - BusLogic_CommandSizeBuckets_T ReadCommandSizeBuckets; - BusLogic_CommandSizeBuckets_T WriteCommandSizeBuckets; - unsigned short CommandAbortsRequested; - unsigned short CommandAbortsAttempted; - unsigned short CommandAbortsCompleted; - unsigned short BusDeviceResetsRequested; - unsigned short BusDeviceResetsAttempted; - unsigned short BusDeviceResetsCompleted; - unsigned short HostAdapterResetsRequested; - unsigned short HostAdapterResetsAttempted; - unsigned short HostAdapterResetsCompleted; +struct BusLogic_TargetStatistics { + unsigned int CommandsAttempted; + unsigned int CommandsCompleted; + unsigned int ReadCommands; + unsigned int WriteCommands; + struct BusLogic_ByteCounter TotalBytesRead; + struct BusLogic_ByteCounter TotalBytesWritten; + BusLogic_CommandSizeBuckets_T ReadCommandSizeBuckets; + BusLogic_CommandSizeBuckets_T WriteCommandSizeBuckets; + unsigned short CommandAbortsRequested; + unsigned short CommandAbortsAttempted; + unsigned short CommandAbortsCompleted; + unsigned short BusDeviceResetsRequested; + unsigned short BusDeviceResetsAttempted; + unsigned short BusDeviceResetsCompleted; + unsigned short HostAdapterResetsRequested; + unsigned short HostAdapterResetsAttempted; + unsigned short HostAdapterResetsCompleted; }; /* @@ -1041,183 +994,179 @@ typedef unsigned int FlashPoint_CardHandle_T; by the FlashPoint SCCB Manager. */ -struct FlashPoint_Info -{ - u32 BaseAddress; /* Bytes 0-3 */ - boolean Present; /* Byte 4 */ - unsigned char IRQ_Channel; /* Byte 5 */ - unsigned char SCSI_ID; /* Byte 6 */ - unsigned char SCSI_LUN; /* Byte 7 */ - unsigned short FirmwareRevision; /* Bytes 8-9 */ - unsigned short SynchronousPermitted; /* Bytes 10-11 */ - unsigned short FastPermitted; /* Bytes 12-13 */ - unsigned short UltraPermitted; /* Bytes 14-15 */ - unsigned short DisconnectPermitted; /* Bytes 16-17 */ - unsigned short WidePermitted; /* Bytes 18-19 */ - boolean ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ - boolean HostWideSCSI:1; /* Byte 20 Bit 1 */ - boolean HostSoftReset:1; /* Byte 20 Bit 2 */ - boolean ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ - boolean LowByteTerminated:1; /* Byte 20 Bit 4 */ - boolean HighByteTerminated:1; /* Byte 20 Bit 5 */ - boolean ReportDataUnderrun:1; /* Byte 20 Bit 6 */ - boolean SCAM_Enabled:1; /* Byte 20 Bit 7 */ - boolean SCAM_Level2:1; /* Byte 21 Bit 0 */ - unsigned char :7; /* Byte 21 Bits 1-7 */ - unsigned char Family; /* Byte 22 */ - unsigned char BusType; /* Byte 23 */ - unsigned char ModelNumber[3]; /* Bytes 24-26 */ - unsigned char RelativeCardNumber; /* Byte 27 */ - unsigned char Reserved[4]; /* Bytes 28-31 */ - unsigned int OS_Reserved; /* Bytes 32-35 */ - unsigned char TranslationInfo[4]; /* Bytes 36-39 */ - unsigned int Reserved2[5]; /* Bytes 40-59 */ - unsigned int SecondaryRange; /* Bytes 60-63 */ +struct FlashPoint_Info { + u32 BaseAddress; /* Bytes 0-3 */ + boolean Present; /* Byte 4 */ + unsigned char IRQ_Channel; /* Byte 5 */ + unsigned char SCSI_ID; /* Byte 6 */ + unsigned char SCSI_LUN; /* Byte 7 */ + unsigned short FirmwareRevision; /* Bytes 8-9 */ + unsigned short SynchronousPermitted; /* Bytes 10-11 */ + unsigned short FastPermitted; /* Bytes 12-13 */ + unsigned short UltraPermitted; /* Bytes 14-15 */ + unsigned short DisconnectPermitted; /* Bytes 16-17 */ + unsigned short WidePermitted; /* Bytes 18-19 */ + boolean ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ + boolean HostWideSCSI:1; /* Byte 20 Bit 1 */ + boolean HostSoftReset:1; /* Byte 20 Bit 2 */ + boolean ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ + boolean LowByteTerminated:1; /* Byte 20 Bit 4 */ + boolean HighByteTerminated:1; /* Byte 20 Bit 5 */ + boolean ReportDataUnderrun:1; /* Byte 20 Bit 6 */ + boolean SCAM_Enabled:1; /* Byte 20 Bit 7 */ + boolean SCAM_Level2:1; /* Byte 21 Bit 0 */ + unsigned char:7; /* Byte 21 Bits 1-7 */ + unsigned char Family; /* Byte 22 */ + unsigned char BusType; /* Byte 23 */ + unsigned char ModelNumber[3]; /* Bytes 24-26 */ + unsigned char RelativeCardNumber; /* Byte 27 */ + unsigned char Reserved[4]; /* Bytes 28-31 */ + unsigned int OS_Reserved; /* Bytes 32-35 */ + unsigned char TranslationInfo[4]; /* Bytes 36-39 */ + unsigned int Reserved2[5]; /* Bytes 40-59 */ + unsigned int SecondaryRange; /* Bytes 60-63 */ }; /* Define the BusLogic Driver Host Adapter structure. */ -struct BusLogic_HostAdapter -{ - struct Scsi_Host *SCSI_Host; - struct pci_dev *PCI_Device; - enum BusLogic_HostAdapterType HostAdapterType; - enum BusLogic_HostAdapterBusType HostAdapterBusType; - unsigned long IO_Address; - unsigned long PCI_Address; - unsigned short AddressCount; - unsigned char HostNumber; - unsigned char ModelName[9]; - unsigned char FirmwareVersion[6]; - unsigned char FullModelName[18]; - unsigned char Bus; - unsigned char Device; - unsigned char IRQ_Channel; - unsigned char DMA_Channel; - unsigned char SCSI_ID; - boolean IRQ_ChannelAcquired:1; - boolean DMA_ChannelAcquired:1; - boolean ExtendedTranslationEnabled:1; - boolean ParityCheckingEnabled:1; - boolean BusResetEnabled:1; - boolean LevelSensitiveInterrupt:1; - boolean HostWideSCSI:1; - boolean HostDifferentialSCSI:1; - boolean HostSupportsSCAM:1; - boolean HostUltraSCSI:1; - boolean ExtendedLUNSupport:1; - boolean TerminationInfoValid:1; - boolean LowByteTerminated:1; - boolean HighByteTerminated:1; - boolean BounceBuffersRequired:1; - boolean StrictRoundRobinModeSupport:1; - boolean SCAM_Enabled:1; - boolean SCAM_Level2:1; - boolean HostAdapterInitialized:1; - boolean HostAdapterExternalReset:1; - boolean HostAdapterInternalError:1; - boolean ProcessCompletedCCBsActive; - volatile boolean HostAdapterCommandCompleted; - unsigned short HostAdapterScatterGatherLimit; - unsigned short DriverScatterGatherLimit; - unsigned short MaxTargetDevices; - unsigned short MaxLogicalUnits; - unsigned short MailboxCount; - unsigned short InitialCCBs; - unsigned short IncrementalCCBs; - unsigned short AllocatedCCBs; - unsigned short DriverQueueDepth; - unsigned short HostAdapterQueueDepth; - unsigned short UntaggedQueueDepth; - unsigned short CommonQueueDepth; - unsigned short BusSettleTime; - unsigned short SynchronousPermitted; - unsigned short FastPermitted; - unsigned short UltraPermitted; - unsigned short WidePermitted; - unsigned short DisconnectPermitted; - unsigned short TaggedQueuingPermitted; - unsigned short ExternalHostAdapterResets; - unsigned short HostAdapterInternalErrors; - unsigned short TargetDeviceCount; - unsigned short MessageBufferLength; - u32 BIOS_Address; - struct BusLogic_DriverOptions *DriverOptions; - struct FlashPoint_Info FlashPointInfo; - FlashPoint_CardHandle_T CardHandle; - struct BusLogic_HostAdapter *Next; - struct BusLogic_CCB *All_CCBs; - struct BusLogic_CCB *Free_CCBs; - struct BusLogic_CCB *FirstCompletedCCB; - struct BusLogic_CCB *LastCompletedCCB; - struct BusLogic_CCB *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; - struct BusLogic_TargetFlags TargetFlags[BusLogic_MaxTargetDevices]; - unsigned char QueueDepth[BusLogic_MaxTargetDevices]; - unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; - unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; - unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; - unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; - unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; - unsigned long LastResetAttempted[BusLogic_MaxTargetDevices]; - unsigned long LastResetCompleted[BusLogic_MaxTargetDevices]; - struct BusLogic_OutgoingMailbox *FirstOutgoingMailbox; - struct BusLogic_OutgoingMailbox *LastOutgoingMailbox; - struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; - struct BusLogic_IncomingMailbox *FirstIncomingMailbox; - struct BusLogic_IncomingMailbox *LastIncomingMailbox; - struct BusLogic_IncomingMailbox *NextIncomingMailbox; - struct BusLogic_TargetStatistics TargetStatistics[BusLogic_MaxTargetDevices]; - unsigned char *MailboxSpace; - dma_addr_t MailboxSpaceHandle; - unsigned int MailboxSize; - unsigned long CCB_Offset; - char MessageBuffer[BusLogic_MessageBufferSize]; +struct BusLogic_HostAdapter { + struct Scsi_Host *SCSI_Host; + struct pci_dev *PCI_Device; + enum BusLogic_HostAdapterType HostAdapterType; + enum BusLogic_HostAdapterBusType HostAdapterBusType; + unsigned long IO_Address; + unsigned long PCI_Address; + unsigned short AddressCount; + unsigned char HostNumber; + unsigned char ModelName[9]; + unsigned char FirmwareVersion[6]; + unsigned char FullModelName[18]; + unsigned char Bus; + unsigned char Device; + unsigned char IRQ_Channel; + unsigned char DMA_Channel; + unsigned char SCSI_ID; + boolean IRQ_ChannelAcquired:1; + boolean DMA_ChannelAcquired:1; + boolean ExtendedTranslationEnabled:1; + boolean ParityCheckingEnabled:1; + boolean BusResetEnabled:1; + boolean LevelSensitiveInterrupt:1; + boolean HostWideSCSI:1; + boolean HostDifferentialSCSI:1; + boolean HostSupportsSCAM:1; + boolean HostUltraSCSI:1; + boolean ExtendedLUNSupport:1; + boolean TerminationInfoValid:1; + boolean LowByteTerminated:1; + boolean HighByteTerminated:1; + boolean BounceBuffersRequired:1; + boolean StrictRoundRobinModeSupport:1; + boolean SCAM_Enabled:1; + boolean SCAM_Level2:1; + boolean HostAdapterInitialized:1; + boolean HostAdapterExternalReset:1; + boolean HostAdapterInternalError:1; + boolean ProcessCompletedCCBsActive; + volatile boolean HostAdapterCommandCompleted; + unsigned short HostAdapterScatterGatherLimit; + unsigned short DriverScatterGatherLimit; + unsigned short MaxTargetDevices; + unsigned short MaxLogicalUnits; + unsigned short MailboxCount; + unsigned short InitialCCBs; + unsigned short IncrementalCCBs; + unsigned short AllocatedCCBs; + unsigned short DriverQueueDepth; + unsigned short HostAdapterQueueDepth; + unsigned short UntaggedQueueDepth; + unsigned short CommonQueueDepth; + unsigned short BusSettleTime; + unsigned short SynchronousPermitted; + unsigned short FastPermitted; + unsigned short UltraPermitted; + unsigned short WidePermitted; + unsigned short DisconnectPermitted; + unsigned short TaggedQueuingPermitted; + unsigned short ExternalHostAdapterResets; + unsigned short HostAdapterInternalErrors; + unsigned short TargetDeviceCount; + unsigned short MessageBufferLength; + u32 BIOS_Address; + struct BusLogic_DriverOptions *DriverOptions; + struct FlashPoint_Info FlashPointInfo; + FlashPoint_CardHandle_T CardHandle; + struct BusLogic_HostAdapter *Next; + struct BusLogic_CCB *All_CCBs; + struct BusLogic_CCB *Free_CCBs; + struct BusLogic_CCB *FirstCompletedCCB; + struct BusLogic_CCB *LastCompletedCCB; + struct BusLogic_CCB *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; + struct BusLogic_TargetFlags TargetFlags[BusLogic_MaxTargetDevices]; + unsigned char QueueDepth[BusLogic_MaxTargetDevices]; + unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; + unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; + unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; + unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; + unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; + unsigned long LastResetAttempted[BusLogic_MaxTargetDevices]; + unsigned long LastResetCompleted[BusLogic_MaxTargetDevices]; + struct BusLogic_OutgoingMailbox *FirstOutgoingMailbox; + struct BusLogic_OutgoingMailbox *LastOutgoingMailbox; + struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; + struct BusLogic_IncomingMailbox *FirstIncomingMailbox; + struct BusLogic_IncomingMailbox *LastIncomingMailbox; + struct BusLogic_IncomingMailbox *NextIncomingMailbox; + struct BusLogic_TargetStatistics TargetStatistics[BusLogic_MaxTargetDevices]; + unsigned char *MailboxSpace; + dma_addr_t MailboxSpaceHandle; + unsigned int MailboxSize; + unsigned long CCB_Offset; + char MessageBuffer[BusLogic_MessageBufferSize]; }; /* Define a structure for the BIOS Disk Parameters. */ -struct BIOS_DiskParameters -{ - int Heads; - int Sectors; - int Cylinders; +struct BIOS_DiskParameters { + int Heads; + int Sectors; + int Cylinders; }; /* Define a structure for the SCSI Inquiry command results. */ -struct SCSI_Inquiry -{ - unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ - unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ - unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ - boolean RMB:1; /* Byte 1 Bit 7 */ - unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ - unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ - unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ - unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ - unsigned char :2; /* Byte 3 Bits 4-5 */ - boolean TrmIOP:1; /* Byte 3 Bit 6 */ - boolean AENC:1; /* Byte 3 Bit 7 */ - unsigned char AdditionalLength; /* Byte 4 */ - unsigned char :8; /* Byte 5 */ - unsigned char :8; /* Byte 6 */ - boolean SftRe:1; /* Byte 7 Bit 0 */ - boolean CmdQue:1; /* Byte 7 Bit 1 */ - boolean :1; /* Byte 7 Bit 2 */ - boolean Linked:1; /* Byte 7 Bit 3 */ - boolean Sync:1; /* Byte 7 Bit 4 */ - boolean WBus16:1; /* Byte 7 Bit 5 */ - boolean WBus32:1; /* Byte 7 Bit 6 */ - boolean RelAdr:1; /* Byte 7 Bit 7 */ - unsigned char VendorIdentification[8]; /* Bytes 8-15 */ - unsigned char ProductIdentification[16]; /* Bytes 16-31 */ - unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ +struct SCSI_Inquiry { + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char:2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char:8; /* Byte 5 */ + unsigned char:8; /* Byte 6 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean:1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ }; /* @@ -1226,7 +1175,7 @@ struct SCSI_Inquiry static inline void BusLogic_AcquireHostAdapterLock(struct BusLogic_HostAdapter *HostAdapter) { - spin_lock_irq(HostAdapter->SCSI_Host->host_lock); + spin_lock_irq(HostAdapter->SCSI_Host->host_lock); } /* @@ -1235,7 +1184,7 @@ static inline void BusLogic_AcquireHostAdapterLock(struct BusLogic_HostAdapter * static inline void BusLogic_ReleaseHostAdapterLock(struct BusLogic_HostAdapter *HostAdapter) { - spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); + spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); } @@ -1244,10 +1193,9 @@ static inline void BusLogic_ReleaseHostAdapterLock(struct BusLogic_HostAdapter * but is only called from the interrupt handler. */ -static inline void BusLogic_AcquireHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, - unsigned long *ProcessorFlags) +static inline void BusLogic_AcquireHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, unsigned long *ProcessorFlags) { - spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); + spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); } @@ -1256,10 +1204,9 @@ static inline void BusLogic_AcquireHostAdapterLockIH(struct BusLogic_HostAdapter but is only called from the interrupt handler. */ -static inline void BusLogic_ReleaseHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, - unsigned long *ProcessorFlags) +static inline void BusLogic_ReleaseHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, unsigned long *ProcessorFlags) { - spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); + spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); } @@ -1270,65 +1217,60 @@ static inline void BusLogic_ReleaseHostAdapterLockIH(struct BusLogic_HostAdapter static inline void BusLogic_SCSIBusReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.SCSIBusReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.SCSIBusReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline void BusLogic_InterruptReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.InterruptReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.InterruptReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline void BusLogic_SoftReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.SoftReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.SoftReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline void BusLogic_HardReset(struct BusLogic_HostAdapter *HostAdapter) { - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.HardReset = true; - outb(ControlRegister.All, - HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); + union BusLogic_ControlRegister ControlRegister; + ControlRegister.All = 0; + ControlRegister.cr.HardReset = true; + outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); } static inline unsigned char BusLogic_ReadStatusRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_StatusRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_StatusRegisterOffset); } static inline void BusLogic_WriteCommandParameterRegister(struct BusLogic_HostAdapter - *HostAdapter, - unsigned char Value) + *HostAdapter, unsigned char Value) { - outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegisterOffset); + outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegisterOffset); } static inline unsigned char BusLogic_ReadDataInRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_DataInRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_DataInRegisterOffset); } static inline unsigned char BusLogic_ReadInterruptRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_InterruptRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_InterruptRegisterOffset); } static inline unsigned char BusLogic_ReadGeometryRegister(struct BusLogic_HostAdapter *HostAdapter) { - return inb(HostAdapter->IO_Address + BusLogic_GeometryRegisterOffset); + return inb(HostAdapter->IO_Address + BusLogic_GeometryRegisterOffset); } /* @@ -1339,7 +1281,7 @@ static inline unsigned char BusLogic_ReadGeometryRegister(struct BusLogic_HostAd static inline void BusLogic_StartMailboxCommand(struct BusLogic_HostAdapter *HostAdapter) { - BusLogic_WriteCommandParameterRegister(HostAdapter, BusLogic_ExecuteMailboxCommand); + BusLogic_WriteCommandParameterRegister(HostAdapter, BusLogic_ExecuteMailboxCommand); } /* @@ -1348,7 +1290,7 @@ static inline void BusLogic_StartMailboxCommand(struct BusLogic_HostAdapter *Hos static inline void BusLogic_Delay(int Seconds) { - mdelay(1000 * Seconds); + mdelay(1000 * Seconds); } /* @@ -1358,12 +1300,12 @@ static inline void BusLogic_Delay(int Seconds) static inline u32 Virtual_to_Bus(void *VirtualAddress) { - return (u32) virt_to_bus(VirtualAddress); + return (u32) virt_to_bus(VirtualAddress); } static inline void *Bus_to_Virtual(u32 BusAddress) { - return (void *) bus_to_virt(BusAddress); + return (void *) bus_to_virt(BusAddress); } /* @@ -1374,7 +1316,7 @@ static inline void *Bus_to_Virtual(u32 BusAddress) static inline u32 Virtual_to_32Bit_Virtual(void *VirtualAddress) { - return (u32) (unsigned long) VirtualAddress; + return (u32) (unsigned long) VirtualAddress; } /* @@ -1384,7 +1326,8 @@ static inline u32 Virtual_to_32Bit_Virtual(void *VirtualAddress) static inline void BusLogic_IncrementErrorCounter(unsigned short *ErrorCounter) { - if (*ErrorCounter < 65535) (*ErrorCounter)++; + if (*ErrorCounter < 65535) + (*ErrorCounter)++; } /* @@ -1392,40 +1335,35 @@ static inline void BusLogic_IncrementErrorCounter(unsigned short *ErrorCounter) */ static inline void BusLogic_IncrementByteCounter(struct BusLogic_ByteCounter - *ByteCounter, - unsigned int Amount) + *ByteCounter, unsigned int Amount) { - ByteCounter->Units += Amount; - if (ByteCounter->Units > 999999999) - { - ByteCounter->Units -= 1000000000; - ByteCounter->Billions++; - } + ByteCounter->Units += Amount; + if (ByteCounter->Units > 999999999) { + ByteCounter->Units -= 1000000000; + ByteCounter->Billions++; + } } /* BusLogic_IncrementSizeBucket increments the Bucket for Amount. */ -static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T - CommandSizeBuckets, - unsigned int Amount) -{ - int Index = 0; - if (Amount < 8*1024) - { - if (Amount < 2*1024) - Index = (Amount < 1*1024 ? 0 : 1); - else Index = (Amount < 4*1024 ? 2 : 3); - } - else if (Amount < 128*1024) - { - if (Amount < 32*1024) - Index = (Amount < 16*1024 ? 4 : 5); - else Index = (Amount < 64*1024 ? 6 : 7); - } - else Index = (Amount < 256*1024 ? 8 : 9); - CommandSizeBuckets[Index]++; +static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T CommandSizeBuckets, unsigned int Amount) +{ + int Index = 0; + if (Amount < 8 * 1024) { + if (Amount < 2 * 1024) + Index = (Amount < 1 * 1024 ? 0 : 1); + else + Index = (Amount < 4 * 1024 ? 2 : 3); + } else if (Amount < 128 * 1024) { + if (Amount < 32 * 1024) + Index = (Amount < 16 * 1024 ? 4 : 5); + else + Index = (Amount < 64 * 1024 ? 6 : 7); + } else + Index = (Amount < 256 * 1024 ? 8 : 9); + CommandSizeBuckets[Index]++; } /* @@ -1450,20 +1388,14 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T static const char *BusLogic_DriverInfo(struct Scsi_Host *); static int BusLogic_DetectHostAdapter(struct scsi_host_template *); static int BusLogic_ReleaseHostAdapter(struct Scsi_Host *); -static int BusLogic_QueueCommand(struct scsi_cmnd *, - void (*CompletionRoutine)(struct scsi_cmnd *)); -static int BusLogic_BIOSDiskParameters(struct scsi_device *, - struct block_device *, - sector_t, int *); -static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, - char **, off_t, int, int); +static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *)); +static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *); +static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int); static int BusLogic_SlaveConfigure(struct scsi_device *); static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *); static irqreturn_t BusLogic_InterruptHandler(int, void *, struct pt_regs *); -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, - boolean HardReset); -static void BusLogic_Message(enum BusLogic_MessageLevel, char *, - struct BusLogic_HostAdapter *, ...); +static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset); +static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...); static int __init BusLogic_Setup(char *); -#endif /* _BUSLOGIC_H */ +#endif /* _BUSLOGIC_H */ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 711865972..60015656c 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -320,7 +320,7 @@ source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" config SCSI_AIC7XXX_OLD tristate "Adaptec AIC7xxx support (old driver)" - depends on SCSI + depends on (ISA || EISA || PCI ) && SCSI help WARNING This driver is an older aic7xxx driver and is no longer under active development. Adaptec, Inc. is writing a new driver to @@ -395,15 +395,7 @@ config SCSI_IN2000 To compile this driver as a module, choose M here: the module will be called in2000. -config SCSI_MEGARAID - tristate "AMI MegaRAID support" - depends on PCI && SCSI - help - This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 - and 467 SCSI host adapters. - - To compile this driver as a module, choose M here: the - module will be called megaraid. +source "drivers/scsi/megaraid/Kconfig.megaraid" config SCSI_SATA bool "Serial ATA (SATA) support" @@ -595,7 +587,7 @@ config SCSI_EATA_MAX_TAGS config SCSI_EATA_PIO tristate "EATA-PIO (old DPT PM2001, PM2012A) support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI ---help--- This driver supports all EATA-PIO protocol compliant SCSI Host Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant @@ -780,6 +772,15 @@ config SCSI_IPS To compile this driver as a module, choose M here: the module will be called ips. +config SCSI_IBMVSCSI + tristate "IBM Virtual SCSI support" + depends on PPC_PSERIES || PPC_ISERIES + help + This is the IBM POWER Virtual SCSI Client + + To compile this driver as a module, choose M here: the + module will be called ibmvscsic. + config SCSI_INITIO tristate "Initio 9100U(W) support" depends on PCI && SCSI && BROKEN @@ -1462,7 +1463,7 @@ config SCSI_DEBUG config SCSI_MESH tristate "MESH (Power Mac internal SCSI) support" - depends on PPC_PMAC && SCSI + depends on PPC32 && PPC_PMAC && SCSI help Many Power Macintoshes and clones have a MESH (Macintosh Enhanced SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the @@ -1507,7 +1508,7 @@ source "drivers/scsi/arm/Kconfig" config JAZZ_ESP bool "MIPS JAZZ FAS216 SCSI support" - depends on MIPS_JAZZ && SCSI + depends on MACH_JAZZ && SCSI help This is the driver for the onboard SCSI host adapter of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 7aebabba4..4173562d0 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -95,7 +95,8 @@ obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o obj-$(CONFIG_SCSI_DC390T) += tmscsim.o -obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o +obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o +obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o obj-$(CONFIG_SCSI_SUNESP) += esp.o obj-$(CONFIG_SCSI_GDTH) += gdth.o @@ -119,6 +120,7 @@ obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_IPR) += ipr.o +obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index e3bb9dde6..2032b6230 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -310,12 +310,8 @@ * possible) function may be used. Before the specific driver initialization * code finishes, NCR5380_print_options should be called. */ - static int do_abort(struct Scsi_Host *host); static void do_reset(struct Scsi_Host *host); -static struct NCR5380_hostdata *first_host = NULL; -static struct NCR5380_hostdata *last_host = NULL; -static struct timer_list usleep_timer; /* * initialize_SCp - init the scsi pointer field @@ -533,9 +529,6 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) #define USLEEP_WAITLONG USLEEP_SLEEP #endif -static struct Scsi_Host *expires_first = NULL; -static spinlock_t timer_lock; /* Guards expires list */ - /* * Function : int should_disconnect (unsigned char cmd) * @@ -578,90 +571,10 @@ static int should_disconnect(unsigned char cmd) } } -/* - * Assumes instance->time_expires has been set in higher level code. - * We should move to a timer per host - * - * Locks: Takes the timer queue lock - */ - -static int NCR5380_set_timer(struct Scsi_Host *instance) -{ - struct Scsi_Host *tmp, **prev; - unsigned long flags; - - if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { - return -1; - } - - spin_lock_irqsave(&timer_lock, flags); - for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) - if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires) - break; - - ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp; - *prev = instance; - - mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); - - spin_unlock_irqrestore(&timer_lock, flags); - return 0; -} - -/** - * NCR5380_timer_fn - handle polled timeouts - * @unused: unused - * - * Walk the list of controllers, find which controllers have exceeded - * their expiry timeout and then schedule the processing co-routine to - * do the real work. - * - * Doing something about unwanted reentrancy here might be useful - * - * Locks: disables irqs, takes and frees the timer lock - */ - -static void NCR5380_timer_fn(unsigned long unused) -{ - struct Scsi_Host *instance; - struct NCR5380_hostdata *hostdata; - unsigned long flags; - - spin_lock_irqsave(&timer_lock, flags); - for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) - { - hostdata = (struct NCR5380_hostdata *) expires_first->hostdata; - schedule_work(&hostdata->coroutine); - instance = hostdata->next_timer; - hostdata->next_timer = NULL; - hostdata->time_expires = 0; - expires_first = instance; - } - - del_timer(&usleep_timer); - if (expires_first) { - usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; - add_timer(&usleep_timer); - } - spin_unlock_irqrestore(&timer_lock, flags); -} - -/** - * NCR5380_all_init - global setup - * - * Set up the global values and timers needed by the NCR5380 driver - */ - -static inline void NCR5380_all_init(void) +static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout) { - static int done = 0; - if (!done) { - dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); - done = 1; - init_timer(&usleep_timer); - spin_lock_init(&timer_lock); - usleep_timer.function = NCR5380_timer_fn; - } + hostdata->time_expires = jiffies + timeout; + schedule_delayed_work(&hostdata->coroutine, hostdata->time_expires); } @@ -787,22 +700,6 @@ static void __init NCR5380_print_options(struct Scsi_Host *instance) } } -/** - * NCR5380_coroutine_running - coroutine status - * @instance: controller to check - * - * Return true if the co-routine for this controller is running - * or scheduled to run - * - * FIXME: this test function belongs in the workqueue code! - */ - -static int NCR5380_coroutine_running(struct Scsi_Host *instance) -{ - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; - return test_bit(0, &hostdata->coroutine.pending); -} - /** * NCR5380_print_status - dump controller info * @instance: controller to dump @@ -819,8 +716,6 @@ static void NCR5380_print_status(struct Scsi_Host *instance) char *start; int len; - printk("NCR5380 : coroutine is%s running.\n", NCR5380_coroutine_running(instance)? "" : "n't"); - NCR5380_dprint(NDEBUG_ANY, instance); NCR5380_dprint_phase(NDEBUG_ANY, instance); @@ -900,7 +795,6 @@ int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, of SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); #endif spin_lock_irq(instance->host_lock); - SPRINTF("NCR5380 : coroutine is%s running.\n", NCR5380_coroutine_running(instance) ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); else @@ -912,7 +806,6 @@ int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, of SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - spin_unlock_irq(instance->host_lock); *start = buffer; @@ -964,7 +857,7 @@ static char *lprint_opcode(int opcode, char *pos, char *buffer, int length) * Locks: interrupts must be enabled when we are called */ -static int __init NCR5380_init(struct Scsi_Host *instance, int flags) +static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags) { NCR5380_local_declare(); int i, pass; @@ -984,7 +877,6 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) #endif NCR5380_setup(instance); - NCR5380_all_init(); hostdata->aborted = 0; hostdata->id_mask = 1 << instance->this_id; @@ -1021,18 +913,8 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) else hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags; - hostdata->next = NULL; - - if (!first_host) - first_host = hostdata; - else - last_host->next = hostdata; - - last_host = hostdata; - hostdata->host = instance; hostdata->time_expires = 0; - hostdata->next_timer = NULL; #ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) @@ -1088,6 +970,19 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) return 0; } +/** + * NCR5380_exit - remove an NCR5380 + * @instance: adapter to remove + */ + +static void __devexit NCR5380_exit(struct Scsi_Host *instance) +{ + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + + cancel_delayed_work(&hostdata->coroutine); + flush_scheduled_work(); +} + /** * NCR5380_queue_command - queue a command * @cmd: SCSI command @@ -1169,6 +1064,7 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) return 0; } + /** * NCR5380_main - NCR state machines * @@ -1184,28 +1080,11 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) static void NCR5380_main(void *p) { struct NCR5380_hostdata *hostdata = p; + struct Scsi_Host *instance = hostdata->host; Scsi_Cmnd *tmp, *prev; - struct Scsi_Host *instance; int done; - unsigned long flags = 0; - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we can exit - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - */ - - instance = hostdata->host; - - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irqsave(instance->host_lock, flags); - + spin_lock_irq(instance->host_lock); do { /* Lock held here */ done = 1; @@ -1286,8 +1165,7 @@ static void NCR5380_main(void *p) LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; - hostdata->time_expires = jiffies + USLEEP_WAITLONG; - NCR5380_set_timer(instance); + NCR5380_set_timer(hostdata, USLEEP_WAITLONG); } } /* if hostdata->selecting */ if (hostdata->connected @@ -1304,8 +1182,7 @@ static void NCR5380_main(void *p) break; } while (!done); - if(instance->irq != SCSI_IRQ_NONE) - spin_unlock_irqrestore(instance->host_lock, flags); + spin_unlock_irq(instance->host_lock); } #ifndef DONT_USE_INTR @@ -1330,12 +1207,13 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; int done; unsigned char basr; + unsigned long flags; dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); do { done = 1; - spin_lock_irq(instance->host_lock); + spin_lock_irqsave(instance->host_lock, flags); /* Look for pending interrupts */ NCR5380_setup(instance); basr = NCR5380_read(BUS_AND_STATUS_REG); @@ -1386,7 +1264,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) #endif } } /* if BASR_IRQ */ - spin_unlock_irq(instance->host_lock); + spin_unlock_irqrestore(instance->host_lock, flags); if(!done) schedule_work(&hostdata->coroutine); } while (!done); @@ -1469,12 +1347,8 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) int err; NCR5380_setup(instance); - if (hostdata->selecting) { - if(instance->irq != SCSI_IRQ_NONE) - spin_unlock_irq(instance->host_lock); - goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the - rest of the code nearly the same */ - } + if (hostdata->selecting) + goto part2; hostdata->restart_select = 0; @@ -1495,16 +1369,12 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); - if(instance->irq != SCSI_IRQ_NONE) - spin_unlock_irq(instance->host_lock); /* We can be relaxed here, interrupts are on, we are in workqueue context, the birds are singing in the trees */ - + spin_unlock_irq(instance->host_lock); err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ); - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); - + spin_lock_irq(instance->host_lock); if (err < 0) { printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); @@ -1628,8 +1498,7 @@ part2: if (!value && (hostdata->select_time < HZ/4)) { /* RvC: we still must wait for a device response */ hostdata->select_time++; /* after 25 ticks the device has failed */ - hostdata->time_expires = jiffies + 1; - NCR5380_set_timer(instance); + NCR5380_set_timer(hostdata, 1); return 0; /* RvC: we return here with hostdata->selecting set, to go to sleep */ } @@ -1638,8 +1507,6 @@ part2: waiting period */ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); NCR5380_reselect(instance); printk("scsi%d : reselection after won arbitration?\n", instance->host_no); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1665,8 +1532,6 @@ part2: NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); cmd->result = DID_BAD_TARGET << 16; collect_stats(hostdata, cmd); cmd->scsi_done(cmd); @@ -1693,11 +1558,13 @@ part2: */ /* Wait for start of REQ/ACK handshake */ - + + spin_unlock_irq(instance->host_lock); err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); + spin_lock_irq(instance->host_lock); - if(err) - { printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); + if(err) { + printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); goto failed; } @@ -1705,9 +1572,6 @@ part2: dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id)); tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun); - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); - len = 1; cmd->tag = 0; @@ -1720,15 +1584,14 @@ part2: hostdata->connected = cmd; hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - initialize_SCp(cmd); - + if (cmd->SCp.ptr != (char *)cmd->sense_buffer) { + initialize_SCp(cmd); + } return 0; /* Selection failed */ failed: - if(instance->irq != SCSI_IRQ_NONE) - spin_lock_irq(instance->host_lock); return -1; } @@ -1804,8 +1667,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed); if (!(tmp & SR_REQ)) { /* timeout condition */ - hostdata->time_expires = jiffies + USLEEP_SLEEP; - NCR5380_set_timer(instance); + NCR5380_set_timer(hostdata, USLEEP_SLEEP); break; } @@ -2643,9 +2505,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { */ NCR5380_transfer_pio(instance, &phase, &len, &data); if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { - hostdata->time_expires = jiffies + USLEEP_SLEEP; + NCR5380_set_timer(hostdata, USLEEP_SLEEP); dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); - NCR5380_set_timer(instance); return; } break; @@ -2664,9 +2525,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { /* RvC: go to sleep if polling time expired */ if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { - hostdata->time_expires = jiffies + USLEEP_SLEEP; + NCR5380_set_timer(hostdata, USLEEP_SLEEP); dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); - NCR5380_set_timer(instance); return; } } diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 321540cb4..b5103f94d 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -251,7 +251,6 @@ struct NCR5380_hostdata { NCR5380_implementation_fields; /* implementation specific */ struct Scsi_Host *host; /* Host backpointer */ - struct NCR5380_hostdata *next; /* Next in our hot chain */ unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ unsigned char targets_present; /* targets we have connected to, so we can call a select @@ -270,7 +269,6 @@ struct NCR5380_hostdata { volatile unsigned aborted:1; /* flag, says aborted */ int flags; unsigned long time_expires; /* in jiffies, set prior to sleeping */ - struct Scsi_Host *next_timer; int select_time; /* timer in select for target response */ volatile Scsi_Cmnd *selecting; struct work_struct coroutine; /* our co-routine */ @@ -295,6 +293,7 @@ struct NCR5380_hostdata { static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); #endif static int NCR5380_init(struct Scsi_Host *instance, int flags); +static void NCR5380_exit(struct Scsi_Host *instance); static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 9f70a7b0b..9cd6f27d7 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -94,7 +94,7 @@ enum { }; /* The master ring of all esp hosts we are managing in this driver. */ -struct NCR_ESP *espchain = 0; +struct NCR_ESP *espchain; int nesps = 0, esps_in_use = 0, esps_running = 0; irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); @@ -555,7 +555,7 @@ struct NCR_ESP* esp_allocate(Scsi_Host_Template *tpnt, void *esp_dev) } else { espchain = esp; } - esp->next = 0; + esp->next = NULL; return esp; } @@ -565,7 +565,7 @@ void esp_deallocate(struct NCR_ESP *esp) struct NCR_ESP *elink; if(espchain == esp) { - espchain = 0; + espchain = NULL; } else { for(elink = espchain; elink && (elink->next != esp); elink = elink->next); if(elink) @@ -708,9 +708,9 @@ void esp_initialize(struct NCR_ESP *esp) } /* Initialize the command queues */ - esp->current_SC = 0; - esp->disconnected_SC = 0; - esp->issue_SC = 0; + esp->current_SC = NULL; + esp->disconnected_SC = NULL; + esp->issue_SC = NULL; /* Clear the state machines. */ esp->targets_present = 0; @@ -1728,7 +1728,7 @@ static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp) ESPLOG(("esp%d: Weird, being reselected but disconnected " "command queue is empty.\n", esp->esp_id)); esp->snip = 0; - esp->current_SC = 0; + esp->current_SC = NULL; sp->SCp.phase = not_issued; append_SC(&esp->issue_SC, sp); } @@ -3393,7 +3393,7 @@ static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs) } static espfunc_t isvc_vector[] = { - 0, + NULL, esp_do_phase_determine, esp_do_resetbus, esp_finish_reset, diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index 3f457dc1b..c407e8643 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -606,22 +606,24 @@ static int NCR53c406a_release(struct Scsi_Host *shost) } /* called from init/main.c */ -static void __init NCR53c406a_setup(char *str, int *ints) +static int __init NCR53c406a_setup(char *str) { static size_t setup_idx = 0; size_t i; + int ints[4]; DEB(printk("NCR53c406a: Setup called\n"); ); if (setup_idx >= PORT_COUNT - 1) { printk("NCR53c406a: Setup called too many times. Bad LILO params?\n"); - return; + return 0; } + get_options(str, 4, ints); if (ints[0] < 1 || ints[0] > 3) { printk("NCR53c406a: Malformed command line\n"); printk("NCR53c406a: Usage: ncr53c406a=[,[,]]\n"); - return; + return 0; } for (i = 0; i < PORT_COUNT && !port_base; i++) if (ports[i] == ints[1]) { @@ -631,7 +633,7 @@ static void __init NCR53c406a_setup(char *str, int *ints) } if (!port_base) { printk("NCR53c406a: Invalid PORTBASE 0x%x specified\n", ints[1]); - return; + return 0; } if (ints[0] > 1) { @@ -654,6 +656,7 @@ static void __init NCR53c406a_setup(char *str, int *ints) fast_pio = ints[3]; DEB(printk("NCR53c406a: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, fast_pio);) + return 1; } __setup("ncr53c406a=", NCR53c406a_setup); diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index d47a86ef5..862014d7b 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c @@ -216,7 +216,21 @@ NCR_Q720_probe(struct device *dev) goto out_free; } - mem_base = (__u32)ioremap(base_addr, mem_size); + if (dma_declare_coherent_memory(dev, base_addr, base_addr, + mem_size, DMA_MEMORY_MAP) + != DMA_MEMORY_MAP) { + printk(KERN_ERR "NCR_Q720: DMA declare memory failed\n"); + goto out_release_region; + } + + /* The first 1k of the memory buffer is a memory map of the registers + */ + mem_base = (__u32)dma_mark_declared_memory_occupied(dev, base_addr, + 1024); + if (IS_ERR((void *)mem_base)) { + printk("NCR_Q720 failed to reserve memory mapped region\n"); + goto out_release; + } /* now also enable accesses in asr 2 */ asr2 = inb(io_base + 0x0a); @@ -296,7 +310,8 @@ NCR_Q720_probe(struct device *dev) return 0; out_release: - iounmap((void *)mem_base); + dma_release_declared_memory(dev); + out_release_region: release_mem_region(base_addr, mem_size); out_free: kfree(p); @@ -321,7 +336,7 @@ NCR_Q720_remove(struct device *dev) if(p->hosts[i]) NCR_Q720_remove_one(p->hosts[i]); - iounmap((void *)p->mem_base); + dma_release_declared_memory(dev); release_mem_region(p->phys_mem_base, p->mem_size); free_irq(p->irq, p); kfree(p); diff --git a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README index 6abbe026b..52015523c 100644 --- a/drivers/scsi/aacraid/README +++ b/drivers/scsi/aacraid/README @@ -10,14 +10,23 @@ the original). Supported Cards/Chipsets ------------------------- - AAR-2410SA SATA + Adaptec 2020S + Adaptec 2025S Adaptec 2120S Adaptec 2200S Adaptec 2230S + Adaptec 2240S + Adaptec 2410SA + Adaptec 2610SA + Adaptec 2810SA + Adaptec 21610SA Adaptec 3230S Adaptec 3240S + Adaptec 4000SAS + Adaptec 4005SAS + Adaptec 4800SAS + Adaptec 4805SAS Adaptec 5400S - ASR-2020S PCI-X Dell PERC 2 Quad Channel Dell PERC 2/Si Dell PERC 3/Si @@ -49,7 +58,6 @@ Adaptec Unix OEM Product Group Mailing List ------------------------- linux-scsi@vger.kernel.org (Interested parties troll here) -http://mbserver.adaptec.com/ (Currently more Community Support than Devel Support) Also note this is very different to Brian's original driver so don't expect him to support it. Adaptec does support this driver. Contact either tech support or Mark Salyzyn. diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 7b02a48a2..bb03a95fa 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -179,6 +179,20 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); static char *aac_get_status_string(u32 status); #endif +/* + * Non dasd selection is handled entirely in aachba now + */ + +MODULE_PARM(nondasd, "i"); +MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); +MODULE_PARM(dacmode, "i"); +MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); +MODULE_PARM(commit, "i"); +MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on"); + +static int nondasd = -1; +static int dacmode = -1; + /** * aac_get_containers - list containers * @common: adapter to probe @@ -481,8 +495,7 @@ int aac_get_adapter_info(struct aac_dev* dev) dev->nondasd_support = 0; if(dev->adapter_info.options & AAC_OPT_NONDASD){ -// dev->nondasd_support = 1; -// dmb - temporarily disable nondasd + dev->nondasd_support = 1; } if(nondasd != -1) { dev->nondasd_support = (nondasd!=0); @@ -491,18 +504,30 @@ int aac_get_adapter_info(struct aac_dev* dev) printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); } - dev->pae_support = 0; + dev->dac_support = 0; if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){ printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id); - dev->pae_support = 1; + dev->dac_support = 1; } - if(paemode != -1){ - dev->pae_support = (paemode!=0); + if(dacmode != -1) { + dev->dac_support = (dacmode!=0); } - if(dev->pae_support != 0) { - printk(KERN_INFO"%s%d: 64 Bit PAE enabled\n", dev->name, dev->id); - pci_set_dma_mask(dev->pdev, (dma_addr_t)0xFFFFFFFFFFFFFFFFULL); + if(dev->dac_support != 0) { + if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL) && + !pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL)) { + printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n", + dev->name, dev->id); + } else if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFULL) && + !pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFULL)) { + printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n", + dev->name, dev->id); + dev->dac_support = 0; + } else { + printk(KERN_WARNING"%s%d: No suitable DMA available.\n", + dev->name, dev->id); + rcode = -ENOMEM; + } } fib_complete(fibptr); @@ -537,7 +562,7 @@ static void read_callback(void *context, struct fib * fibptr) scsicmd->use_sg, scsicmd->sc_data_direction); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr, + pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen, scsicmd->sc_data_direction); readreply = (struct aac_read_reply *)fib_data(fibptr); @@ -582,7 +607,7 @@ static void write_callback(void *context, struct fib * fibptr) scsicmd->use_sg, scsicmd->sc_data_direction); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr, + pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen, scsicmd->sc_data_direction); @@ -644,7 +669,7 @@ int aac_read(struct scsi_cmnd * scsicmd, int cid) fib_init(cmd_fibcontext); - if(dev->pae_support == 1){ + if(dev->dac_support == 1) { struct aac_read64 *readcmd; readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext); readcmd->command = cpu_to_le32(VM_CtHostRead64); @@ -752,7 +777,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) } fib_init(cmd_fibcontext); - if(dev->pae_support == 1){ + if(dev->dac_support == 1) { struct aac_write64 *writecmd; writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext); writecmd->command = cpu_to_le32(VM_CtHostWrite64); @@ -1220,7 +1245,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr) scsicmd->use_sg, scsicmd->sc_data_direction); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (ulong)scsicmd->SCp.ptr, scsicmd->request_bufflen, + pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen, scsicmd->sc_data_direction); /* @@ -1348,7 +1373,12 @@ static void aac_srb_callback(void *context, struct fib * fibptr) case SRB_STATUS_DOMAIN_VALIDATION_FAIL: default: #ifdef AAC_DETAILED_STATUS_INFO - printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",le32_to_cpu(srbreply->srb_status&0x3f),aac_get_status_string(le32_to_cpu(srbreply->srb_status)), scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status) ); + printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", + le32_to_cpu(srbreply->srb_status & 0x3F), + aac_get_status_string( + le32_to_cpu(srbreply->srb_status) & 0x3F), + scsicmd->cmnd[0], + le32_to_cpu(srbreply->scsi_status)); #endif scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; break; @@ -1358,7 +1388,10 @@ static void aac_srb_callback(void *context, struct fib * fibptr) scsicmd->result |= SAM_STAT_CHECK_CONDITION; len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))? sizeof(scsicmd->sense_buffer):srbreply->sense_data_size; - dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len)); +#ifdef AAC_DETAILED_STATUS_INFO + dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", + le32_to_cpu(srbreply->status), len)); +#endif memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); } @@ -1437,7 +1470,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len); - if( dev->pae_support ==1 ) { + if( dev->dac_support == 1 ) { aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg); srbcmd->count = cpu_to_le32(scsicmd->request_bufflen); @@ -1532,7 +1565,7 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg) psg->count = cpu_to_le32(1); psg->sg[0].addr = cpu_to_le32(addr); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)(ulong)addr; + scsicmd->SCp.dma_handle = addr; byte_count = scsicmd->request_bufflen; } return byte_count; @@ -1593,7 +1626,7 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p psg->sg[0].addr[1] = (u32)(le_addr>>32); psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)(ulong)addr; + scsicmd->SCp.dma_handle = addr; byte_count = scsicmd->request_bufflen; } return byte_count; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 8b077f224..20302a3e8 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -28,10 +28,7 @@ #define aac_phys_to_logical(x) (x+1) #define aac_logical_to_phys(x) (x?x-1:0) -#define AAC_DETAILED_STATUS_INFO - -extern int nondasd; -extern int paemode; +/* #define AAC_DETAILED_STATUS_INFO */ struct diskparm { @@ -404,15 +401,15 @@ struct aac_init }; enum aac_log_level { - LOG_INIT = 10, - LOG_INFORMATIONAL = 20, - LOG_WARNING = 30, - LOG_LOW_ERROR = 40, - LOG_MEDIUM_ERROR = 50, - LOG_HIGH_ERROR = 60, - LOG_PANIC = 70, - LOG_DEBUG = 80, - LOG_WINDBG_PRINT = 90 + LOG_AAC_INIT = 10, + LOG_AAC_INFORMATIONAL = 20, + LOG_AAC_WARNING = 30, + LOG_AAC_LOW_ERROR = 40, + LOG_AAC_MEDIUM_ERROR = 50, + LOG_AAC_HIGH_ERROR = 60, + LOG_AAC_PANIC = 70, + LOG_AAC_DEBUG = 80, + LOG_AAC_WINDBG_PRINT = 90 }; #define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT 0x030b @@ -841,7 +838,7 @@ struct aac_dev * lets break them out so we don't have to do an AND to check them */ u8 nondasd_support; - u8 pae_support; + u8 dac_support; }; #define AllocateAndMapFibSpace(dev, MapFibContext) \ diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 36ae4af39..7f3a22200 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -480,7 +480,7 @@ int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) default: data_dir = DMA_NONE; } - if (dev->pae_support == 1) { + if (dev->dac_support == 1) { struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; byte_count = 0; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index b5ac3c270..f53956f77 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -761,7 +761,7 @@ void aac_printf(struct aac_dev *dev, u32 val) length = 255; if (cp[length] != 0) cp[length] = 0; - if (level == LOG_HIGH_ERROR) + if (level == LOG_AAC_HIGH_ERROR) printk(KERN_WARNING "aacraid:%s", cp); else printk(KERN_INFO "aacraid:%s", cp); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index c55219142..04a8a571a 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -62,15 +63,7 @@ MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " "Adaptec Advanced Raid Products, " "and HP NetRAID-4M SCSI driver"); MODULE_LICENSE("GPL"); - - -int nondasd = -1; -module_param(nondasd, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); - -int paemode = -1; -module_param(paemode, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(paemode, "Control whether dma addressing is using PAE. 0=off, 1=on"); +MODULE_VERSION(AAC_DRIVER_VERSION); struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS]; static unsigned aac_count; @@ -83,44 +76,54 @@ static int aac_cfg_major = -1; * Note: The last field is used to index into aac_drivers below. */ static struct pci_device_id aac_pci_tbl[] = { - { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si */ - { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di */ - { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si */ - { 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Si */ - { 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di */ - { 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di */ - { 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di */ - { 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di */ - { 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di */ - { 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult*/ - { 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat*/ - { 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader)*/ - { 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan)*/ - { 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m)*/ - { 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220*/ - { 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230*/ - - { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier)*/ - { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado)*/ - { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020 ZCR PCI-X U320 */ - { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025 ZCR DIMM U320 */ - { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 20 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ - - { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 21 }, /* Perc 320/DC*/ - { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 22 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 23 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 24 }, /* Dell PERC2 "Quad Channel" */ - { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 25 }, /* HP NetRAID-4M */ - + { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */ + { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */ + { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */ + { 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ + { 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di (Viper/PERC3DiV) */ + { 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di (Lexus/PERC3DiL) */ + { 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ + { 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di (Dagger/PERC3DiD) */ + { 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di (Boxster/PERC3DiB) */ + { 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult */ + { 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat */ + { 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader) */ + { 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan) */ + { 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m) */ + { 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220 (Legend Crusader) */ + { 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230 (Legend Vulcan) */ + + { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier) */ + { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado) */ + { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { 0x9005, 0x0286, 0x9005, 0x028d, 0, 0, 21 }, /* ASR-2130S (Lancer) */ + { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 22 }, /* Jupiter Platform */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 23 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 24 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 25 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 26 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 27 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 28 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 29 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* SATA 6Ch (Bearcat) */ - - { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 31 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ - { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 32 }, /* ASR-2020SA (ZCR PCI-X SATA) */ - { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 33 }, /* ASR-2025SA (ZCR DIMM SATA) */ + { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* AAR-2610SA PCI SATA 6ch */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 31 }, /* ASR-2240S */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 32 }, /* ASR-4005SAS */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 33 }, /* ASR-4000SAS */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 34 }, /* ASR-4800SAS */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 35 }, /* ASR-4805SAS */ + + { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 36 }, /* Perc 320/DC*/ + { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 37 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 38 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 39 }, /* Dell PERC2/QC */ + { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 40 }, /* HP NetRAID-4M */ + + { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 41 }, /* Dell Catchall */ + { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 42 }, /* Legend Catchall */ + { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 43 }, /* Adaptec Catch All */ + { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 44 }, /* Adaptec Rocket Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -131,44 +134,54 @@ MODULE_DEVICE_TABLE(pci, aac_pci_tbl); * for the card. At that time we can remove the channels from here */ static struct aac_driver_ident aac_drivers[] = { - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 2/Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di */ - { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT }, /* catapult*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT }, /* tomcat*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT }, /* Adaptec 2120S (Crusader)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan-2m)*/ - { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT }, /* Legend S220*/ - { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT }, /* Legend S230*/ - - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020 ZCR PCI-X U320 */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025 ZCR DIMM U320 */ - { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ - - { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT }, /* Dell PERC2 "Quad Channel" */ - { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4 }, /* HP NetRAID-4M */ - + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 2/Si (Iguana/PERC2Si) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Opal/PERC3Di) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si (SlimFast/PERC3Si */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Viper/PERC3DiV) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Lexus/PERC3DiL) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Dagger/PERC3DiD) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Boxster/PERC3DiB) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT }, /* catapult */ + { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT }, /* tomcat */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT }, /* Adaptec 2120S (Crusader) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan-2m) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT }, /* Legend S220 (Legend Crusader) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT }, /* Legend S230 (Legend Vulcan) */ + + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2 }, /* Jupiter Platform */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ { aac_rx_init, "aacraid", "DELL ", "CERC SR2 ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ { aac_rx_init, "aacraid", "ADAPTEC ", "SO-DIMM SATA ZCR", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "SATA 6Channel ", 1 }, /* SATA 6Ch (Bearcat) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2610SA ", 1 }, /* SATA 6Ch (Bearcat) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS */ - { aac_rkt_init,"aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA (ZCR PCI-X SATA) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA (ZCR DIMM SATA) */ + { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ + { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/ + { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/ + { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT }, /* Dell PERC2/QC */ + { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4 }, /* HP NetRAID-4M */ + + { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Dell Catchall */ + { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Legend Catchall */ + { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Adaptec Catch All */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec Rocket Catch All */ }; #ifdef CONFIG_COMPAT @@ -408,15 +421,17 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) } } spin_unlock_irqrestore(&dev->list_lock, flags); + if (active) + break; - /* - * We can exit If all the commands are complete - */ - if (active == 0) - return SUCCESS; } + /* + * We can exit If all the commands are complete + */ + if (active == 0) + return SUCCESS; spin_unlock_irq(host->host_lock); - scsi_sleep(HZ); + ssleep(1); spin_lock_irq(host->host_lock); } printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index d796cac2a..40d282fb7 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -15,16 +15,6 @@ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) * changed its name to ConnectCom Solutions, Inc. * - * There is an AdvanSys Linux WWW page at: - * http://www.connectcom.net/downloads/software/os/linux.html - * http://www.advansys.com/linux.html - * - * The latest released version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux/linux.tgz - * ftp://ftp.connectcom.net/pub/linux/linux.tgz - * - * Please send questions, comments, bug reports to: - * support@connectcom.net */ /* @@ -41,7 +31,6 @@ H. Release History I. Known Problems/Fix List J. Credits (Chronological Order) - K. ConnectCom (AdvanSys) Contact Information A. Linux Kernels Supported by this Driver @@ -2032,9 +2021,6 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushort); #define ADV_LIB_VERSION_MAJOR 5 #define ADV_LIB_VERSION_MINOR 14 -/* d_os_dep.h */ -#define ADV_OS_LINUX - /* * Define Adv Library required special types. */ @@ -3370,9 +3356,9 @@ do { \ /* * Default EEPROM Configuration structure defined in a_init.c. */ -extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; -extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; -extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; +static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; +static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; +static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; /* * DvcGetPhyAddr() flag arguments diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h index 5230ba01c..3f4bde023 100644 --- a/drivers/scsi/advansys.h +++ b/drivers/scsi/advansys.h @@ -13,37 +13,11 @@ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) * changed its name to ConnectCom Solutions, Inc. * - * There is an AdvanSys Linux WWW page at: - * http://www.connectcom.net/downloads/software/os/linux.html - * http://www.advansys.com/linux.html - * - * The latest released version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux/linux.tgz - * ftp://ftp.connectcom.net/pub/linux/linux.tgz - * - * Please send questions, comments, bug reports to: - * linux@connectcom.net or bfrey@turbolinux.com.cn */ #ifndef _ADVANSYS_H #define _ADVANSYS_H -#include -#ifndef LINUX_VERSION_CODE -#include -#endif /* LINUX_VERSION_CODE */ - -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) -/* Driver supported only in version 2.2 and version >= 2.4. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ - (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ - LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) -#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels." -#endif -#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) -#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0)) - /* * Scsi_Host_Template function prototypes. */ diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 4c5e9c38f..8b93d6e43 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -1479,7 +1479,7 @@ static int aha1542_bus_reset(Scsi_Cmnd * SCpnt) * we are pretty desperate anyways. */ spin_unlock_irq(SCpnt->device->host->host_lock); - scsi_sleep(4 * HZ); + ssleep(4); spin_lock_irq(SCpnt->device->host->host_lock); WAIT(STATUS(SCpnt->device->host->io_port), @@ -1543,7 +1543,7 @@ static int aha1542_host_reset(Scsi_Cmnd * SCpnt) * we are pretty desperate anyways. */ spin_unlock_irq(SCpnt->device->host->host_lock); - scsi_sleep(4 * HZ); + ssleep(4); spin_lock_irq(SCpnt->device->host->host_lock); WAIT(STATUS(SCpnt->device->host->io_port), diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h index cba290ce9..c402351dc 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/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index b29981521..c2523a30a 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -46,7 +46,7 @@ config AIC79XX_RESET_DELAY_MS config AIC79XX_BUILD_FIRMWARE bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC79XX + depends on SCSI_AIC79XX && !PREVENT_FIRMWARE_BUILD help This option should only be enabled if you are modifying the firmware source to the aic79xx driver and wish to have the generated firmware diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 473a658d2..8398e0dd4 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -61,7 +61,7 @@ config AIC7XXX_PROBE_EISA_VL config AIC7XXX_BUILD_FIRMWARE bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC7XXX + depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD help This option should only be enabled if you are modifying the firmware source to the aic7xxx driver and wish to have the generated firmware diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 68b4539a4..c9f3a52f1 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -61,6 +61,7 @@ #endif #include /* For fetching system memory size */ +#include /* For ssleep/msleep */ /* * Lock protecting manipulation of the ahd softc list. @@ -415,7 +416,6 @@ uint32_t aic79xx_periodic_otag; /* * Module information and settable options. */ -#ifdef MODULE static char *aic79xx = NULL; /* * Just in case someone uses commas to separate items on the insmod @@ -426,9 +426,8 @@ static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n"; MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); -#endif +MODULE_VERSION(AIC79XX_DRIVER_VERSION); MODULE_PARM(aic79xx, "s"); MODULE_PARM_DESC(aic79xx, "period delimited, options string.\n" @@ -463,7 +462,6 @@ MODULE_PARM_DESC(aic79xx, " Change Read Streaming for Controller's 2 and 3\n" "\n" " options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'"); -#endif static void ahd_linux_handle_scsi_status(struct ahd_softc *, struct ahd_linux_device *, @@ -513,9 +511,6 @@ static void ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ); -static __inline int - ahd_linux_dv_fallback(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); static int ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, @@ -2915,6 +2910,19 @@ out: ahd_unlock(ahd, &s); } +static __inline int +ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) +{ + u_long s; + int retval; + + ahd_lock(ahd, &s); + retval = ahd_linux_fallback(ahd, devinfo); + ahd_unlock(ahd, &s); + + return (retval); +} + static void ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, @@ -3163,7 +3171,7 @@ ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, break; } if (status & SSQ_DELAY) - scsi_sleep(1 * HZ); + ssleep(1); break; case SS_START: @@ -3323,7 +3331,7 @@ ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, } if (targ->dv_state_retry <= 10) { if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) - scsi_sleep(ahd->our_id*HZ/10); + msleep(ahd->our_id*1000/10); break; } #ifdef AHD_DEBUG @@ -3367,7 +3375,7 @@ ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, targ->dv_state_retry--; } else if (targ->dv_state_retry < 60) { if ((status & SSQ_DELAY) != 0) - scsi_sleep(1 * HZ); + ssleep(1); } else { #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_DV) { @@ -3551,19 +3559,6 @@ ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, cmd->cmnd[4] = le | SSS_START; } -static __inline int -ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - u_long s; - int retval; - - ahd_lock(ahd, &s); - retval = ahd_linux_fallback(ahd, devinfo); - ahd_unlock(ahd, &s); - - return (retval); -} - static int ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 913984539..7cc83dafa 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -452,8 +452,10 @@ ahd_pci_test_register_access(struct ahd_softc *ahd) * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flaged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); while (ahd_is_paused(ahd) == 0) ; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 3c7a4854d..ecbc05d84 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -140,6 +140,7 @@ #include /* For fetching system memory size */ #include /* For block_size() */ +#include /* For ssleep/msleep */ /* * Lock protecting manipulation of the ahc softc list. @@ -436,7 +437,6 @@ uint32_t aic7xxx_periodic_otag; /* * Module information and settable options. */ -#ifdef MODULE static char *aic7xxx = NULL; /* * Just in case someone uses commas to separate items on the insmod @@ -447,9 +447,8 @@ static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n"; MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); -#endif +MODULE_VERSION(AIC7XXX_DRIVER_VERSION); MODULE_PARM(aic7xxx, "s"); MODULE_PARM_DESC(aic7xxx, "period delimited, options string.\n" @@ -479,7 +478,6 @@ MODULE_PARM_DESC(aic7xxx, "\n" " options aic7xxx 'aic7xxx=probe_eisa_vl.tag_info:{{}.{.10}}.seltime:1'\n" ); -#endif static void ahc_linux_handle_scsi_status(struct ahc_softc *, struct ahc_linux_device *, @@ -2825,7 +2823,7 @@ ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd, break; } if (status & SSQ_DELAY) - scsi_sleep(1 * HZ); + ssleep(1); break; case SS_START: @@ -2985,7 +2983,7 @@ ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd, } if (targ->dv_state_retry <= 10) { if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) - scsi_sleep(ahc->our_id*HZ/10); + msleep(ahc->our_id*1000/10); break; } #ifdef AHC_DEBUG @@ -3029,7 +3027,7 @@ ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd, targ->dv_state_retry--; } else if (targ->dv_state_retry < 60) { if ((status & SSQ_DELAY) != 0) - scsi_sleep(1 * HZ); + ssleep(1); } else { #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 01cfab0e3..476780bae 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -1284,8 +1284,10 @@ ahc_pci_test_register_access(struct ahc_softc *ahc) * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flagged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); while (ahc_is_paused(ahc) == 0) ; diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index e8c345b8e..8c91fda64 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -34,10 +34,14 @@ $(PROG): ${GENHDRS} $(SRCS) $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) $(LIBS) aicdb.h: - @if [ -e "/usr/include/db3/db_185.h" ]; then \ + @if [ -e "/usr/include/db4/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db3/db_185.h" ]; then \ echo "#include " > aicdb.h; \ elif [ -e "/usr/include/db2/db_185.h" ]; then \ echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db1/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ elif [ -e "/usr/include/db/db_185.h" ]; then \ echo "#include " > aicdb.h; \ elif [ -e "/usr/include/db_185.h" ]; then \ diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 3d6149675..c92226b8c 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -10489,7 +10489,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd) aic_outb(p, lastphase | ATNO, SCSISIGO); unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(HZ); + ssleep(1); spin_lock_irq(p->host->host_lock); if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) return FAILED; @@ -10548,7 +10548,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd) aic_outb(p, saved_scbptr, SCBPTR); unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(HZ/4); + msleep(1000/4); spin_lock_irq(p->host->host_lock); if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) return FAILED; @@ -10786,7 +10786,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd) } unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(HZ/4); + msleep(1000/4); spin_lock_irq(p->host->host_lock); if (p->flags & AHC_ABORT_PENDING) { @@ -10887,7 +10887,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd) aic7xxx_run_done_queue(p, TRUE); unpause_sequencer(p, FALSE); spin_unlock_irq(p->host->host_lock); - scsi_sleep(2 * HZ); + ssleep(2); spin_lock_irq(p->host->host_lock); return SUCCESS; } @@ -11139,6 +11139,7 @@ aic7xxx_print_scratch_ram(struct aic7xxx_host *p) #include "aic7xxx_old/aic7xxx_proc.c" MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(AIC7XXX_H_VERSION); static Scsi_Host_Template driver_template = { diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index 6dad72222..27271bfc0 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -321,6 +321,7 @@ static void __devexit cumanascsi1_remove(struct expansion_card *ec) scsi_remove_host(host); free_irq(host->irq, host); + NCR5380_exit(host); release_region(host->io_port, host->n_io_port); scsi_host_put(host); } diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c index 57e79614f..303648a84 100644 --- a/drivers/scsi/arm/ecoscsi.c +++ b/drivers/scsi/arm/ecoscsi.c @@ -222,6 +222,7 @@ static void __exit ecoscsi_exit(void) if (shpnt->irq != IRQ_NONE) free_irq(shpnt->irq, NULL); + NCR5380_exit(host); if (shpnt->io_port) release_region(shpnt->io_port, shpnt->n_io_port); diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 530b59c01..5f037d24c 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -231,7 +231,8 @@ static void eesoxscsi_buffer_in(void *buf, int length, void *base) * Align buffer. */ if (((u32)buf) & 2 && status >= 2) { - *((u16 *)buf)++ = readl(reg_dmadata); + *(u16 *)buf = readl(reg_dmadata); + buf += 2; status -= 2; length -= 2; } @@ -243,8 +244,10 @@ static void eesoxscsi_buffer_in(void *buf, int length, void *base) l1 |= readl(reg_dmadata) << 16; l2 = readl(reg_dmadata) & mask; l2 |= readl(reg_dmadata) << 16; - *((u32 *)buf)++ = l1; - *((u32 *)buf)++ = l2; + *(u32 *)buf = l1; + buf += 4; + *(u32 *)buf = l2; + buf += 4; length -= 8; continue; } @@ -255,13 +258,15 @@ static void eesoxscsi_buffer_in(void *buf, int length, void *base) l1 = readl(reg_dmadata) & mask; l1 |= readl(reg_dmadata) << 16; - *((u32 *)buf)++ = l1; + *(u32 *)buf = l1; + buf += 4; length -= 4; continue; } if (status >= 2) { - *((u16 *)buf)++ = readl(reg_dmadata); + *(u16 *)buf = readl(reg_dmadata); + buf += 2; length -= 2; } } while (length); @@ -305,7 +310,8 @@ static void eesoxscsi_buffer_out(void *buf, int length, void *base) * Align buffer. */ if (((u32)buf) & 2 && status >= 2) { - writel(*((u16 *)buf)++ << 16, reg_dmadata); + writel(*(u16 *)buf << 16, reg_dmadata); + buf += 2; status -= 2; length -= 2; } @@ -313,8 +319,10 @@ static void eesoxscsi_buffer_out(void *buf, int length, void *base) if (status >= 8) { unsigned long l1, l2; - l1 = *((u32 *)buf)++; - l2 = *((u32 *)buf)++; + l1 = *(u32 *)buf; + buf += 4; + l2 = *(u32 *)buf; + buf += 4; writel(l1 << 16, reg_dmadata); writel(l1, reg_dmadata); @@ -327,7 +335,8 @@ static void eesoxscsi_buffer_out(void *buf, int length, void *base) if (status >= 4) { unsigned long l1; - l1 = *((u32 *)buf)++; + l1 = *(u32 *)buf; + buf += 4; writel(l1 << 16, reg_dmadata); writel(l1, reg_dmadata); @@ -336,7 +345,8 @@ static void eesoxscsi_buffer_out(void *buf, int length, void *base) } if (status >= 2) { - writel(*((u16 *)buf)++ << 16, reg_dmadata); + writel(*(u16 *)buf << 16, reg_dmadata); + buf += 2; length -= 2; } } while (length); diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index f54b47025..bd607455e 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2681,7 +2681,7 @@ int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) * IRQs after the sleep. */ spin_unlock_irq(info->host->host_lock); - scsi_sleep(50 * HZ/100); + msleep(50 * 1000/100); spin_lock_irq(info->host->host_lock); /* @@ -2920,7 +2920,7 @@ int fas216_add(struct Scsi_Host *host, struct device *dev) * scsi standard says wait 250ms */ spin_unlock_irq(info->host->host_lock); - scsi_sleep(100*HZ/100); + msleep(100*1000/100); spin_lock_irq(info->host->host_lock); fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c index ecfee930c..ff2554f4c 100644 --- a/drivers/scsi/arm/oak.c +++ b/drivers/scsi/arm/oak.c @@ -179,6 +179,7 @@ static void __devexit oakscsi_remove(struct expansion_card *ec) ecard_set_drvdata(ec, NULL); scsi_remove_host(host); + NCR5380_exit(host); release_region(host->io_port, host->n_io_port); scsi_host_put(host); } diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index c030c0a68..adad8d394 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -39,6 +39,7 @@ enum { ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ + PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ @@ -58,6 +59,7 @@ enum { ich5_sata = 1, piix4_pata = 2, ich6_sata = 3, + ich6_sata_rm = 4, }; static int piix_init_one (struct pci_dev *pdev, @@ -65,10 +67,8 @@ static int piix_init_one (struct pci_dev *pdev, static void piix_pata_phy_reset(struct ata_port *ap); static void piix_sata_phy_reset(struct ata_port *ap); -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); static unsigned int in_module_init = 1; @@ -87,13 +87,9 @@ static struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, - - /* ICH6 operates in two modes, "looks-like-ICH5" mode, - * and enhanced mode, with queueing and other fancy stuff. - * This is distinguished by PCI class code. - */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, - { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, { } /* terminate list */ }; @@ -108,6 +104,7 @@ static struct pci_driver piix_pci_driver = { static Scsi_Host_Template piix_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -126,17 +123,18 @@ static Scsi_Host_Template piix_sht = { static struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, + .set_dmamode = piix_set_dmamode, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = piix_pata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -151,18 +149,17 @@ static struct ata_port_operations piix_pata_ops = { static struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = piix_sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -181,7 +178,12 @@ static struct ata_port_info piix_port_info[] = { .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -191,8 +193,9 @@ static struct ata_port_info piix_port_info[] = { .sht = &piix_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, @@ -200,7 +203,12 @@ static struct ata_port_info piix_port_info[] = { { .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -211,8 +219,21 @@ static struct ata_port_info piix_port_info[] = { .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich6_sata_rm */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, }; @@ -368,11 +389,11 @@ static void piix_sata_phy_reset(struct ata_port *ap) * None (inherited from caller). */ -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) { + unsigned int pio = adev->pio_mode - XFER_PIO_0; struct pci_dev *dev = ap->host_set->pdev; - unsigned int is_slave = (adev->flags & ATA_DFLAG_MASTER) ? 0 : 1; + unsigned int is_slave = (adev->devno != 0); unsigned int master_port= ap->port_no ? 0x42 : 0x40; unsigned int slave_port = 0x44; u16 master_data; @@ -409,7 +430,7 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, } /** - * piix_set_udmamode - Initialize host controller PATA PIO timings + * piix_set_dmamode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um * @udma: udma mode, 0 - 6 @@ -420,9 +441,9 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, * None (inherited from caller). */ -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) { + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ struct pci_dev *dev = ap->host_set->pdev; u8 maslave = ap->port_no ? 0x42 : 0x40; u8 speed = udma; @@ -452,25 +473,38 @@ static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, case XFER_UDMA_3: case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: break; default: BUG(); return; } - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } /* move to PCI layer, integrate w/ MSI stuff */ @@ -485,6 +519,42 @@ static void pci_enable_intx(struct pci_dev *pdev) } } +#define AHCI_PCI_BAR 5 +#define AHCI_GLOBAL_CTL 0x04 +#define AHCI_ENABLE (1 << 31) +static int piix_disable_ahci(struct pci_dev *pdev) +{ + void *mmio; + unsigned long addr; + u32 tmp; + int rc = 0; + + /* BUG: pci_enable_device has not yet been called. This + * works because this device is usually set up by BIOS. + */ + + addr = pci_resource_start(pdev, AHCI_PCI_BAR); + if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + return 0; + + mmio = ioremap(addr, 64); + if (!mmio) + return -ENOMEM; + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) { + tmp &= ~AHCI_ENABLE; + writel(tmp, mmio + AHCI_GLOBAL_CTL); + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) + rc = -EIO; + } + + iounmap(mmio); + return rc; +} + /** * piix_init_one - Register PIIX ATA PCI device with kernel services * @pdev: PCI device to register @@ -517,6 +587,12 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) port_info[0] = &piix_port_info[ent->driver_data]; port_info[1] = NULL; + if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } + if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { u8 tmp; pci_read_config_byte(pdev, ICH5_PMR, &tmp); diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 9cf23b9f2..49feb64cd 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -363,7 +363,7 @@ go_42: /* * Clear it off the queue */ - dev->id[target_id].curr_req = 0; + dev->id[target_id].curr_req = NULL; dev->working--; spin_unlock_irqrestore(dev->host->host_lock, flags); /* @@ -2263,10 +2263,10 @@ static int atp870u_init_tables(struct Scsi_Host *host) dev->in_snd = 0; dev->in_int = 0; for (k = 0; k < qcnt; k++) { - dev->querequ[k] = 0; + dev->querequ[k] = NULL; } for (k = 0; k < 16; k++) { - dev->id[k].curr_req = 0; + dev->id[k].curr_req = NULL; dev->sp[k] = 0x04; } return 0; diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c index a69bd792e..bd94c70f4 100644 --- a/drivers/scsi/cpqfcTScontrol.c +++ b/drivers/scsi/cpqfcTScontrol.c @@ -116,7 +116,6 @@ int CpqTsCreateTachLiteQues( void* pHBA, int opcode) cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle); /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */ - memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE)); if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!! { diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c index 8778aac34..58d140cd1 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/dc395x.c b/drivers/scsi/dc395x.c index bde847c73..b08c3e6b1 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -376,6 +376,8 @@ static void disconnect(struct AdapterCtlBlk *acb); static void reselect(struct AdapterCtlBlk *acb); static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); +static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb); static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code, @@ -384,13 +386,11 @@ static void scsi_reset_detect(struct AdapterCtlBlk *acb); static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); -static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb); -static inline void set_xfer_rate(struct AdapterCtlBlk *acb, +static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb); static void waiting_timeout(unsigned long ptr); @@ -989,7 +989,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, srb->sg_count = 0; srb->total_xfer_length = 0; srb->sg_bus_addr = 0; - srb->virt_addr = 0; + srb->virt_addr = NULL; srb->sg_index = 0; srb->adapter_status = 0; srb->target_status = 0; @@ -1676,6 +1676,23 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, } +#define DC395x_ENABLE_MSGOUT \ + DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \ + srb->state |= SRB_MSGOUT + + +/* abort command */ +static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) +{ + srb->msgout_buf[0] = ABORT; + srb->msg_count = 1; + DC395x_ENABLE_MSGOUT; + srb->state &= ~SRB_MSGIN; + srb->state |= SRB_MSGOUT; +} + + /** * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to * have been triggered for this card. @@ -1999,7 +2016,7 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) } dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n"); - srb->virt_addr = 0; + srb->virt_addr = NULL; } @@ -2583,11 +2600,6 @@ static inline u8 msgin_completed(u8 * msgbuf, u32 len) return 1; } -#define DC395x_ENABLE_MSGOUT \ - DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \ - srb->state |= SRB_MSGOUT - - /* reject_msg */ static inline void msgin_reject(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) @@ -2603,18 +2615,6 @@ static inline void msgin_reject(struct AdapterCtlBlk *acb, } -/* abort command */ -static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - srb->msgout_buf[0] = ABORT; - srb->msg_count = 1; - DC395x_ENABLE_MSGOUT; - srb->state &= ~SRB_MSGIN; - srb->state |= SRB_MSGOUT; -} - - static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, u8 tag) { @@ -3656,7 +3656,7 @@ static void scsi_reset_detect(struct AdapterCtlBlk *acb) } else { acb->acb_flag |= RESET_DETECT; reset_dev_param(acb); - doing_srb_done(acb, DID_RESET, 0, 1); + doing_srb_done(acb, DID_RESET, NULL, 1); /*DC395x_RecoverSRB( acb ); */ acb->active_dcb = NULL; acb->acb_flag = 0; diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c index 26e060bb8..21a701c6c 100644 --- a/drivers/scsi/dmx3191d.c +++ b/drivers/scsi/dmx3191d.c @@ -106,9 +106,10 @@ static const char * dmx3191d_info(struct Scsi_Host *host) { static int dmx3191d_release_resources(struct Scsi_Host *instance) { - release_region(instance->io_port, DMX3191D_REGION); if(instance->irq!=SCSI_IRQ_NONE) free_irq(instance->irq, instance); + NCR5380_exit(instance); + release_region(instance->io_port, DMX3191D_REGION); return 0; } diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 624c7ee5d..6611113a2 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -451,6 +451,7 @@ static int dtc_release(struct Scsi_Host *shost) { if (shost->irq) free_irq(shost->irq, NULL); + NCR5380_exit(shost); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); scsi_unregister(shost); diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index e2c07fca0..0ee49dc50 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -59,6 +59,8 @@ #include #include #include +#include + #include #include @@ -511,8 +513,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) HD(cmd)->state = RESET; spin_unlock_irq(host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(3 * HZ); + msleep(3000); spin_lock_irq(host->host_lock); DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit)); diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h index 85beb4750..73f7d6968 100644 --- a/drivers/scsi/esp.h +++ b/drivers/scsi/esp.h @@ -77,8 +77,8 @@ struct scsi_cmnd; /* We get one of these for each ESP probed. */ struct esp { - unsigned long eregs; /* ESP controller registers */ - unsigned long dregs; /* DMA controller registers */ + void __iomem *eregs; /* ESP controller registers */ + void __iomem *dregs; /* DMA controller registers */ struct sbus_dma *dma; /* DMA controller sw state */ struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ struct sbus_dev *sdev; /* Pointer to SBus entry */ diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index 763e33b13..32e0cd597 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -78,6 +78,7 @@ **************************************************************************/ #include +#include #include #include #include @@ -288,7 +289,7 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs); static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 }; static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; -static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; +static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; /* host information */ static int found = 0; @@ -297,16 +298,20 @@ static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL }; static int user_fifo_count = 0; static int user_fifo_size = 0; -static void fd_mcs_setup(char *str, int *ints) +static int __init fd_mcs_setup(char *str) { static int done_setup = 0; + int ints[3]; + get_options(str, 3, ints); if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) { printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n"); + return 0; } user_fifo_count = ints[0] >= 1 ? ints[1] : 0; user_fifo_size = ints[0] >= 2 ? ints[2] : 0; + return 1; } __setup("fd_mcs=", fd_mcs_setup); @@ -391,7 +396,7 @@ static int fd_mcs_detect(Scsi_Host_Template * tpnt) } else { bios = addresses[pos2 >> 6]; port = ports[(pos2 >> 4) & 0x03]; - irq = ints[(pos2 >> 1) & 0x07]; + irq = interrupts[(pos2 >> 1) & 0x07]; } if (irq) { diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 6529f0c55..a78b6f257 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: 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: No BIOS, using port_base = 0x%x, irq = %d\n", port_base, interrupt_level ); #endif + if (!request_region(port_base, 0x10, "fdomain")) { + printk( "scsi: port 0x%x is busy\n", port_base ); + printk( "scsi: Bad LILO/INSMOD parameters?\n" ); + return NULL; + } if (!fdomain_is_valid_port( port_base )) { printk( "scsi: Cannot locate chip at port base 0x%x\n", port_base ); printk( "scsi: 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: 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: 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: 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/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index bcf97ec03..9c1f8cc4d 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -501,6 +501,10 @@ int generic_NCR5380_release_resources(struct Scsi_Host *instance) { NCR5380_local_declare(); NCR5380_setup(instance); + + if (instance->irq != SCSI_IRQ_NONE) + free_irq(instance->irq, NULL); + NCR5380_exit(instance); #ifndef CONFIG_SCSI_G_NCR5380_MEM release_region(instance->NCR5380_instance_name, instance->n_io_port); @@ -508,8 +512,6 @@ int generic_NCR5380_release_resources(struct Scsi_Host *instance) release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); #endif - if (instance->irq != SCSI_IRQ_NONE) - free_irq(instance->irq, NULL); return 0; } diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 6cb8fa2bd..df28e91a6 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -571,12 +571,12 @@ static struct timer_list gdth_timer; #define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) -#define gdth_readb(addr) readb((ulong)(addr)) -#define gdth_readw(addr) readw((ulong)(addr)) -#define gdth_readl(addr) (ulong32)readl((ulong)(addr)) -#define gdth_writeb(b,addr) writeb((b),(ulong)(addr)) -#define gdth_writew(b,addr) writew((b),(ulong)(addr)) -#define gdth_writel(b,addr) writel((ulong32)(b),(ulong)(addr)) +#define gdth_readb(addr) readb(addr) +#define gdth_readw(addr) readw(addr) +#define gdth_readl(addr) readl(addr) +#define gdth_writeb(b,addr) writeb((b),(addr)) +#define gdth_writew(b,addr) writew((b),(addr)) +#define gdth_writel(b,addr) writel((b),(addr)) static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ @@ -618,9 +618,6 @@ static unchar gdth_direction_tab[0x100] = { }; /* __initfunc, __initdata macros */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -#define __devinitdata -#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #define GDTH_INITFUNC(type, func) type __init func #include @@ -778,7 +775,7 @@ GDTH_INITFUNC(static int, gdth_search_eisa(ushort eisa_adr)) GDTH_INITFUNC(static int, gdth_search_isa(ulong32 bios_adr)) { - void *addr; + void __iomem *addr; ulong32 id; TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); @@ -1053,7 +1050,7 @@ GDTH_INITFUNC(static int, gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)) GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)) { - register gdt2_dpram_str *dp2_ptr; + register gdt2_dpram_str __iomem *dp2_ptr; int i; unchar irq_drq,prot_ver; ulong32 retries; @@ -1065,10 +1062,10 @@ GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)) printk("GDT-ISA: Initialization error (DPMEM remap error)\n"); return 0; } - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */ /* reset interface area */ - memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u)); + memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u)); if (gdth_readl(&dp2_ptr->u) != 0) { printk("GDT-ISA: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); @@ -1153,9 +1150,9 @@ GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)) GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) { - register gdt6_dpram_str *dp6_ptr; - register gdt6c_dpram_str *dp6c_ptr; - register gdt6m_dpram_str *dp6m_ptr; + register gdt6_dpram_str __iomem *dp6_ptr; + register gdt6c_dpram_str __iomem *dp6c_ptr; + register gdt6m_dpram_str __iomem *dp6m_ptr; ulong32 retries; unchar prot_ver; ushort command; @@ -1183,7 +1180,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) return 0; } /* check and reset interface area */ - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", @@ -1208,7 +1205,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); @@ -1222,7 +1219,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) return 0; } } - memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u)); + memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u)); if (gdth_readl(&dp6_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); @@ -1293,7 +1290,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) return 0; } /* check and reset interface area */ - dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + dp6c_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", @@ -1318,7 +1315,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + dp6c_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); @@ -1332,7 +1329,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) return 0; } } - memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u)); + memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u)); if (gdth_readl(&dp6c_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); @@ -1428,13 +1425,14 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) pcistr->pdev->rom_address); #endif + dp6m_ptr = ha->brd; + /* Ensure that it is safe to access the non HW portions of DPMEM. * Aditional check needed for Xscale based RAID controllers */ - while( ((int)gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg) ) & 3 ) + while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 ) gdth_delay(1); /* check and reset interface area */ - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", @@ -1459,7 +1457,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); @@ -1473,7 +1471,7 @@ GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) return 0; } } - memset_io((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u)); + memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u)); /* disable board interrupts, deinit services */ gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4, @@ -1556,9 +1554,9 @@ GDTH_INITFUNC(static void, gdth_enable_int(int hanum)) { gdth_ha_str *ha; ulong flags; - gdt2_dpram_str *dp2_ptr; - gdt6_dpram_str *dp6_ptr; - gdt6m_dpram_str *dp6m_ptr; + gdt2_dpram_str __iomem *dp2_ptr; + gdt6_dpram_str __iomem *dp6_ptr; + gdt6m_dpram_str __iomem *dp6m_ptr; TRACE(("gdth_enable_int() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -1569,12 +1567,12 @@ GDTH_INITFUNC(static void, gdth_enable_int(int hanum)) outb(0xff, ha->bmic + EDENABREG); outb(0x01, ha->bmic + EINTENABREG); } else if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; gdth_writeb(1, &dp2_ptr->io.irqdel); gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index); gdth_writeb(1, &dp2_ptr->io.irqen); } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writeb(1, &dp6_ptr->io.irqdel); gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index); gdth_writeb(1, &dp6_ptr->io.irqen); @@ -1582,7 +1580,7 @@ GDTH_INITFUNC(static void, gdth_enable_int(int hanum)) outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); outb(0x03, PTR2USHORT(&ha->plx->control1)); } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4, &dp6m_ptr->i960r.edoor_en_reg); @@ -1608,15 +1606,15 @@ static int gdth_get_status(unchar *pIStatus,int irq) *pIStatus = inb((ushort)ha->bmic + EDOORREG); else if (ha->type == GDT_ISA) *pIStatus = - gdth_readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index); + gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCI) *pIStatus = - gdth_readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index); + gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCINEW) *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg)); else if (ha->type == GDT_PCIMPR) *pIStatus = - gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg); + gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg); if (*pIStatus) return i; /* board found */ @@ -1636,14 +1634,14 @@ static int gdth_test_busy(int hanum) if (ha->type == GDT_EISA) gdtsema0 = (int)inb(ha->bmic + SEMA0REG); else if (ha->type == GDT_ISA) - gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Sema0); + gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCI) - gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Sema0); + gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCINEW) gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg)); else if (ha->type == GDT_PCIMPR) gdtsema0 = - (int)gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg); + (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); return (gdtsema0 & 1); } @@ -1679,13 +1677,13 @@ static void gdth_set_sema0(int hanum) if (ha->type == GDT_EISA) { outb(1, ha->bmic + SEMA0REG); } else if (ha->type == GDT_ISA) { - gdth_writeb(1, &((gdt2_dpram_str *)ha->brd)->u.ic.Sema0); + gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCI) { - gdth_writeb(1, &((gdt6_dpram_str *)ha->brd)->u.ic.Sema0); + gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->sema0_reg)); } else if (ha->type == GDT_PCIMPR) { - gdth_writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg); + gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); } } @@ -1694,10 +1692,10 @@ static void gdth_copy_command(int hanum) { register gdth_ha_str *ha; register gdth_cmd_str *cmd_ptr; - register gdt6m_dpram_str *dp6m_ptr; - register gdt6c_dpram_str *dp6c_ptr; - gdt6_dpram_str *dp6_ptr; - gdt2_dpram_str *dp2_ptr; + register gdt6m_dpram_str __iomem *dp6m_ptr; + register gdt6c_dpram_str __iomem *dp6c_ptr; + gdt6_dpram_str __iomem *dp6_ptr; + gdt2_dpram_str __iomem *dp2_ptr; ushort cp_count,dp_offset,cmd_no; TRACE(("gdth_copy_command() hanum %d\n",hanum)); @@ -1720,28 +1718,28 @@ static void gdth_copy_command(int hanum) /* set offset and service, copy command to DPMEM */ if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp2_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCINEW) { - dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + dp6c_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); gdth_writew((ushort)cmd_ptr->Service, @@ -1780,13 +1778,13 @@ static void gdth_release_event(int hanum) outl(ha->ccb_phys, ha->bmic + MAILBOXREG); outb(ha->pccb->Service, ha->bmic + LDOORREG); } else if (ha->type == GDT_ISA) { - gdth_writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event); + gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCI) { - gdth_writeb(0, &((gdt6_dpram_str *)ha->brd)->io.event); + gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->ldoor_reg)); } else if (ha->type == GDT_PCIMPR) { - gdth_writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg); + gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg); } } @@ -3419,7 +3417,7 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, /* no GDTH_LOCK_HA() ! */ TRACE2(("gdth_store_event() source %d idx %d\n", source, idx)); if (source == 0) /* no source -> no event */ - return 0; + return NULL; if (ebuffer[elastidx].event_source == source && ebuffer[elastidx].event_idx == idx && @@ -3538,9 +3536,9 @@ static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) #endif { register gdth_ha_str *ha; - gdt6m_dpram_str *dp6m_ptr = NULL; - gdt6_dpram_str *dp6_ptr; - gdt2_dpram_str *dp2_ptr; + gdt6m_dpram_str __iomem *dp6m_ptr = NULL; + gdt6_dpram_str __iomem *dp6_ptr; + gdt2_dpram_str __iomem *dp2_ptr; Scsi_Cmnd *scp; int hanum, rval, i; unchar IStatus; @@ -3619,7 +3617,7 @@ static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ } else if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; + dp2_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; ha->status = gdth_readw(&dp2_ptr->u.ic.Status); @@ -3634,7 +3632,7 @@ static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; + dp6_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; ha->status = gdth_readw(&dp6_ptr->u.ic.Status); @@ -3662,7 +3660,7 @@ static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + dp6m_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; #ifdef INT_COAL @@ -3692,10 +3690,10 @@ static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) if (ha->service != SCREENSERVICE && (ha->fw_vers & 0xff) >= 0x1a) { ha->dvr.severity = gdth_readb - (&((gdt6m_dpram_str *)ha->brd)->i960r.severity); + (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity); for (i = 0; i < 256; ++i) { ha->dvr.event_string[i] = gdth_readb - (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]); + (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]); if (ha->dvr.event_string[i] == 0) break; } diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 78a93cbac..bf269f05e 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -868,7 +868,7 @@ typedef struct { ushort raw_feat; /* feat. raw service (s/g,..)*/ ushort screen_feat; /* feat. raw service (s/g,..)*/ ushort bmic; /* BMIC address (EISA) */ - void *brd; /* DPRAM address */ + void __iomem *brd; /* DPRAM address */ ulong32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ gdth_cmd_str *pccb; /* address command structure */ diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 12c5245c2..e552bac6d 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -75,9 +75,9 @@ void scsi_host_cancel(struct Scsi_Host *shost, int recovery) **/ void scsi_remove_host(struct Scsi_Host *shost) { + scsi_forget_host(shost); scsi_host_cancel(shost, 0); scsi_proc_host_rm(shost); - scsi_forget_host(shost); set_bit(SHOST_DEL, &shost->shost_state); diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile new file mode 100644 index 000000000..4e247b6b8 --- /dev/null +++ b/drivers/scsi/ibmvscsi/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o + +ibmvscsic-y += ibmvscsi.o +ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o +ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c new file mode 100644 index 000000000..210ee7d0d --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -0,0 +1,1393 @@ +/* ------------------------------------------------------------ + * ibmvscsi.c + * (C) Copyright IBM Corporation 1994, 2004 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * 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 + * + * ------------------------------------------------------------ + * Emulation of a SCSI host adapter for Virtual I/O devices + * + * This driver supports the SCSI adapter implemented by the IBM + * Power5 firmware. That SCSI adapter is not a physical adapter, + * but allows Linux SCSI peripheral drivers to directly + * access devices in another logical partition on the physical system. + * + * The virtual adapter(s) are present in the open firmware device + * tree just like real adapters. + * + * One of the capabilities provided on these systems is the ability + * to DMA between partitions. The architecture states that for VSCSI, + * the server side is allowed to DMA to and from the client. The client + * is never trusted to DMA to or from the server directly. + * + * Messages are sent between partitions on a "Command/Response Queue" + * (CRQ), which is just a buffer of 16 byte entries in the receiver's + * Senders cannot access the buffer directly, but send messages by + * making a hypervisor call and passing in the 16 bytes. The hypervisor + * puts the message in the next 16 byte space in round-robbin fashion, + * turns on the high order bit of the message (the valid bit), and + * generates an interrupt to the receiver (if interrupts are turned on.) + * The receiver just turns off the valid bit when they have copied out + * the message. + * + * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit + * (IU) (as defined in the T10 standard available at www.t10.org), gets + * a DMA address for the message, and sends it to the server as the + * payload of a CRQ message. The server DMAs the SRP IU and processes it, + * including doing any additional data transfers. When it is done, it + * DMAs the SRP response back to the same address as the request came from, + * and sends a CRQ message back to inform the client that the request has + * completed. + * + * Note that some of the underlying infrastructure is different between + * machines conforming to the "RS/6000 Platform Architecture" (RPA) and + * the older iSeries hypervisor models. To support both, some low level + * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c. + * The Makefile should pick one, not two, not zero, of these. + * + * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor + * interfaces. It would be really nice to abstract this above an RDMA + * layer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* The values below are somewhat arbitrary default values, but + * OS/400 will use 3 busses (disks, CDs, tapes, I think.) + * Note that there are 3 bits of channel value, 6 bits of id, and + * 5 bits of LUN. + */ +static int max_id = 64; +static int max_channel = 3; +static int init_timeout = 5; +static int max_requests = 50; + +#define IBMVSCSI_VERSION "1.5.1" + +MODULE_DESCRIPTION("IBM Virtual SCSI"); +MODULE_AUTHOR("Dave Boutcher"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(IBMVSCSI_VERSION); + +module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_id, "Largest ID value for each channel"); +module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_channel, "Largest channel value"); +module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); +module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter"); + +/* ------------------------------------------------------------ + * Routines for the event pool and event structs + */ +/** + * initialize_event_pool: - Allocates and initializes the event pool for a host + * @pool: event_pool to be initialized + * @size: Number of events in pool + * @hostdata: ibmvscsi_host_data who owns the event pool + * + * Returns zero on success. +*/ +static int initialize_event_pool(struct event_pool *pool, + int size, struct ibmvscsi_host_data *hostdata) +{ + int i; + + pool->size = size; + pool->next = 0; + pool->events = kmalloc(pool->size * sizeof(*pool->events), GFP_KERNEL); + if (!pool->events) + return -ENOMEM; + memset(pool->events, 0x00, pool->size * sizeof(*pool->events)); + + pool->iu_storage = + dma_alloc_coherent(hostdata->dev, + pool->size * sizeof(*pool->iu_storage), + &pool->iu_token, 0); + if (!pool->iu_storage) { + kfree(pool->events); + return -ENOMEM; + } + + for (i = 0; i < pool->size; ++i) { + struct srp_event_struct *evt = &pool->events[i]; + memset(&evt->crq, 0x00, sizeof(evt->crq)); + atomic_set(&evt->free, 1); + evt->crq.valid = 0x80; + evt->crq.IU_length = sizeof(*evt->xfer_iu); + evt->crq.IU_data_ptr = pool->iu_token + + sizeof(*evt->xfer_iu) * i; + evt->xfer_iu = pool->iu_storage + i; + evt->hostdata = hostdata; + } + + return 0; +} + +/** + * release_event_pool: - Frees memory of an event pool of a host + * @pool: event_pool to be released + * @hostdata: ibmvscsi_host_data who owns the even pool + * + * Returns zero on success. +*/ +static void release_event_pool(struct event_pool *pool, + struct ibmvscsi_host_data *hostdata) +{ + int i, in_use = 0; + for (i = 0; i < pool->size; ++i) + if (atomic_read(&pool->events[i].free) != 1) + ++in_use; + if (in_use) + printk(KERN_WARNING + "ibmvscsi: releasing event pool with %d " + "events still in use?\n", in_use); + kfree(pool->events); + dma_free_coherent(hostdata->dev, + pool->size * sizeof(*pool->iu_storage), + pool->iu_storage, pool->iu_token); +} + +/** + * valid_event_struct: - Determines if event is valid. + * @pool: event_pool that contains the event + * @evt: srp_event_struct to be checked for validity + * + * Returns zero if event is invalid, one otherwise. +*/ +static int valid_event_struct(struct event_pool *pool, + struct srp_event_struct *evt) +{ + int index = evt - pool->events; + if (index < 0 || index >= pool->size) /* outside of bounds */ + return 0; + if (evt != pool->events + index) /* unaligned */ + return 0; + return 1; +} + +/** + * ibmvscsi_free-event_struct: - Changes status of event to "free" + * @pool: event_pool that contains the event + * @evt: srp_event_struct to be modified + * +*/ +static void free_event_struct(struct event_pool *pool, + struct srp_event_struct *evt) +{ + if (!valid_event_struct(pool, evt)) { + printk(KERN_ERR + "ibmvscsi: Freeing invalid event_struct %p " + "(not in pool %p)\n", evt, pool->events); + return; + } + if (atomic_inc_return(&evt->free) != 1) { + printk(KERN_ERR + "ibmvscsi: Freeing event_struct %p " + "which is not in use!\n", evt); + return; + } +} + +/** + * get_evt_struct: - Gets the next free event in pool + * @pool: event_pool that contains the events to be searched + * + * Returns the next event in "free" state, and NULL if none are free. + * Note that no synchronization is done here, we assume the host_lock + * will syncrhonze things. +*/ +static struct srp_event_struct *get_event_struct(struct event_pool *pool) +{ + int i; + int poolsize = pool->size; + int offset = pool->next; + + for (i = 0; i < poolsize; i++) { + offset = (offset + 1) % poolsize; + if (!atomic_dec_if_positive(&pool->events[offset].free)) { + pool->next = offset; + return &pool->events[offset]; + } + } + + printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n"); + return NULL; +} + +/** + * init_event_struct: Initialize fields in an event struct that are always + * required. + * @evt: The event + * @done: Routine to call when the event is responded to + * @format: SRP or MAD format + * @timeout: timeout value set in the CRQ + */ +static void init_event_struct(struct srp_event_struct *evt_struct, + void (*done) (struct srp_event_struct *), + u8 format, + int timeout) +{ + evt_struct->cmnd = NULL; + evt_struct->cmnd_done = NULL; + evt_struct->crq.format = format; + evt_struct->crq.timeout = timeout; + evt_struct->done = done; +} + +/* ------------------------------------------------------------ + * Routines for receiving SCSI responses from the hosting partition + */ + +/** + * set_srp_direction: Set the fields in the srp related to data + * direction and number of buffers based on the direction in + * the scsi_cmnd and the number of buffers + */ +static void set_srp_direction(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, + int numbuf) +{ + if (numbuf == 0) + return; + + if (numbuf == 1) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) + srp_cmd->data_out_format = SRP_DIRECT_BUFFER; + else + srp_cmd->data_in_format = SRP_DIRECT_BUFFER; + } else { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + srp_cmd->data_out_format = SRP_INDIRECT_BUFFER; + srp_cmd->data_out_count = numbuf; + } else { + srp_cmd->data_in_format = SRP_INDIRECT_BUFFER; + srp_cmd->data_in_count = numbuf; + } + } +} + +/** + * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format + * @cmd: srp_cmd whose additional_data member will be unmapped + * @dev: device for which the memory is mapped + * +*/ +static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) +{ + int i; + + if ((cmd->data_out_format == SRP_NO_BUFFER) && + (cmd->data_in_format == SRP_NO_BUFFER)) + return; + else if ((cmd->data_out_format == SRP_DIRECT_BUFFER) || + (cmd->data_in_format == SRP_DIRECT_BUFFER)) { + struct memory_descriptor *data = + (struct memory_descriptor *)cmd->additional_data; + dma_unmap_single(dev, data->virtual_address, data->length, + DMA_BIDIRECTIONAL); + } else { + struct indirect_descriptor *indirect = + (struct indirect_descriptor *)cmd->additional_data; + int num_mapped = indirect->head.length / + sizeof(indirect->list[0]); + for (i = 0; i < num_mapped; ++i) { + struct memory_descriptor *data = &indirect->list[i]; + dma_unmap_single(dev, + data->virtual_address, + data->length, DMA_BIDIRECTIONAL); + } + } +} + +/** + * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields + * @cmd: Scsi_Cmnd with the scatterlist + * @srp_cmd: srp_cmd that contains the memory descriptor + * @dev: device for which to map dma memory + * + * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd. + * Returns 1 on success. +*/ +static int map_sg_data(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, struct device *dev) +{ + + int i, sg_mapped; + u64 total_length = 0; + struct scatterlist *sg = cmd->request_buffer; + struct memory_descriptor *data = + (struct memory_descriptor *)srp_cmd->additional_data; + struct indirect_descriptor *indirect = + (struct indirect_descriptor *)data; + + sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL); + + if (sg_mapped == 0) + return 0; + + set_srp_direction(cmd, srp_cmd, sg_mapped); + + /* special case; we can use a single direct descriptor */ + if (sg_mapped == 1) { + data->virtual_address = sg_dma_address(&sg[0]); + data->length = sg_dma_len(&sg[0]); + data->memory_handle = 0; + return 1; + } + + if (sg_mapped > MAX_INDIRECT_BUFS) { + printk(KERN_ERR + "ibmvscsi: More than %d mapped sg entries, got %d\n", + MAX_INDIRECT_BUFS, sg_mapped); + return 0; + } + + indirect->head.virtual_address = 0; + indirect->head.length = sg_mapped * sizeof(indirect->list[0]); + indirect->head.memory_handle = 0; + for (i = 0; i < sg_mapped; ++i) { + struct memory_descriptor *descr = &indirect->list[i]; + struct scatterlist *sg_entry = &sg[i]; + descr->virtual_address = sg_dma_address(sg_entry); + descr->length = sg_dma_len(sg_entry); + descr->memory_handle = 0; + total_length += sg_dma_len(sg_entry); + } + indirect->total_length = total_length; + + return 1; +} + +/** + * map_single_data: - Maps memory and initializes memory decriptor fields + * @cmd: struct scsi_cmnd with the memory to be mapped + * @srp_cmd: srp_cmd that contains the memory descriptor + * @dev: device for which to map dma memory + * + * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd. + * Returns 1 on success. +*/ +static int map_single_data(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, struct device *dev) +{ + struct memory_descriptor *data = + (struct memory_descriptor *)srp_cmd->additional_data; + + data->virtual_address = + dma_map_single(dev, cmd->request_buffer, + cmd->request_bufflen, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(data->virtual_address)) { + printk(KERN_ERR + "ibmvscsi: Unable to map request_buffer for command!\n"); + return 0; + } + data->length = cmd->request_bufflen; + data->memory_handle = 0; + + set_srp_direction(cmd, srp_cmd, 1); + + return 1; +} + +/** + * map_data_for_srp_cmd: - Calls functions to map data for srp cmds + * @cmd: struct scsi_cmnd with the memory to be mapped + * @srp_cmd: srp_cmd that contains the memory descriptor + * @dev: dma device for which to map dma memory + * + * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds + * Returns 1 on success. +*/ +static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, + struct srp_cmd *srp_cmd, struct device *dev) +{ + switch (cmd->sc_data_direction) { + case DMA_FROM_DEVICE: + case DMA_TO_DEVICE: + break; + case DMA_NONE: + return 1; + case DMA_BIDIRECTIONAL: + printk(KERN_ERR + "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n"); + return 0; + default: + printk(KERN_ERR + "ibmvscsi: Unknown data direction 0x%02x; can't map!\n", + cmd->sc_data_direction); + return 0; + } + + if (!cmd->request_buffer) + return 1; + if (cmd->use_sg) + return map_sg_data(cmd, srp_cmd, dev); + return map_single_data(cmd, srp_cmd, dev); +} + +/* ------------------------------------------------------------ + * Routines for sending and receiving SRPs + */ +/** + * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq() + * @evt_struct: evt_struct to be sent + * @hostdata: ibmvscsi_host_data of host + * + * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) + * Note that this routine assumes that host_lock is held for synchronization +*/ +static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, + struct ibmvscsi_host_data *hostdata) +{ + struct scsi_cmnd *cmnd = evt_struct->cmnd; + u64 *crq_as_u64 = (u64 *) &evt_struct->crq; + int rc; + + /* If we have exhausted our request limit, just fail this request. + * Note that there are rare cases involving driver generated requests + * (such as task management requests) that the mid layer may think we + * can handle more requests (can_queue) when we actually can't + */ + if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && + (atomic_dec_if_positive(&hostdata->request_limit) < 0)) { + /* See if the adapter is disabled */ + if (atomic_read(&hostdata->request_limit) < 0) { + if (cmnd) + cmnd->result = DID_ERROR << 16; + if (evt_struct->cmnd_done) + evt_struct->cmnd_done(cmnd); + unmap_cmd_data(&evt_struct->iu.srp.cmd, + hostdata->dev); + free_event_struct(&hostdata->pool, evt_struct); + return 0; + } else { + printk("ibmvscsi: Warning, request_limit exceeded\n"); + unmap_cmd_data(&evt_struct->iu.srp.cmd, + hostdata->dev); + free_event_struct(&hostdata->pool, evt_struct); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + + /* Copy the IU into the transfer area */ + *evt_struct->xfer_iu = evt_struct->iu; + evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct; + + /* Add this to the sent list. We need to do this + * before we actually send + * in case it comes back REALLY fast + */ + list_add_tail(&evt_struct->list, &hostdata->sent); + + if ((rc = + ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { + list_del(&evt_struct->list); + + cmnd = evt_struct->cmnd; + printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n", + rc); + unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev); + free_event_struct(&hostdata->pool, evt_struct); + if (cmnd) + cmnd->result = DID_ERROR << 16; + if (evt_struct->cmnd_done) + evt_struct->cmnd_done(cmnd); + } + + return 0; +} + +/** + * handle_cmd_rsp: - Handle responses from commands + * @evt_struct: srp_event_struct to be handled + * + * Used as a callback by when sending scsi cmds. + * Gets called by ibmvscsi_handle_crq() +*/ +static void handle_cmd_rsp(struct srp_event_struct *evt_struct) +{ + struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp; + struct scsi_cmnd *cmnd = evt_struct->cmnd; + + if (cmnd) { + cmnd->result = rsp->status; + if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION) + memcpy(cmnd->sense_buffer, + rsp->sense_and_response_data, + rsp->sense_data_list_length); + unmap_cmd_data(&evt_struct->iu.srp.cmd, + evt_struct->hostdata->dev); + + if (rsp->doover) + cmnd->resid = rsp->data_out_residual_count; + else if (rsp->diover) + cmnd->resid = rsp->data_in_residual_count; + } + + if (evt_struct->cmnd_done) + evt_struct->cmnd_done(cmnd); +} + +/** + * lun_from_dev: - Returns the lun of the scsi device + * @dev: struct scsi_device + * +*/ +static inline u16 lun_from_dev(struct scsi_device *dev) +{ + return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun; +} + +/** + * ibmvscsi_queue: - The queuecommand function of the scsi template + * @cmd: struct scsi_cmnd to be executed + * @done: Callback function to be called when cmd is completed +*/ +static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, + void (*done) (struct scsi_cmnd *)) +{ + struct srp_cmd *srp_cmd; + struct srp_event_struct *evt_struct; + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; + u16 lun = lun_from_dev(cmnd->device); + + evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) + return SCSI_MLQUEUE_HOST_BUSY; + + init_event_struct(evt_struct, + handle_cmd_rsp, + VIOSRP_SRP_FORMAT, + cmnd->timeout); + + evt_struct->cmnd = cmnd; + evt_struct->cmnd_done = done; + + /* Set up the actual SRP IU */ + srp_cmd = &evt_struct->iu.srp.cmd; + memset(srp_cmd, 0x00, sizeof(*srp_cmd)); + srp_cmd->type = SRP_CMD_TYPE; + memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); + srp_cmd->lun = ((u64) lun) << 48; + + if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) { + printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n"); + free_event_struct(&hostdata->pool, evt_struct); + return SCSI_MLQUEUE_HOST_BUSY; + } + + /* Fix up dma address of the buffer itself */ + if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || + (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) { + struct indirect_descriptor *indirect = + (struct indirect_descriptor *)srp_cmd->additional_data; + indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + + offsetof(struct srp_cmd, additional_data) + + offsetof(struct indirect_descriptor, list); + } + + return ibmvscsi_send_srp_event(evt_struct, hostdata); +} + +/* ------------------------------------------------------------ + * Routines for driver initialization + */ +/** + * adapter_info_rsp: - Handle response to MAD adapter info request + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending adapter_info. Gets called + * by ibmvscsi_handle_crq() +*/ +static void adapter_info_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + dma_unmap_single(hostdata->dev, + evt_struct->iu.mad.adapter_info.buffer, + evt_struct->iu.mad.adapter_info.common.length, + DMA_BIDIRECTIONAL); + + if (evt_struct->xfer_iu->mad.adapter_info.common.status) { + printk("ibmvscsi: error %d getting adapter info\n", + evt_struct->xfer_iu->mad.adapter_info.common.status); + } else { + printk("ibmvscsi: host srp version: %s, " + "host partition %s (%d), OS %d\n", + hostdata->madapter_info.srp_version, + hostdata->madapter_info.partition_name, + hostdata->madapter_info.partition_number, + hostdata->madapter_info.os_type); + } +} + +/** + * send_mad_adapter_info: - Sends the mad adapter info request + * and stores the result so it can be retrieved with + * sysfs. We COULD consider causing a failure if the + * returned SRP version doesn't match ours. + * @hostdata: ibmvscsi_host_data of host + * + * Returns zero if successful. +*/ +static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) +{ + struct viosrp_adapter_info *req; + struct srp_event_struct *evt_struct; + + memset(&hostdata->madapter_info, 0x00, sizeof(hostdata->madapter_info)); + + evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) { + printk(KERN_ERR "ibmvscsi: couldn't allocate an event " + "for ADAPTER_INFO_REQ!\n"); + return; + } + + init_event_struct(evt_struct, + adapter_info_rsp, + VIOSRP_MAD_FORMAT, + init_timeout * HZ); + + req = &evt_struct->iu.mad.adapter_info; + memset(req, 0x00, sizeof(*req)); + + req->common.type = VIOSRP_ADAPTER_INFO_TYPE; + req->common.length = sizeof(hostdata->madapter_info); + req->buffer = dma_map_single(hostdata->dev, + &hostdata->madapter_info, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(req->buffer)) { + printk(KERN_ERR + "ibmvscsi: Unable to map request_buffer " + "for adapter_info!\n"); + free_event_struct(&hostdata->pool, evt_struct); + return; + } + + if (ibmvscsi_send_srp_event(evt_struct, hostdata)) + printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n"); +}; + +/** + * login_rsp: - Handle response to SRP login request + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending srp_login. Gets called + * by ibmvscsi_handle_crq() +*/ +static void login_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + switch (evt_struct->xfer_iu->srp.generic.type) { + case SRP_LOGIN_RSP_TYPE: /* it worked! */ + break; + case SRP_LOGIN_REJ_TYPE: /* refused! */ + printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n"); + /* Login failed. */ + atomic_set(&hostdata->request_limit, -1); + return; + default: + printk(KERN_ERR + "ibmvscsi: Invalid login response typecode 0x%02x!\n", + evt_struct->xfer_iu->srp.generic.type); + /* Login failed. */ + atomic_set(&hostdata->request_limit, -1); + return; + } + + printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n"); + + if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta > + (max_requests - 2)) + evt_struct->xfer_iu->srp.login_rsp.request_limit_delta = + max_requests - 2; + + /* Now we know what the real request-limit is */ + atomic_set(&hostdata->request_limit, + evt_struct->xfer_iu->srp.login_rsp.request_limit_delta); + + hostdata->host->can_queue = + evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2; + + if (hostdata->host->can_queue < 1) { + printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); + return; + } + + send_mad_adapter_info(hostdata); + return; +} + +/** + * send_srp_login: - Sends the srp login + * @hostdata: ibmvscsi_host_data of host + * + * Returns zero if successful. +*/ +static int send_srp_login(struct ibmvscsi_host_data *hostdata) +{ + int rc; + unsigned long flags; + struct srp_login_req *login; + struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) { + printk(KERN_ERR + "ibmvscsi: couldn't allocate an event for login req!\n"); + return FAILED; + } + + init_event_struct(evt_struct, + login_rsp, + VIOSRP_SRP_FORMAT, + init_timeout * HZ); + + login = &evt_struct->iu.srp.login_req; + login->type = SRP_LOGIN_REQ_TYPE; + login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); + login->required_buffer_formats = 0x0006; + + /* Start out with a request limit of 1, since this is negotiated in + * the login request we are just sending + */ + atomic_set(&hostdata->request_limit, 1); + + spin_lock_irqsave(hostdata->host->host_lock, flags); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return rc; +}; + +/** + * sync_completion: Signal that a synchronous command has completed + * Note that after returning from this call, the evt_struct is freed. + * the caller waiting on this completion shouldn't touch the evt_struct + * again. + */ +static void sync_completion(struct srp_event_struct *evt_struct) +{ + complete(&evt_struct->comp); +} + +/** + * ibmvscsi_abort: Abort a command...from scsi host template + * send this over to the server and wait synchronously for the response + */ +static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) +{ + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)cmd->device->host->hostdata; + struct srp_tsk_mgmt *tsk_mgmt; + struct srp_event_struct *evt; + struct srp_event_struct *tmp_evt, *found_evt; + u16 lun = lun_from_dev(cmd->device); + + /* First, find this command in our sent list so we can figure + * out the correct tag + */ + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } + } + + if (!found_evt) + return FAILED; + + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n"); + return FAILED; + } + + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout * HZ); + + tsk_mgmt = &evt->iu.srp.tsk_mgmt; + + /* Set up an abort SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->type = SRP_TSK_MGMT_TYPE; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->task_mgmt_flags = 0x01; /* ABORT TASK */ + tsk_mgmt->managed_task_tag = (u64) found_evt; + + printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n", + tsk_mgmt->lun, tsk_mgmt->managed_task_tag); + + init_completion(&evt->comp); + if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: failed to send abort() event\n"); + return FAILED; + } + + spin_unlock_irq(hostdata->host->host_lock); + wait_for_completion(&evt->comp); + spin_lock_irq(hostdata->host->host_lock); + + /* Because we dropped the spinlock above, it's possible + * The event is no longer in our list. Make sure it didn't + * complete while we were aborting + */ + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } + } + + printk(KERN_INFO + "ibmvscsi: successfully aborted task tag 0x%lx\n", + tsk_mgmt->managed_task_tag); + + if (found_evt == NULL) + return SUCCESS; + + cmd->result = (DID_ABORT << 16); + list_del(&found_evt->list); + unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); + free_event_struct(&found_evt->hostdata->pool, found_evt); + atomic_inc(&hostdata->request_limit); + return SUCCESS; +} + +/** + * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host + * template send this over to the server and wait synchronously for the + * response + */ +static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) +{ + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)cmd->device->host->hostdata; + + struct srp_tsk_mgmt *tsk_mgmt; + struct srp_event_struct *evt; + struct srp_event_struct *tmp_evt, *pos; + u16 lun = lun_from_dev(cmd->device); + + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n"); + return FAILED; + } + + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout * HZ); + + tsk_mgmt = &evt->iu.srp.tsk_mgmt; + + /* Set up a lun reset SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->type = SRP_TSK_MGMT_TYPE; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->task_mgmt_flags = 0x08; /* LUN RESET */ + + printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n", + tsk_mgmt->lun); + + init_completion(&evt->comp); + if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: failed to send reset event\n"); + return FAILED; + } + + spin_unlock_irq(hostdata->host->host_lock); + wait_for_completion(&evt->comp); + spin_lock_irq(hostdata->host->host_lock); + + /* We need to find all commands for this LUN that have not yet been + * responded to, and fail them with DID_RESET + */ + list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { + if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) { + if (tmp_evt->cmnd) + tmp_evt->cmnd->result = (DID_RESET << 16); + list_del(&tmp_evt->list); + unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev); + free_event_struct(&tmp_evt->hostdata->pool, + tmp_evt); + atomic_inc(&hostdata->request_limit); + if (tmp_evt->cmnd_done) + tmp_evt->cmnd_done(tmp_evt->cmnd); + else if (tmp_evt->done) + tmp_evt->done(tmp_evt); + } + } + return SUCCESS; +} + +/** + * purge_requests: Our virtual adapter just shut down. purge any sent requests + * @hostdata: the adapter + */ +static void purge_requests(struct ibmvscsi_host_data *hostdata) +{ + struct srp_event_struct *tmp_evt, *pos; + unsigned long flags; + + spin_lock_irqsave(hostdata->host->host_lock, flags); + list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { + list_del(&tmp_evt->list); + if (tmp_evt->cmnd) { + tmp_evt->cmnd->result = (DID_ERROR << 16); + unmap_cmd_data(&tmp_evt->iu.srp.cmd, + tmp_evt->hostdata->dev); + if (tmp_evt->cmnd_done) + tmp_evt->cmnd_done(tmp_evt->cmnd); + } else { + if (tmp_evt->done) { + tmp_evt->done(tmp_evt); + } + } + free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); + } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); +} + +/** + * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ + * @crq: Command/Response queue + * @hostdata: ibmvscsi_host_data of host + * +*/ +void ibmvscsi_handle_crq(struct viosrp_crq *crq, + struct ibmvscsi_host_data *hostdata) +{ + unsigned long flags; + struct srp_event_struct *evt_struct = + (struct srp_event_struct *)crq->IU_data_ptr; + switch (crq->valid) { + case 0xC0: /* initialization */ + switch (crq->format) { + case 0x01: /* Initialization message */ + printk(KERN_INFO "ibmvscsi: partner initialized\n"); + /* Send back a response */ + if (ibmvscsi_send_crq(hostdata, + 0xC002000000000000LL, 0) == 0) { + /* Now login */ + send_srp_login(hostdata); + } else { + printk(KERN_ERR + "ibmvscsi: Unable to send init rsp\n"); + } + + break; + case 0x02: /* Initialization response */ + printk(KERN_INFO + "ibmvscsi: partner initialization complete\n"); + + /* Now login */ + send_srp_login(hostdata); + break; + default: + printk(KERN_ERR "ibmvscsi: unknown crq message type\n"); + } + return; + case 0xFF: /* Hypervisor telling us the connection is closed */ + printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n"); + + atomic_set(&hostdata->request_limit, -1); + purge_requests(hostdata); + ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + return; + case 0x80: /* real payload */ + break; + default: + printk(KERN_ERR + "ibmvscsi: got an invalid message type 0x%02x\n", + crq->valid); + return; + } + + /* The only kind of payload CRQs we should get are responses to + * things we send. Make sure this response is to something we + * actually sent + */ + if (!valid_event_struct(&hostdata->pool, evt_struct)) { + printk(KERN_ERR + "ibmvscsi: returned correlation_token 0x%p is invalid!\n", + (void *)crq->IU_data_ptr); + return; + } + + if (crq->format == VIOSRP_SRP_FORMAT) + atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta, + &hostdata->request_limit); + + if (evt_struct->done) + evt_struct->done(evt_struct); + else + printk(KERN_ERR + "ibmvscsi: returned done() is NULL; not running it!\n"); + + /* + * Lock the host_lock before messing with these structures, since we + * are running in a task context + */ + spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags); + list_del(&evt_struct->list); + free_event_struct(&evt_struct->hostdata->pool, evt_struct); + spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags); +} + +/** + * ibmvscsi_get_host_config: Send the command to the server to get host + * configuration data. The data is opaque to us. + */ +static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, + unsigned char *buffer, int length) +{ + struct viosrp_host_config *host_config; + struct srp_event_struct *evt_struct; + int rc; + + evt_struct = get_event_struct(&hostdata->pool); + if (!evt_struct) { + printk(KERN_ERR + "ibmvscsi: could't allocate event for HOST_CONFIG!\n"); + return -1; + } + + init_event_struct(evt_struct, + sync_completion, + VIOSRP_MAD_FORMAT, + init_timeout * HZ); + + host_config = &evt_struct->iu.mad.host_config; + + /* Set up a lun reset SRP command */ + memset(host_config, 0x00, sizeof(*host_config)); + host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; + host_config->common.length = length; + host_config->buffer = dma_map_single(hostdata->dev, buffer, length, + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(host_config->buffer)) { + printk(KERN_ERR + "ibmvscsi: dma_mapping error " "getting host config\n"); + free_event_struct(&hostdata->pool, evt_struct); + return -1; + } + + init_completion(&evt_struct->comp); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata); + if (rc == 0) { + wait_for_completion(&evt_struct->comp); + dma_unmap_single(hostdata->dev, host_config->buffer, + length, DMA_BIDIRECTIONAL); + } + + return rc; +} + +/* ------------------------------------------------------------ + * sysfs attributes + */ +static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%s\n", + hostdata->madapter_info.srp_version); + return len; +} + +static struct class_device_attribute ibmvscsi_host_srp_version = { + .attr = { + .name = "srp_version", + .mode = S_IRUGO, + }, + .show = show_host_srp_version, +}; + +static ssize_t show_host_partition_name(struct class_device *class_dev, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%s\n", + hostdata->madapter_info.partition_name); + return len; +} + +static struct class_device_attribute ibmvscsi_host_partition_name = { + .attr = { + .name = "partition_name", + .mode = S_IRUGO, + }, + .show = show_host_partition_name, +}; + +static ssize_t show_host_partition_number(struct class_device *class_dev, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%d\n", + hostdata->madapter_info.partition_number); + return len; +} + +static struct class_device_attribute ibmvscsi_host_partition_number = { + .attr = { + .name = "partition_number", + .mode = S_IRUGO, + }, + .show = show_host_partition_number, +}; + +static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%d\n", + hostdata->madapter_info.mad_version); + return len; +} + +static struct class_device_attribute ibmvscsi_host_mad_version = { + .attr = { + .name = "mad_version", + .mode = S_IRUGO, + }, + .show = show_host_mad_version, +}; + +static ssize_t show_host_os_type(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + int len; + + len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type); + return len; +} + +static struct class_device_attribute ibmvscsi_host_os_type = { + .attr = { + .name = "os_type", + .mode = S_IRUGO, + }, + .show = show_host_os_type, +}; + +static ssize_t show_host_config(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)shost->hostdata; + + /* returns null-terminated host config data */ + if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0) + return strlen(buf); + else + return 0; +} + +static struct class_device_attribute ibmvscsi_host_config = { + .attr = { + .name = "config", + .mode = S_IRUGO, + }, + .show = show_host_config, +}; + +static struct class_device_attribute *ibmvscsi_attrs[] = { + &ibmvscsi_host_srp_version, + &ibmvscsi_host_partition_name, + &ibmvscsi_host_partition_number, + &ibmvscsi_host_mad_version, + &ibmvscsi_host_os_type, + &ibmvscsi_host_config, + NULL +}; + +/* ------------------------------------------------------------ + * SCSI driver registration + */ +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION, + .proc_name = "ibmvscsi", + .queuecommand = ibmvscsi_queuecommand, + .eh_abort_handler = ibmvscsi_eh_abort_handler, + .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, + .cmd_per_lun = 16, + .can_queue = 1, /* Updated after SRP_LOGIN */ + .this_id = -1, + .sg_tablesize = MAX_INDIRECT_BUFS, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = ibmvscsi_attrs, +}; + +/** + * Called by bus code for each adapter + */ +static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + struct ibmvscsi_host_data *hostdata; + struct Scsi_Host *host; + struct device *dev = &vdev->dev; + unsigned long wait_switch = 0; + + vdev->dev.driver_data = NULL; + + host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); + if (!host) { + printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n"); + goto scsi_host_alloc_failed; + } + + hostdata = (struct ibmvscsi_host_data *)host->hostdata; + memset(hostdata, 0x00, sizeof(*hostdata)); + INIT_LIST_HEAD(&hostdata->sent); + hostdata->host = host; + hostdata->dev = dev; + atomic_set(&hostdata->request_limit, -1); + + if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, + max_requests) != 0) { + printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n"); + goto init_crq_failed; + } + if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n"); + goto init_pool_failed; + } + + host->max_lun = 8; + host->max_id = max_id; + host->max_channel = max_channel; + + if (scsi_add_host(hostdata->host, hostdata->dev)) + goto add_host_failed; + + /* Try to send an initialization message. Note that this is allowed + * to fail if the other end is not acive. In that case we don't + * want to scan + */ + if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) { + /* + * Wait around max init_timeout secs for the adapter to finish + * initializing. When we are done initializing, we will have a + * valid request_limit. We don't want Linux scanning before + * we are ready. + */ + for (wait_switch = jiffies + (init_timeout * HZ); + time_before(jiffies, wait_switch) && + atomic_read(&hostdata->request_limit) < 0;) { + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100); + } + + /* if we now have a valid request_limit, initiate a scan */ + if (atomic_read(&hostdata->request_limit) > 0) + scsi_scan_host(host); + } + + vdev->dev.driver_data = hostdata; + return 0; + + add_host_failed: + release_event_pool(&hostdata->pool, hostdata); + init_pool_failed: + ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests); + init_crq_failed: + scsi_host_put(host); + scsi_host_alloc_failed: + return -1; +} + +static int ibmvscsi_remove(struct vio_dev *vdev) +{ + struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; + release_event_pool(&hostdata->pool, hostdata); + ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, + max_requests); + + scsi_remove_host(hostdata->host); + scsi_host_put(hostdata->host); + + return 0; +} + +/** + * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we + * support. + */ +static struct vio_device_id ibmvscsi_device_table[] __devinitdata = { + {"vscsi", "IBM,v-scsi"}, + {0,} +}; + +MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table); +static struct vio_driver ibmvscsi_driver = { + .name = "ibmvscsi", + .id_table = ibmvscsi_device_table, + .probe = ibmvscsi_probe, + .remove = ibmvscsi_remove +}; + +int __init ibmvscsi_module_init(void) +{ + return vio_register_driver(&ibmvscsi_driver); +} + +void __exit ibmvscsi_module_exit(void) +{ + vio_unregister_driver(&ibmvscsi_driver); +} + +module_init(ibmvscsi_module_init); +module_exit(ibmvscsi_module_exit); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h new file mode 100644 index 000000000..dbe1735e5 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -0,0 +1,108 @@ +/* ------------------------------------------------------------ + * ibmvscsi.h + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * 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 + * + * ------------------------------------------------------------ + * Emulation of a SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ +#ifndef IBMVSCSI_H +#define IBMVSCSI_H +#include +#include +#include +#include +#include "viosrp.h" + +struct scsi_cmnd; +struct Scsi_Host; + +/* Number of indirect bufs...the list of these has to fit in the + * additional data of the srp_cmd struct along with the indirect + * descriptor + */ +#define MAX_INDIRECT_BUFS 10 + +/* ------------------------------------------------------------ + * Data Structures + */ +/* an RPA command/response transport queue */ +struct crq_queue { + struct viosrp_crq *msgs; + int size, cur; + dma_addr_t msg_token; + spinlock_t lock; +}; + +/* a unit of work for the hosting partition */ +struct srp_event_struct { + union viosrp_iu *xfer_iu; + struct scsi_cmnd *cmnd; + struct list_head list; + void (*done) (struct srp_event_struct *); + struct viosrp_crq crq; + struct ibmvscsi_host_data *hostdata; + atomic_t free; + union viosrp_iu iu; + void (*cmnd_done) (struct scsi_cmnd *); + struct completion comp; +}; + +/* a pool of event structs for use */ +struct event_pool { + struct srp_event_struct *events; + u32 size; + int next; + union viosrp_iu *iu_storage; + dma_addr_t iu_token; +}; + +/* all driver data associated with a host adapter */ +struct ibmvscsi_host_data { + atomic_t request_limit; + struct device *dev; + struct event_pool pool; + struct crq_queue queue; + struct tasklet_struct srp_task; + struct list_head sent; + struct Scsi_Host *host; + struct mad_adapter_info_data madapter_info; +}; + +/* routines for managing a command/response queue */ +int ibmvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests); +void ibmvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests); +void ibmvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata); + +void ibmvscsi_handle_crq(struct viosrp_crq *crq, + struct ibmvscsi_host_data *hostdata); +int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, + u64 word1, u64 word2); + +#endif /* IBMVSCSI_H */ diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c new file mode 100644 index 000000000..e9202f2a8 --- /dev/null +++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c @@ -0,0 +1,144 @@ +/* ------------------------------------------------------------ + * iSeries_vscsi.c + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * 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 + * + * ------------------------------------------------------------ + * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ + +#include +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* global variables */ +static struct ibmvscsi_host_data *single_host_data; + +/* ------------------------------------------------------------ + * Routines for direct interpartition interaction + */ +struct srp_lp_event { + struct HvLpEvent lpevt; /* 0x00-0x17 */ + u32 reserved1; /* 0x18-0x1B; unused */ + u16 version; /* 0x1C-0x1D; unused */ + u16 subtype_rc; /* 0x1E-0x1F; unused */ + struct viosrp_crq crq; /* 0x20-0x3F */ +}; + +/** + * standard interface for handling logical partition events. + */ +static void ibmvscsi_handle_event(struct HvLpEvent *lpevt) +{ + struct srp_lp_event *evt = (struct srp_lp_event *)lpevt; + + if (!evt) { + printk(KERN_ERR "ibmvscsi: received null event\n"); + return; + } + + if (single_host_data == NULL) { + printk(KERN_ERR + "ibmvscsi: received event, no adapter present\n"); + return; + } + + ibmvscsi_handle_crq(&evt->crq, single_host_data); +} + +/* ------------------------------------------------------------ + * Routines for driver initialization + */ +int ibmvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + int rc; + + single_host_data = hostdata; + rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0); + if (rc < 0) { + printk("viopath_open failed with rc %d in open_event_path\n", + rc); + goto viopath_open_failed; + } + + rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event); + if (rc < 0) { + printk("vio_setHandler failed with rc %d in open_event_path\n", + rc); + goto vio_setHandler_failed; + } + return 0; + + vio_setHandler_failed: + viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); + viopath_open_failed: + return -1; +} + +void ibmvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + vio_clearHandler(viomajorsubtype_scsi); + viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); +} + +/** + * reset_crq_queue: - resets a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + * no-op for iSeries + */ +void ibmvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ +} + +/** + * ibmvscsi_send_crq: - Send a CRQ + * @hostdata: the adapter + * @word1: the first 64 bits of the data + * @word2: the second 64 bits of the data + */ +int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) +{ + single_host_data = hostdata; + return HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_scsi, + HvLpEvent_AckInd_NoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, + VIOVERSION << 16, word1, word2, 0, + 0); +} diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c new file mode 100644 index 000000000..b4e82654e --- /dev/null +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -0,0 +1,260 @@ +/* ------------------------------------------------------------ + * rpa_vscsi.c + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * + * 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 + * + * ------------------------------------------------------------ + * RPA-specific functions of the SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ + +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* ------------------------------------------------------------ + * Routines for managing the command/response queue + */ +/** + * ibmvscsi_handle_event: - Interrupt handler for crq events + * @irq: number of irq to handle, not used + * @dev_instance: ibmvscsi_host_data of host that received interrupt + * @regs: pt_regs with registers + * + * Disables interrupts and schedules srp_task + * Always returns IRQ_HANDLED + */ +static irqreturn_t ibmvscsi_handle_event(int irq, + void *dev_instance, + struct pt_regs *regs) +{ + struct ibmvscsi_host_data *hostdata = + (struct ibmvscsi_host_data *)dev_instance; + vio_disable_interrupts(to_vio_dev(hostdata->dev)); + tasklet_schedule(&hostdata->srp_task); + return IRQ_HANDLED; +} + +/** + * release_crq_queue: - Deallocates data and unregisters CRQ + * @queue: crq_queue to initialize and register + * @host_data: ibmvscsi_host_data of host + * + * Frees irq, deallocates a page for messages, unmaps dma, and unregisters + * the crq with the hypervisor. + */ +void ibmvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + long rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + free_irq(vdev->irq, (void *)hostdata); + tasklet_kill(&hostdata->srp_task); + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + dma_unmap_single(hostdata->dev, + queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); + free_page((unsigned long)queue->msgs); +} + +/** + * crq_queue_next_crq: - Returns the next entry in message queue + * @queue: crq_queue to use + * + * Returns pointer to next entry in queue, or NULL if there are no new + * entried in the CRQ. + */ +static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue) +{ + struct viosrp_crq *crq; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + crq = &queue->msgs[queue->cur]; + if (crq->valid & 0x80) { + if (++queue->cur == queue->size) + queue->cur = 0; + } else + crq = NULL; + spin_unlock_irqrestore(&queue->lock, flags); + + return crq; +} + +/** + * ibmvscsi_send_crq: - Send a CRQ + * @hostdata: the adapter + * @word1: the first 64 bits of the data + * @word2: the second 64 bits of the data + */ +int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) +{ + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); +} + +/** + * ibmvscsi_task: - Process srps asynchronously + * @data: ibmvscsi_host_data of host + */ +static void ibmvscsi_task(void *data) +{ + struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + struct viosrp_crq *crq; + int done = 0; + + while (!done) { + /* Pull all the valid messages off the CRQ */ + while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { + ibmvscsi_handle_crq(crq, hostdata); + crq->valid = 0x00; + } + + vio_enable_interrupts(vdev); + if ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { + vio_disable_interrupts(vdev); + ibmvscsi_handle_crq(crq, hostdata); + crq->valid = 0x00; + } else { + done = 1; + } + } +} + +/** + * initialize_crq_queue: - Initializes and registers CRQ with hypervisor + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + * Allocates a page for messages, maps it for dma, and registers + * the crq with the hypervisor. + * Returns zero on success. + */ +int ibmvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + int rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); + + if (!queue->msgs) + goto malloc_failed; + queue->size = PAGE_SIZE / sizeof(*queue->msgs); + + queue->msg_token = dma_map_single(hostdata->dev, queue->msgs, + queue->size * sizeof(*queue->msgs), + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(queue->msg_token)) + goto map_failed; + + rc = plpar_hcall_norets(H_REG_CRQ, + vdev->unit_address, + queue->msg_token, PAGE_SIZE); + if (rc == 2) { + /* Adapter is good, but other end is not ready */ + printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n"); + } else if (rc != 0) { + printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc); + goto reg_crq_failed; + } + + if (request_irq(vdev->irq, + ibmvscsi_handle_event, + 0, "ibmvscsi", (void *)hostdata) != 0) { + printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n", + vdev->irq); + goto req_irq_failed; + } + + rc = vio_enable_interrupts(vdev); + if (rc != 0) { + printk(KERN_ERR "ibmvscsi: Error %d enabling interrupts!!!\n", + rc); + goto req_irq_failed; + } + + queue->cur = 0; + queue->lock = SPIN_LOCK_UNLOCKED; + + tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, + (unsigned long)hostdata); + + return 0; + + req_irq_failed: + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + reg_crq_failed: + dma_unmap_single(hostdata->dev, + queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); + map_failed: + free_page((unsigned long)queue->msgs); + malloc_failed: + return -1; +} + +/** + * reset_crq_queue: - resets a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + */ +void ibmvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ + int rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + /* Close the CRQ */ + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + + /* Clean out the queue */ + memset(queue->msgs, 0x00, PAGE_SIZE); + queue->cur = 0; + + /* And re-open it again */ + rc = plpar_hcall_norets(H_REG_CRQ, + vdev->unit_address, + queue->msg_token, PAGE_SIZE); + if (rc == 2) { + /* Adapter is good, but other end is not ready */ + printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n"); + } else if (rc != 0) { + printk(KERN_WARNING + "ibmvscsi: couldn't register crq--rc 0x%x\n", rc); + } +} diff --git a/drivers/scsi/ibmvscsi/srp.h b/drivers/scsi/ibmvscsi/srp.h new file mode 100644 index 000000000..e952c1cd9 --- /dev/null +++ b/drivers/scsi/ibmvscsi/srp.h @@ -0,0 +1,225 @@ +/*****************************************************************************/ +/* srp.h -- SCSI RDMA Protocol definitions */ +/* */ +/* Written By: Colin Devilbis, IBM Corporation */ +/* */ +/* Copyright (C) 2003 IBM Corporation */ +/* */ +/* 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 */ +/* */ +/* */ +/* This file contains structures and definitions for the SCSI RDMA Protocol */ +/* (SRP) as defined in the T10 standard available at www.t10.org. This */ +/* file was based on the 16a version of the standard */ +/* */ +/*****************************************************************************/ +#ifndef SRP_H +#define SRP_H + +#define PACKED __attribute__((packed)) + +enum srp_types { + SRP_LOGIN_REQ_TYPE = 0x00, + SRP_LOGIN_RSP_TYPE = 0xC0, + SRP_LOGIN_REJ_TYPE = 0x80, + SRP_I_LOGOUT_TYPE = 0x03, + SRP_T_LOGOUT_TYPE = 0x80, + SRP_TSK_MGMT_TYPE = 0x01, + SRP_CMD_TYPE = 0x02, + SRP_RSP_TYPE = 0xC1, + SRP_CRED_REQ_TYPE = 0x81, + SRP_CRED_RSP_TYPE = 0x41, + SRP_AER_REQ_TYPE = 0x82, + SRP_AER_RSP_TYPE = 0x42 +}; + +enum srp_descriptor_formats { + SRP_NO_BUFFER = 0x00, + SRP_DIRECT_BUFFER = 0x01, + SRP_INDIRECT_BUFFER = 0x02 +}; + +struct memory_descriptor { + u64 virtual_address; + u32 memory_handle; + u32 length; +}; + +struct indirect_descriptor { + struct memory_descriptor head; + u32 total_length; + struct memory_descriptor list[1] PACKED; +}; + +struct srp_generic { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +struct srp_login_req { + u8 type; + u8 reserved1[7]; + u64 tag; + u32 max_requested_initiator_to_target_iulen; + u32 reserved2; + u16 required_buffer_formats; + u8 reserved3:6; + u8 multi_channel_action:2; + u8 reserved4; + u32 reserved5; + u8 initiator_port_identifier[16]; + u8 target_port_identifier[16]; +}; + +struct srp_login_rsp { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; + u32 max_initiator_to_target_iulen; + u32 max_target_to_initiator_iulen; + u16 supported_buffer_formats; + u8 reserved2:6; + u8 multi_channel_result:2; + u8 reserved3; + u8 reserved4[24]; +}; + +struct srp_login_rej { + u8 type; + u8 reserved1[3]; + u32 reason; + u64 tag; + u64 reserved2; + u16 supported_buffer_formats; + u8 reserved3[6]; +}; + +struct srp_i_logout { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +struct srp_t_logout { + u8 type; + u8 reserved1[3]; + u32 reason; + u64 tag; +}; + +struct srp_tsk_mgmt { + u8 type; + u8 reserved1[7]; + u64 tag; + u32 reserved2; + u64 lun PACKED; + u8 reserved3; + u8 reserved4; + u8 task_mgmt_flags; + u8 reserved5; + u64 managed_task_tag; + u64 reserved6; +}; + +struct srp_cmd { + u8 type; + u32 reserved1 PACKED; + u8 data_out_format:4; + u8 data_in_format:4; + u8 data_out_count; + u8 data_in_count; + u64 tag; + u32 reserved2; + u64 lun PACKED; + u8 reserved3; + u8 reserved4:5; + u8 task_attribute:3; + u8 reserved5; + u8 additional_cdb_len; + u8 cdb[16]; + u8 additional_data[0x100 - 0x30]; +}; + +struct srp_rsp { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; + u16 reserved2; + u8 reserved3:2; + u8 diunder:1; + u8 diover:1; + u8 dounder:1; + u8 doover:1; + u8 snsvalid:1; + u8 rspvalid:1; + u8 status; + u32 data_in_residual_count; + u32 data_out_residual_count; + u32 sense_data_list_length; + u32 response_data_list_length; + u8 sense_and_response_data[18]; +}; + +struct srp_cred_req { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; +}; + +struct srp_cred_rsp { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +struct srp_aer_req { + u8 type; + u8 reserved1[3]; + u32 request_limit_delta; + u64 tag; + u32 reserved2; + u64 lun; + u32 sense_data_list_length; + u32 reserved3; + u8 sense_data[20]; +}; + +struct srp_aer_rsp { + u8 type; + u8 reserved1[7]; + u64 tag; +}; + +union srp_iu { + struct srp_generic generic; + struct srp_login_req login_req; + struct srp_login_rsp login_rsp; + struct srp_login_rej login_rej; + struct srp_i_logout i_logout; + struct srp_t_logout t_logout; + struct srp_tsk_mgmt tsk_mgmt; + struct srp_cmd cmd; + struct srp_rsp rsp; + struct srp_cred_req cred_req; + struct srp_cred_rsp cred_rsp; + struct srp_aer_req aer_req; + struct srp_aer_rsp aer_rsp; +}; + +#endif diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h new file mode 100644 index 000000000..6a6bba8a2 --- /dev/null +++ b/drivers/scsi/ibmvscsi/viosrp.h @@ -0,0 +1,126 @@ +/*****************************************************************************/ +/* srp.h -- SCSI RDMA Protocol definitions */ +/* */ +/* Written By: Colin Devilbis, IBM Corporation */ +/* */ +/* Copyright (C) 2003 IBM Corporation */ +/* */ +/* 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 */ +/* */ +/* */ +/* This file contains structures and definitions for IBM RPA (RS/6000 */ +/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */ +/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */ +/* commands between logical partitions. */ +/* */ +/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */ +/* between partitions. The definitions in this file are architected, */ +/* and cannot be changed without breaking compatibility with other versions */ +/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/ +/* between logical partitions */ +/*****************************************************************************/ +#ifndef VIOSRP_H +#define VIOSRP_H +#include "srp.h" + +enum viosrp_crq_formats { + VIOSRP_SRP_FORMAT = 0x01, + VIOSRP_MAD_FORMAT = 0x02, + VIOSRP_OS400_FORMAT = 0x03, + VIOSRP_AIX_FORMAT = 0x04, + VIOSRP_LINUX_FORMAT = 0x06, + VIOSRP_INLINE_FORMAT = 0x07 +}; + +struct viosrp_crq { + u8 valid; /* used by RPA */ + u8 format; /* SCSI vs out-of-band */ + u8 reserved; + u8 status; /* non-scsi failure? (e.g. DMA failure) */ + u16 timeout; /* in seconds */ + u16 IU_length; /* in bytes */ + u64 IU_data_ptr; /* the TCE for transferring data */ +}; + +/* MADs are Management requests above and beyond the IUs defined in the SRP + * standard. + */ +enum viosrp_mad_types { + VIOSRP_EMPTY_IU_TYPE = 0x01, + VIOSRP_ERROR_LOG_TYPE = 0x02, + VIOSRP_ADAPTER_INFO_TYPE = 0x03, + VIOSRP_HOST_CONFIG_TYPE = 0x04 +}; + +/* + * Common MAD header + */ +struct mad_common { + u32 type; + u16 status; + u16 length; + u64 tag; +}; + +/* + * All SRP (and MAD) requests normally flow from the + * client to the server. There is no way for the server to send + * an asynchronous message back to the client. The Empty IU is used + * to hang out a meaningless request to the server so that it can respond + * asynchrouously with something like a SCSI AER + */ +struct viosrp_empty_iu { + struct mad_common common; + u64 buffer; + u32 port; +}; + +struct viosrp_error_log { + struct mad_common common; + u64 buffer; +}; + +struct viosrp_adapter_info { + struct mad_common common; + u64 buffer; +}; + +struct viosrp_host_config { + struct mad_common common; + u64 buffer; +}; + +union mad_iu { + struct viosrp_empty_iu empty_iu; + struct viosrp_error_log error_log; + struct viosrp_adapter_info adapter_info; + struct viosrp_host_config host_config; +}; + +union viosrp_iu { + union srp_iu srp; + union mad_iu mad; +}; + +struct mad_adapter_info_data { + char srp_version[8]; + char partition_name[96]; + u32 partition_number; + u32 mad_version; + u32 os_type; + u32 port_max_txu[8]; /* per-port maximum transfer */ +}; + +#endif diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 915d593fb..eda703d73 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -758,7 +758,7 @@ static void imm_interrupt(void *data) case DID_OK: break; case DID_NO_CONNECT: - printk("imm: no device at SCSI ID %i\n", cmd->target); + printk("imm: no device at SCSI ID %i\n", cmd->device->id); break; case DID_BUS_BUSY: printk("imm: BUS BUSY - EPP timeout detected\n"); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index bf3942769..40bfff7f2 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1,7 +1,7 @@ /* * ipr.c -- driver for IBM Power Linux RAID adapters * - * Written By: Brian King, IBM Corporation + * Written By: Brian King , IBM Corporation * * Copyright (C) 2003, 2004 IBM Corporation * @@ -93,7 +93,7 @@ static spinlock_t ipr_driver_lock = SPIN_LOCK_UNLOCKED; /* This table describes the differences between DMA controller chips */ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { - { /* Gemstone */ + { /* Gemstone and Citrine */ .mailbox = 0x0042C, .cache_line_size = 0x20, { @@ -208,6 +208,8 @@ struct ipr_error_table_t ipr_error_table[] = { "Synchronization required"}, {0x024E0000, 0, 0, "No ready, IOA shutdown"}, + {0x025A0000, 0, 0, + "Not ready, IOA has been shutdown"}, {0x02670100, 0, 1, "3020: Storage subsystem configuration error"}, {0x03110B00, 0, 0, @@ -880,11 +882,13 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) **/ static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num) { - char buffer[max_t(int, sizeof(struct ipr_std_inq_vpids), - IPR_SERIAL_NUM_LEN) + 1]; + char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + + IPR_SERIAL_NUM_LEN]; - memcpy(buffer, vpids, sizeof(struct ipr_std_inq_vpids)); - buffer[sizeof(struct ipr_std_inq_vpids)] = '\0'; + memcpy(buffer, vpids->vendor_id, IPR_VENDOR_ID_LEN); + memcpy(buffer + IPR_VENDOR_ID_LEN, vpids->product_id, + IPR_PROD_ID_LEN); + buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0'; ipr_err("Vendor/Product ID: %s\n", buffer); memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN); @@ -1765,6 +1769,33 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) #define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0) #endif +/** + * ipr_release_dump - Free adapter dump memory + * @kref: kref struct + * + * Return value: + * nothing + **/ +static void ipr_release_dump(struct kref *kref) +{ + struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref); + struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; + unsigned long lock_flags = 0; + int i; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ioa_cfg->dump = NULL; + ioa_cfg->sdt_state = INACTIVE; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + for (i = 0; i < dump->ioa_dump.next_page_index; i++) + free_page((unsigned long) dump->ioa_dump.ioa_data[i]); + + kfree(dump); + LEAVE; +} + /** * ipr_worker_thread - Worker thread * @data: ioa config struct @@ -1791,13 +1822,14 @@ static void ipr_worker_thread(void *data) if (ioa_cfg->sdt_state == GET_DUMP) { dump = ioa_cfg->dump; - if (!dump || !kobject_get(&dump->kobj)) { + if (!dump) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return; } + kref_get(&dump->kref); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); ipr_get_ioa_dump(ioa_cfg, dump); - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); if (ioa_cfg->sdt_state == DUMP_OBTAINED) @@ -2008,7 +2040,7 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev, wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); /* Wait for a second for any errors to be logged */ - schedule_timeout(HZ); + msleep(1000); } else { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return -EIO; @@ -2392,15 +2424,15 @@ static ssize_t ipr_read_dump(struct kobject *kobj, char *buf, spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); dump = ioa_cfg->dump; - if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump || !kobject_get(&dump->kobj)) { + if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return 0; } - + kref_get(&dump->kref); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); if (off > dump->driver_dump.hdr.len) { - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); return 0; } @@ -2450,41 +2482,10 @@ static ssize_t ipr_read_dump(struct kobject *kobj, char *buf, count -= len; } - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); return rc; } -/** - * ipr_release_dump - Free adapter dump memory - * @kobj: kobject struct - * - * Return value: - * nothing - **/ -static void ipr_release_dump(struct kobject *kobj) -{ - struct ipr_dump *dump = container_of(kobj,struct ipr_dump,kobj); - struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; - unsigned long lock_flags = 0; - int i; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ioa_cfg->dump = NULL; - ioa_cfg->sdt_state = INACTIVE; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - for (i = 0; i < dump->ioa_dump.next_page_index; i++) - free_page((unsigned long) dump->ioa_dump.ioa_data[i]); - - kfree(dump); - LEAVE; -} - -static struct kobj_type ipr_dump_kobj_type = { - .release = ipr_release_dump, -}; - /** * ipr_alloc_dump - Prepare for adapter dump * @ioa_cfg: ioa config struct @@ -2506,8 +2507,7 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) } memset(dump, 0, sizeof(struct ipr_dump)); - kobject_init(&dump->kobj); - dump->kobj.ktype = &ipr_dump_kobj_type; + kref_init(&dump->kref); dump->ioa_cfg = ioa_cfg; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -2554,7 +2554,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) ioa_cfg->dump = NULL; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - kobject_put(&dump->kobj); + kref_put(&dump->kref, ipr_release_dump); LEAVE; return 0; @@ -2690,8 +2690,6 @@ static ssize_t ipr_store_tcq_enable(struct device *dev, struct ipr_resource_entry *res; unsigned long lock_flags = 0; int tcq_active = simple_strtoul(buf, NULL, 10); - int qdepth = IPR_MAX_CMD_PER_LUN; - int tagged = 0; ssize_t len = -ENXIO; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -2699,13 +2697,13 @@ static ssize_t ipr_store_tcq_enable(struct device *dev, res = (struct ipr_resource_entry *)sdev->hostdata; if (res) { - res->tcq_active = 0; - qdepth = res->qdepth; - if (ipr_is_gscsi(res) && sdev->tagged_supported) { if (tcq_active) { - tagged = MSG_ORDERED_TAG; res->tcq_active = 1; + scsi_activate_tcq(sdev, res->qdepth); + } else { + res->tcq_active = 0; + scsi_deactivate_tcq(sdev, res->qdepth); } len = strlen(buf); @@ -2715,7 +2713,6 @@ static ssize_t ipr_store_tcq_enable(struct device *dev, } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_adjust_queue_depth(sdev, tagged, qdepth); return len; } @@ -2785,7 +2782,8 @@ static int ipr_biosparam(struct scsi_device *sdev, struct block_device *block_device, sector_t capacity, int *parm) { - int heads, sectors, cylinders; + int heads, sectors; + sector_t cylinders; heads = 128; sectors = 32; @@ -2849,8 +2847,8 @@ static int ipr_slave_configure(struct scsi_device *sdev) sdev->scsi_level = 4; if (ipr_is_vset_device(res)) sdev->timeout = IPR_VSET_RW_TIMEOUT; - - sdev->allow_restart = 1; + if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) + sdev->allow_restart = 1; scsi_adjust_queue_depth(sdev, 0, res->qdepth); } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); @@ -3080,7 +3078,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; struct ipr_cmd_pkt *cmd_pkt; - u32 ioasc, ioarcb_addr; + u32 ioasc; int op_found = 0; ENTER; @@ -3101,21 +3099,15 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) if (!op_found) return SUCCESS; - ioarcb_addr = be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr); - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_ABORT_TASK; - cmd_pkt->cdb[2] = (ioarcb_addr >> 24) & 0xff; - cmd_pkt->cdb[3] = (ioarcb_addr >> 16) & 0xff; - cmd_pkt->cdb[4] = (ioarcb_addr >> 8) & 0xff; - cmd_pkt->cdb[5] = ioarcb_addr & 0xff; + cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; ipr_cmd->u.sdev = scsi_cmd->device; ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]); - ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_ABORT_TASK_TIMEOUT); + ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); /* @@ -3737,7 +3729,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, switch (ioasc & IPR_IOASC_IOASC_MASK) { case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: - scsi_cmd->result |= (DID_ERROR << 16); + scsi_cmd->result |= (DID_IMM_RETRY << 16); break; case IPR_IOASC_IR_RESOURCE_HANDLE: scsi_cmd->result |= (DID_NO_CONNECT << 16); @@ -3873,7 +3865,7 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, * We have told the host to stop giving us new requests, but * ERP ops don't count. FIXME */ - if (unlikely(!ioa_cfg->allow_cmds)) + if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead)) return SCSI_MLQUEUE_HOST_BUSY; /* @@ -5437,13 +5429,15 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) **/ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg) { + struct pci_dev *pdev = ioa_cfg->pdev; + ENTER; - free_irq(ioa_cfg->pdev->irq, ioa_cfg); + free_irq(pdev->irq, ioa_cfg); iounmap((void *) ioa_cfg->hdw_dma_regs); - release_mem_region(ioa_cfg->hdw_dma_regs_pci, - pci_resource_len(ioa_cfg->pdev, 0)); + pci_release_regions(pdev); ipr_free_mem(ioa_cfg); scsi_host_put(ioa_cfg->host); + pci_disable_device(pdev); LEAVE; } @@ -5458,7 +5452,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) { struct ipr_cmnd *ipr_cmd; struct ipr_ioarcb *ioarcb; - u32 dma_addr; + dma_addr_t dma_addr; int i; ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev, @@ -5508,14 +5502,15 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) **/ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) { - int i; + struct pci_dev *pdev = ioa_cfg->pdev; + int i, rc = -ENOMEM; ENTER; ioa_cfg->res_entries = kmalloc(sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL); if (!ioa_cfg->res_entries) - goto cleanup; + goto out; memset(ioa_cfg->res_entries, 0, sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS); @@ -5528,24 +5523,24 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) &ioa_cfg->vpd_cbs_dma); if (!ioa_cfg->vpd_cbs) - goto cleanup; + goto out_free_res_entries; if (ipr_alloc_cmd_blks(ioa_cfg)) - goto cleanup; + goto out_free_vpd_cbs; ioa_cfg->host_rrq = pci_alloc_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, &ioa_cfg->host_rrq_dma); if (!ioa_cfg->host_rrq) - goto cleanup; + goto out_ipr_free_cmd_blocks; ioa_cfg->cfg_table = pci_alloc_consistent(ioa_cfg->pdev, sizeof(struct ipr_config_table), &ioa_cfg->cfg_table_dma); if (!ioa_cfg->cfg_table) - goto cleanup; + goto out_free_host_rrq; for (i = 0; i < IPR_NUM_HCAMS; i++) { ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev, @@ -5553,9 +5548,8 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) &ioa_cfg->hostrcb_dma[i]); if (!ioa_cfg->hostrcb[i]) - goto cleanup; + goto out_free_hostrcb_dma; - memset(ioa_cfg->hostrcb[i], 0, sizeof(struct ipr_hostrcb)); ioa_cfg->hostrcb[i]->hostrcb_dma = ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); @@ -5565,19 +5559,35 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) IPR_NUM_TRACE_ENTRIES, GFP_KERNEL); if (!ioa_cfg->trace) - goto cleanup; + goto out_free_hostrcb_dma; memset(ioa_cfg->trace, 0, sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES); + rc = 0; +out: LEAVE; - return 0; - -cleanup: - ipr_free_mem(ioa_cfg); + return rc; - LEAVE; - return -ENOMEM; +out_free_hostrcb_dma: + while (i-- > 0) { + pci_free_consistent(pdev, sizeof(struct ipr_hostrcb), + ioa_cfg->hostrcb[i], + ioa_cfg->hostrcb_dma[i]); + } + pci_free_consistent(pdev, sizeof(struct ipr_config_table), + ioa_cfg->cfg_table, ioa_cfg->cfg_table_dma); +out_free_host_rrq: + pci_free_consistent(pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, + ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); +out_ipr_free_cmd_blocks: + ipr_free_cmd_blks(ioa_cfg); +out_free_vpd_cbs: + pci_free_consistent(pdev, sizeof(struct ipr_misc_cbs), + ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); +out_free_res_entries: + kfree(ioa_cfg->res_entries); + goto out; } /** @@ -5678,7 +5688,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, if ((rc = pci_enable_device(pdev))) { dev_err(&pdev->dev, "Cannot enable adapter\n"); - return rc; + goto out; } dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); @@ -5687,7 +5697,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, if (!host) { dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_disable; } ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; @@ -5697,12 +5708,11 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ipr_regs_pci = pci_resource_start(pdev, 0); - if (!request_mem_region(ipr_regs_pci, - pci_resource_len(pdev, 0), IPR_NAME)) { + rc = pci_request_regions(pdev, IPR_NAME); + if (rc < 0) { dev_err(&pdev->dev, "Couldn't register memory range of registers\n"); - scsi_host_put(host); - return -ENOMEM; + goto out_scsi_host_put; } ipr_regs = (unsigned long)ioremap(ipr_regs_pci, @@ -5711,9 +5721,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, if (!ipr_regs) { dev_err(&pdev->dev, "Couldn't map memory range of registers\n"); - release_mem_region(ipr_regs_pci, pci_resource_len(pdev, 0)); - scsi_host_put(host); - return -ENOMEM; + rc = -ENOMEM; + goto out_release_regions; } ioa_cfg->hdw_dma_regs = ipr_regs; @@ -5723,11 +5732,10 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ipr_init_ioa_cfg(ioa_cfg, host, pdev); pci_set_master(pdev); - rc = pci_set_dma_mask(pdev, 0xffffffff); - if (rc != PCIBIOS_SUCCESSFUL) { + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc < 0) { dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); - rc = -EIO; goto cleanup_nomem; } @@ -5755,8 +5763,12 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg))) goto cleanup_nomem; - if ((rc = ipr_alloc_mem(ioa_cfg))) - goto cleanup; + rc = ipr_alloc_mem(ioa_cfg); + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't allocate enough memory for device driver!\n"); + goto cleanup_nomem; + } ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg); @@ -5772,18 +5784,20 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, spin_unlock(&ipr_driver_lock); LEAVE; - return 0; +out: + return rc; -cleanup: - dev_err(&pdev->dev, "Couldn't allocate enough memory for device driver!\n"); cleanup_nolog: ipr_free_mem(ioa_cfg); cleanup_nomem: iounmap((void *) ipr_regs); - release_mem_region(ipr_regs_pci, pci_resource_len(pdev, 0)); +out_release_regions: + pci_release_regions(pdev); +out_scsi_host_put: scsi_host_put(host); - - return rc; +out_disable: + pci_disable_device(pdev); + goto out; } /** @@ -5988,9 +6002,15 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_570F, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); @@ -6009,16 +6029,14 @@ static struct pci_driver ipr_driver = { * ipr_init - Module entry point * * Return value: - * 0 on success / non-zero on failure + * 0 on success / negative value on failure **/ static int __init ipr_init(void) { ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", IPR_DRIVER_VERSION, IPR_DRIVER_DATE); - pci_register_driver(&ipr_driver); - - return 0; + return pci_module_init(&ipr_driver); } /** diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 6d616ac42..e91afc446 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1,7 +1,7 @@ /* * ipr.h -- driver for IBM Power Linux RAID adapters * - * Written By: Brian King, IBM Corporation + * Written By: Brian King , IBM Corporation * * Copyright (C) 2003, 2004 IBM Corporation * @@ -19,6 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * Alan Cox - Removed several careless u32/dma_addr_t errors + * that broke 64bit platforms. */ #ifndef _IPR_H @@ -27,6 +29,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_KDB @@ -36,8 +39,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.0.10" -#define IPR_DRIVER_DATE "(June 7, 2004)" +#define IPR_DRIVER_VERSION "2.0.11" +#define IPR_DRIVER_DATE "(August 3, 2004)" /* * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing @@ -72,6 +75,8 @@ #define IPR_SUBS_DEV_ID_5703 0x0278 #define IPR_SUBS_DEV_ID_572E 0x02D3 #define IPR_SUBS_DEV_ID_573D 0x02D4 +#define IPR_SUBS_DEV_ID_570F 0x02BD +#define IPR_SUBS_DEV_ID_571B 0x02BE #define IPR_NAME "ipr" @@ -148,7 +153,6 @@ #define IPR_BUS_RESET 0x10 #define IPR_ID_HOST_RR_Q 0xC4 #define IPR_QUERY_IOA_CONFIG 0xC5 -#define IPR_ABORT_TASK 0xC7 #define IPR_CANCEL_ALL_REQUESTS 0xCE #define IPR_HOST_CONTROLLED_ASYNC 0xCF #define IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE 0x01 @@ -667,7 +671,7 @@ struct ipr_hcam { struct ipr_hostrcb { struct ipr_hcam hcam; - u32 hostrcb_dma; + dma_addr_t hostrcb_dma; struct list_head queue; }; @@ -850,7 +854,7 @@ struct ipr_ioa_cfg { char cfg_table_start[8]; #define IPR_CFG_TBL_START "cfg" struct ipr_config_table *cfg_table; - u32 cfg_table_dma; + dma_addr_t cfg_table_dma; char resource_table_label[8]; #define IPR_RES_TABLE_LABEL "res_tbl" @@ -861,12 +865,12 @@ struct ipr_ioa_cfg { char ipr_hcam_label[8]; #define IPR_HCAM_LABEL "hcams" struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS]; - u32 hostrcb_dma[IPR_NUM_HCAMS]; + dma_addr_t hostrcb_dma[IPR_NUM_HCAMS]; struct list_head hostrcb_free_q; struct list_head hostrcb_pending_q; u32 *host_rrq; - u32 host_rrq_dma; + dma_addr_t host_rrq_dma; #define IPR_HRRQ_REQ_RESP_HANDLE_MASK 0xfffffffc #define IPR_HRRQ_RESP_BIT_SET 0x00000002 #define IPR_HRRQ_TOGGLE_BIT 0x00000001 @@ -905,7 +909,7 @@ struct ipr_ioa_cfg { enum ipr_sdt_state sdt_state; struct ipr_misc_cbs *vpd_cbs; - u32 vpd_cbs_dma; + dma_addr_t vpd_cbs_dma; struct pci_pool *ipr_cmd_pool; @@ -1029,7 +1033,7 @@ struct ipr_ioa_dump { }__attribute__((packed, aligned (4))); struct ipr_dump { - struct kobject kobj; + struct kref kref; struct ipr_ioa_cfg *ioa_cfg; struct ipr_driver_dump driver_dump; struct ipr_ioa_dump ioa_dump; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index dc110cc80..b2e7c233c 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -215,7 +215,7 @@ MODULE_PARM(ips, "s"); #endif #else #define IPS_SG_ADDRESS(sg) (page_address((sg)->page) ? \ - page_address((sg)->page)+(sg)->offset : 0) + page_address((sg)->page)+(sg)->offset : NULL) #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0) #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0) #endif @@ -474,21 +474,17 @@ static uint32_t ips_statupd_copperhead(ips_ha_t *); static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); static uint32_t ips_statupd_morpheus(ips_ha_t *); static ips_scb_t *ips_getscb(ips_ha_t *); -static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_copp_head(ips_copp_queue_t *, +static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); +static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); +static void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline void ips_putq_copp_tail(ips_copp_queue_t *, - ips_copp_wait_item_t *); -static inline ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); -static inline ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); -static inline Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); -static inline Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); -static inline ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, +static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); +static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); +static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); +static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); +static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); +static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); static int ips_is_passthru(Scsi_Cmnd *); static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); @@ -1885,7 +1881,7 @@ ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) /* Fill in a single scb sg_list element from an address */ /* return a -1 if a breakup occurred */ /****************************************************************************/ -static inline int +static int ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, ips_scb_t * scb, int indx, unsigned int e_len) { @@ -2950,7 +2946,7 @@ ips_next(ips_ha_t * ha, int intr) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) { METHOD_TRACE("ips_putq_scb_head", 1); @@ -2967,38 +2963,6 @@ ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) queue->count++; } -/****************************************************************************/ -/* */ -/* Routine Name: ips_putq_scb_tail */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the tail of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item) -{ - METHOD_TRACE("ips_putq_scb_tail", 1); - - if (!item) - return; - - item->q_next = NULL; - - if (queue->tail) - queue->tail->q_next = item; - - queue->tail = item; - - if (!queue->head) - queue->head = item; - - queue->count++; -} - /****************************************************************************/ /* */ /* Routine Name: ips_removeq_scb_head */ @@ -3010,7 +2974,7 @@ ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t * queue) { ips_scb_t *item; @@ -3045,7 +3009,7 @@ ips_removeq_scb_head(ips_scb_queue_t * queue) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) { ips_scb_t *p; @@ -3080,34 +3044,6 @@ ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) return (NULL); } -/****************************************************************************/ -/* */ -/* Routine Name: ips_putq_wait_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item) -{ - METHOD_TRACE("ips_putq_wait_head", 1); - - if (!item) - return; - - item->host_scribble = (char *) queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - /****************************************************************************/ /* */ /* Routine Name: ips_putq_wait_tail */ @@ -3119,7 +3055,7 @@ ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) { METHOD_TRACE("ips_putq_wait_tail", 1); @@ -3151,7 +3087,7 @@ ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait_head(ips_wait_queue_t * queue) { Scsi_Cmnd *item; @@ -3186,7 +3122,7 @@ ips_removeq_wait_head(ips_wait_queue_t * queue) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) { Scsi_Cmnd *p; @@ -3221,34 +3157,6 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) return (NULL); } -/****************************************************************************/ -/* */ -/* Routine Name: ips_putq_copp_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) -{ - METHOD_TRACE("ips_putq_copp_head", 1); - - if (!item) - return; - - item->next = queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - /****************************************************************************/ /* */ /* Routine Name: ips_putq_copp_tail */ @@ -3260,7 +3168,7 @@ ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { METHOD_TRACE("ips_putq_copp_tail", 1); @@ -3292,7 +3200,7 @@ ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t * queue) { ips_copp_wait_item_t *item; @@ -3327,7 +3235,7 @@ ips_removeq_copp_head(ips_copp_queue_t * queue) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { ips_copp_wait_item_t *p; @@ -6946,8 +6854,8 @@ ips_abort_init(ips_ha_t * ha, int index) { ha->active = 0; ips_free(ha); - ips_ha[index] = 0; - ips_sh[index] = 0; + ips_ha[index] = NULL; + ips_sh[index] = NULL; return -1; } diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 7f2d11d87..8325e0912 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -43,18 +43,21 @@ #include #include #include +#include #include "libata.h" static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); -static void __ata_dev_select (struct ata_port *ap, unsigned int device); -static void ata_host_set_pio(struct ata_port *ap); -static void ata_host_set_udma(struct ata_port *ap); -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device); static void ata_set_mode(struct ata_port *ap); +static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static int fgb(u32 bitmap); +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out); +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -64,17 +67,17 @@ MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); /** - * ata_tf_load_pio - send taskfile registers to host controller + * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * - * Outputs ATA taskfile to standard ATA host controller using PIO. + * Outputs ATA taskfile to standard ATA host controller. * * LOCKING: * Inherited from caller. */ -void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -132,23 +135,23 @@ void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) * Inherited from caller. */ -void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, ap->ioaddr.ctl_addr); + writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void *) ioaddr->feature_addr); - writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr); - writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr); - writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr); - writeb(tf->hob_lbah, (void *) ioaddr->lbah_addr); + writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr); + writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr); + writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr); + writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr); + writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr); VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", tf->hob_feature, tf->hob_nsect, @@ -158,11 +161,11 @@ void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } if (is_addr) { - writeb(tf->feature, (void *) ioaddr->feature_addr); - writeb(tf->nsect, (void *) ioaddr->nsect_addr); - writeb(tf->lbal, (void *) ioaddr->lbal_addr); - writeb(tf->lbam, (void *) ioaddr->lbam_addr); - writeb(tf->lbah, (void *) ioaddr->lbah_addr); + writeb(tf->feature, (void __iomem *) ioaddr->feature_addr); + writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr); + writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr); + writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr); + writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr); VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", tf->feature, tf->nsect, @@ -172,26 +175,34 @@ void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } if (tf->flags & ATA_TFLAG_DEVICE) { - writeb(tf->device, (void *) ioaddr->device_addr); + writeb(tf->device, (void __iomem *) ioaddr->device_addr); VPRINTK("device 0x%X\n", tf->device); } ata_wait_idle(ap); } +void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_tf_load_mmio(ap, tf); + else + ata_tf_load_pio(ap, tf); +} + /** - * ata_exec_command_pio - issue ATA command to host controller + * ata_exec_command - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues PIO write to ATA command register, with proper + * Issues PIO/MMIO write to ATA command register, with proper * synchronization with interrupt handler / other threads. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -212,20 +223,28 @@ void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void *) ap->ioaddr.command_addr); + writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr); ata_pause(ap); } +void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_exec_command_mmio(ap, tf); + else + ata_exec_command_pio(ap, tf); +} + /** * ata_exec - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues PIO write to ATA command register, with proper + * Issues PIO/MMIO write to ATA command register, with proper * synchronization with interrupt handler / other threads. * * LOCKING: @@ -248,7 +267,7 @@ static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) * @tf: ATA taskfile register set * * Issues ATA taskfile register set to ATA host controller, - * via PIO, with proper synchronization with interrupt handler and + * with proper synchronization with interrupt handler and * other threads. * * LOCKING: @@ -268,7 +287,7 @@ static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) * @tf: ATA taskfile register set * * Issues ATA taskfile register set to ATA host controller, - * via PIO, with proper synchronization with interrupt handler and + * with proper synchronization with interrupt handler and * other threads. * * LOCKING: @@ -282,18 +301,18 @@ void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf) } /** - * ata_tf_read_pio - input device's ATA taskfile shadow registers + * ata_tf_read - input device's ATA taskfile shadow registers * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * * Reads ATA taskfile registers for currently-selected device - * into @tf via PIO. + * into @tf. * * LOCKING: * Inherited from caller. */ -void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -325,38 +344,46 @@ void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) * Inherited from caller. */ -void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->nsect = readb((void *)ioaddr->nsect_addr); - tf->lbal = readb((void *)ioaddr->lbal_addr); - tf->lbam = readb((void *)ioaddr->lbam_addr); - tf->lbah = readb((void *)ioaddr->lbah_addr); - tf->device = readb((void *)ioaddr->device_addr); + tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); + tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); + tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); + tf->lbah = readb((void __iomem *)ioaddr->lbah_addr); + tf->device = readb((void __iomem *)ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - writeb(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr); - tf->hob_feature = readb((void *)ioaddr->error_addr); - tf->hob_nsect = readb((void *)ioaddr->nsect_addr); - tf->hob_lbal = readb((void *)ioaddr->lbal_addr); - tf->hob_lbam = readb((void *)ioaddr->lbam_addr); - tf->hob_lbah = readb((void *)ioaddr->lbah_addr); + writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr); + tf->hob_feature = readb((void __iomem *)ioaddr->error_addr); + tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr); + tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr); + tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr); + tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr); } } +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_tf_read_mmio(ap, tf); + else + ata_tf_read_pio(ap, tf); +} + /** - * ata_check_status_pio - Read device status reg & clear interrupt + * ata_check_status - Read device status reg & clear interrupt * @ap: port where the device is * * Reads ATA taskfile status register for currently-selected device - * via PIO and return it's value. This also clears pending interrupts + * and return it's value. This also clears pending interrupts * from this device * * LOCKING: * Inherited from caller. */ -u8 ata_check_status_pio(struct ata_port *ap) +static u8 ata_check_status_pio(struct ata_port *ap) { return inb(ap->ioaddr.status_addr); } @@ -372,9 +399,16 @@ u8 ata_check_status_pio(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -u8 ata_check_status_mmio(struct ata_port *ap) +static u8 ata_check_status_mmio(struct ata_port *ap) +{ + return readb((void __iomem *) ap->ioaddr.status_addr); +} + +u8 ata_check_status(struct ata_port *ap) { - return readb((void *) ap->ioaddr.status_addr); + if (ap->flags & ATA_FLAG_MMIO) + return ata_check_status_mmio(ap); + return ata_check_status_pio(ap); } /** @@ -524,7 +558,7 @@ static void ata_dev_set_protocol(struct ata_device *dev) dev->write_cmd = (cmd >> 8) & 0xff; } -static const char * udma_str[] = { +static const char * xfer_mode_str[] = { "UDMA/16", "UDMA/25", "UDMA/33", @@ -533,6 +567,14 @@ static const char * udma_str[] = { "UDMA/100", "UDMA/133", "UDMA7", + "MWDMA0", + "MWDMA1", + "MWDMA2", + "PIO0", + "PIO1", + "PIO2", + "PIO3", + "PIO4", }; /** @@ -550,16 +592,24 @@ static const char * udma_str[] = { * @udma_mask, or the constant C string "". */ -static const char *ata_udma_string(unsigned int udma_mask) +static const char *ata_mode_string(unsigned int mask) { int i; - for (i = 7; i >= 0; i--) { - if (udma_mask & (1 << i)) - return udma_str[i]; - } + for (i = 7; i >= 0; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--) + if (mask & (1 << i)) + goto out; return ""; + +out: + return xfer_mode_str[i]; } /** @@ -586,7 +636,7 @@ static unsigned int ata_pio_devchk(struct ata_port *ap, struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); outb(0x55, ioaddr->nsect_addr); outb(0xaa, ioaddr->lbal_addr); @@ -630,19 +680,19 @@ static unsigned int ata_mmio_devchk(struct ata_port *ap, struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); - writeb(0x55, (void *) ioaddr->nsect_addr); - writeb(0xaa, (void *) ioaddr->lbal_addr); + writeb(0x55, (void __iomem *) ioaddr->nsect_addr); + writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); - writeb(0xaa, (void *) ioaddr->nsect_addr); - writeb(0x55, (void *) ioaddr->lbal_addr); + writeb(0xaa, (void __iomem *) ioaddr->nsect_addr); + writeb(0x55, (void __iomem *) ioaddr->lbal_addr); - writeb(0x55, (void *) ioaddr->nsect_addr); - writeb(0xaa, (void *) ioaddr->lbal_addr); + writeb(0x55, (void __iomem *) ioaddr->nsect_addr); + writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); - nsect = readb((void *) ioaddr->nsect_addr); - lbal = readb((void *) ioaddr->lbal_addr); + nsect = readb((void __iomem *) ioaddr->nsect_addr); + lbal = readb((void __iomem *) ioaddr->lbal_addr); if ((nsect == 0x55) && (lbal == 0xaa)) return 1; /* we found a device */ @@ -651,7 +701,7 @@ static unsigned int ata_mmio_devchk(struct ata_port *ap, } /** - * ata_dev_devchk - PATA device presence detection + * ata_devchk - PATA device presence detection * @ap: ATA channel to examine * @device: Device to examine (starting at zero) * @@ -663,7 +713,7 @@ static unsigned int ata_mmio_devchk(struct ata_port *ap, * caller. */ -static unsigned int ata_dev_devchk(struct ata_port *ap, +static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) { if (ap->flags & ATA_FLAG_MMIO) @@ -687,7 +737,7 @@ static unsigned int ata_dev_devchk(struct ata_port *ap, * the event of failure. */ -static unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -735,7 +785,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) unsigned int class; u8 err; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); memset(&tf, 0, sizeof(tf)); @@ -798,8 +848,12 @@ void ata_dev_id_string(struct ata_device *dev, unsigned char *s, } } +void ata_noop_dev_select (struct ata_port *ap, unsigned int device) +{ +} + /** - * __ata_dev_select - Select device 0/1 on ATA bus + * ata_std_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select * @@ -811,7 +865,7 @@ void ata_dev_id_string(struct ata_device *dev, unsigned char *s, * caller. */ -static void __ata_dev_select (struct ata_port *ap, unsigned int device) +void ata_std_dev_select (struct ata_port *ap, unsigned int device) { u8 tmp; @@ -821,7 +875,7 @@ static void __ata_dev_select (struct ata_port *ap, unsigned int device) tmp = ATA_DEVICE_OBS | ATA_DEV1; if (ap->flags & ATA_FLAG_MMIO) { - writeb(tmp, (void *) ap->ioaddr.device_addr); + writeb(tmp, (void __iomem *) ap->ioaddr.device_addr); } else { outb(tmp, ap->ioaddr.device_addr); } @@ -839,7 +893,7 @@ static void __ata_dev_select (struct ata_port *ap, unsigned int device) * make either device 0, or device 1, active on the * ATA channel. * - * This is a high-level version of __ata_dev_select(), + * This is a high-level version of ata_std_dev_select(), * which additionally provides the services of inserting * the proper pauses and status polling, where needed. * @@ -856,7 +910,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, if (wait) ata_wait_idle(ap); - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); if (wait) { if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI) @@ -930,10 +984,14 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; unsigned int i; - u16 tmp, udma_modes; + u16 tmp; + unsigned long xfer_modes; u8 status; - struct ata_taskfile tf; unsigned int using_edd; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; if (!ata_dev_present(dev)) { DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", @@ -953,27 +1011,34 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) ata_dev_select(ap, device, 1, 1); /* select device 0/1 */ -retry: - ata_tf_init(ap, &tf, device); - tf.ctl |= ATA_NIEN; - tf.protocol = ATA_PROT_PIO; + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->pci_dma_dir = PCI_DMA_FROMDEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + +retry: if (dev->class == ATA_DEV_ATA) { - tf.command = ATA_CMD_ID_ATA; + qc->tf.command = ATA_CMD_ID_ATA; DPRINTK("do ATA identify\n"); } else { - tf.command = ATA_CMD_ID_ATAPI; + qc->tf.command = ATA_CMD_ID_ATAPI; DPRINTK("do ATAPI identify\n"); } - ata_tf_to_host(ap, &tf); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) + if (rc) goto err_out; + else + wait_for_completion(&wait); status = ata_chk_status(ap); if (status & ATA_ERR) { @@ -988,44 +1053,21 @@ retry: * ATA software reset (SRST, the default) does not appear * to have this problem. */ - if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) { + if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { u8 err = ata_chk_err(ap); if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; + qc->cursg = 0; + qc->cursg_ofs = 0; + qc->cursect = 0; + qc->nsect = 1; goto retry; } } goto err_out; } - /* make sure we have BSY=0, DRQ=1 */ - if ((status & ATA_DRQ) == 0) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - /* read IDENTIFY [X] DEVICE page */ - if (ap->flags & ATA_FLAG_MMIO) { - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = readw((void *)ap->ioaddr.data_addr); - } else - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = inw(ap->ioaddr.data_addr); - - /* wait for host_idle */ - status = ata_wait_idle(ap); - if (status & (ATA_BUSY | ATA_DRQ)) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - ata_irq_on(ap); /* re-enable interrupts */ + swap_buf_le16(dev->id, ATA_ID_WORDS); /* print device capabilities */ printk(KERN_DEBUG "ata%u: dev %u cfg " @@ -1045,12 +1087,13 @@ retry: goto err_out_nosup; } - /* we require UDMA support */ - udma_modes = - tmp = dev->id[ATA_ID_UDMA_MODES]; - if ((tmp & 0xff) == 0) { - printk(KERN_DEBUG "ata%u: no udma\n", ap->id); - goto err_out_nosup; + /* quick-n-dirty find max transfer mode; for printk only */ + xfer_modes = dev->id[ATA_ID_UDMA_MODES]; + if (!xfer_modes) + xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; + if (!xfer_modes) { + xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); + xfer_modes |= (0x7 << ATA_SHIFT_PIO); } ata_dump_id(dev); @@ -1083,7 +1126,7 @@ retry: /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", ap->id, device, - ata_udma_string(udma_modes), + ata_mode_string(xfer_modes), (unsigned long long)dev->n_sectors, dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } @@ -1093,15 +1136,18 @@ retry: if (ata_id_is_ata(dev)) /* sanity check */ goto err_out_nosup; - /* see if 16-byte commands supported */ - tmp = dev->id[0] & 0x3; - if (tmp == 1) - ap->host->max_cmd_len = 16; + rc = atapi_cdb_len(dev->id); + if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { + printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); + goto err_out_nosup; + } + ap->cdb_len = (unsigned int) rc; + ap->host->max_cmd_len = (unsigned char) ap->cdb_len; /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", ap->id, device, - ata_udma_string(udma_modes)); + ata_mode_string(xfer_modes)); } DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap)); @@ -1171,13 +1217,13 @@ void ata_port_probe(struct ata_port *ap) } /** - * sata_phy_reset - + * __sata_phy_reset - * @ap: * * LOCKING: * */ -void sata_phy_reset(struct ata_port *ap) +void __sata_phy_reset(struct ata_port *ap) { u32 sstatus; unsigned long timeout = jiffies + (HZ * 5); @@ -1215,6 +1261,21 @@ void sata_phy_reset(struct ata_port *ap) return; } + ap->cbl = ATA_CBL_SATA; +} + +/** + * __sata_phy_reset - + * @ap: + * + * LOCKING: + * + */ +void sata_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; ata_bus_reset(ap); } @@ -1232,6 +1293,101 @@ void ata_port_disable(struct ata_port *ap) ap->flags |= ATA_FLAG_PORT_DISABLED; } +static struct { + unsigned int shift; + u8 base; +} xfer_mode_classes[] = { + { ATA_SHIFT_UDMA, XFER_UDMA_0 }, + { ATA_SHIFT_MWDMA, XFER_MW_DMA_0 }, + { ATA_SHIFT_PIO, XFER_PIO_0 }, +}; + +static inline u8 base_from_shift(unsigned int shift) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) + if (xfer_mode_classes[i].shift == shift) + return xfer_mode_classes[i].base; + + return 0xff; +} + +static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +{ + int ofs, idx; + u8 base; + + if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) + return; + + if (dev->xfer_shift == ATA_SHIFT_PIO) + dev->flags |= ATA_DFLAG_PIO; + + ata_dev_set_xfermode(ap, dev); + + base = base_from_shift(dev->xfer_shift); + ofs = dev->xfer_mode - base; + idx = ofs + dev->xfer_shift; + WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str)); + + DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n", + idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs); + + printk(KERN_INFO "ata%u: dev %u configured for %s\n", + ap->id, dev->devno, xfer_mode_str[idx]); +} + +static int ata_host_set_pio(struct ata_port *ap) +{ + unsigned int mask; + int x, i; + u8 base, xfer_mode; + + mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO); + x = fgb(mask); + if (x < 0) { + printk(KERN_WARNING "ata%u: no PIO support\n", ap->id); + return -1; + } + + base = base_from_shift(ATA_SHIFT_PIO); + xfer_mode = base + x; + + DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n", + (int)base, (int)xfer_mode, mask, x); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->pio_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = ATA_SHIFT_PIO; + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, dev); + } + } + + return 0; +} + +static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, + unsigned int xfer_shift) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->dma_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = xfer_shift; + if (ap->ops->set_dmamode) + ap->ops->set_dmamode(ap, dev); + } + } +} + /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed @@ -1241,29 +1397,28 @@ void ata_port_disable(struct ata_port *ap) */ static void ata_set_mode(struct ata_port *ap) { - unsigned int force_pio, i; + unsigned int i, xfer_shift; + u8 xfer_mode; + int rc; - ata_host_set_pio(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + /* step 1: always set host PIO timings */ + rc = ata_host_set_pio(ap); + if (rc) + goto err_out; - ata_host_set_udma(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + /* step 2: choose the best data xfer mode */ + xfer_mode = xfer_shift = 0; + rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift); + if (rc) + goto err_out; -#ifdef ATA_FORCE_PIO - force_pio = 1; -#else - force_pio = 0; -#endif + /* step 3: if that xfer mode isn't PIO, set host DMA timings */ + if (xfer_shift != ATA_SHIFT_PIO) + ata_host_set_dma(ap, xfer_mode, xfer_shift); - if (force_pio) { - ata_dev_set_pio(ap, 0); - ata_dev_set_pio(ap, 1); - } else { - ata_dev_set_udma(ap, 0); - ata_dev_set_udma(ap, 1); - } + /* step 4: update devices' xfer mode */ + ata_dev_set_mode(ap, &ap->device[0]); + ata_dev_set_mode(ap, &ap->device[1]); if (ap->flags & ATA_FLAG_PORT_DISABLED) return; @@ -1275,6 +1430,11 @@ static void ata_set_mode(struct ata_port *ap) struct ata_device *dev = &ap->device[i]; ata_dev_set_protocol(dev); } + + return; + +err_out: + ata_port_disable(ap); } /** @@ -1328,23 +1488,23 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) unsigned int dev1 = devmask & (1 << 1); unsigned long timeout; - /* if device 0 was found in ata_dev_devchk, wait for its + /* if device 0 was found in ata_devchk, wait for its * BSY bit to clear */ if (dev0) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); - /* if device 1 was found in ata_dev_devchk, wait for + /* if device 1 was found in ata_devchk, wait for * register access, then wait for BSY to clear */ timeout = jiffies + ATA_TMOUT_BOOT; while (dev1) { u8 nsect, lbal; - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (ap->flags & ATA_FLAG_MMIO) { - nsect = readb((void *) ioaddr->nsect_addr); - lbal = readb((void *) ioaddr->lbal_addr); + nsect = readb((void __iomem *) ioaddr->nsect_addr); + lbal = readb((void __iomem *) ioaddr->lbal_addr); } else { nsect = inb(ioaddr->nsect_addr); lbal = inb(ioaddr->lbal_addr); @@ -1361,11 +1521,11 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); /* is all this really necessary? */ - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); if (dev1) - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (dev0) - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); } /** @@ -1408,11 +1568,11 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, /* software reset. causes dev0 to be selected */ if (ap->flags & ATA_FLAG_MMIO) { - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); udelay(20); /* FIXME: flush */ - writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr); udelay(20); /* FIXME: flush */ - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); } else { outb(ap->ctl, ioaddr->ctl_addr); udelay(10); @@ -1469,9 +1629,9 @@ void ata_bus_reset(struct ata_port *ap) if (ap->flags & ATA_FLAG_SATA_RESET) dev0 = 1; else { - dev0 = ata_dev_devchk(ap, 0); + dev0 = ata_devchk(ap, 0); if (slave_possible) - dev1 = ata_dev_devchk(ap, 1); + dev1 = ata_devchk(ap, 1); } if (dev0) @@ -1480,7 +1640,7 @@ void ata_bus_reset(struct ata_port *ap) devmask |= (1 << 1); /* select device 0 again */ - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) @@ -1488,7 +1648,7 @@ void ata_bus_reset(struct ata_port *ap) else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) { /* set up device control */ if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); rc = ata_bus_edd(ap); @@ -1509,9 +1669,9 @@ void ata_bus_reset(struct ata_port *ap) /* is double-select really necessary? */ if (ap->device[1].class != ATA_DEV_NONE) - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (ap->device[0].class != ATA_DEV_NONE) - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); /* if no devices were detected, disable this port */ if ((ap->device[0].class == ATA_DEV_NONE) && @@ -1521,7 +1681,7 @@ void ata_bus_reset(struct ata_port *ap) if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { /* set up device control for ATA_FLAG_SATA_RESET */ if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); } @@ -1536,116 +1696,102 @@ err_out: DPRINTK("EXIT\n"); } -/** - * ata_host_set_pio - - * @ap: - * - * LOCKING: - */ - -static void ata_host_set_pio(struct ata_port *ap) +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) { struct ata_device *master, *slave; - unsigned int pio, i; - u16 mask; + unsigned int mask; master = &ap->device[0]; slave = &ap->device[1]; assert (ata_dev_present(master) || ata_dev_present(slave)); - mask = ap->pio_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_PIO_MODES] & 0x03); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03); - - /* require pio mode 3 or 4 support for host and all devices */ - if (mask == 0) { - printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n", - ap->id); - goto err_out; + if (shift == ATA_SHIFT_UDMA) { + mask = ap->udma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + } + else if (shift == ATA_SHIFT_MWDMA) { + mask = ap->mwdma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); + } + else if (shift == ATA_SHIFT_PIO) { + mask = ap->pio_mask; + if (ata_dev_present(master)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + if (ata_dev_present(slave)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + } + else { + mask = 0xffffffff; /* shut up compiler warning */ + BUG(); } - pio = (mask & ATA_ID_PIO4) ? 4 : 3; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].pio_mode = (pio == 3) ? - XFER_PIO_3 : XFER_PIO_4; - if (ap->ops->set_piomode) - ap->ops->set_piomode(ap, &ap->device[i], pio); - } + return mask; +} - return; +/* find greatest bit */ +static int fgb(u32 bitmap) +{ + unsigned int i; + int x = -1; -err_out: - ap->ops->port_disable(ap); + for (i = 0; i < 32; i++) + if (bitmap & (1 << i)) + x = i; + + return x; } /** - * ata_host_set_udma - + * ata_choose_xfer_mode - * @ap: * * LOCKING: + * + * RETURNS: + * Zero on success, negative on error. */ -static void ata_host_set_udma(struct ata_port *ap) +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out) { - struct ata_device *master, *slave; - u16 mask; - unsigned int i, j; - int udma_mode = -1; + unsigned int mask, shift; + int x, i; - master = &ap->device[0]; - slave = &ap->device[1]; + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) { + shift = xfer_mode_classes[i].shift; + mask = ata_get_mode_mask(ap, shift); - assert (ata_dev_present(master) || ata_dev_present(slave)); - assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0); - - DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n", - ap->udma_mask, - (!ata_dev_present(master)) ? 0xff : - (master->id[ATA_ID_UDMA_MODES] & 0xff), - (!ata_dev_present(slave)) ? 0xff : - (slave->id[ATA_ID_UDMA_MODES] & 0xff)); - - mask = ap->udma_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - - i = XFER_UDMA_7; - while (i >= XFER_UDMA_0) { - j = i - XFER_UDMA_0; - DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j); - if (mask & (1 << j)) { - udma_mode = i; - break; + x = fgb(mask); + if (x >= 0) { + *xfer_mode_out = xfer_mode_classes[i].base + x; + *xfer_shift_out = shift; + return 0; } - - i--; } - /* require udma for host and all attached devices */ - if (udma_mode < 0) { - printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n", - ap->id); - goto err_out; - } - - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].udma_mode = udma_mode; - if (ap->ops->set_udmamode) - ap->ops->set_udmamode(ap, &ap->device[i], - udma_mode); - } - - return; - -err_out: - ap->ops->port_disable(ap); + return -1; } /** @@ -1658,88 +1804,38 @@ err_out: static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) { - struct ata_taskfile tf; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); - tf.ctl |= ATA_NIEN; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = SETFEATURES_XFER; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - if (dev->flags & ATA_DFLAG_PIO) - tf.nsect = dev->pio_mode; - else - tf.nsect = dev->udma_mode; - /* do bus reset */ - ata_tf_to_host(ap, &tf); + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + qc->tf.command = ATA_CMD_SET_FEATURES; + qc->tf.feature = SETFEATURES_XFER; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = dev->xfer_mode; - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - ata_irq_on(ap); /* re-enable interrupts */ + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - ata_wait_idle(ap); + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); DPRINTK("EXIT\n"); } -/** - * ata_dev_set_udma - Set ATA device's transfer mode to Ultra DMA - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->udma_mode >= XFER_UDMA_0) && - (dev->udma_mode <= XFER_UDMA_7)); - printk(KERN_INFO "ata%u: dev %u configured for %s\n", - ap->id, device, - udma_str[dev->udma_mode - XFER_UDMA_0]); -} - -/** - * ata_dev_set_pio - Set ATA device's transfer mode to PIO - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - /* force PIO mode */ - dev->flags |= ATA_DFLAG_PIO; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->pio_mode >= XFER_PIO_3) && - (dev->pio_mode <= XFER_PIO_4)); - printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n", - ap->id, device, - dev->pio_mode == 3 ? '3' : '4'); -} - /** * ata_sg_clean - * @qc: @@ -1789,7 +1885,7 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) idx = 0; for (nelem = qc->n_elem; nelem; nelem--,sg++) { - u32 addr, boundary; + u32 addr, offset; u32 sg_len, len; /* determine if physical DMA addr spans 64K boundary. @@ -1800,10 +1896,10 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) sg_len = sg_dma_len(sg); while (sg_len) { - boundary = (addr & ~0xffff) + (0xffff + 1); + offset = addr & 0xffff; len = sg_len; - if ((addr + sg_len) > boundary) - len = boundary - addr; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; ap->prd[idx].addr = cpu_to_le32(addr); ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff); @@ -2003,7 +2099,7 @@ static void ata_pio_complete (struct ata_port *ap) } drv_stat = ata_wait_idle(ap); - if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; return; } @@ -2018,6 +2114,126 @@ static void ata_pio_complete (struct ata_port *ap) ata_qc_complete(qc, drv_stat); } +void swap_buf_le16(u16 *buf, unsigned int buf_words) +{ +#ifdef __BIG_ENDIAN + unsigned int i; + + for (i = 0; i < buf_words; i++) + buf[i] = le16_to_cpu(buf[i]); +#endif /* __BIG_ENDIAN */ +} + +static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + + if (write_data) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(mmio)); + } +} + +static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int dwords = buflen >> 1; + + if (write_data) + outsw(ap->ioaddr.data_addr, buf, dwords); + else + insw(ap->ioaddr.data_addr, buf, dwords); +} + +static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int do_write) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_mmio_data_xfer(ap, buf, buflen, do_write); + else + ata_pio_data_xfer(ap, buf, buflen, do_write); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct page *page; + unsigned char *buf; + + if (qc->cursect == (qc->nsect - 1)) + ap->pio_task_state = PIO_ST_LAST; + + page = sg[qc->cursg].page; + buf = kmap(page) + + sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); + + qc->cursect++; + qc->cursg_ofs++; + + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { + qc->cursg++; + qc->cursg_ofs = 0; + } + + DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + + /* do the actual data transfer */ + do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); + + kunmap(page); +} + +static void atapi_pio_sector(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *dev = qc->dev; + unsigned int i, ireason, bc_lo, bc_hi, bytes; + int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0; + + ap->ops->tf_read(ap, &qc->tf); + ireason = qc->tf.nsect; + bc_lo = qc->tf.lbam; + bc_hi = qc->tf.lbah; + bytes = (bc_hi << 8) | bc_lo; + + /* shall be cleared to zero, indicating xfer of data */ + if (ireason & (1 << 0)) + goto err_out; + + /* make sure transfer direction matches expected */ + i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; + if (do_write != i_write) + goto err_out; + + /* make sure byte count is multiple of sector size; not + * required by standard (warning! warning!), but IDE driver + * does this to simplify things a bit. We are lazy, and + * follow suit. + */ + if (bytes & (ATA_SECT_SIZE - 1)) + goto err_out; + + for (i = 0; i < (bytes >> 9); i++) + ata_pio_sector(qc); + + return; + +err_out: + printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", + ap->id, dev->devno); + ap->pio_task_state = PIO_ST_ERR; +} + /** * ata_pio_sector - * @ap: @@ -2025,12 +2241,9 @@ static void ata_pio_complete (struct ata_port *ap) * LOCKING: */ -static void ata_pio_sector(struct ata_port *ap) +static void ata_pio_block(struct ata_port *ap) { struct ata_queued_cmd *qc; - struct scatterlist *sg; - struct page *page; - unsigned char *buf; u8 status; /* @@ -2061,36 +2274,29 @@ static void ata_pio_sector(struct ata_port *ap) qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - sg = qc->sg; - - if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; + if (is_atapi_taskfile(&qc->tf)) + atapi_pio_sector(qc); + else + ata_pio_sector(qc); +} - page = sg[qc->cursg].page; - buf = kmap(page) + - sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); +static void ata_pio_error(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + u8 drv_stat; - qc->cursect++; - qc->cursg_ofs++; + qc = ata_qc_from_tag(ap, ap->active_tag); + assert(qc != NULL); - if (qc->flags & ATA_QCFLAG_SG) - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { - qc->cursg++; - qc->cursg_ofs = 0; - } + drv_stat = ata_chk_status(ap); + printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", + ap->id, drv_stat); - DPRINTK("data %s, drv_stat 0x%X\n", - qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read", - status); + ap->pio_task_state = PIO_ST_IDLE; - /* do the actual data transfer */ - /* FIXME: mmio-ize */ - if (qc->tf.flags & ATA_TFLAG_WRITE) - outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); - else - insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); + ata_irq_on(ap); - kunmap(page); + ata_qc_complete(qc, drv_stat | ATA_ERR); } static void ata_pio_task(void *_data) @@ -2100,7 +2306,7 @@ static void ata_pio_task(void *_data) switch (ap->pio_task_state) { case PIO_ST: - ata_pio_sector(ap); + ata_pio_block(ap); break; case PIO_ST_LAST: @@ -2113,15 +2319,8 @@ static void ata_pio_task(void *_data) break; case PIO_ST_TMOUT: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; - break; - case PIO_ST_ERR: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; + ata_pio_error(ap); break; } @@ -2180,7 +2379,6 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) /* fall through */ - case ATA_PROT_NODATA: default: ata_altstatus(ap); drv_stat = ata_chk_status(ap); @@ -2287,8 +2485,6 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, ata_tf_init(ap, &qc->tf, dev->devno); - if (likely((dev->flags & ATA_DFLAG_PIO) == 0)) - qc->flags |= ATA_QCFLAG_DMA; if (dev->flags & ATA_DFLAG_LBA48) qc->tf.flags |= ATA_TFLAG_LBA48; } @@ -2296,6 +2492,11 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, return qc; } +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +{ + return 0; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -2335,11 +2536,16 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) do_clear = 1; } - if (qc->waiting) - complete(qc->waiting); + if (qc->waiting) { + struct completion *waiting = qc->waiting; + qc->waiting = NULL; + complete(waiting); + } if (likely(do_clear)) clear_bit(tag, &ap->qactive); + + VPRINTK("EXIT\n"); } /** @@ -2422,6 +2628,12 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_ATAPI: + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); + queue_work(ata_wq, &ap->packet_task); + break; + + case ATA_PROT_ATAPI_NODATA: ata_tf_to_host_nolock(ap, &qc->tf); queue_work(ata_wq, &ap->packet_task); break; @@ -2441,19 +2653,19 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) } /** - * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) + * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) +static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 dmactl; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ mb(); /* make sure PRD table writes are visible to controller */ @@ -2471,17 +2683,17 @@ void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) } /** - * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) + * ata_bmdma_start - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) +static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; u8 dmactl; /* start host DMA transaction */ @@ -2509,7 +2721,7 @@ void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) +static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); @@ -2537,7 +2749,7 @@ void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_start_pio (struct ata_queued_cmd *qc) +static void ata_bmdma_start_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; u8 dmactl; @@ -2548,6 +2760,22 @@ void ata_bmdma_start_pio (struct ata_queued_cmd *qc) ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } +void ata_bmdma_start(struct ata_queued_cmd *qc) +{ + if (qc->ap->flags & ATA_FLAG_MMIO) + ata_bmdma_start_mmio(qc); + else + ata_bmdma_start_pio(qc); +} + +void ata_bmdma_setup(struct ata_queued_cmd *qc) +{ + if (qc->ap->flags & ATA_FLAG_MMIO) + ata_bmdma_setup_mmio(qc); + else + ata_bmdma_setup_pio(qc); +} + void ata_bmdma_irq_clear(struct ata_port *ap) { ata_bmdma_ack_irq(ap); @@ -2581,7 +2809,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, case ATA_PROT_ATAPI: /* check status of DMA engine */ host_stat = ata_bmdma_status(ap); - VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); /* if it's not our irq... */ if (!(host_stat & ATA_DMA_INTR)) @@ -2592,6 +2820,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* fall through */ + case ATA_PROT_ATAPI_NODATA: case ATA_PROT_NODATA: /* check altstatus */ status = ata_altstatus(ap); @@ -2602,7 +2831,8 @@ inline unsigned int ata_host_intr (struct ata_port *ap, status = ata_chk_status(ap); if (unlikely(status & ATA_BUSY)) goto idle_irq; - DPRINTK("BUS_NODATA (dev_stat 0x%X)\n", status); + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); /* ack bmdma irq events */ ata_bmdma_ack_irq(ap); @@ -2701,21 +2931,20 @@ static void atapi_packet_task(void *_data) /* make sure DRQ is set */ status = ata_chk_status(ap); - if ((status & ATA_DRQ) == 0) + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) goto err_out; /* send SCSI cdb */ - /* FIXME: mmio-ize */ DPRINTK("send cdb\n"); - outsl(ap->ioaddr.data_addr, - qc->scsicmd->cmnd, ap->host->max_cmd_len / 4); + assert(ap->cdb_len >= 12); + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* if we are DMA'ing, irq handler takes over from here */ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) ap->ops->bmdma_start(qc); /* initiate bmdma */ /* non-data commands are also handled via irq */ - else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) { + else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { /* do nothing */ } @@ -2804,11 +3033,11 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->host_set = host_set; ap->port_no = port_no; ap->pio_mask = ent->pio_mask; + ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; ap->cbl = ATA_CBL_NONE; - ap->device[0].flags = ATA_DFLAG_MASTER; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; @@ -2901,19 +3130,23 @@ int ata_device_add(struct ata_probe_ent *ent) /* register each port bound to this device */ for (i = 0; i < ent->n_ports; i++) { struct ata_port *ap; + unsigned long xfer_mode_mask; ap = ata_host_add(ent, host_set, i); if (!ap) goto err_out; host_set->ports[i] = ap; + xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | + (ap->mwdma_mask << ATA_SHIFT_MWDMA) | + (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " "bmdma 0x%lX irq %lu\n", ap->id, ap->flags & ATA_FLAG_SATA ? 'S' : 'P', - ata_udma_string(ent->udma_mask), + ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, ap->ioaddr.ctl_addr, ap->ioaddr.bmdma_addr, @@ -3035,6 +3268,95 @@ void ata_std_ports(struct ata_ioports *ioaddr) ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } +static struct ata_probe_ent * +ata_probe_ent_alloc(int n, struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent; + int i; + + probe_ent = kmalloc(sizeof(*probe_ent) * n, GFP_KERNEL); + if (!probe_ent) { + printk(KERN_ERR DRV_NAME "(%s): out of memory\n", + pci_name(pdev)); + return NULL; + } + + memset(probe_ent, 0, sizeof(*probe_ent) * n); + + for (i = 0; i < n; i++) { + INIT_LIST_HEAD(&probe_ent[i].node); + probe_ent[i].pdev = pdev; + + probe_ent[i].sht = port[i]->sht; + probe_ent[i].host_flags = port[i]->host_flags; + probe_ent[i].pio_mask = port[i]->pio_mask; + probe_ent[i].mwdma_mask = port[i]->mwdma_mask; + probe_ent[i].udma_mask = port[i]->udma_mask; + probe_ent[i].port_ops = port[i]->port_ops; + + } + + return probe_ent; +} + +struct ata_probe_ent * +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(1, pdev, port); + if (!probe_ent) + return NULL; + + probe_ent->n_ports = 2; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + + ata_std_ports(&probe_ent->port[0]); + ata_std_ports(&probe_ent->port[1]); + + return probe_ent; +} + +struct ata_probe_ent * +ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(2, pdev, port); + if (!probe_ent) + return NULL; + + probe_ent[0].n_ports = 1; + probe_ent[0].irq = 14; + + probe_ent[1].n_ports = 1; + probe_ent[1].irq = 15; + + probe_ent[0].port[0].cmd_addr = 0x1f0; + probe_ent[0].port[0].altstatus_addr = + probe_ent[0].port[0].ctl_addr = 0x3f6; + probe_ent[0].port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent[1].port[0].cmd_addr = 0x170; + probe_ent[1].port[0].altstatus_addr = + probe_ent[1].port[0].ctl_addr = 0x376; + probe_ent[1].port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; + + ata_std_ports(&probe_ent[0].port[0]); + ata_std_ports(&probe_ent[1].port[0]); + + return probe_ent; +} + /** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized @@ -3052,20 +3374,20 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; - struct ata_port_info *port0, *port1; + struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; int rc; DPRINTK("ENTER\n"); - port0 = port_info[0]; + port[0] = port_info[0]; if (n_ports > 1) - port1 = port_info[1]; + port[1] = port_info[1]; else - port1 = port0; + port[1] = port[0]; - if ((port0->host_flags & ATA_FLAG_NO_LEGACY) == 0) { + if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0) { /* TODO: support transitioning to native mode? */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); @@ -3126,75 +3448,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (legacy_mode) { + probe_ent = ata_pci_init_legacy_mode(pdev, port); + if (probe_ent) + probe_ent2 = &probe_ent[1]; + } else + probe_ent = ata_pci_init_native_mode(pdev, port); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - probe_ent->pdev = pdev; - INIT_LIST_HEAD(&probe_ent->node); - - if (legacy_mode) { - probe_ent2 = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (!probe_ent2) { - rc = -ENOMEM; - goto err_out_free_ent; - } - - memset(probe_ent2, 0, sizeof(*probe_ent)); - probe_ent2->pdev = pdev; - INIT_LIST_HEAD(&probe_ent2->node); - } - - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - probe_ent->sht = port0->sht; - probe_ent->host_flags = port0->host_flags; - probe_ent->pio_mask = port0->pio_mask; - probe_ent->udma_mask = port0->udma_mask; - probe_ent->port_ops = port0->port_ops; - - if (legacy_mode) { - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->n_ports = 1; - probe_ent->irq = 14; - ata_std_ports(&probe_ent->port[0]); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - ata_std_ports(&probe_ent2->port[0]); - - probe_ent2->sht = port1->sht; - probe_ent2->host_flags = port1->host_flags; - probe_ent2->pio_mask = port1->pio_mask; - probe_ent2->udma_mask = port1->udma_mask; - probe_ent2->port_ops = port1->port_ops; - } else { - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - } - pci_set_master(pdev); /* FIXME: check ata_device_add return */ @@ -3203,17 +3467,13 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, ata_device_add(probe_ent); if (legacy_mode & (1 << 1)) ata_device_add(probe_ent2); - kfree(probe_ent2); } else { ata_device_add(probe_ent); - assert(probe_ent2 == NULL); } kfree(probe_ent); return 0; -err_out_free_ent: - kfree(probe_ent); err_out_regions: if (legacy_mode & (1 << 0)) release_region(0x1f0, 8); @@ -3363,34 +3623,35 @@ EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_eng_timeout); -EXPORT_SYMBOL_GPL(ata_tf_load_pio); -EXPORT_SYMBOL_GPL(ata_tf_load_mmio); -EXPORT_SYMBOL_GPL(ata_tf_read_pio); -EXPORT_SYMBOL_GPL(ata_tf_read_mmio); +EXPORT_SYMBOL_GPL(ata_tf_load); +EXPORT_SYMBOL_GPL(ata_tf_read); +EXPORT_SYMBOL_GPL(ata_noop_dev_select); +EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); -EXPORT_SYMBOL_GPL(ata_check_status_pio); -EXPORT_SYMBOL_GPL(ata_check_status_mmio); -EXPORT_SYMBOL_GPL(ata_exec_command_pio); -EXPORT_SYMBOL_GPL(ata_exec_command_mmio); +EXPORT_SYMBOL_GPL(ata_pci_init_legacy_mode); +EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); +EXPORT_SYMBOL_GPL(ata_check_status); +EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_qc_prep); -EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio); -EXPORT_SYMBOL_GPL(ata_bmdma_start_pio); -EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio); -EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio); +EXPORT_SYMBOL_GPL(ata_bmdma_setup); +EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_phy_reset); +EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); +EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); +EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_id_string); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index b3340607b..47c0af26f 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -29,6 +29,7 @@ #include "scsi.h" #include #include +#include #include "libata.h" @@ -36,6 +37,8 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); /** @@ -67,6 +70,43 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } +int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) +{ + struct ata_port *ap; + struct ata_device *dev; + int val = -EINVAL, rc = -EINVAL; + + ap = (struct ata_port *) &scsidev->host->hostdata[0]; + if (!ap) + goto out; + + dev = ata_scsi_find_dev(ap, scsidev); + if (!dev) { + rc = -ENODEV; + goto out; + } + + switch (cmd) { + case ATA_IOC_GET_IO32: + val = 0; + if (copy_to_user(arg, &val, 1)) + return -EFAULT; + return 0; + + case ATA_IOC_SET_IO32: + val = (unsigned long) arg; + if (val != 0) + return -EINVAL; + return 0; + + default: + rc = -EOPNOTSUPP; + break; + } + +out: + return rc; +} /** * ata_scsi_qc_new - acquire new ata_queued_cmd reference @@ -120,34 +160,158 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, * ata_to_sense_error - convert ATA error to SCSI error * @qc: Command that we are erroring out * - * Converts an ATA error into a SCSI error. - * - * Right now, this routine is laughably primitive. We - * don't even examine what ATA told us, we just look at - * the command data direction, and return a fatal SCSI - * sense error based on that. + * Converts an ATA error into a SCSI error. While we are at it + * we decode and dump the ATA error for the user so that they + * have some idea what really happened at the non make-believe + * layer. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_to_sense_error(struct ata_queued_cmd *qc) +void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + u8 err = 0; + unsigned char *sb = cmd->sense_buffer; + /* Based on the 3ware driver translation table */ + static unsigned char sense_table[][4] = { + /* BBD|ECC|ID|MAR */ + {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* BBD|ECC|ID */ + {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* ECC|MC|MARK */ + {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error + /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */ + {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error + /* MC|ID|ABRT|TRK0|MARK */ + {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready + /* MCR|MARK */ + {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready + /* Bad address mark */ + {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field + /* TRK0 */ + {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error + /* Abort & !ICRC */ + {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command + /* Media change request */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline + /* SRV */ + {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found + /* Media change */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline + /* ECC */ + {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error + /* BBD - block marked bad */ + {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + static unsigned char stat_table[][4] = { + /* Must be first because BUSY means no other bits valid */ + {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now + {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault + {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now + {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + int i = 0; cmd->result = SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = MEDIUM_ERROR; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - + + /* + * Is this an error we can process/parse + */ + + if(drv_stat & ATA_ERR) + /* Read the err bits */ + err = ata_chk_err(qc->ap); + + /* Display the ATA level error info */ + + printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); + if(drv_stat & 0x80) + { + printk("Busy "); + err = 0; /* Data is not valid in this case */ + } + else { + if(drv_stat & 0x40) printk("DriveReady "); + if(drv_stat & 0x20) printk("DeviceFault "); + if(drv_stat & 0x10) printk("SeekComplete "); + if(drv_stat & 0x08) printk("DataRequest "); + if(drv_stat & 0x04) printk("CorrectedError "); + if(drv_stat & 0x02) printk("Index "); + if(drv_stat & 0x01) printk("Error "); + } + printk("}\n"); + + if(err) + { + printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); + if(err & 0x04) printk("DriveStatusError "); + if(err & 0x80) + { + if(err & 0x04) + printk("BadCRC "); + else + printk("Sector "); + } + if(err & 0x40) printk("UncorrectableError "); + if(err & 0x10) printk("SectorIdNotFound "); + if(err & 0x02) printk("TrackZeroNotFound "); + if(err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + + /* Should we dump sector info here too ?? */ + } + + + /* Look for err */ + while(sense_table[i][0] != 0xFF) + { + /* Look for best matches first */ + if((sense_table[i][0] & err) == sense_table[i][0]) + { + sb[0] = 0x70; + sb[2] = sense_table[i][1]; + sb[7] = 0x0a; + sb[12] = sense_table[i][2]; + sb[13] = sense_table[i][3]; + return; + } + i++; + } + /* No immediate match */ + if(err) + printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); + + /* Fall back to interpreting status bits */ + while(stat_table[i][0] != 0xFF) + { + if(stat_table[i][0] & drv_stat) + { + sb[0] = 0x70; + sb[2] = stat_table[i][1]; + sb[7] = 0x0a; + sb[12] = stat_table[i][2]; + sb[13] = stat_table[i][3]; + return; + } + i++; + } + /* No error ?? */ + printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ + + sb[0] = 0x70; + sb[2] = MEDIUM_ERROR; + sb[7] = 0x0A; if (cmd->sc_data_direction == SCSI_DATA_READ) { - cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */ - cmd->sense_buffer[13] = 0x04; + sb[12] = 0x11; /* "unrecovered read error" */ + sb[13] = 0x04; } else { - cmd->sense_buffer[12] = 0x0C; /* "write error - */ - cmd->sense_buffer[13] = 0x02; /* auto-reallocation failed" */ + sb[12] = 0x0C; /* "write error - */ + sb[13] = 0x02; /* auto-reallocation failed" */ } } @@ -214,10 +378,134 @@ int ata_scsi_error(struct Scsi_Host *host) ap = (struct ata_port *) &host->hostdata[0]; ap->ops->eng_timeout(ap); + /* TODO: this is per-command; when queueing is supported + * this code will either change or move to a more + * appropriate place + */ + host->host_failed--; + DPRINTK("EXIT\n"); return 0; } +/** + * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate (ignored) + * + * Sets up an ATA taskfile to issue FLUSH CACHE or + * FLUSH CACHE EXT. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + + if ((tf->flags & ATA_TFLAG_LBA48) && + (ata_id_has_flush_ext(qc->dev))) + tf->command = ATA_CMD_FLUSH_EXT; + else + tf->command = ATA_CMD_FLUSH; + + return 0; +} + +/** + * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Converts SCSI VERIFY command to an ATA READ VERIFY command. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + u64 dev_sectors = qc->dev->n_sectors; + u64 sect = 0; + u32 n_sect = 0; + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->device |= ATA_LBA; + + if (scsicmd[0] == VERIFY) { + sect |= ((u64)scsicmd[2]) << 24; + sect |= ((u64)scsicmd[3]) << 16; + sect |= ((u64)scsicmd[4]) << 8; + sect |= ((u64)scsicmd[5]); + + n_sect |= ((u32)scsicmd[7]) << 8; + n_sect |= ((u32)scsicmd[8]); + } + + else if (scsicmd[0] == VERIFY_16) { + sect |= ((u64)scsicmd[2]) << 56; + sect |= ((u64)scsicmd[3]) << 48; + sect |= ((u64)scsicmd[4]) << 40; + sect |= ((u64)scsicmd[5]) << 32; + sect |= ((u64)scsicmd[6]) << 24; + sect |= ((u64)scsicmd[7]) << 16; + sect |= ((u64)scsicmd[8]) << 8; + sect |= ((u64)scsicmd[9]); + + n_sect |= ((u32)scsicmd[10]) << 24; + n_sect |= ((u32)scsicmd[11]) << 16; + n_sect |= ((u32)scsicmd[12]) << 8; + n_sect |= ((u32)scsicmd[13]); + } + + else + return 1; + + if (!n_sect) + return 1; + if (sect >= dev_sectors) + return 1; + if ((sect + n_sect) > dev_sectors) + return 1; + if (lba48) { + if (n_sect > (64 * 1024)) + return 1; + } else { + if (n_sect > 256) + return 1; + } + + if (lba48) { + tf->hob_nsect = (n_sect >> 8) & 0xff; + + tf->hob_lbah = (sect >> 40) & 0xff; + tf->hob_lbam = (sect >> 32) & 0xff; + tf->hob_lbal = (sect >> 24) & 0xff; + } else + tf->device |= (sect >> 24) & 0xf; + + tf->nsect = n_sect & 0xff; + + tf->hob_lbah = (sect >> 16) & 0xff; + tf->hob_lbam = (sect >> 8) & 0xff; + tf->hob_lbal = sect & 0xff; + + return 0; +} + /** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile @@ -244,10 +532,6 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->hob_nsect = 0; - tf->hob_lbal = 0; - tf->hob_lbam = 0; - tf->hob_lbah = 0; tf->protocol = qc->dev->xfer_protocol; tf->device |= ATA_LBA; @@ -339,14 +623,10 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { - if (is_atapi_taskfile(&qc->tf)) - cmd->result = SAM_STAT_CHECK_CONDITION; - else - ata_to_sense_error(qc); - } else { + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else cmd->result = SAM_STAT_GOOD; - } qc->scsidone(cmd); @@ -534,7 +814,7 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, 0, 0x5, /* claim SPC-3 version compatibility */ 2, - 96 - 4 + 95 - 4 }; /* set scsi removeable (RMB) bit per ata bit */ @@ -545,7 +825,7 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > 36) { + if (buflen > 35) { memcpy(&rbuf[8], "ATA ", 8); ata_dev_id_string(dev, &rbuf[16], ATA_ID_PROD_OFS, 16); ata_dev_id_string(dev, &rbuf[32], ATA_ID_FW_REV_OFS, 4); @@ -964,6 +1244,31 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 done(cmd); } +static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + cmd->result = SAM_STAT_CHECK_CONDITION; + else { + u8 *scsicmd = cmd->cmnd; + + if (scsicmd[0] == INQUIRY) { + u8 *buf = NULL; + unsigned int buflen; + + buflen = ata_scsi_rbuf_get(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } + + qc->scsidone(cmd); + + return 0; +} /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized @@ -979,6 +1284,13 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + int using_pio = (dev->flags & ATA_DFLAG_PIO); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); + + qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -988,19 +1300,18 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) qc->tf.command = ATA_CMD_PACKET; - /* no data - interrupt-driven */ - if (cmd->sc_data_direction == SCSI_DATA_NONE) - qc->tf.protocol = ATA_PROT_ATAPI; - - /* PIO data xfer - polling */ - else if ((qc->flags & ATA_QCFLAG_DMA) == 0) { - ata_qc_set_polling(qc); - qc->tf.protocol = ATA_PROT_ATAPI; + /* no data, or PIO data xfer */ + if (using_pio || nodata) { + if (nodata) + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + else + qc->tf.protocol = ATA_PROT_ATAPI; qc->tf.lbam = (8 * 1024) & 0xff; qc->tf.lbah = (8 * 1024) >> 8; + } - /* DMA data xfer - interrupt-driven */ - } else { + /* DMA data xfer */ + else { qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; @@ -1031,19 +1342,19 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * Associated ATA device, or %NULL if not found. */ -static inline struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) { struct ata_device *dev; /* skip commands not addressed to targets we simulate */ - if (likely(cmd->device->id < ATA_MAX_DEVICES)) - dev = &ap->device[cmd->device->id]; + if (likely(scsidev->id < ATA_MAX_DEVICES)) + dev = &ap->device[scsidev->id]; else return NULL; - if (unlikely((cmd->device->channel != 0) || - (cmd->device->lun != 0))) + if (unlikely((scsidev->channel != 0) || + (scsidev->lun != 0))) return NULL; if (unlikely(!ata_dev_present(dev))) @@ -1059,6 +1370,7 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) /** * ata_get_xlat_func - check if SCSI to ATA translation is possible + * @dev: ATA device * @cmd: SCSI command opcode to consider * * Look up the SCSI command given, and determine whether the @@ -1068,7 +1380,7 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) * Pointer to translation function if possible, %NULL if not. */ -static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) +static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) { switch (cmd) { case READ_6: @@ -1079,6 +1391,15 @@ static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) case WRITE_10: case WRITE_16: return ata_scsi_rw_xlat; + + case SYNCHRONIZE_CACHE: + if (ata_try_flush_cache(dev)) + return ata_scsi_flush_xlat; + break; + + case VERIFY: + case VERIFY_16: + return ata_scsi_verify_xlat; } return NULL; @@ -1096,11 +1417,12 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd) { #ifdef ATA_DEBUG + struct scsi_device *scsidev = cmd->device; u8 *scsicmd = cmd->cmnd; DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", ap->id, - cmd->device->channel, cmd->device->id, cmd->device->lun, + scsidev->channel, scsidev->id, scsidev->lun, scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], scsicmd[8]); @@ -1130,12 +1452,13 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct ata_port *ap; struct ata_device *dev; + struct scsi_device *scsidev = cmd->device; - ap = (struct ata_port *) &cmd->device->host->hostdata[0]; + ap = (struct ata_port *) &scsidev->host->hostdata[0]; ata_scsi_dump_cdb(ap, cmd); - dev = ata_scsi_find_dev(ap, cmd); + dev = ata_scsi_find_dev(ap, scsidev); if (unlikely(!dev)) { cmd->result = (DID_BAD_TARGET << 16); done(cmd); @@ -1143,7 +1466,8 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) } if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(cmd->cmnd[0]); + ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, + cmd->cmnd[0]); if (xlat_func) ata_scsi_translate(ap, dev, cmd, done, xlat_func); @@ -1184,7 +1508,7 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, switch(scsicmd[0]) { /* no-op's, complete with success */ - case SYNCHRONIZE_CACHE: /* FIXME: temporary */ + case SYNCHRONIZE_CACHE: case REZERO_UNIT: case SEEK_6: case SEEK_10: diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 460c72c1b..68c268e41 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -42,10 +42,11 @@ extern int ata_qc_issue(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); +extern void swap_buf_le16(u16 *buf, unsigned int buf_words); /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc); +extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index f343fc704..ef6a0c807 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -326,6 +326,7 @@ int macscsi_release (struct Scsi_Host *shpnt) { if (shpnt->irq != SCSI_IRQ_NONE) free_irq (shpnt->irq, NCR5380_intr); + NCR5380_exit(shpnt); return 0; } diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c index e64b8ec2f..d959c627a 100644 --- a/drivers/scsi/mca_53c9x.c +++ b/drivers/scsi/mca_53c9x.c @@ -238,15 +238,15 @@ int mca_esp_detect(Scsi_Host_Template *tpnt) /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; + esp->dma_barrier = NULL; + esp->dma_drain = NULL; + esp->dma_invalidate = NULL; + esp->dma_irq_entry = NULL; + esp->dma_irq_exit = NULL; esp->dma_led_on = dma_led_on; esp->dma_led_off = dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; + esp->dma_poll = NULL; + esp->dma_reset = NULL; /* Set the command buffer */ diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 5fd685e9a..bdab1b659 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -25,11 +25,8 @@ * 518, 520, 531, 532 * * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, - * and others. Please send updates to the public mailing list - * linux-megaraid-devel@dell.com, and subscribe to and read archives of this - * list at http://lists.us.dell.com/. - * - * For history of changes, see ChangeLog.megaraid. + * and others. Please send updates to the mailing list + * linux-scsi@vger.kernel.org . * */ @@ -53,9 +50,12 @@ #include "megaraid.h" +#define MEGARAID_MODULE_VERSION "2.00.3" + MODULE_AUTHOR ("LSI Logic Corporation"); MODULE_DESCRIPTION ("LSI Logic MegaRAID driver"); MODULE_LICENSE ("GPL"); +MODULE_VERSION(MEGARAID_MODULE_VERSION); static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN; MODULE_PARM(max_cmd_per_lun, "i"); diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid new file mode 100644 index 000000000..97c7a7634 --- /dev/null +++ b/drivers/scsi/megaraid/Kconfig.megaraid @@ -0,0 +1,77 @@ +config MEGARAID_NEWGEN + bool "LSI Logic New Generation RAID Device Drivers" + depends on PCI && SCSI + help + LSI Logic RAID Device Drivers + +config MEGARAID_MM + tristate "LSI Logic Management Module (New Driver)" + depends on PCI && SCSI && MEGARAID_NEWGEN + help + Management Module provides ioctl, sysfs support for LSI Logic + RAID controllers. + To compile this driver as a module, choose M here: the + module will be called megaraid_mm + + +config MEGARAID_MAILBOX + tristate "LSI Logic MegaRAID Driver (New Driver)" + depends on PCI && SCSI && MEGARAID_MM + help + List of supported controllers + + OEM Product Name VID :DID :SVID:SSID + --- ------------ ---- ---- ---- ---- + Dell PERC3/QC 101E:1960:1028:0471 + Dell PERC3/DC 101E:1960:1028:0493 + Dell PERC3/SC 101E:1960:1028:0475 + Dell PERC3/Di 1028:000E:1028:0123 + Dell PERC4/SC 1000:1960:1028:0520 + Dell PERC4/DC 1000:1960:1028:0518 + Dell PERC4/QC 1000:0407:1028:0531 + Dell PERC4/Di 1028:000F:1028:014A + Dell PERC 4e/Si 1028:0013:1028:016c + Dell PERC 4e/Di 1028:0013:1028:016d + Dell PERC 4e/Di 1028:0013:1028:016e + Dell PERC 4e/Di 1028:0013:1028:016f + Dell PERC 4e/Di 1028:0013:1028:0170 + Dell PERC 4e/DC 1000:0408:1028:0002 + Dell PERC 4e/SC 1000:0408:1028:0001 + LSI MegaRAID SCSI 320-0 1000:1960:1000:A520 + LSI MegaRAID SCSI 320-1 1000:1960:1000:0520 + LSI MegaRAID SCSI 320-2 1000:1960:1000:0518 + LSI MegaRAID SCSI 320-0X 1000:0407:1000:0530 + LSI MegaRAID SCSI 320-2X 1000:0407:1000:0532 + LSI MegaRAID SCSI 320-4X 1000:0407:1000:0531 + LSI MegaRAID SCSI 320-1E 1000:0408:1000:0001 + LSI MegaRAID SCSI 320-2E 1000:0408:1000:0002 + LSI MegaRAID SATA 150-4 1000:1960:1000:4523 + LSI MegaRAID SATA 150-6 1000:1960:1000:0523 + LSI MegaRAID SATA 300-4X 1000:0409:1000:3004 + LSI MegaRAID SATA 300-8X 1000:0409:1000:3008 + INTEL RAID Controller SRCU42X 1000:0407:8086:0532 + INTEL RAID Controller SRCS16 1000:1960:8086:0523 + INTEL RAID Controller SRCU42E 1000:0408:8086:0002 + INTEL RAID Controller SRCZCRX 1000:0407:8086:0530 + INTEL RAID Controller SRCS28X 1000:0409:8086:3008 + INTEL RAID Controller SROMBU42E 1000:0408:8086:3431 + INTEL RAID Controller SROMBU42E 1000:0408:8086:3499 + INTEL RAID Controller SRCU51L 1000:1960:8086:0520 + FSC MegaRAID PCI Express ROMB 1000:0408:1734:1065 + ACER MegaRAID ROMB-2E 1000:0408:1025:004D + + To compile this driver as a module, choose M here: the + module will be called megaraid_mbox + +if MEGARAID_NEWGEN=n +config MEGARAID_LEGACY + tristate "LSI Logic Legacy MegaRAID Driver" + depends on PCI && SCSI + help + This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490 + and 467 SCSI host adapters. This driver also support the all U320 + RAID controllers + + To compile this driver as a module, choose M here: the + module will be called megaraid +endif diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile new file mode 100644 index 000000000..6dd99f275 --- /dev/null +++ b/drivers/scsi/megaraid/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o +obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h new file mode 100644 index 000000000..3052869f5 --- /dev/null +++ b/drivers/scsi/megaraid/mbox_defs.h @@ -0,0 +1,790 @@ +/* + * + * Linux MegaRAID Unified device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : mbox_defs.h + * + */ +#ifndef _MRAID_MBOX_DEFS_H_ +#define _MRAID_MBOX_DEFS_H_ + +#include + +/* + * Commands and states for mailbox based controllers + */ + +#define MBOXCMD_LREAD 0x01 +#define MBOXCMD_LWRITE 0x02 +#define MBOXCMD_PASSTHRU 0x03 +#define MBOXCMD_ADPEXTINQ 0x04 +#define MBOXCMD_ADAPTERINQ 0x05 +#define MBOXCMD_LREAD64 0xA7 +#define MBOXCMD_LWRITE64 0xA8 +#define MBOXCMD_PASSTHRU64 0xC3 +#define MBOXCMD_EXTPTHRU 0xE3 + +#define MAIN_MISC_OPCODE 0xA4 +#define GET_MAX_SG_SUPPORT 0x01 +#define SUPPORT_EXT_CDB 0x16 + +#define FC_NEW_CONFIG 0xA1 +#define NC_SUBOP_PRODUCT_INFO 0x0E +#define NC_SUBOP_ENQUIRY3 0x0F +#define ENQ3_GET_SOLICITED_FULL 0x02 +#define OP_DCMD_READ_CONFIG 0x04 +#define NEW_READ_CONFIG_8LD 0x67 +#define READ_CONFIG_8LD 0x07 +#define FLUSH_ADAPTER 0x0A +#define FLUSH_SYSTEM 0xFE + +/* + * Command for random deletion of logical drives + */ +#define FC_DEL_LOGDRV 0xA4 +#define OP_SUP_DEL_LOGDRV 0x2A +#define OP_GET_LDID_MAP 0x18 +#define OP_DEL_LOGDRV 0x1C + +/* + * BIOS commands + */ +#define IS_BIOS_ENABLED 0x62 +#define GET_BIOS 0x01 +#define CHNL_CLASS 0xA9 +#define GET_CHNL_CLASS 0x00 +#define SET_CHNL_CLASS 0x01 +#define CH_RAID 0x01 +#define CH_SCSI 0x00 +#define BIOS_PVT_DATA 0x40 +#define GET_BIOS_PVT_DATA 0x00 + + +/* + * Commands to support clustering + */ +#define GET_TARGET_ID 0x7D +#define CLUSTER_OP 0x70 +#define GET_CLUSTER_MODE 0x02 +#define CLUSTER_CMD 0x6E +#define RESERVE_LD 0x01 +#define RELEASE_LD 0x02 +#define RESET_RESERVATIONS 0x03 +#define RESERVATION_STATUS 0x04 +#define RESERVE_PD 0x05 +#define RELEASE_PD 0x06 + + +/* + * Module battery status + */ +#define BATTERY_MODULE_MISSING 0x01 +#define BATTERY_LOW_VOLTAGE 0x02 +#define BATTERY_TEMP_HIGH 0x04 +#define BATTERY_PACK_MISSING 0x08 +#define BATTERY_CHARGE_MASK 0x30 +#define BATTERY_CHARGE_DONE 0x00 +#define BATTERY_CHARGE_INPROG 0x10 +#define BATTERY_CHARGE_FAIL 0x20 +#define BATTERY_CYCLES_EXCEEDED 0x40 + +/* + * Physical drive states. + */ +#define PDRV_UNCNF 0 +#define PDRV_ONLINE 3 +#define PDRV_FAILED 4 +#define PDRV_RBLD 5 +#define PDRV_HOTSPARE 6 + + +/* + * Raid logical drive states. + */ +#define RDRV_OFFLINE 0 +#define RDRV_DEGRADED 1 +#define RDRV_OPTIMAL 2 +#define RDRV_DELETED 3 + +/* + * Read, write and cache policies + */ +#define NO_READ_AHEAD 0 +#define READ_AHEAD 1 +#define ADAP_READ_AHEAD 2 +#define WRMODE_WRITE_THRU 0 +#define WRMODE_WRITE_BACK 1 +#define CACHED_IO 0 +#define DIRECT_IO 1 + +#define MAX_LOGICAL_DRIVES_8LD 8 +#define MAX_LOGICAL_DRIVES_40LD 40 +#define FC_MAX_PHYSICAL_DEVICES 256 +#define MAX_MBOX_CHANNELS 5 +#define MAX_MBOX_TARGET 15 +#define MBOX_MAX_PHYSICAL_DRIVES MAX_MBOX_CHANNELS*MAX_MBOX_TARGET +#define MAX_ROW_SIZE_40LD 32 +#define MAX_ROW_SIZE_8LD 8 +#define SPAN_DEPTH_8_SPANS 8 +#define SPAN_DEPTH_4_SPANS 4 +#define MAX_REQ_SENSE_LEN 0x20 + + + +/** + * struct mbox_t - Driver and f/w handshake structure. + * @cmd : firmware command + * @cmdid : command id + * @numsectors : number of sectors to be transferred + * @lba : Logical Block Address on LD + * @xferaddr : DMA address for data transfer + * @logdrv : logical drive number + * @numsge : number of scatter gather elements in sg list + * @resvd : reserved + * @busy : f/w busy, must wait to issue more commands. + * @numstatus : number of commands completed. + * @status : status of the commands completed + * @completed : array of completed command ids. + * @poll : poll and ack sequence + * @ack : poll and ack sequence + * + * The central handshake structure between the driver and the firmware. This + * structure must be allocated by the driver and aligned at 8-byte boundary. + */ +#define MBOX_MAX_FIRMWARE_STATUS 46 +typedef struct { + uint8_t cmd; + uint8_t cmdid; + uint16_t numsectors; + uint32_t lba; + uint32_t xferaddr; + uint8_t logdrv; + uint8_t numsge; + uint8_t resvd; + uint8_t busy; + uint8_t numstatus; + uint8_t status; + uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; + uint8_t poll; + uint8_t ack; +} __attribute__ ((packed)) mbox_t; + + +/** + * mbox64_t - 64-bit extension for the mailbox + * @segment_lo : the low 32-bits of the address of the scatter-gather list + * @segment_hi : the upper 32-bits of the address of the scatter-gather list + * @mbox : 32-bit mailbox, whose xferadder field must be set to + * 0xFFFFFFFF + * + * This is the extension of the 32-bit mailbox to be able to perform DMA + * beyond 4GB address range. + */ +typedef struct { + uint32_t xferaddr_lo; + uint32_t xferaddr_hi; + mbox_t mbox32; +} __attribute__ ((packed)) mbox64_t; + +/* + * mailbox structure used for internal commands + */ +typedef struct { + u8 cmd; + u8 cmdid; + u8 opcode; + u8 subopcode; + u32 lba; + u32 xferaddr; + u8 logdrv; + u8 rsvd[3]; + u8 numstatus; + u8 status; +} __attribute__ ((packed)) int_mbox_t; + +/** + * mraid_passthru_t - passthru structure to issue commands to physical devices + * @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr + * @ars : set if ARS required after check condition + * @islogical : set if command meant for logical devices + * @logdrv : logical drive number if command for LD + * @channel : Channel on which physical device is located + * @target : SCSI target of the device + * @queuetag : unused + * @queueaction : unused + * @cdb : SCSI CDB + * @cdblen : length of the CDB + * @reqsenselen : amount of request sense data to be returned + * @reqsensearea : Sense information buffer + * @numsge : number of scatter-gather elements in the sg list + * @scsistatus : SCSI status of the command completed. + * @dataxferaddr : DMA data transfer address + * @dataxferlen : amount of the data to be transferred. + */ +typedef struct { + uint8_t timeout :3; + uint8_t ars :1; + uint8_t reserved :3; + uint8_t islogical :1; + uint8_t logdrv; + uint8_t channel; + uint8_t target; + uint8_t queuetag; + uint8_t queueaction; + uint8_t cdb[10]; + uint8_t cdblen; + uint8_t reqsenselen; + uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; + uint8_t numsge; + uint8_t scsistatus; + uint32_t dataxferaddr; + uint32_t dataxferlen; +} __attribute__ ((packed)) mraid_passthru_t; + +typedef struct { + + uint32_t dataxferaddr_lo; + uint32_t dataxferaddr_hi; + mraid_passthru_t pthru32; + +} __attribute__ ((packed)) mega_passthru64_t; + +/** + * mraid_epassthru_t - passthru structure to issue commands to physical devices + * @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr + * @ars : set if ARS required after check condition + * @rsvd1 : reserved field + * @cd_rom : (?) + * @rsvd2 : reserved field + * @islogical : set if command meant for logical devices + * @logdrv : logical drive number if command for LD + * @channel : Channel on which physical device is located + * @target : SCSI target of the device + * @queuetag : unused + * @queueaction : unused + * @cdblen : length of the CDB + * @rsvd3 : reserved field + * @cdb : SCSI CDB + * @numsge : number of scatter-gather elements in the sg list + * @status : SCSI status of the command completed. + * @reqsenselen : amount of request sense data to be returned + * @reqsensearea : Sense information buffer + * @rsvd4 : reserved field + * @dataxferaddr : DMA data transfer address + * @dataxferlen : amount of the data to be transferred. + */ +typedef struct { + uint8_t timeout :3; + uint8_t ars :1; + uint8_t rsvd1 :1; + uint8_t cd_rom :1; + uint8_t rsvd2 :1; + uint8_t islogical :1; + uint8_t logdrv; + uint8_t channel; + uint8_t target; + uint8_t queuetag; + uint8_t queueaction; + uint8_t cdblen; + uint8_t rsvd3; + uint8_t cdb[16]; + uint8_t numsge; + uint8_t status; + uint8_t reqsenselen; + uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; + uint8_t rsvd4; + uint32_t dataxferaddr; + uint32_t dataxferlen; +} __attribute__ ((packed)) mraid_epassthru_t; + + +/** + * mraid_pinfo_t - product info, static information about the controller + * @data_size : current size in bytes (not including resvd) + * @config_signature : Current value is 0x00282008 + * @fw_version : Firmware version + * @bios_version : version of the BIOS + * @product_name : Name given to the controller + * @max_commands : Maximum concurrent commands supported + * @nchannels : Number of SCSI Channels detected + * @fc_loop_present : Number of Fibre Loops detected + * @mem_type : EDO, FPM, SDRAM etc + * @signature : + * @dram_size : In terms of MB + * @subsysid : device PCI subsystem ID + * @subsysvid : device PCI subsystem vendor ID + * @notify_counters : + * @pad1k : 135 + 889 resvd = 1024 total size + * + * This structures holds the information about the controller which is not + * expected to change dynamically. + * + * The current value of config signature is 0x00282008: + * 0x28 = MAX_LOGICAL_DRIVES, + * 0x20 = Number of stripes and + * 0x08 = Number of spans + */ +typedef struct { + uint32_t data_size; + uint32_t config_signature; + uint8_t fw_version[16]; + uint8_t bios_version[16]; + uint8_t product_name[80]; + uint8_t max_commands; + uint8_t nchannels; + uint8_t fc_loop_present; + uint8_t mem_type; + uint32_t signature; + uint16_t dram_size; + uint16_t subsysid; + uint16_t subsysvid; + uint8_t notify_counters; + uint8_t pad1k[889]; +} __attribute__ ((packed)) mraid_pinfo_t; + + +/** + * mraid_notify_t - the notification structure + * @global_counter : Any change increments this counter + * @param_counter : Indicates any params changed + * @param_id : Param modified - defined below + * @param_val : New val of last param modified + * @write_config_counter : write config occurred + * @write_config_rsvd : + * @ldrv_op_counter : Indicates ldrv op started/completed + * @ldrv_opid : ldrv num + * @ldrv_opcmd : ldrv operation - defined below + * @ldrv_opstatus : status of the operation + * @ldrv_state_counter : Indicates change of ldrv state + * @ldrv_state_id : ldrv num + * @ldrv_state_new : New state + * @ldrv_state_old : old state + * @pdrv_state_counter : Indicates change of ldrv state + * @pdrv_state_id : pdrv id + * @pdrv_state_new : New state + * @pdrv_state_old : old state + * @pdrv_fmt_counter : Indicates pdrv format started/over + * @pdrv_fmt_id : pdrv id + * @pdrv_fmt_val : format started/over + * @pdrv_fmt_rsvd : + * @targ_xfer_counter : Indicates SCSI-2 Xfer rate change + * @targ_xfer_id : pdrv Id + * @targ_xfer_val : new Xfer params of last pdrv + * @targ_xfer_rsvd : + * @fcloop_id_chg_counter : Indicates loopid changed + * @fcloopid_pdrvid : pdrv id + * @fcloop_id0 : loopid on fc loop 0 + * @fcloop_id1 : loopid on fc loop 1 + * @fcloop_state_counter : Indicates loop state changed + * @fcloop_state0 : state of fc loop 0 + * @fcloop_state1 : state of fc loop 1 + * @fcloop_state_rsvd : + */ +typedef struct { + uint32_t global_counter; + uint8_t param_counter; + uint8_t param_id; + uint16_t param_val; + uint8_t write_config_counter; + uint8_t write_config_rsvd[3]; + uint8_t ldrv_op_counter; + uint8_t ldrv_opid; + uint8_t ldrv_opcmd; + uint8_t ldrv_opstatus; + uint8_t ldrv_state_counter; + uint8_t ldrv_state_id; + uint8_t ldrv_state_new; + uint8_t ldrv_state_old; + uint8_t pdrv_state_counter; + uint8_t pdrv_state_id; + uint8_t pdrv_state_new; + uint8_t pdrv_state_old; + uint8_t pdrv_fmt_counter; + uint8_t pdrv_fmt_id; + uint8_t pdrv_fmt_val; + uint8_t pdrv_fmt_rsvd; + uint8_t targ_xfer_counter; + uint8_t targ_xfer_id; + uint8_t targ_xfer_val; + uint8_t targ_xfer_rsvd; + uint8_t fcloop_id_chg_counter; + uint8_t fcloopid_pdrvid; + uint8_t fcloop_id0; + uint8_t fcloop_id1; + uint8_t fcloop_state_counter; + uint8_t fcloop_state0; + uint8_t fcloop_state1; + uint8_t fcloop_state_rsvd; +} __attribute__ ((packed)) mraid_notify_t; + + +/** + * mraid_inquiry3_t - enquiry for device information + * + * @data_size : current size in bytes (not including resvd) + * @notify : + * @notify_rsvd : + * @rebuild_rate : rebuild rate (0% - 100%) + * @cache_flush_int : cache flush interval in seconds + * @sense_alert : + * @drive_insert_count : drive insertion count + * @battery_status : + * @num_ldrv : no. of Log Drives configured + * @recon_state : state of reconstruct + * @ldrv_op_status : logdrv Status + * @ldrv_size : size of each log drv + * @ldrv_prop : + * @ldrv_state : state of log drives + * @pdrv_state : state of phys drvs. + * @pdrv_format : + * @targ_xfer : phys device transfer rate + * @pad1k : 761 + 263reserved = 1024 bytes total size + */ +#define MAX_NOTIFY_SIZE 0x80 +#define CUR_NOTIFY_SIZE sizeof(mraid_notify_t) + +typedef struct { + uint32_t data_size; + + mraid_notify_t notify; + + uint8_t notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; + + uint8_t rebuild_rate; + uint8_t cache_flush_int; + uint8_t sense_alert; + uint8_t drive_insert_count; + + uint8_t battery_status; + uint8_t num_ldrv; + uint8_t recon_state[MAX_LOGICAL_DRIVES_40LD / 8]; + uint16_t ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8]; + + uint32_t ldrv_size[MAX_LOGICAL_DRIVES_40LD]; + uint8_t ldrv_prop[MAX_LOGICAL_DRIVES_40LD]; + uint8_t ldrv_state[MAX_LOGICAL_DRIVES_40LD]; + uint8_t pdrv_state[FC_MAX_PHYSICAL_DEVICES]; + uint16_t pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16]; + + uint8_t targ_xfer[80]; + uint8_t pad1k[263]; +} __attribute__ ((packed)) mraid_inquiry3_t; + + +/** + * mraid_adapinfo_t - information about the adapter + * @max_commands : max concurrent commands supported + * @rebuild_rate : rebuild rate - 0% thru 100% + * @max_targ_per_chan : max targ per channel + * @nchannels : number of channels on HBA + * @fw_version : firmware version + * @age_of_flash : number of times FW has been flashed + * @chip_set_value : contents of 0xC0000832 + * @dram_size : in MB + * @cache_flush_interval : in seconds + * @bios_version : + * @board_type : + * @sense_alert : + * @write_config_count : increase with every configuration change + * @drive_inserted_count : increase with every drive inserted + * @inserted_drive : channel:Id of inserted drive + * @battery_status : bit 0: battery module missing + * bit 1: VBAD + * bit 2: temprature high + * bit 3: battery pack missing + * bit 4,5: + * 00 - charge complete + * 01 - fast charge in progress + * 10 - fast charge fail + * 11 - undefined + * bit 6: counter > 1000 + * bit 7: Undefined + * @dec_fault_bus_info : + */ +typedef struct { + uint8_t max_commands; + uint8_t rebuild_rate; + uint8_t max_targ_per_chan; + uint8_t nchannels; + uint8_t fw_version[4]; + uint16_t age_of_flash; + uint8_t chip_set_value; + uint8_t dram_size; + uint8_t cache_flush_interval; + uint8_t bios_version[4]; + uint8_t board_type; + uint8_t sense_alert; + uint8_t write_config_count; + uint8_t battery_status; + uint8_t dec_fault_bus_info; +} __attribute__ ((packed)) mraid_adapinfo_t; + + +/** + * mraid_ldrv_info_t - information about the logical drives + * @nldrv : Number of logical drives configured + * @rsvd : + * @size : size of each logical drive + * @prop : + * @state : state of each logical drive + */ +typedef struct { + uint8_t nldrv; + uint8_t rsvd[3]; + uint32_t size[MAX_LOGICAL_DRIVES_8LD]; + uint8_t prop[MAX_LOGICAL_DRIVES_8LD]; + uint8_t state[MAX_LOGICAL_DRIVES_8LD]; +} __attribute__ ((packed)) mraid_ldrv_info_t; + + +/** + * mraid_pdrv_info_t - information about the physical drives + * @pdrv_state : state of each physical drive + */ +typedef struct { + uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES]; + uint8_t rsvd; +} __attribute__ ((packed)) mraid_pdrv_info_t; + + +/** + * mraid_inquiry_t - RAID inquiry, mailbox command 0x05 + * @mraid_adapinfo_t : adapter information + * @mraid_ldrv_info_t : logical drives information + * @mraid_pdrv_info_t : physical drives information + */ +typedef struct { + mraid_adapinfo_t adapter_info; + mraid_ldrv_info_t logdrv_info; + mraid_pdrv_info_t pdrv_info; +} __attribute__ ((packed)) mraid_inquiry_t; + + +/** + * mraid_extinq_t - RAID extended inquiry, mailbox command 0x04 + * + * @raid_inq : raid inquiry + * @phys_drv_format : + * @stack_attn : + * @modem_status : + * @rsvd : + */ +typedef struct { + mraid_inquiry_t raid_inq; + uint16_t phys_drv_format[MAX_MBOX_CHANNELS]; + uint8_t stack_attn; + uint8_t modem_status; + uint8_t rsvd[2]; +} __attribute__ ((packed)) mraid_extinq_t; + + +/** + * adap_device_t - device information + * @channel : channel fpor the device + * @target : target ID of the device + */ +typedef struct { + uint8_t channel; + uint8_t target; +}__attribute__ ((packed)) adap_device_t; + + +/** + * adap_span_40ld_t - 40LD span + * @start_blk : starting block + * @num_blks : number of blocks + */ +typedef struct { + uint32_t start_blk; + uint32_t num_blks; + adap_device_t device[MAX_ROW_SIZE_40LD]; +}__attribute__ ((packed)) adap_span_40ld_t; + + +/** + * adap_span_8ld_t - 8LD span + * @start_blk : starting block + * @num_blks : number of blocks + */ +typedef struct { + uint32_t start_blk; + uint32_t num_blks; + adap_device_t device[MAX_ROW_SIZE_8LD]; +}__attribute__ ((packed)) adap_span_8ld_t; + + +/** + * logdrv_param_t - logical drives parameters + * + * @span_depth : total number of spans + * @level : RAID level + * @read_ahead : read ahead, no read ahead, adaptive read ahead + * @stripe_sz : encoded stripe size + * @status : status of the logical drive + * @write_mode : write mode, write_through/write_back + * @direct_io : direct io or through cache + * @row_size : number of stripes in a row + */ +typedef struct { + uint8_t span_depth; + uint8_t level; + uint8_t read_ahead; + uint8_t stripe_sz; + uint8_t status; + uint8_t write_mode; + uint8_t direct_io; + uint8_t row_size; +} __attribute__ ((packed)) logdrv_param_t; + + +/** + * logdrv_40ld_t - logical drive definition for 40LD controllers + * @lparam : logical drives parameters + * @span : span + */ +typedef struct { + logdrv_param_t lparam; + adap_span_40ld_t span[SPAN_DEPTH_8_SPANS]; +}__attribute__ ((packed)) logdrv_40ld_t; + + +/** + * logdrv_8ld_span8_t - logical drive definition for 8LD controllers + * @lparam : logical drives parameters + * @span : span + * + * 8-LD logical drive with upto 8 spans + */ +typedef struct { + logdrv_param_t lparam; + adap_span_8ld_t span[SPAN_DEPTH_8_SPANS]; +}__attribute__ ((packed)) logdrv_8ld_span8_t; + + +/** + * logdrv_8ld_span4_t - logical drive definition for 8LD controllers + * @lparam : logical drives parameters + * @span : span + * + * 8-LD logical drive with upto 4 spans + */ +typedef struct { + logdrv_param_t lparam; + adap_span_8ld_t span[SPAN_DEPTH_4_SPANS]; +}__attribute__ ((packed)) logdrv_8ld_span4_t; + + +/** + * phys_drive_t - physical device information + * @type : Type of the device + * @cur_status : current status of the device + * @tag_depth : Level of tagging + * @sync_neg : sync negotiation - ENABLE or DISBALE + * @size : configurable size in terms of 512 byte + */ +typedef struct { + uint8_t type; + uint8_t cur_status; + uint8_t tag_depth; + uint8_t sync_neg; + uint32_t size; +}__attribute__ ((packed)) phys_drive_t; + + +/** + * disk_array_40ld_t - disk array for 40LD controllers + * @numldrv : number of logical drives + * @resvd : + * @ldrv : logical drives information + * @pdrv : physical drives information + */ +typedef struct { + uint8_t numldrv; + uint8_t resvd[3]; + logdrv_40ld_t ldrv[MAX_LOGICAL_DRIVES_40LD]; + phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; +}__attribute__ ((packed)) disk_array_40ld_t; + + +/** + * disk_array_8ld_span8_t - disk array for 8LD controllers + * @numldrv : number of logical drives + * @resvd : + * @ldrv : logical drives information + * @pdrv : physical drives information + * + * Disk array for 8LD logical drives with upto 8 spans + */ +typedef struct { + uint8_t numldrv; + uint8_t resvd[3]; + logdrv_8ld_span8_t ldrv[MAX_LOGICAL_DRIVES_8LD]; + phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; +}__attribute__ ((packed)) disk_array_8ld_span8_t; + + +/** + * disk_array_8ld_span4_t - disk array for 8LD controllers + * @numldrv : number of logical drives + * @resvd : + * @ldrv : logical drives information + * @pdrv : physical drives information + * + * Disk array for 8LD logical drives with upto 4 spans + */ +typedef struct { + uint8_t numldrv; + uint8_t resvd[3]; + logdrv_8ld_span4_t ldrv[MAX_LOGICAL_DRIVES_8LD]; + phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; +}__attribute__ ((packed)) disk_array_8ld_span4_t; + + +/** + * private_bios_data - bios private data for boot devices + * @geometry : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB, + * 0x1000 - 8GB, Others values are invalid + * @unused : bits 4-7 are unused + * @boot_drv : logical drive set as boot drive, 0..7 - for 8LD cards, + * 0..39 - for 40LD cards + * @cksum : 0-(sum of first 13 bytes of this structure) + */ +struct private_bios_data { + uint8_t geometry :4; + uint8_t unused :4; + uint8_t boot_drv; + uint8_t rsvd[12]; + uint16_t cksum; +} __attribute__ ((packed)); + + +/** + * mbox_sgl64 - 64-bit scatter list for mailbox based controllers + * @address : address of the buffer + * @length : data transfer length + */ +typedef struct { + uint64_t address; + uint32_t length; +} __attribute__ ((packed)) mbox_sgl64; + +/** + * mbox_sgl32 - 32-bit scatter list for mailbox based controllers + * @address : address of the buffer + * @length : data transfer length + */ +typedef struct { + uint32_t address; + uint32_t length; +} __attribute__ ((packed)) mbox_sgl32; + +#endif // _MRAID_MBOX_DEFS_H_ + +/* vim: set ts=8 sw=8 tw=78: */ diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h new file mode 100644 index 000000000..e15117529 --- /dev/null +++ b/drivers/scsi/megaraid/mega_common.h @@ -0,0 +1,283 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : mega_common.h + * + * Libaray of common routine used by all low-level megaraid drivers + */ + +#ifndef _MEGA_COMMON_H_ +#define _MEGA_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define LSI_MAX_CHANNELS 16 +#define LSI_MAX_LOGICAL_DRIVES_64LD (64+1) + + +/** + * scb_t - scsi command control block + * @param ccb : command control block for individual driver + * @param list : list of control blocks + * @param gp : general purpose field for LLDs + * @param sno : all SCBs have a serial number + * @param scp : associated scsi command + * @param state : current state of scb + * @param dma_dir : direction of data transfer + * @param dma_type : transfer with sg list, buffer, or no data transfer + * @param dev_channel : actual channel on the device + * @param dev_target : actual target on the device + * @param status : completion status + * + * This is our central data structure to issue commands the each driver. + * Driver specific data structures are maintained in the ccb field. + * scb provides a field 'gp', which can be used by LLD for its own purposes + * + * dev_channel and dev_target must be initialized with the actual channel and + * target on the controller. + */ +typedef struct { + caddr_t ccb; + struct list_head list; + unsigned long gp; + unsigned int sno; + struct scsi_cmnd *scp; + uint32_t state; + uint32_t dma_direction; + uint32_t dma_type; + uint16_t dev_channel; + uint16_t dev_target; + uint32_t status; +} scb_t; + +/* + * SCB states as it transitions from one state to another + */ +#define SCB_FREE 0x0000 /* on the free list */ +#define SCB_ACTIVE 0x0001 /* off the free list */ +#define SCB_PENDQ 0x0002 /* on the pending queue */ +#define SCB_ISSUED 0x0004 /* issued - owner f/w */ +#define SCB_ABORT 0x0008 /* Got an abort for this one */ +#define SCB_RESET 0x0010 /* Got a reset for this one */ + +/* + * DMA types for scb + */ +#define MRAID_DMA_NONE 0x0000 /* no data transfer for this command */ +#define MRAID_DMA_WSG 0x0001 /* data transfer using a sg list */ +#define MRAID_DMA_WBUF 0x0002 /* data transfer using a contiguous buffer */ + + +/** + * struct adapter_t - driver's initialization structure + * @param dpc_h : tasklet handle + * @param pdev : pci configuration pointer for kernel + * @param host : pointer to host structure of mid-layer + * @param host_lock : pointer to appropriate lock + * @param lock : synchronization lock for mid-layer and driver + * @param quiescent : driver is quiescent for now. + * @param outstanding_cmds : number of commands pending in the driver + * @param kscb_list : pointer to the bulk of SCBs pointers for IO + * @param kscb_pool : pool of free scbs for IO + * @param kscb_pool_lock : lock for pool of free scbs + * @param pend_list : pending commands list + * @param pend_list_lock : exlusion lock for pending commands list + * @param completed_list : list of completed commands + * @param completed_list_lock : exclusion lock for list of completed commands + * @param sglen : max sg elements supported + * @param device_ids : to convert kernel device addr to our devices. + * @param raid_device : raid adapter specific pointer + * @param max_channel : maximum channel number supported - inclusive + * @param max_target : max target supported - inclusive + * @param max_lun : max lun supported - inclusive + * @param unique_id : unique identifier for each adapter + * @param irq : IRQ for this adapter + * @param ito : internal timeout value, (-1) means no timeout + * @param ibuf : buffer to issue internal commands + * @param ibuf_dma_h : dma handle for the above buffer + * @param uscb_list : SCB pointers for user cmds, common mgmt module + * @param uscb_pool : pool of SCBs for user commands + * @param uscb_pool_lock : exclusion lock for these SCBs + * @param max_cmds : max outstanding commands + * @param fw_version : firmware version + * @param bios_version : bios version + * @param max_cdb_sz : biggest CDB size supported. + * @param ha : is high availability present - clustering + * @param init_id : initiator ID, the default value should be 7 + * @param max_sectors : max sectors per request + * @param cmd_per_lun : max outstanding commands per LUN + * @param being_detached : set when unloading, no more mgmt calls + * + * + * mraid_setup_device_map() can be called anytime after the device map is + * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is + * required, usually from LLD's queue entry point. The formar API sets up the + * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the + * device in question is a logical drive. + * + * quiescent flag should be set by the driver if it is not accepting more + * commands + * + * NOTE: The fields of this structures are placed to minimize cache misses + */ + +// amount of space required to store the bios and firmware version strings +#define VERSION_SIZE 16 + +typedef struct { + struct tasklet_struct dpc_h; + struct pci_dev *pdev; + struct Scsi_Host *host; + spinlock_t *host_lock; + spinlock_t lock; + uint8_t quiescent; + int outstanding_cmds; + scb_t *kscb_list; + struct list_head kscb_pool; + spinlock_t kscb_pool_lock; + struct list_head pend_list; + spinlock_t pend_list_lock; + struct list_head completed_list; + spinlock_t completed_list_lock; + uint16_t sglen; + int device_ids[LSI_MAX_CHANNELS] + [LSI_MAX_LOGICAL_DRIVES_64LD]; + caddr_t raid_device; + uint8_t max_channel; + uint16_t max_target; + uint8_t max_lun; + + uint32_t unique_id; + uint8_t irq; + uint8_t ito; + caddr_t ibuf; + dma_addr_t ibuf_dma_h; + scb_t *uscb_list; + struct list_head uscb_pool; + spinlock_t uscb_pool_lock; + int max_cmds; + uint8_t fw_version[VERSION_SIZE]; + uint8_t bios_version[VERSION_SIZE]; + uint8_t max_cdb_sz; + uint8_t ha; + uint16_t init_id; + uint16_t max_sectors; + uint16_t cmd_per_lun; + atomic_t being_detached; +} adapter_t; + +#define SCSI_FREE_LIST_LOCK(adapter) (&adapter->kscb_pool_lock) +#define USER_FREE_LIST_LOCK(adapter) (&adapter->uscb_pool_lock) +#define PENDING_LIST_LOCK(adapter) (&adapter->pend_list_lock) +#define COMPLETED_LIST_LOCK(adapter) (&adapter->completed_list_lock) + + +// conversion from scsi command +#define SCP2HOST(scp) (scp)->device->host // to host +#define SCP2HOSTDATA(scp) SCP2HOST(scp)->hostdata // to soft state +#define SCP2CHANNEL(scp) (scp)->device->channel // to channel +#define SCP2TARGET(scp) (scp)->device->id // to target +#define SCP2LUN(scp) (scp)->device->lun // to LUN + +// generic macro to convert scsi command and host to controller's soft state +#define SCSIHOST2ADAP(host) (((caddr_t *)(host->hostdata))[0]) +#define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp)) + + +/** + * MRAID_GET_DEVICE_MAP - device ids + * @param adp - Adapter's soft state + * @param scp - mid-layer scsi command pointer + * @param p_chan - physical channel on the controller + * @param target - target id of the device or logical drive number + * @param islogical - set if the command is for the logical drive + * + * Macro to retrieve information about device class, logical or physical and + * the corresponding physical channel and target or logical drive number + **/ +#define MRAID_IS_LOGICAL(adp, scp) \ + (SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0 + +#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \ + /* \ + * Is the request coming for the virtual channel \ + */ \ + islogical = MRAID_IS_LOGICAL(adp, scp); \ + \ + /* \ + * Get an index into our table of drive ids mapping \ + */ \ + if (islogical) { \ + p_chan = 0xFF; \ + target = \ + (adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)]; \ + } \ + else { \ + p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)] \ + [SCP2TARGET(scp)] >> 8) & 0xFF; \ + target = ((adp)->device_ids[SCP2CHANNEL(scp)] \ + [SCP2TARGET(scp)] & 0xFF); \ + } + +/* + * ### Helper routines ### + */ +#define LSI_DBGLVL mraid_debug_level // each LLD must define a global + // mraid_debug_level + +#ifdef DEBUG +#if defined (_ASSERT_PANIC) +#define ASSERT_ACTION panic +#else +#define ASSERT_ACTION printk +#endif + +#define ASSERT(expression) \ + if (!(expression)) { \ + ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \ + #expression, __FILE__, __LINE__, __FUNCTION__); \ + } +#else +#define ASSERT(expression) +#endif + +/* + * struct mraid_pci_blk - structure holds DMA memory block info + * @param vaddr : virtual address to a memory block + * @param dma_addr : DMA handle to a memory block + * + * This structure is filled up for the caller. It is the responsibilty of the + * caller to allocate this array big enough to store addresses for all + * requested elements + */ +struct mraid_pci_blk { + caddr_t vaddr; + dma_addr_t dma_addr; +}; + +#endif // _MEGA_COMMON_H_ + +// vim: set ts=8 sw=8 tw=78: diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h new file mode 100644 index 000000000..44584ca08 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_ioctl.h @@ -0,0 +1,291 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : megaraid_ioctl.h + * + * Definitions to interface with user level applications + */ + +#ifndef _MEGARAID_IOCTL_H_ +#define _MEGARAID_IOCTL_H_ + +#include +#include + +#include "mbox_defs.h" + +/** + * con_log() - console log routine + * @param level : indicates the severity of the message. + * @fparam mt : format string + * + * con_log displays the error messages on the console based on the current + * debug level. Also it attaches the appropriate kernel severity level with + * the message. + * + * + * consolge messages debug levels + */ +#define CL_ANN 0 /* print unconditionally, announcements */ +#define CL_DLEVEL1 1 /* debug level 1, informative */ +#define CL_DLEVEL2 2 /* debug level 2, verbose */ +#define CL_DLEVEL3 3 /* debug level 3, very verbose */ + +#define con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt; + +/* + * Definitions & Declarations needed to use common management module + */ + +#define MEGAIOC_MAGIC 'm' +#define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0, mimd_t) + +#define MEGAIOC_QNADAP 'm' /* Query # of adapters */ +#define MEGAIOC_QDRVRVER 'e' /* Query driver version */ +#define MEGAIOC_QADAPINFO 'g' /* Query adapter information */ + +#define USCSICMD 0x80 +#define UIOC_RD 0x00001 +#define UIOC_WR 0x00002 + +#define MBOX_CMD 0x00000 +#define GET_DRIVER_VER 0x10000 +#define GET_N_ADAP 0x20000 +#define GET_ADAP_INFO 0x30000 +#define GET_CAP 0x40000 +#define GET_STATS 0x50000 +#define GET_IOCTL_VERSION 0x01 + +#define EXT_IOCTL_SIGN_SZ 16 +#define EXT_IOCTL_SIGN "$$_EXTD_IOCTL_$$" + +#define MBOX_LEGACY 0x00 /* ioctl has legacy mbox*/ +#define MBOX_HPE 0x01 /* ioctl has hpe mbox */ + +#define APPTYPE_MIMD 0x00 /* old existing apps */ +#define APPTYPE_UIOC 0x01 /* new apps using uioc */ + +#define IOCTL_ISSUE 0x00000001 /* Issue ioctl */ +#define IOCTL_ABORT 0x00000002 /* Abort previous ioctl */ + +#define DRVRTYPE_MBOX 0x00000001 /* regular mbox driver */ +#define DRVRTYPE_HPE 0x00000002 /* new hpe driver */ + +#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) ) +#define GETADAP(mkadap) ((mkadap) ^ MEGAIOC_MAGIC << 8) + +#define MAX_DMA_POOLS 5 /* 4k, 8k, 16k, 32k, 64k*/ + + +/** + * struct uioc_t - the common ioctl packet structure + * + * @signature : Must be "$$_EXTD_IOCTL_$$" + * @mb_type : Type of the mail box (MB_LEGACY or MB_HPE) + * @app_type : Type of the issuing application (existing or new) + * @opcode : Opcode of the command + * @adapno : Adapter number + * @cmdbuf : Pointer to buffer - can point to mbox or plain data buffer + * @xferlen : xferlen for DCMD and non mailbox commands + * @data_dir : Direction of the data transfer + * @status : Status from the driver + * @reserved : reserved bytes for future expansion + * + * @user_data : user data transfer address is saved in this + * @user_data_len: length of the data buffer sent by user app + * @user_pthru : user passthru address is saves in this (null if DCMD) + * @pthru32 : kernel address passthru (allocated per kioc) + * @pthru32_h : physicall address of @pthru32 + * @list : for kioc free pool list maintenance + * @done : call back routine for llds to call when kioc is completed + * @buf_vaddr : dma pool buffer attached to kioc for data transfer + * @buf_paddr : physical address of the dma pool buffer + * @pool_index : index of the dma pool that @buf_vaddr is taken from + * @free_buf : indicates if buffer needs to be freed after kioc completes + * + * Note : All LSI drivers understand only this packet. Any other + * : format sent by applications would be converted to this. + */ +typedef struct uioc { + +/* User Apps: */ + + uint8_t signature[EXT_IOCTL_SIGN_SZ]; + uint16_t mb_type; + uint16_t app_type; + uint32_t opcode; + uint32_t adapno; + uint64_t cmdbuf; + uint32_t xferlen; + uint32_t data_dir; + int32_t status; + uint8_t reserved[128]; + +/* Driver Data: */ + void __user * user_data; + uint32_t user_data_len; + mraid_passthru_t __user *user_pthru; + + mraid_passthru_t *pthru32; + dma_addr_t pthru32_h; + + struct list_head list; + void (*done)(struct uioc*); + + caddr_t buf_vaddr; + dma_addr_t buf_paddr; + uint8_t pool_index; + uint8_t free_buf; + +} __attribute__ ((aligned(1024),packed)) uioc_t; + + +/** + * struct mraid_hba_info - information about the controller + * + * @param pci_vendor_id : PCI vendor id + * @param pci_device_id : PCI device id + * @param subsystem_vendor_id : PCI subsystem vendor id + * @param subsystem_device_id : PCI subsystem device id + * @param baseport : base port of hba memory + * @param pci_bus : PCI bus + * @param pci_dev_fn : PCI device/function values + * @param irq : interrupt vector for the device + * + * Extended information of 256 bytes about the controller. Align on the single + * byte boundary so that 32-bit applications can be run on 64-bit platform + * drivers withoug re-compilation. + * NOTE: reduce the number of reserved bytes whenever new field are added, so + * that total size of the structure remains 256 bytes. + */ +typedef struct mraid_hba_info { + + uint16_t pci_vendor_id; + uint16_t pci_device_id; + uint16_t subsys_vendor_id; + uint16_t subsys_device_id; + + uint64_t baseport; + uint8_t pci_bus; + uint8_t pci_dev_fn; + uint8_t pci_slot; + uint8_t irq; + + uint32_t unique_id; + uint32_t host_no; + + uint8_t num_ldrv; +} __attribute__ ((aligned(256), packed)) mraid_hba_info_t; + + +/** + * mcontroller : adapter info structure for old mimd_t apps + * + * @base : base address + * @irq : irq number + * @numldrv : number of logical drives + * @pcibus : pci bus + * @pcidev : pci device + * @pcifun : pci function + * @pciid : pci id + * @pcivendor : vendor id + * @pcislot : slot number + * @uid : unique id + */ +typedef struct mcontroller { + + uint64_t base; + uint8_t irq; + uint8_t numldrv; + uint8_t pcibus; + uint16_t pcidev; + uint8_t pcifun; + uint16_t pciid; + uint16_t pcivendor; + uint8_t pcislot; + uint32_t uid; + +} __attribute__ ((packed)) mcontroller_t; + + +/** + * mm_dmapool_t : Represents one dma pool with just one buffer + * + * @vaddr : Virtual address + * @paddr : DMA physicall address + * @bufsize : In KB - 4 = 4k, 8 = 8k etc. + * @handle : Handle to the dma pool + * @lock : lock to synchronize access to the pool + * @in_use : If pool already in use, attach new block + */ +typedef struct mm_dmapool { + caddr_t vaddr; + dma_addr_t paddr; + uint32_t buf_size; + struct dma_pool *handle; + spinlock_t lock; + uint8_t in_use; +} mm_dmapool_t; + + +/** + * mraid_mmadp_t: Structure that drivers pass during (un)registration + * + * @unique_id : Any unique id (usually PCI bus+dev+fn) + * @drvr_type : megaraid or hpe (DRVRTYPE_MBOX or DRVRTYPE_HPE) + * @drv_data : Driver specific; not touched by the common module + * @timeout : timeout for issued kiocs + * @max_kioc : Maximum ioctl packets acceptable by the lld + * @pdev : pci dev; used for allocating dma'ble memory + * @issue_uioc : Driver supplied routine to issue uioc_t commands + * : issue_uioc(drvr_data, kioc, ISSUE/ABORT, uioc_done) + * @list : attach with the global list of adapters + * @kioc_list : block of mem for @max_kioc number of kiocs + * @kioc_pool : pool of free kiocs + * @kioc_pool_lock : protection for free pool + * @kioc_semaphore : so as not to exceed @max_kioc parallel ioctls + * @mbox_list : block of mem for @max_kioc number of mboxes + * @pthru_dma_pool : DMA pool to allocate passthru packets + * @dma_pool_list : array of dma pools + */ + +typedef struct mraid_mmadp { + +/* Filled by driver */ + + uint32_t unique_id; + uint32_t drvr_type; + unsigned long drvr_data; + uint8_t timeout; + uint8_t max_kioc; + + struct pci_dev *pdev; + + int(*issue_uioc)(unsigned long, uioc_t *, uint32_t); + +/* Maintained by common module */ + + struct list_head list; + uioc_t *kioc_list; + struct list_head kioc_pool; + spinlock_t kioc_pool_lock; + struct semaphore kioc_semaphore; + + mbox64_t *mbox_list; + struct dma_pool *pthru_dma_pool; + mm_dmapool_t dma_pool_list[MAX_DMA_POOLS]; + +} mraid_mmadp_t; + +int mraid_mm_register_adp(mraid_mmadp_t *); +int mraid_mm_unregister_adp(uint32_t); + +#endif /* _MEGARAID_IOCTL_H_ */ diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c new file mode 100644 index 000000000..7afd6a5f1 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -0,0 +1,3891 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : megaraid_mbox.c + * Version : v2.20.4 (September 27 2004) + * + * Authors: + * Atul Mukker + * Sreenivas Bagalkote + * Manoj Jose + * + * List of supported controllers + * + * OEM Product Name VID DID SSVID SSID + * --- ------------ --- --- ---- ---- + * Dell PERC3/QC 101E 1960 1028 0471 + * Dell PERC3/DC 101E 1960 1028 0493 + * Dell PERC3/SC 101E 1960 1028 0475 + * Dell PERC3/Di 1028 1960 1028 0123 + * Dell PERC4/SC 1000 1960 1028 0520 + * Dell PERC4/DC 1000 1960 1028 0518 + * Dell PERC4/QC 1000 0407 1028 0531 + * Dell PERC4/Di 1028 000F 1028 014A + * Dell PERC 4e/Si 1028 0013 1028 016c + * Dell PERC 4e/Di 1028 0013 1028 016d + * Dell PERC 4e/Di 1028 0013 1028 016e + * Dell PERC 4e/Di 1028 0013 1028 016f + * Dell PERC 4e/Di 1028 0013 1028 0170 + * Dell PERC 4e/DC 1000 0408 1028 0002 + * Dell PERC 4e/SC 1000 0408 1028 0001 + * + * + * LSI MegaRAID SCSI 320-0 1000 1960 1000 A520 + * LSI MegaRAID SCSI 320-1 1000 1960 1000 0520 + * LSI MegaRAID SCSI 320-2 1000 1960 1000 0518 + * LSI MegaRAID SCSI 320-0X 1000 0407 1000 0530 + * LSI MegaRAID SCSI 320-2X 1000 0407 1000 0532 + * LSI MegaRAID SCSI 320-4X 1000 0407 1000 0531 + * LSI MegaRAID SCSI 320-1E 1000 0408 1000 0001 + * LSI MegaRAID SCSI 320-2E 1000 0408 1000 0002 + * LSI MegaRAID SATA 150-4 1000 1960 1000 4523 + * LSI MegaRAID SATA 150-6 1000 1960 1000 0523 + * LSI MegaRAID SATA 300-4X 1000 0409 1000 3004 + * LSI MegaRAID SATA 300-8X 1000 0409 1000 3008 + * + * INTEL RAID Controller SRCU42X 1000 0407 8086 0532 + * INTEL RAID Controller SRCS16 1000 1960 8086 0523 + * INTEL RAID Controller SRCU42E 1000 0408 8086 0002 + * INTEL RAID Controller SRCZCRX 1000 0407 8086 0530 + * INTEL RAID Controller SRCS28X 1000 0409 8086 3008 + * INTEL RAID Controller SROMBU42E 1000 0408 8086 3431 + * INTEL RAID Controller SROMBU42E 1000 0408 8086 3499 + * INTEL RAID Controller SRCU51L 1000 1960 8086 0520 + * + * + * FSC MegaRAID PCI Express ROMB 1000 0408 1734 1065 + * + * + * ACER MegaRAID ROMB-2E 1000 0408 1025 004D + * + * + * For history of changes, see Documentation/ChangeLog.megaraid + */ + +#include "megaraid_mbox.h" + +static int megaraid_init(void); +static void megaraid_exit(void); + +static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); +static void megaraid_detach_one(struct pci_dev *); +static void megaraid_mbox_shutdown(struct device *); + +static int megaraid_io_attach(adapter_t *); +static void megaraid_io_detach(adapter_t *); + +static int megaraid_init_mbox(adapter_t *); +static void megaraid_fini_mbox(adapter_t *); + +static int megaraid_alloc_cmd_packets(adapter_t *); +static void megaraid_free_cmd_packets(adapter_t *); + +static int megaraid_mbox_setup_dma_pools(adapter_t *); +static void megaraid_mbox_teardown_dma_pools(adapter_t *); + +static int megaraid_abort_handler(struct scsi_cmnd *); +static int megaraid_reset_handler(struct scsi_cmnd *); + +static int mbox_post_sync_cmd(adapter_t *, uint8_t []); +static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []); +static int megaraid_busywait_mbox(mraid_device_t *); +static int megaraid_mbox_product_info(adapter_t *); +static int megaraid_mbox_extended_cdb(adapter_t *); +static int megaraid_mbox_support_ha(adapter_t *, uint16_t *); +static int megaraid_mbox_support_random_del(adapter_t *); +static int megaraid_mbox_get_max_sg(adapter_t *); +static void megaraid_mbox_enum_raid_scsi(adapter_t *); +static void megaraid_mbox_flush_cache(adapter_t *); + +static void megaraid_mbox_display_scb(adapter_t *, scb_t *); +static void megaraid_mbox_setup_device_map(adapter_t *); + +static int megaraid_queue_command(struct scsi_cmnd *, + void (*)(struct scsi_cmnd *)); +static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static void megaraid_mbox_runpendq(adapter_t *, scb_t *); +static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, + struct scsi_cmnd *); +static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *, + struct scsi_cmnd *); + +static irqreturn_t megaraid_isr(int, void *, struct pt_regs *); + +static void megaraid_mbox_dpc(unsigned long); + +static int megaraid_cmm_register(adapter_t *); +static int megaraid_cmm_unregister(adapter_t *); +static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t); +static int megaraid_mbox_mm_command(adapter_t *, uioc_t *); +static void megaraid_mbox_mm_done(adapter_t *, scb_t *); +static int gather_hbainfo(adapter_t *, mraid_hba_info_t *); +static int wait_till_fw_empty(adapter_t *); + + + +MODULE_AUTHOR("LSI Logic Corporation"); +MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MEGARAID_VERSION); + +/* + * ### modules parameters for driver ### + */ + +/** + * Set to enable driver to expose unconfigured disk to kernel + */ +static int megaraid_expose_unconf_disks = 0; +module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0); +MODULE_PARM_DESC(unconf_disks, + "Set to expose unconfigured disks to kernel (default=0)"); + +/** + * driver wait time if the adapter's mailbox is busy + */ +static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT; +module_param_named(busy_wait, max_mbox_busy_wait, int, 0); +MODULE_PARM_DESC(busy_wait, + "Max wait for mailbox in microseconds if busy (default=10)"); + +/** + * number of sectors per IO command + */ +static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS; +module_param_named(max_sectors, megaraid_max_sectors, int, 0); +MODULE_PARM_DESC(max_sectors, + "Maximum number of sectors per IO command (default=128)"); + +/** + * number of commands per logical unit + */ +static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN; +module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0); +MODULE_PARM_DESC(cmd_per_lun, + "Maximum number of commands per logical unit (default=64)"); + + +/** + * Fast driver load option, skip scanning for physical devices during load. + * This would result in non-disk devices being skipped during driver load + * time. These can be later added though, using /proc/scsi/scsi + */ +static unsigned int megaraid_fast_load = 0; +module_param_named(fast_load, megaraid_fast_load, int, 0); +MODULE_PARM_DESC(fast_load, + "Faster loading of the driver, skips physical devices! (default=0)"); + + +/** + * mraid_debug level - threshold for amount of information to be displayed by + * the driver. This level can be changed through modules parameters, ioctl or + * sysfs/proc interface. By default, print the announcement messages only. + */ +int mraid_debug_level = CL_ANN; +module_param_named(debug_level, mraid_debug_level, int, 0); +MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)"); + +/* + * ### global data ### + */ +static uint8_t megaraid_mbox_version[8] = + { 0x02, 0x20, 0x04, 0x00, 9, 27, 20, 4 }; + + +/* + * PCI table for all supported controllers. + */ +static struct pci_device_id pci_id_table_g[] = { + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4_DI_DISCOVERY, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_DI_DISCOVERY, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4_SC, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_SC, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4_DC, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_DC, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4_QC, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_QC, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4_DI_EVERGLADES, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4_DI_EVERGLADES, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_SI_BIGBEND, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_SI_BIGBEND, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_KOBUK, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_KOBUK, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_CORVETTE, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_CORVETTE, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_EXPEDITION, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION, + }, + { + PCI_VENDOR_ID_DELL, + PCI_DEVICE_ID_PERC4E_DI_GUADALUPE, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4E_DC_320_2E, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_DC_320_2E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_PERC4E_SC_320_1E, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC4E_SC_320_1E, + }, + { + PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC3_QC, + }, + { + PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC3_DC, + }, + { + PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, + PCI_VENDOR_ID_DELL, + PCI_SUBSYS_ID_PERC3_SC, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_0, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_0, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_1, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_1, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_2, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_2, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_0x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_2x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_4x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_1E, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SCSI_320_2E, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_I4_133_RAID, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_I4_133_RAID, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_150_4, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_150_4, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_150_6, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_150_6, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_300_4x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_300_4x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_SATA_300_8x, + PCI_VENDOR_ID_LSI_LOGIC, + PCI_SUBSYS_ID_MEGARAID_SATA_300_8x, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCU42X, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCU42X, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCS16, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCS16, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCU42E, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCU42E, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCZCRX, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCS28X, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCS28X, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK, + PCI_VENDOR_ID_INTEL, + PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB, + PCI_SUBSYS_ID_FSC, + PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB, + }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E, + PCI_VENDOR_ID_AI, + PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E, + }, + {0} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, pci_id_table_g); + + +static struct pci_driver megaraid_pci_driver_g = { + .name = "megaraid", + .id_table = pci_id_table_g, + .probe = megaraid_probe_one, + .remove = __devexit_p(megaraid_detach_one), + .driver = { + .shutdown = megaraid_mbox_shutdown, + } +}; + + +/* + * Scsi host template for megaraid unified driver + */ +static struct scsi_host_template megaraid_template_g = { + .module = THIS_MODULE, + .name = "LSI Logic MegaRAID driver", + .proc_name = "megaraid", + .queuecommand = megaraid_queue_command, + .eh_abort_handler = megaraid_abort_handler, + .eh_device_reset_handler = megaraid_reset_handler, + .eh_bus_reset_handler = megaraid_reset_handler, + .eh_host_reset_handler = megaraid_reset_handler, + .use_clustering = ENABLE_CLUSTERING, +}; + + +/** + * megaraid_init - module load hook + * + * We register ourselves as hotplug enabled module and let PCI subsystem + * discover our adaters + **/ +static int __init +megaraid_init(void) +{ + int rval; + + // Announce the driver version + con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION, + MEGARAID_EXT_VERSION)); + + // check validity of module parameters + if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: max commands per lun reset to %d\n", + MBOX_MAX_SCSI_CMDS)); + + megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; + } + + + // register as a PCI hot-plug driver module + if ((rval = pci_module_init(&megaraid_pci_driver_g))) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not register hotplug support.\n")); + } + + return rval; +} + + +/** + * megaraid_exit - driver unload entry point + * + * We simply unwrap the megaraid_init routine here + */ +static void __exit +megaraid_exit(void) +{ + con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); + + // unregister as PCI hotplug driver + pci_unregister_driver(&megaraid_pci_driver_g); + + return; +} + + +/** + * megaraid_probe_one - PCI hotplug entry point + * @param pdev : handle to this controller's PCI configuration space + * @param id : pci device id of the class of controllers + * + * This routine should be called whenever a new adapter is detected by the + * PCI hotplug susbsytem. + **/ +static int __devinit +megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + adapter_t *adapter; + + + // detected a new controller + con_log(CL_ANN, (KERN_INFO + "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device)); + + con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); + + if (pci_enable_device(pdev)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: pci_enable_device failed\n")); + + return -ENODEV; + } + + // Enable bus-mastering on this controller + pci_set_master(pdev); + + // Allocate the per driver initialization structure + adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL); + + if (adapter == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__)); + + goto out_probe_one; + } + memset(adapter, 0, sizeof(adapter_t)); + + + // set up PCI related soft state and other pre-known parameters + adapter->unique_id = pdev->bus->number << 8 | pdev->devfn; + adapter->irq = pdev->irq; + adapter->pdev = pdev; + + atomic_set(&adapter->being_detached, 0); + + // Setup the default DMA mask. This would be changed later on + // depending on hardware capabilities + if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFF) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: pci_set_dma_mask failed:%d\n", __LINE__)); + + goto out_free_adapter; + } + + + // Initialize the synchronization lock for kernel and LLD + spin_lock_init(&adapter->lock); + adapter->host_lock = &adapter->lock; + + + // Initialize the command queues: the list of free SCBs and the list + // of pending SCBs. + INIT_LIST_HEAD(&adapter->kscb_pool); + spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); + + INIT_LIST_HEAD(&adapter->pend_list); + spin_lock_init(PENDING_LIST_LOCK(adapter)); + + INIT_LIST_HEAD(&adapter->completed_list); + spin_lock_init(COMPLETED_LIST_LOCK(adapter)); + + + // Start the mailbox based controller + if (megaraid_init_mbox(adapter) != 0) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: maibox adapter did not initialize\n")); + + goto out_free_adapter; + } + + // Register with LSI Common Management Module + if (megaraid_cmm_register(adapter) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not register with management module\n")); + + goto out_fini_mbox; + } + + // setup adapter handle in PCI soft state + pci_set_drvdata(pdev, adapter); + + // attach with scsi mid-layer + if (megaraid_io_attach(adapter) != 0) { + + con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); + + goto out_cmm_unreg; + } + + return 0; + +out_cmm_unreg: + pci_set_drvdata(pdev, NULL); + megaraid_cmm_unregister(adapter); +out_fini_mbox: + megaraid_fini_mbox(adapter); +out_free_adapter: + kfree(adapter); +out_probe_one: + pci_disable_device(pdev); + + return -ENODEV; +} + + +/** + * megaraid_detach_one - release the framework resources and call LLD release + * routine + * @param pdev : handle for our PCI cofiguration space + * + * This routine is called during driver unload. We free all the allocated + * resources and call the corresponding LLD so that it can also release all + * its resources. + * + * This routine is also called from the PCI hotplug system + **/ +static void +megaraid_detach_one(struct pci_dev *pdev) +{ + adapter_t *adapter; + struct Scsi_Host *host; + + + // Start a rollback on this adapter + adapter = pci_get_drvdata(pdev); + + if (!adapter) { + con_log(CL_ANN, (KERN_CRIT + "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device)); + + return; + } + else { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device)); + } + + + host = adapter->host; + + // do not allow any more requests from the management module for this + // adapter. + // FIXME: How do we account for the request which might still be + // pending with us? + atomic_set(&adapter->being_detached, 1); + + // detach from the IO sub-system + megaraid_io_detach(adapter); + + // reset the device state in the PCI structure. We check this + // condition when we enter here. If the device state is NULL, + // that would mean the device has already been removed + pci_set_drvdata(pdev, NULL); + + // Unregister from common management module + // + // FIXME: this must return success or failure for conditions if there + // is a command pending with LLD or not. + megaraid_cmm_unregister(adapter); + + // finalize the mailbox based controller and release all resources + megaraid_fini_mbox(adapter); + + kfree(adapter); + + scsi_host_put(host); + + pci_disable_device(pdev); + + return; +} + + +/** + * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA + * @param device : generice driver model device + * + * Shutdown notification, perform flush cache + */ +static void +megaraid_mbox_shutdown(struct device *device) +{ + adapter_t *adapter = pci_get_drvdata(to_pci_dev(device)); + static int counter; + + if (!adapter) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: null device in shutdown\n")); + return; + } + + // flush caches now + con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", + counter++)); + + megaraid_mbox_flush_cache(adapter); + + con_log(CL_ANN, ("done\n")); +} + + +/** + * megaraid_io_attach - attach a device with the IO subsystem + * @param adapter : controller's soft state + * + * Attach this device with the IO subsystem + **/ +static int +megaraid_io_attach(adapter_t *adapter) +{ + struct Scsi_Host *host; + + // Initialize SCSI Host structure + host = scsi_host_alloc(&megaraid_template_g, 8); + if (!host) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: scsi_register failed\n")); + + return -1; + } + + SCSIHOST2ADAP(host) = (caddr_t)adapter; + adapter->host = host; + + // export the parameters required by the mid-layer + scsi_assign_lock(host, adapter->host_lock); + scsi_set_device(host, &adapter->pdev->dev); + + host->irq = adapter->irq; + host->unique_id = adapter->unique_id; + host->can_queue = adapter->max_cmds; + host->this_id = adapter->init_id; + host->sg_tablesize = adapter->sglen; + host->max_sectors = adapter->max_sectors; + host->cmd_per_lun = adapter->cmd_per_lun; + host->max_channel = adapter->max_channel; + host->max_id = adapter->max_target; + host->max_lun = adapter->max_lun; + + + // notify mid-layer about the new controller + if (scsi_add_host(host, &adapter->pdev->dev)) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: scsi_add_host failed\n")); + + scsi_host_put(host); + + return -1; + } + + scsi_scan_host(host); + + return 0; +} + + +/** + * megaraid_io_detach - detach a device from the IO subsystem + * @param adapter : controller's soft state + * + * Detach this device from the IO subsystem + **/ +static void +megaraid_io_detach(adapter_t *adapter) +{ + struct Scsi_Host *host; + + con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); + + host = adapter->host; + + scsi_remove_host(host); + + return; +} + + +/* + * START: Mailbox Low Level Driver + * + * This is section specific to the single mailbox based controllers + */ + +/** + * megaraid_init_mbox - initialize controller + * @param adapter - our soft state + * + * . Allocate 16-byte aligned mailbox memory for firmware handshake + * . Allocate controller's memory resources + * . Find out all initialization data + * . Allocate memory required for all the commands + * . Use internal library of FW routines, build up complete soft state + */ +static int __init +megaraid_init_mbox(adapter_t *adapter) +{ + struct pci_dev *pdev; + mraid_device_t *raid_dev; + int i; + + + adapter->ito = MBOX_TIMEOUT; + pdev = adapter->pdev; + + /* + * Allocate and initialize the init data structure for mailbox + * controllers + */ + raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL); + if (raid_dev == NULL) return -1; + + memset(raid_dev, 0, sizeof(mraid_device_t)); + + /* + * Attach the adapter soft state to raid device soft state + */ + adapter->raid_device = (caddr_t)raid_dev; + raid_dev->fast_load = megaraid_fast_load; + + + // our baseport + raid_dev->baseport = pci_resource_start(pdev, 0); + + if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: mem region busy\n")); + + goto out_free_raid_dev; + } + + raid_dev->baseaddr = (unsigned long) + ioremap_nocache(raid_dev->baseport, 128); + + if (!raid_dev->baseaddr) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not map hba memory\n") ); + + goto out_release_regions; + } + + // + // Setup the rest of the soft state using the library of FW routines + // + + // request IRQ and register the interrupt service routine + if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid", + adapter)) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); + + goto out_iounmap; + } + + + // initialize the mutual exclusion lock for the mailbox + spin_lock_init(&raid_dev->mailbox_lock); + + // allocate memory required for commands + if (megaraid_alloc_cmd_packets(adapter) != 0) { + goto out_free_irq; + } + + // Product info + if (megaraid_mbox_product_info(adapter) != 0) { + goto out_alloc_cmds; + } + + // Do we support extended CDBs + adapter->max_cdb_sz = 10; + if (megaraid_mbox_extended_cdb(adapter) == 0) { + adapter->max_cdb_sz = 16; + } + + /* + * Do we support cluster environment, if we do, what is the initiator + * id. + * NOTE: In a non-cluster aware firmware environment, the LLD should + * return 7 as initiator id. + */ + adapter->ha = 0; + adapter->init_id = -1; + if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { + adapter->ha = 1; + } + + /* + * Prepare the device ids array to have the mapping between the kernel + * device address and megaraid device address. + * We export the physical devices on their actual addresses. The + * logical drives are exported on a virtual SCSI channel + */ + megaraid_mbox_setup_device_map(adapter); + + // If the firmware supports random deletion, update the device id map + if (megaraid_mbox_support_random_del(adapter)) { + + // Change the logical drives numbers in device_ids array one + // slot in device_ids is reserved for target id, that's why + // "<=" below + for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { + adapter->device_ids[adapter->max_channel][i] += 0x80; + } + adapter->device_ids[adapter->max_channel][adapter->init_id] = + 0xFF; + } + + /* + * find out the maximum number of scatter-gather elements supported by + * this firmware + */ + adapter->sglen = megaraid_mbox_get_max_sg(adapter); + + // enumerate RAID and SCSI channels so that all devices on SCSI + // channels can later be exported, including disk devices + megaraid_mbox_enum_raid_scsi(adapter); + + /* + * Other parameters required by upper layer + * + * maximum number of sectors per IO command + */ + adapter->max_sectors = megaraid_max_sectors; + + /* + * number of queued commands per LUN. + */ + adapter->cmd_per_lun = megaraid_cmd_per_lun; + + // Set the DMA mask to 64-bit. All supported controllers as capable of + // DMA in this range + if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFFFFFFFFFFULL) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: could not set DMA mask for 64-bit.\n")); + + goto out_alloc_cmds; + } + + // setup tasklet for DPC + tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, + (unsigned long)adapter); + + con_log(CL_DLEVEL1, (KERN_INFO + "megaraid mbox hba successfully initialized\n")); + + return 0; + +out_alloc_cmds: + megaraid_free_cmd_packets(adapter); +out_free_irq: + free_irq(adapter->irq, adapter); +out_iounmap: + iounmap((caddr_t)raid_dev->baseaddr); +out_release_regions: + pci_release_regions(pdev); +out_free_raid_dev: + kfree(raid_dev); + + return -1; +} + + +/** + * megaraid_fini_mbox - undo controller initialization + * @param adapter : our soft state + */ +static void +megaraid_fini_mbox(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + + // flush all caches + megaraid_mbox_flush_cache(adapter); + + tasklet_kill(&adapter->dpc_h); + + megaraid_free_cmd_packets(adapter); + + free_irq(adapter->irq, adapter); + + iounmap((caddr_t)raid_dev->baseaddr); + + pci_release_regions(adapter->pdev); + + kfree(raid_dev); + + return; +} + + +/** + * megaraid_alloc_cmd_packets - allocate shared mailbox + * @param adapter : soft state of the raid controller + * + * Allocate and align the shared mailbox. This maibox is used to issue + * all the commands. For IO based controllers, the mailbox is also regsitered + * with the FW. Allocate memory for all commands as well. + * This is our big allocator + */ +static int +megaraid_alloc_cmd_packets(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + struct pci_dev *pdev; + unsigned long align; + scb_t *scb; + mbox_ccb_t *ccb; + struct mraid_pci_blk *epthru_pci_blk; + struct mraid_pci_blk *sg_pci_blk; + struct mraid_pci_blk *mbox_pci_blk; + int i; + + pdev = adapter->pdev; + + /* + * Setup the mailbox + * Allocate the common 16-byte aligned memory for the handshake + * mailbox. + */ + raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev, + sizeof(mbox64_t), &raid_dev->una_mbox64_dma); + + if (!raid_dev->una_mbox64) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + return -1; + } + memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t)); + + /* + * Align the mailbox at 16-byte boundary + */ + raid_dev->mbox = &raid_dev->una_mbox64->mbox32; + + raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & + (~0UL ^ 0xFUL)); + + raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); + + align = ((void *)raid_dev->mbox - + ((void *)&raid_dev->una_mbox64->mbox32)); + + raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + + align; + + // Allocate memory for commands issued internally + adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE, + &adapter->ibuf_dma_h); + if (!adapter->ibuf) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + + goto out_free_common_mbox; + } + memset(adapter->ibuf, 0, MBOX_IBUF_SIZE); + + // Allocate memory for our SCSI Command Blocks and their associated + // memory + + /* + * Allocate memory for the base list of scb. Later allocate memory for + * CCBs and embedded components of each CCB and point the pointers in + * scb to the allocated components + * NOTE: The code to allocate SCB will be duplicated in all the LLD + * since the calling routine does not yet know the number of available + * commands. + */ + adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS, + GFP_KERNEL); + + if (adapter->kscb_list == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + goto out_free_ibuf; + } + memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS); + + // memory allocation for our command packets + if (megaraid_mbox_setup_dma_pools(adapter) != 0) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + goto out_free_scb_list; + } + + // Adjust the scb pointers and link in the free pool + epthru_pci_blk = raid_dev->epthru_pool; + sg_pci_blk = raid_dev->sg_pool; + mbox_pci_blk = raid_dev->mbox_pool; + + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + scb = adapter->kscb_list + i; + ccb = raid_dev->ccb_list + i; + + ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16); + ccb->raw_mbox = (uint8_t *)ccb->mbox; + ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8); + ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16; + + // make sure the mailbox is aligned properly + if (ccb->mbox_dma_h & 0x0F) { + con_log(CL_ANN, (KERN_CRIT + "megaraid mbox: not aligned on 16-bytes\n")); + + goto out_teardown_dma_pools; + } + + ccb->epthru = (mraid_epassthru_t *) + epthru_pci_blk[i].vaddr; + ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr; + ccb->pthru = (mraid_passthru_t *)ccb->epthru; + ccb->pthru_dma_h = ccb->epthru_dma_h; + + + ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr; + ccb->sgl_dma_h = sg_pci_blk[i].dma_addr; + ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64; + + scb->ccb = (caddr_t)ccb; + scb->gp = 0; + + scb->sno = i; // command index + + scb->scp = NULL; + scb->state = SCB_FREE; + scb->dma_direction = PCI_DMA_NONE; + scb->dma_type = MRAID_DMA_NONE; + scb->dev_channel = -1; + scb->dev_target = -1; + + // put scb in the free pool + list_add_tail(&scb->list, &adapter->kscb_pool); + } + + return 0; + +out_teardown_dma_pools: + megaraid_mbox_teardown_dma_pools(adapter); +out_free_scb_list: + kfree(adapter->kscb_list); +out_free_ibuf: + pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, + adapter->ibuf_dma_h); +out_free_common_mbox: + pci_free_consistent(adapter->pdev, sizeof(mbox64_t), + (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); + + return -1; +} + + +/** + * megaraid_free_cmd_packets - free memory + * @param adapter : soft state of the raid controller + * + * Release memory resources allocated for commands + */ +static void +megaraid_free_cmd_packets(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + + megaraid_mbox_teardown_dma_pools(adapter); + + kfree(adapter->kscb_list); + + pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE, + (void *)adapter->ibuf, adapter->ibuf_dma_h); + + pci_free_consistent(adapter->pdev, sizeof(mbox64_t), + (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); + return; +} + + +/** + * megaraid_mbox_setup_dma_pools - setup dma pool for command packets + * @param adapter : HBA soft state + * + * setup the dma pools for mailbox, passthru and extended passthru structures, + * and scatter-gather lists + */ +static int +megaraid_mbox_setup_dma_pools(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + struct mraid_pci_blk *epthru_pci_blk; + struct mraid_pci_blk *sg_pci_blk; + struct mraid_pci_blk *mbox_pci_blk; + int i; + + + + // Allocate memory for 16-bytes aligned mailboxes + raid_dev->mbox_pool_handle = pci_pool_create("megaraid mbox pool", + adapter->pdev, + sizeof(mbox64_t) + 16, + 16, 0); + + if (raid_dev->mbox_pool_handle == NULL) { + goto fail_setup_dma_pool; + } + + mbox_pci_blk = raid_dev->mbox_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + mbox_pci_blk[i].vaddr = pci_pool_alloc( + raid_dev->mbox_pool_handle, + GFP_KERNEL, + &mbox_pci_blk[i].dma_addr); + if (!mbox_pci_blk[i].vaddr) { + goto fail_setup_dma_pool; + } + } + + /* + * Allocate memory for each embedded passthru strucuture pointer + * Request for a 128 bytes aligned structure for each passthru command + * structure + * Since passthru and extended passthru commands are exclusive, they + * share common memory pool. Passthru structures piggyback on memory + * allocted to extended passthru since passthru is smaller of the two + */ + raid_dev->epthru_pool_handle = pci_pool_create("megaraid mbox pthru", + adapter->pdev, sizeof(mraid_epassthru_t), 128, 0); + + if (raid_dev->epthru_pool_handle == NULL) { + goto fail_setup_dma_pool; + } + + epthru_pci_blk = raid_dev->epthru_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + epthru_pci_blk[i].vaddr = pci_pool_alloc( + raid_dev->epthru_pool_handle, + GFP_KERNEL, + &epthru_pci_blk[i].dma_addr); + if (!epthru_pci_blk[i].vaddr) { + goto fail_setup_dma_pool; + } + } + + + // Allocate memory for each scatter-gather list. Request for 512 bytes + // alignment for each sg list + raid_dev->sg_pool_handle = pci_pool_create("megaraid mbox sg", + adapter->pdev, + sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE, + 512, 0); + + if (raid_dev->sg_pool_handle == NULL) { + goto fail_setup_dma_pool; + } + + sg_pci_blk = raid_dev->sg_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + sg_pci_blk[i].vaddr = pci_pool_alloc( + raid_dev->sg_pool_handle, + GFP_KERNEL, + &sg_pci_blk[i].dma_addr); + if (!sg_pci_blk[i].vaddr) { + goto fail_setup_dma_pool; + } + } + + return 0; + +fail_setup_dma_pool: + megaraid_mbox_teardown_dma_pools(adapter); + return -1; +} + + +/** + * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets + * @param adapter : HBA soft state + * + * teardown the dma pool for mailbox, passthru and extended passthru + * structures, and scatter-gather lists + */ +static void +megaraid_mbox_teardown_dma_pools(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + struct mraid_pci_blk *epthru_pci_blk; + struct mraid_pci_blk *sg_pci_blk; + struct mraid_pci_blk *mbox_pci_blk; + int i; + + + sg_pci_blk = raid_dev->sg_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) { + pci_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr, + sg_pci_blk[i].dma_addr); + } + if (raid_dev->sg_pool_handle) + pci_pool_destroy(raid_dev->sg_pool_handle); + + + epthru_pci_blk = raid_dev->epthru_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) { + pci_pool_free(raid_dev->epthru_pool_handle, + epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr); + } + if (raid_dev->epthru_pool_handle) + pci_pool_destroy(raid_dev->epthru_pool_handle); + + + mbox_pci_blk = raid_dev->mbox_pool; + for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) { + pci_pool_free(raid_dev->mbox_pool_handle, + mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr); + } + if (raid_dev->mbox_pool_handle) + pci_pool_destroy(raid_dev->mbox_pool_handle); + + return; +} + + +/** + * megaraid_alloc_scb - detach and return a scb from the free list + * @adapter : controller's soft state + * + * return the scb from the head of the free list. NULL if there are none + * available + **/ +static inline scb_t * +megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp) +{ + struct list_head *head = &adapter->kscb_pool; + scb_t *scb = NULL; + unsigned long flags; + + // detach scb from free pool + spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); + + if (list_empty(head)) { + spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); + return NULL; + } + + scb = list_entry(head->next, scb_t, list); + list_del_init(&scb->list); + + spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); + + scb->state = SCB_ACTIVE; + scb->scp = scp; + scb->dma_type = MRAID_DMA_NONE; + + return scb; +} + + +/** + * megaraid_dealloc_scb - return the scb to the free pool + * @adapter : controller's soft state + * @scb : scb to be freed + * + * return the scb back to the free list of scbs. The caller must 'flush' the + * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc. + * NOTE NOTE: Make sure the scb is not on any list before calling this + * routine. + **/ +static inline void +megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb) +{ + unsigned long flags; + + // put scb in the free pool + scb->state = SCB_FREE; + scb->scp = NULL; + spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); + + list_add(&scb->list, &adapter->kscb_pool); + + spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); + + return; +} + + +/** + * megaraid_mbox_mksgl - make the scatter-gather list + * @adapter - controller's soft state + * @scb - scsi control block + * + * prepare the scatter-gather list + */ +static inline int +megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb) +{ + struct scatterlist *sgl; + mbox_ccb_t *ccb; + struct page *page; + unsigned long offset; + struct scsi_cmnd *scp; + int sgcnt; + int i; + + + scp = scb->scp; + ccb = (mbox_ccb_t *)scb->ccb; + + // no mapping required if no data to be transferred + if (!scp->request_buffer || !scp->request_bufflen) + return 0; + + if (!scp->use_sg) { /* scatter-gather list not used */ + + page = virt_to_page(scp->request_buffer); + + offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK); + + ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset, + scp->request_bufflen, + scb->dma_direction); + scb->dma_type = MRAID_DMA_WBUF; + + /* + * We need to handle special 64-bit commands that need a + * minimum of 1 SG + */ + sgcnt = 1; + ccb->sgl64[0].address = ccb->buf_dma_h; + ccb->sgl64[0].length = scp->request_bufflen; + + return sgcnt; + } + + sgl = (struct scatterlist *)scp->request_buffer; + + // The number of sg elements returned must not exceed our limit + sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg, + scb->dma_direction); + + if (sgcnt > adapter->sglen) { + con_log(CL_ANN, (KERN_CRIT + "megaraid critical: too many sg elements:%d\n", + sgcnt)); + BUG(); + } + + scb->dma_type = MRAID_DMA_WSG; + + for (i = 0; i < sgcnt; i++, sgl++) { + ccb->sgl64[i].address = sg_dma_address(sgl); + ccb->sgl64[i].length = sg_dma_len(sgl); + } + + // Return count of SG nodes + return sgcnt; +} + + +/** + * mbox_post_cmd - issue a mailbox command + * @adapter - controller's soft state + * @scb - command to be issued + * + * post the command to the controller if mailbox is availble. + */ +static inline int +mbox_post_cmd(adapter_t *adapter, scb_t *scb) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox64_t *mbox64; + mbox_t *mbox; + mbox_ccb_t *ccb; + unsigned long flags; + unsigned int i = 0; + + + ccb = (mbox_ccb_t *)scb->ccb; + mbox = raid_dev->mbox; + mbox64 = raid_dev->mbox64; + + /* + * Check for busy mailbox. If it is, return failure - the caller + * should retry later. + */ + spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); + + if (unlikely(mbox->busy)) { + do { + udelay(1); + i++; + rmb(); + } while(mbox->busy && (i < max_mbox_busy_wait)); + + if (mbox->busy) { + + spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); + + return -1; + } + } + + + // Copy this command's mailbox data into "adapter's" mailbox + memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22); + mbox->cmdid = scb->sno; + + adapter->outstanding_cmds++; + + if (scb->dma_direction == PCI_DMA_TODEVICE) { + if (!scb->scp->use_sg) { // sg list not used + pci_dma_sync_single(adapter->pdev, ccb->buf_dma_h, + scb->scp->request_bufflen, + PCI_DMA_TODEVICE); + } + else { + pci_dma_sync_sg(adapter->pdev, scb->scp->request_buffer, + scb->scp->use_sg, PCI_DMA_TODEVICE); + } + } + + mbox->busy = 1; // Set busy + mbox->poll = 0; + mbox->ack = 0; + wmb(); + + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); + + return 0; +} + + +/** + * megaraid_queue_command - generic queue entry point for all LLDs + * @scp : pointer to the scsi command to be executed + * @done : callback routine to be called after the cmd has be completed + * + * Queue entry point for mailbox based controllers. + */ +static int +megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *)) +{ + adapter_t *adapter; + scb_t *scb; + int if_busy; + + adapter = SCP2ADAPTER(scp); + scp->scsi_done = done; + scp->result = 0; + + ASSERT(spin_is_locked(adapter->host_lock)); + + spin_unlock(adapter->host_lock); + + /* + * Allocate and build a SCB request + * if_busy flag will be set if megaraid_mbox_build_cmd() command could + * not allocate scb. We will return non-zero status in that case. + * NOTE: scb can be null even though certain commands completed + * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would + * return 0 in that case, and we would do the callback right away. + */ + if_busy = 0; + scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy); + + if (scb) { + megaraid_mbox_runpendq(adapter, scb); + } + + spin_lock(adapter->host_lock); + + if (!scb) { // command already completed + done(scp); + } + + return if_busy; +} + + +/** + * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid + * firmware lingua + * @adapter - controller's soft state + * @scp - mid-layer scsi command pointer + * @busy - set if request could not be completed because of lack of + * resources + * + * convert the command issued by mid-layer to format understood by megaraid + * firmware. We also complete certain command without sending them to firmware + */ +static scb_t * +megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) +{ + mraid_device_t *rdev = ADAP2RAIDDEV(adapter); + int channel; + int target; + int islogical; + mbox_ccb_t *ccb; + mraid_passthru_t *pthru; + mbox64_t *mbox64; + mbox_t *mbox; + scb_t *scb; + char skip[] = "skipping"; + char scan[] = "scanning"; + char *ss; + + + /* + * Get the appropriate device map for the device this command is + * intended for + */ + MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical); + + /* + * Logical drive commands + */ + if (islogical) { + switch (scp->cmnd[0]) { + case TEST_UNIT_READY: + /* + * Do we support clustering and is the support enabled + * If no, return success always + */ + if (!adapter->ha) { + scp->result = (DID_OK << 16); + return NULL; + } + + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + scb->dma_direction = scp->sc_data_direction; + scb->dev_channel = 0xFF; + scb->dev_target = target; + ccb = (mbox_ccb_t *)scb->ccb; + + /* + * The command id will be provided by the command + * issuance routine + */ + ccb->raw_mbox[0] = CLUSTER_CMD; + ccb->raw_mbox[2] = RESERVATION_STATUS; + ccb->raw_mbox[3] = target; + + return scb; + + case MODE_SENSE: + if (scp->use_sg) { + struct scatterlist *sgl; + caddr_t vaddr; + + sgl = (struct scatterlist *)scp->request_buffer; + if (sgl->page) { + vaddr = (caddr_t) + (page_address((&sgl[0])->page) + + (&sgl[0])->offset); + + memset(vaddr, 0, scp->cmnd[4]); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: invalid sg:%d\n", + __LINE__)); + } + } + else { + memset(scp->request_buffer, 0, scp->cmnd[4]); + } + scp->result = (DID_OK << 16); + return NULL; + + case INQUIRY: + /* + * Display the channel scan for logical drives + * Do not display scan for a channel if already done. + */ + if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { + + con_log(CL_ANN, (KERN_INFO + "scsi[%d]: scanning scsi channel %d", + adapter->host->host_no, + SCP2CHANNEL(scp))); + + con_log(CL_ANN, ( + " [virtual] for logical drives\n")); + + rdev->last_disp |= (1L << SCP2CHANNEL(scp)); + } + + /* Fall through */ + + case READ_CAPACITY: + /* + * Do not allow LUN > 0 for logical drives and + * requests for more than 40 logical drives + */ + if (SCP2LUN(scp)) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + + /* Allocate a SCB and initialize passthru */ + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = 0xFF; + scb->dev_target = target; + pthru = ccb->pthru; + mbox = ccb->mbox; + mbox64 = ccb->mbox64; + + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 1; + pthru->logdrv = target; + pthru->cdblen = scp->cmd_len; + memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); + + mbox->cmd = MBOXCMD_PASSTHRU64; + scb->dma_direction = scp->sc_data_direction; + + pthru->dataxferlen = scp->request_bufflen; + pthru->dataxferaddr = ccb->sgl_dma_h; + pthru->numsge = megaraid_mbox_mksgl(adapter, + scb); + + mbox->xferaddr = 0xFFFFFFFF; + mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h; + mbox64->xferaddr_hi = 0; + + return scb; + + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + + /* + * Allocate a SCB and initialize mailbox + */ + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = 0xFF; + scb->dev_target = target; + mbox = ccb->mbox; + mbox64 = ccb->mbox64; + mbox->logdrv = target; + + /* + * A little HACK: 2nd bit is zero for all scsi read + * commands and is set for all scsi write commands + */ + mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64: + MBOXCMD_LREAD64 ; + + /* + * 6-byte READ(0x08) or WRITE(0x0A) cdb + */ + if (scp->cmd_len == 6) { + mbox->numsectors = (uint32_t)scp->cmnd[4]; + mbox->lba = + ((uint32_t)scp->cmnd[1] << 16) | + ((uint32_t)scp->cmnd[2] << 8) | + (uint32_t)scp->cmnd[3]; + + mbox->lba &= 0x1FFFFF; + } + + /* + * 10-byte READ(0x28) or WRITE(0x2A) cdb + */ + else if (scp->cmd_len == 10) { + mbox->numsectors = + (uint32_t)scp->cmnd[8] | + ((uint32_t)scp->cmnd[7] << 8); + mbox->lba = + ((uint32_t)scp->cmnd[2] << 24) | + ((uint32_t)scp->cmnd[3] << 16) | + ((uint32_t)scp->cmnd[4] << 8) | + (uint32_t)scp->cmnd[5]; + } + + /* + * 12-byte READ(0xA8) or WRITE(0xAA) cdb + */ + else if (scp->cmd_len == 12) { + mbox->lba = + ((uint32_t)scp->cmnd[2] << 24) | + ((uint32_t)scp->cmnd[3] << 16) | + ((uint32_t)scp->cmnd[4] << 8) | + (uint32_t)scp->cmnd[5]; + + mbox->numsectors = + ((uint32_t)scp->cmnd[6] << 24) | + ((uint32_t)scp->cmnd[7] << 16) | + ((uint32_t)scp->cmnd[8] << 8) | + (uint32_t)scp->cmnd[9]; + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid: unsupported CDB length\n")); + + megaraid_dealloc_scb(adapter, scb); + + scp->result = (DID_ERROR << 16); + return NULL; + } + + scb->dma_direction = scp->sc_data_direction; + + // Calculate Scatter-Gather info + mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h; + mbox->numsge = megaraid_mbox_mksgl(adapter, + scb); + mbox->xferaddr = 0xFFFFFFFF; + mbox64->xferaddr_hi = 0; + + return scb; + + case RESERVE: + case RELEASE: + /* + * Do we support clustering and is the support enabled + */ + if (!adapter->ha) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + /* + * Allocate a SCB and initialize mailbox + */ + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = 0xFF; + scb->dev_target = target; + ccb->raw_mbox[0] = CLUSTER_CMD; + ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? + RESERVE_LD : RELEASE_LD; + + ccb->raw_mbox[3] = target; + scb->dma_direction = scp->sc_data_direction; + + return scb; + + default: + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + } + else { // Passthru device commands + + // Do not allow access to target id > 15 or LUN > 7 + if (target > 15 || SCP2LUN(scp) > 7) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + // if fast load option was set and scan for last device is + // over, reset the fast_load flag so that during a possible + // next scan, devices can be made available + if (rdev->fast_load && (target == 15) && + (SCP2CHANNEL(scp) == adapter->max_channel -1)) { + + con_log(CL_ANN, (KERN_INFO + "megaraid[%d]: physical device scan re-enabled\n", + adapter->host->host_no)); + rdev->fast_load = 0; + } + + /* + * Display the channel scan for physical devices + */ + if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { + + ss = rdev->fast_load ? skip : scan; + + con_log(CL_ANN, (KERN_INFO + "scsi[%d]: %s scsi channel %d [Phy %d]", + adapter->host->host_no, ss, SCP2CHANNEL(scp), + channel)); + + con_log(CL_ANN, ( + " for non-raid devices\n")); + + rdev->last_disp |= (1L << SCP2CHANNEL(scp)); + } + + // disable channel sweep if fast load option given + if (rdev->fast_load) { + scp->result = (DID_BAD_TARGET << 16); + return NULL; + } + + // Allocate a SCB and initialize passthru + if (!(scb = megaraid_alloc_scb(adapter, scp))) { + scp->result = (DID_ERROR << 16); + *busy = 1; + return NULL; + } + + ccb = (mbox_ccb_t *)scb->ccb; + scb->dev_channel = channel; + scb->dev_target = target; + scb->dma_direction = scp->sc_data_direction; + mbox = ccb->mbox; + mbox64 = ccb->mbox64; + + // Does this firmware support extended CDBs + if (adapter->max_cdb_sz == 16) { + mbox->cmd = MBOXCMD_EXTPTHRU; + + megaraid_mbox_prepare_epthru(adapter, scb, scp); + + mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h; + mbox64->xferaddr_hi = 0; + mbox->xferaddr = 0xFFFFFFFF; + } + else { + mbox->cmd = MBOXCMD_PASSTHRU64; + + megaraid_mbox_prepare_pthru(adapter, scb, scp); + + mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h; + mbox64->xferaddr_hi = 0; + mbox->xferaddr = 0xFFFFFFFF; + } + return scb; + } + + // NOT REACHED +} + + +/** + * megaraid_mbox_runpendq - execute commands queued in the pending queue + * @adapter : controller's soft state + * @scb : SCB to be queued in the pending list + * + * scan the pending list for commands which are not yet issued and try to + * post to the controller. The SCB can be a null pointer, which would indicate + * no SCB to be queue, just try to execute the ones in the pending list. + * + * NOTE: We do not actually traverse the pending list. The SCBs are plucked + * out from the head of the pending list. If it is successfully issued, the + * next SCB is at the head now. + */ +static void +megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q) +{ + scb_t *scb; + unsigned long flags; + + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + + if (scb_q) { + scb_q->state = SCB_PENDQ; + list_add_tail(&scb_q->list, &adapter->pend_list); + } + + // if the adapter in not in quiescent mode, post the commands to FW + if (adapter->quiescent) { + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + return; + } + + while (!list_empty(&adapter->pend_list)) { + + ASSERT(spin_is_locked(PENDING_LIST_LOCK(adapter))); + + scb = list_entry(adapter->pend_list.next, scb_t, list); + + // remove the scb from the pending list and try to + // issue. If we are unable to issue it, put back in + // the pending list and return + + list_del_init(&scb->list); + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + // if mailbox was busy, return SCB back to pending + // list. Make sure to add at the head, since that's + // where it would have been removed from + + scb->state = SCB_ISSUED; + + if (mbox_post_cmd(adapter, scb) != 0) { + + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + + scb->state = SCB_PENDQ; + + list_add(&scb->list, &adapter->pend_list); + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), + flags); + + return; + } + + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + } + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + + return; +} + + +/** + * megaraid_mbox_prepare_pthru - prepare a command for physical devices + * @adapter - pointer to controller's soft state + * @scb - scsi control block + * @scp - scsi command from the mid-layer + * + * prepare a command for the scsi physical devices + */ +static void +megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, + struct scsi_cmnd *scp) +{ + mbox_ccb_t *ccb; + mraid_passthru_t *pthru; + uint8_t channel; + uint8_t target; + + ccb = (mbox_ccb_t *)scb->ccb; + pthru = ccb->pthru; + channel = scb->dev_channel; + target = scb->dev_target; + + pthru->timeout = 1; // 0=6sec, 1=60sec, 2=10min, 3=3hrs + pthru->ars = 1; + pthru->islogical = 0; + pthru->channel = 0; + pthru->target = (channel << 4) | target; + pthru->logdrv = SCP2LUN(scp); + pthru->reqsenselen = 14; + pthru->cdblen = scp->cmd_len; + + memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); + + if (scp->request_bufflen) { + pthru->dataxferlen = scp->request_bufflen; + pthru->dataxferaddr = ccb->sgl_dma_h; + pthru->numsge = megaraid_mbox_mksgl(adapter, scb); + } + else { + pthru->dataxferaddr = 0; + pthru->dataxferlen = 0; + pthru->numsge = 0; + } + return; +} + + +/** + * megaraid_mbox_prepare_epthru - prepare a command for physical devices + * @adapter - pointer to controller's soft state + * @scb - scsi control block + * @scp - scsi command from the mid-layer + * + * prepare a command for the scsi physical devices. This rountine prepares + * commands for devices which can take extended CDBs (>10 bytes) + */ +static void +megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, + struct scsi_cmnd *scp) +{ + mbox_ccb_t *ccb; + mraid_epassthru_t *epthru; + uint8_t channel; + uint8_t target; + + ccb = (mbox_ccb_t *)scb->ccb; + epthru = ccb->epthru; + channel = scb->dev_channel; + target = scb->dev_target; + + epthru->timeout = 1; // 0=6sec, 1=60sec, 2=10min, 3=3hrs + epthru->ars = 1; + epthru->islogical = 0; + epthru->channel = 0; + epthru->target = (channel << 4) | target; + epthru->logdrv = SCP2LUN(scp); + epthru->reqsenselen = 14; + epthru->cdblen = scp->cmd_len; + + memcpy(epthru->cdb, scp->cmnd, scp->cmd_len); + + if (scp->request_bufflen) { + epthru->dataxferlen = scp->request_bufflen; + epthru->dataxferaddr = ccb->sgl_dma_h; + epthru->numsge = megaraid_mbox_mksgl(adapter, scb); + } + else { + epthru->dataxferaddr = 0; + epthru->dataxferlen = 0; + epthru->numsge = 0; + } + return; +} + + +/** + * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs + * @adapter - controller's soft state + * + * Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the + * completed command and put them on the completed list for later processing. + * + * Returns: 1 if the interrupt is valid, 0 otherwise + */ +static inline int +megaraid_ack_sequence(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + scb_t *scb; + uint8_t nstatus; + uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; + struct list_head clist; + int handled; + uint32_t dword; + unsigned long flags; + int i, j; + + + mbox = raid_dev->mbox; + + // move the SCBs from the firmware completed array to our local list + INIT_LIST_HEAD(&clist); + + // loop till F/W has more commands for us to complete + handled = 0; + spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); + do { + /* + * Check if a valid interrupt is pending. If found, force the + * interrupt line low. + */ + dword = RDOUTDOOR(raid_dev); + if (dword != 0x10001234) break; + + handled = 1; + + WROUTDOOR(raid_dev, 0x10001234); + + nstatus = 0; + // wait for valid numstatus to post + for (i = 0; i < 0xFFFFF; i++) { + if (mbox->numstatus != 0xFF) { + nstatus = mbox->numstatus; + break; + } + rmb(); + } + mbox->numstatus = 0xFF; + + adapter->outstanding_cmds -= nstatus; + + for (i = 0; i < nstatus; i++) { + + // wait for valid command index to post + for (j = 0; j < 0xFFFFF; j++) { + if (mbox->completed[i] != 0xFF) break; + rmb(); + } + completed[i] = mbox->completed[i]; + mbox->completed[i] = 0xFF; + + if (completed[i] == 0xFF) { + con_log(CL_ANN, (KERN_CRIT + "megaraid: command posting timed out\n")); + + BUG(); + continue; + } + + // Get SCB associated with this command id + if (completed[i] >= MBOX_MAX_SCSI_CMDS) { + // a cmm command + scb = adapter->uscb_list + (completed[i] - + MBOX_MAX_SCSI_CMDS); + } + else { + // an os command + scb = adapter->kscb_list + completed[i]; + } + + scb->status = mbox->status; + list_add_tail(&scb->list, &clist); + } + + // Acknowledge interrupt + WRINDOOR(raid_dev, 0x02); + + } while(1); + + spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); + + + // put the completed commands in the completed list. DPC would + // complete these commands later + spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); + + list_splice(&clist, &adapter->completed_list); + + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); + + + // schedule the DPC if there is some work for it + if (handled) + tasklet_schedule(&adapter->dpc_h); + + return handled; +} + + +/** + * megaraid_isr - isr for memory based mailbox based controllers + * @irq - irq + * @devp - pointer to our soft state + * @regs - unused + * + * Interrupt service routine for memory-mapped mailbox controllers. + */ +static irqreturn_t +megaraid_isr(int irq, void *devp, struct pt_regs *regs) +{ + adapter_t *adapter = devp; + int handled; + + handled = megaraid_ack_sequence(adapter); + + /* Loop through any pending requests */ + if (!adapter->quiescent) { + megaraid_mbox_runpendq(adapter, NULL); + } + + return IRQ_RETVAL(handled); +} + + +/** + * megaraid_mbox_sync_scb - sync kernel buffers + * @adapter : controller's soft state + * @scb : pointer to the resource packet + * + * DMA sync if required. + */ +static inline void +megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb) +{ + mbox_ccb_t *ccb; + + ccb = (mbox_ccb_t *)scb->ccb; + + switch (scb->dma_type) { + + case MRAID_DMA_WBUF: + if (scb->dma_direction == PCI_DMA_FROMDEVICE) { + pci_dma_sync_single(adapter->pdev, + ccb->buf_dma_h, + scb->scp->request_bufflen, + PCI_DMA_FROMDEVICE); + } + + pci_unmap_page(adapter->pdev, ccb->buf_dma_h, + scb->scp->request_bufflen, scb->dma_direction); + + break; + + case MRAID_DMA_WSG: + if (scb->dma_direction == PCI_DMA_FROMDEVICE) { + pci_dma_sync_sg(adapter->pdev, + scb->scp->request_buffer, + scb->scp->use_sg, PCI_DMA_FROMDEVICE); + } + + pci_unmap_sg(adapter->pdev, scb->scp->request_buffer, + scb->scp->use_sg, scb->dma_direction); + + break; + + default: + break; + } + + return; +} + + +/** + * megaraid_mbox_dpc - the tasklet to complete the commands from completed list + * @devp : pointer to HBA soft state + * + * Pick up the commands from the completed list and send back to the owners. + * This is a reentrant function and does not assume any locks are held while + * it is being called. + */ +static void +megaraid_mbox_dpc(unsigned long devp) +{ + adapter_t *adapter = (adapter_t *)devp; + mraid_device_t *raid_dev; + struct list_head clist; + struct scatterlist *sgl; + scb_t *scb; + scb_t *tmp; + struct scsi_cmnd *scp; + mraid_passthru_t *pthru; + mraid_epassthru_t *epthru; + mbox_ccb_t *ccb; + int islogical; + int pdev_index; + int pdev_state; + mbox_t *mbox; + unsigned long flags; + uint8_t c; + int status; + + + if (!adapter) return; + + raid_dev = ADAP2RAIDDEV(adapter); + + // move the SCBs from the completed list to our local list + INIT_LIST_HEAD(&clist); + + spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); + + list_splice_init(&adapter->completed_list, &clist); + + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); + + + list_for_each_entry_safe(scb, tmp, &clist, list) { + + status = scb->status; + scp = scb->scp; + ccb = (mbox_ccb_t *)scb->ccb; + pthru = ccb->pthru; + epthru = ccb->epthru; + mbox = ccb->mbox; + + // Make sure f/w has completed a valid command + if (scb->state != SCB_ISSUED) { + con_log(CL_ANN, (KERN_CRIT + "megaraid critical err: invalid command %d:%d:%p\n", + scb->sno, scb->state, scp)); + BUG(); + continue; // Must never happen! + } + + // check for the management command and complete it right away + if (scb->sno >= MBOX_MAX_SCSI_CMDS) { + scb->state = SCB_FREE; + scb->status = status; + + // remove from local clist + list_del_init(&scb->list); + + megaraid_mbox_mm_done(adapter, scb); + + continue; + } + + // Was an abort issued for this command earlier + if (scb->state & SCB_ABORT) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: aborted cmd %lx[%x] completed\n", + scp->serial_number, scb->sno)); + } + + /* + * If the inquiry came of a disk drive which is not part of + * any RAID array, expose it to the kernel. For this to be + * enabled, user must set the "megaraid_expose_unconf_disks" + * flag to 1 by specifying it on module parameter list. + * This would enable data migration off drives from other + * configurations. + */ + islogical = MRAID_IS_LOGICAL(adapter, scp); + if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0 + && IS_RAID_CH(raid_dev, scb->dev_channel)) { + + if (scp->use_sg) { + sgl = (struct scatterlist *) + scp->request_buffer; + + if (sgl->page) { + c = *(unsigned char *) + (page_address((&sgl[0])->page) + + (&sgl[0])->offset); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: invalid sg:%d\n", + __LINE__)); + c = 0; + } + } + else { + c = *(uint8_t *)scp->request_buffer; + } + + if ((c & 0x1F ) == TYPE_DISK) { + pdev_index = (scb->dev_channel * 16) + + scb->dev_target; + pdev_state = + raid_dev->pdrv_state[pdev_index] & 0x0F; + + if (pdev_state == PDRV_ONLINE || + pdev_state == PDRV_FAILED || + pdev_state == PDRV_RBLD || + pdev_state == PDRV_HOTSPARE || + megaraid_expose_unconf_disks == 0) { + + status = 0xF0; + } + } + } + + // Convert MegaRAID status to Linux error code + switch (status) { + + case 0x00: + + scp->result = (DID_OK << 16); + break; + + case 0x02: + + /* set sense_buffer and result fields */ + if (mbox->cmd == MBOXCMD_PASSTHRU || + mbox->cmd == MBOXCMD_PASSTHRU64) { + + memcpy(scp->sense_buffer, pthru->reqsensearea, + 14); + + scp->result = DRIVER_SENSE << 24 | + DID_OK << 16 | CHECK_CONDITION << 1; + } + else { + if (mbox->cmd == MBOXCMD_EXTPTHRU) { + + memcpy(scp->sense_buffer, + epthru->reqsensearea, 14); + + scp->result = DRIVER_SENSE << 24 | + DID_OK << 16 | + CHECK_CONDITION << 1; + } else { + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = ABORTED_COMMAND; + scp->result = CHECK_CONDITION << 1; + } + } + break; + + case 0x08: + + scp->result = DID_BUS_BUSY << 16 | status; + break; + + default: + + /* + * If TEST_UNIT_READY fails, we know RESERVATION_STATUS + * failed + */ + if (scp->cmnd[0] == TEST_UNIT_READY) { + scp->result = DID_ERROR << 16 | + RESERVATION_CONFLICT << 1; + } + else + /* + * Error code returned is 1 if Reserve or Release + * failed or the input parameter is invalid + */ + if (status == 1 && (scp->cmnd[0] == RESERVE || + scp->cmnd[0] == RELEASE)) { + + scp->result = DID_ERROR << 16 | + RESERVATION_CONFLICT << 1; + } + else { + scp->result = DID_BAD_TARGET << 16 | status; + } + } + + // print a debug message for all failed commands + if (status) { + megaraid_mbox_display_scb(adapter, scb); + } + + // Free our internal resources and call the mid-layer callback + // routine + megaraid_mbox_sync_scb(adapter, scb); + + // remove from local clist + list_del_init(&scb->list); + + // put back in free list + megaraid_dealloc_scb(adapter, scb); + + // send the scsi packet back to kernel + spin_lock(adapter->host_lock); + scp->scsi_done(scp); + spin_unlock(adapter->host_lock); + } + + return; +} + + +/** + * megaraid_abort_handler - abort the scsi command + * @scp : command to be aborted + * + * Abort a previous SCSI request. Only commands on the pending list can be + * aborted. All the commands issued to the F/W must complete. + **/ +static int +megaraid_abort_handler(struct scsi_cmnd *scp) +{ + adapter_t *adapter; + mraid_device_t *raid_dev; + scb_t *scb; + scb_t *tmp; + int found; + unsigned long flags; + int i; + + + adapter = SCP2ADAPTER(scp); + raid_dev = ADAP2RAIDDEV(adapter); + + ASSERT(spin_is_locked(adapter->host_lock)); + + con_log(CL_ANN, (KERN_WARNING + "megaraid: aborting-%ld cmd=%x \n", + scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp), + SCP2TARGET(scp), SCP2LUN(scp))); + + // If FW has stopped responding, simply return failure + if (raid_dev->hw_error) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: hw error, not aborting\n")); + return FAILED; + } + + // There might a race here, where the command was completed by the + // firmware and now it is on the completed list. Before we could + // complete the command to the kernel in dpc, the abort came. + // Find out if this is the case to avoid the race. + scb = NULL; + spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); + list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) { + + if (scb->scp == scp) { // Found command + + list_del_init(&scb->list); // from completed list + + con_log(CL_ANN, (KERN_WARNING + "megaraid: %ld:%d[%d:%d], abort from completed list\n", + scp->serial_number, scb->sno, + scb->dev_channel, scb->dev_target)); + + scp->result = (DID_ABORT << 16); + scp->scsi_done(scp); + + megaraid_dealloc_scb(adapter, scb); + + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), + flags); + + return SUCCESS; + } + } + spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); + + + // Find out if this command is still on the pending list. If it is and + // was never issued, abort and return success. If the command is owned + // by the firmware, we must wait for it to complete by the FW. + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { + + if (scb->scp == scp) { // Found command + + list_del_init(&scb->list); // from pending list + + ASSERT(!(scb->state & SCB_ISSUED)); + + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: %ld[%d:%d], driver owner\n", + scp->serial_number, scb->dev_channel, + scb->dev_target)); + + scp->result = (DID_ABORT << 16); + scp->scsi_done(scp); + + megaraid_dealloc_scb(adapter, scb); + + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), + flags); + + return SUCCESS; + } + } + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + + // Check do we even own this command, in which case this would be + // owned by the firmware. The only way to locate the FW scb is to + // traverse through the list of all SCB, since driver does not + // maintain these SCBs on any list + found = 0; + for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { + scb = adapter->kscb_list + i; + + if (scb->scp == scp) { + + found = 1; + + if (!(scb->state & SCB_ISSUED)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: %ld%d[%d:%d], invalid state\n", + scp->serial_number, scb->sno, scb->dev_channel, + scb->dev_target)); + BUG(); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: %ld:%d[%d:%d], fw owner\n", + scp->serial_number, scb->sno, scb->dev_channel, + scb->dev_target)); + } + } + } + + if (!found) { + con_log(CL_ANN, (KERN_WARNING + "megaraid abort: scsi cmd:%ld, do now own\n", + scp->serial_number)); + + // FIXME: Should there be a callback for this command? + return SUCCESS; + } + + // We cannot actually abort a command owned by firmware, return + // failure and wait for reset. In host reset handler, we will find out + // if the HBA is still live + return FAILED; +} + + +/** + * megaraid_reset_handler - device reset hadler for mailbox based driver + * @scp : reference command + * + * Reset handler for the mailbox based controller. First try to find out if + * the FW is still live, in which case the outstanding commands counter mut go + * down to 0. If that happens, also issue the reservation reset command to + * relinquish (possible) reservations on the logical drives connected to this + * host + **/ +static int +megaraid_reset_handler(struct scsi_cmnd *scp) +{ + adapter_t *adapter; + scb_t *scb; + scb_t *tmp; + mraid_device_t *raid_dev; + unsigned long flags; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + int recovery_window; + int recovering; + int i; + + adapter = SCP2ADAPTER(scp); + raid_dev = ADAP2RAIDDEV(adapter); + + ASSERT(spin_is_locked(adapter->host_lock)); + + con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n")); + + // return failure if adapter is not responding + if (raid_dev->hw_error) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: hw error, cannot reset\n")); + return FAILED; + } + + + // Under exceptional conditions, FW can take up to 3 minutes to + // complete command processing. Wait for additional 2 minutes for the + // pending commands counter to go down to 0. If it doesn't, let the + // controller be marked offline + // Also, reset all the commands currently owned by the driver + spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); + list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { + + list_del_init(&scb->list); // from pending list + + con_log(CL_ANN, (KERN_WARNING + "megaraid: %ld:%d[%d:%d], reset from pending list\n", + scp->serial_number, scb->sno, + scb->dev_channel, scb->dev_target)); + + scp->result = (DID_RESET << 16); + scp->scsi_done(scp); + + megaraid_dealloc_scb(adapter, scb); + } + spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); + + if (adapter->outstanding_cmds) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid: %d outstanding commands. Max wait %d sec\n", + adapter->outstanding_cmds, MBOX_RESET_WAIT)); + } + + spin_unlock(adapter->host_lock); + + recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; + + recovering = adapter->outstanding_cmds; + + for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) { + + megaraid_ack_sequence(adapter); + + // print a message once every 5 seconds only + if (!(i % 5)) { + con_log(CL_ANN, ( + "megaraid mbox: Wait for %d commands to complete:%d\n", + adapter->outstanding_cmds, + MBOX_RESET_WAIT - i)); + } + + // bailout if no recovery happended in reset time + if ((i == MBOX_RESET_WAIT) && + (recovering == adapter->outstanding_cmds)) { + break; + } + + msleep(1000); + } + + spin_lock(adapter->host_lock); + + // If still outstanding commands, bail out + if (adapter->outstanding_cmds) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: critical hardware error!\n")); + + raid_dev->hw_error = 1; + + return FAILED; + } + else { + con_log(CL_ANN, (KERN_NOTICE + "megaraid mbox: reset sequence completed sucessfully\n")); + } + + + // If the controller supports clustering, reset reservations + if (!adapter->ha) return SUCCESS; + + // clear reservations if any + raw_mbox[0] = CLUSTER_CMD; + raw_mbox[2] = RESET_RESERVATIONS; + + rval = SUCCESS; + if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) { + con_log(CL_ANN, + (KERN_INFO "megaraid: reservation reset\n")); + } + else { + rval = FAILED; + con_log(CL_ANN, (KERN_WARNING + "megaraid: reservation reset failed\n")); + } + + return rval; +} + + +/* + * START: internal commands library + * + * This section of the driver has the common routine used by the driver and + * also has all the FW routines + */ + +/** + * mbox_post_sync_cmd() - blocking command to the mailbox based controllers + * @adapter - controller's soft state + * @raw_mbox - the mailbox + * + * Issue a scb in synchronous and non-interrupt mode for mailbox based + * controllers + */ +static int +mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox64_t *mbox64; + mbox_t *mbox; + uint8_t status; + int i; + + + mbox64 = raid_dev->mbox64; + mbox = raid_dev->mbox; + + /* + * Wait until mailbox is free + */ + if (megaraid_busywait_mbox(raid_dev) != 0) + goto blocked_mailbox; + + /* + * Copy mailbox data into host structure + */ + memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); + mbox->cmdid = 0xFE; + mbox->busy = 1; + mbox->poll = 0; + mbox->ack = 0; + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + + wmb(); + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + // wait for maximum 1 second for status to post. If the status is not + // available within 1 second, assume FW is initializing and wait + // for an extended amount of time + if (mbox->numstatus == 0xFF) { // status not yet available + udelay(25);; + + for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) { + rmb(); + msleep(1); + } + + + if (i == 1000) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid mailbox: wait for FW to boot ")); + + for (i = 0; (mbox->numstatus == 0xFF) && + (i < MBOX_RESET_WAIT); i++) { + rmb(); + con_log(CL_ANN, ("\b\b\b\b\b[%03d]", + MBOX_RESET_WAIT - i)); + msleep(1000); + } + + if (i == MBOX_RESET_WAIT) { + + con_log(CL_ANN, ( + "\nmegaraid mailbox: status not available\n")); + + return -1; + } + con_log(CL_ANN, ("\b\b\b\b\b[ok] \n")); + } + } + + // wait for maximum 1 second for poll semaphore + if (mbox->poll != 0x77) { + udelay(25); + + for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) { + rmb(); + msleep(1); + } + + if (i == 1000) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: could not get poll semaphore\n")); + return -1; + } + } + + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); + wmb(); + + // wait for maximum 1 second for acknowledgement + if (RDINDOOR(raid_dev) & 0x2) { + udelay(25); + + for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) { + rmb(); + msleep(1); + } + + if (i == 1000) { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: could not acknowledge\n")); + return -1; + } + } + mbox->poll = 0; + mbox->ack = 0x77; + + status = mbox->status; + + // invalidate the completed command id array. After command + // completion, firmware would write the valid id. + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) { + mbox->completed[i] = 0xFF; + } + + return status; + +blocked_mailbox: + + con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") ); + return -1; +} + + +/** + * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers + * @adapter - controller's soft state + * @raw_mbox - the mailbox + * + * Issue a scb in synchronous and non-interrupt mode for mailbox based + * controllers. This is a faster version of the synchronous command and + * therefore can be called in interrupt-context as well + */ +static int +mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + long i; + + + mbox = raid_dev->mbox; + + // return immediately if the mailbox is busy + if (mbox->busy) return -1; + + // Copy mailbox data into host structure + memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14); + mbox->cmdid = 0xFE; + mbox->busy = 1; + mbox->poll = 0; + mbox->ack = 0; + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + + wmb(); + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + for (i = 0; i < 0xFFFFF; i++) { + if (mbox->numstatus != 0xFF) break; + } + + if (i == 0xFFFFF) { + // We may need to re-calibrate the counter + con_log(CL_ANN, (KERN_CRIT + "megaraid: fast sync command timed out\n")); + } + + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); + wmb(); + + return mbox->status; +} + + +/** + * megaraid_busywait_mbox() - Wait until the controller's mailbox is available + * @raid_dev - RAID device (HBA) soft state + * + * wait until the controller's mailbox is available to accept more commands. + * wait for at most 1 second + */ +static int +megaraid_busywait_mbox(mraid_device_t *raid_dev) +{ + mbox_t *mbox = raid_dev->mbox; + int i = 0; + + if (mbox->busy) { + udelay(25); + for (i = 0; mbox->busy && i < 1000; i++) + msleep(1); + } + + if (i < 1000) return 0; + else return -1; +} + + +/** + * megaraid_mbox_product_info - some static information about the controller + * @adapter - our soft state + * + * issue commands to the controller to grab some parameters required by our + * caller. + */ +static int +megaraid_mbox_product_info(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + mraid_pinfo_t *pinfo; + dma_addr_t pinfo_dma_h; + mraid_inquiry3_t *mraid_inq3; + int i; + + + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + mbox = (mbox_t *)raw_mbox; + + /* + * Issue an ENQUIRY3 command to find out certain adapter parameters, + * e.g., max channels, max commands etc. + */ + pinfo = pci_alloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + &pinfo_dma_h); + + if (pinfo == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + + return -1; + } + memset(pinfo, 0, sizeof(mraid_pinfo_t)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = FC_NEW_CONFIG; + raw_mbox[2] = NC_SUBOP_ENQUIRY3; + raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; + + // Issue the command + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + + con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n")); + + pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + pinfo, pinfo_dma_h); + + return -1; + } + + /* + * Collect information about state of each physical drive + * attached to the controller. We will expose all the disks + * which are not part of RAID + */ + mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf; + for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) { + raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i]; + } + + /* + * Get product info for information like number of channels, + * maximum commands supported. + */ + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + mbox->xferaddr = (uint32_t)pinfo_dma_h; + + raw_mbox[0] = FC_NEW_CONFIG; + raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; + + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid: product info failed\n")); + + pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + pinfo, pinfo_dma_h); + + return -1; + } + + /* + * Setup some parameters for host, as required by our caller + */ + adapter->max_channel = pinfo->nchannels; + + /* + * we will export all the logical drives on a single channel. + * Add 1 since inquires do not come for inititor ID + */ + adapter->max_target = MAX_LOGICAL_DRIVES_40LD + 1; + adapter->max_lun = 8; // up to 8 LUNs for non-disk devices + + /* + * These are the maximum outstanding commands for the scsi-layer + */ + adapter->max_cmds = MBOX_MAX_SCSI_CMDS; + + memset(adapter->fw_version, 0, VERSION_SIZE); + memset(adapter->bios_version, 0, VERSION_SIZE); + + memcpy(adapter->fw_version, pinfo->fw_version, 4); + adapter->fw_version[4] = 0; + + memcpy(adapter->bios_version, pinfo->bios_version, 4); + adapter->bios_version[4] = 0; + + con_log(CL_ANN, (KERN_NOTICE + "megaraid: fw version:[%s] bios version:[%s]\n", + adapter->fw_version, adapter->bios_version)); + + pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo, + pinfo_dma_h); + + return 0; +} + + + +/** + * megaraid_mbox_extended_cdb - check for support for extended CDBs + * @adapter - soft state for the controller + * + * this routine check whether the controller in question supports extended + * ( > 10 bytes ) CDBs + */ +static int +megaraid_mbox_extended_cdb(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = MAIN_MISC_OPCODE; + raw_mbox[2] = SUPPORT_EXT_CDB; + + /* + * Issue the command + */ + rval = 0; + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + rval = -1; + } + + return rval; +} + + +/** + * megaraid_mbox_support_ha - Do we support clustering + * @adapter - soft state for the controller + * @init_id - ID of the initiator + * + * Determine if the firmware supports clustering and the ID of the initiator. + */ +static int +megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = GET_TARGET_ID; + + // Issue the command + *init_id = 7; + rval = -1; + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + + *init_id = *(uint8_t *)adapter->ibuf; + + con_log(CL_ANN, (KERN_INFO + "megaraid: cluster firmware, initiator ID: %d\n", + *init_id)); + + rval = 0; + } + + return rval; +} + + +/** + * megaraid_mbox_support_random_del - Do we support random deletion + * @adapter - soft state for the controller + * + * Determine if the firmware supports random deletion + * Return: 1 is operation supported, 0 otherwise + */ +static int +megaraid_mbox_support_random_del(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int rval; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + raw_mbox[0] = FC_DEL_LOGDRV; + raw_mbox[0] = OP_SUP_DEL_LOGDRV; + + // Issue the command + rval = 0; + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + + con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n")); + + rval = 1; + } + + return rval; +} + + +/** + * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware + * @adapter - soft state for the controller + * + * Find out the maximum number of scatter-gather elements supported by the + * firmware + */ +static int +megaraid_mbox_get_max_sg(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + int nsg; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = MAIN_MISC_OPCODE; + raw_mbox[2] = GET_MAX_SG_SUPPORT; + + // Issue the command + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + nsg = *(uint8_t *)adapter->ibuf; + } + else { + nsg = MBOX_DEFAULT_SG_SIZE; + } + + if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE; + + return nsg; +} + + +/** + * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels + * @adapter - soft state for the controller + * + * Enumerate the RAID and SCSI channels for ROMB platoforms so that channels + * can be exported as regular SCSI channels + */ +static void +megaraid_mbox_enum_raid_scsi(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; + + memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); + + raw_mbox[0] = CHNL_CLASS; + raw_mbox[2] = GET_CHNL_CLASS; + + // Issue the command. If the command fails, all channels are RAID + // channels + raid_dev->channel_class = 0xFF; + if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { + raid_dev->channel_class = *(uint8_t *)adapter->ibuf; + } + + return; +} + + +/** + * megaraid_mbox_flush_cache - flush adapter and disks cache + * @param adapter : soft state for the controller + * + * Flush adapter cache followed by disks cache + */ +static void +megaraid_mbox_flush_cache(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + raw_mbox[0] = FLUSH_ADAPTER; + + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + con_log(CL_ANN, ("megaraid: flush adapter failed\n")); + } + + raw_mbox[0] = FLUSH_SYSTEM; + + if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { + con_log(CL_ANN, ("megaraid: flush disks cache failed\n")); + } + + return; +} + + +/** + * megaraid_mbox_display_scb - display SCB information, mostly debug purposes + * @param adapter : controllers' soft state + * @param scb : SCB to be displayed + * @param level : debug level for console print + * + * Diplay information about the given SCB iff the current debug level is + * verbose + */ +static void +megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) +{ + mbox_ccb_t *ccb; + struct scsi_cmnd *scp; + mbox_t *mbox; + int level; + int i; + + + ccb = (mbox_ccb_t *)scb->ccb; + scp = scb->scp; + mbox = ccb->mbox; + + level = CL_DLEVEL3; + + con_log(level, (KERN_NOTICE + "megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status, + mbox->cmd, scb->sno)); + + con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n", + mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, + mbox->numsge)); + + if (!scp) return; + + con_log(level, (KERN_NOTICE "scsi cmnd: ")); + + for (i = 0; i < scp->cmd_len; i++) { + con_log(level, ("%#2.02x ", scp->cmnd[i])); + } + + con_log(level, ("\n")); + + return; +} + + +/** + * megaraid_mbox_setup_device_map - manage device ids + * @adapter : Driver's soft state + * + * Manange the device ids to have an appropraite mapping between the kernel + * scsi addresses and megaraid scsi and logical drive addresses. We export + * scsi devices on their actual addresses, whereas the logical drives are + * exported on a virtual scsi channel. + **/ +static void +megaraid_mbox_setup_device_map(adapter_t *adapter) +{ + uint8_t c; + uint8_t t; + + /* + * First fill the values on the logical drive channel + */ + for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) + adapter->device_ids[adapter->max_channel][t] = + (t < adapter->init_id) ? t : t - 1; + + adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; + + /* + * Fill the values on the physical devices channels + */ + for (c = 0; c < adapter->max_channel; c++) + for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) + adapter->device_ids[c][t] = (c << 8) | t; +} + + +/* + * END: internal commands library + */ + +/* + * START: Interface for the common management module + * + * This is the module, which interfaces with the common mangement module to + * provide support for ioctl and sysfs + */ + +/** + * megaraid_cmm_register - register with the mangement module + * @param adapter : HBA soft state + * + * Register with the management module, which allows applications to issue + * ioctl calls to the drivers. This interface is used by the management module + * to setup sysfs support as well. + */ +static int +megaraid_cmm_register(adapter_t *adapter) +{ + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mraid_mmadp_t adp; + scb_t *scb; + mbox_ccb_t *ccb; + int rval; + int i; + + // Allocate memory for the base list of scb for management module. + adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS, + GFP_KERNEL); + + if (adapter->uscb_list == NULL) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + return -1; + } + memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS); + + + // Initialize the synchronization parameters for resources for + // commands for management module + INIT_LIST_HEAD(&adapter->uscb_pool); + + spin_lock_init(USER_FREE_LIST_LOCK(adapter)); + + + + // link all the packets. Note, CCB for commands, coming from the + // commom management module, mailbox physical address are already + // setup by it. We just need placeholder for that in our local command + // control blocks + for (i = 0; i < MBOX_MAX_USER_CMDS; i++) { + + scb = adapter->uscb_list + i; + ccb = raid_dev->uccb_list + i; + + scb->ccb = (caddr_t)ccb; + ccb->mbox64 = raid_dev->umbox64 + i; + ccb->mbox = &ccb->mbox64->mbox32; + ccb->raw_mbox = (uint8_t *)ccb->mbox; + + scb->gp = 0; + + // COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR + // COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER) + scb->sno = i + MBOX_MAX_SCSI_CMDS; + + scb->scp = NULL; + scb->state = SCB_FREE; + scb->dma_direction = PCI_DMA_NONE; + scb->dma_type = MRAID_DMA_NONE; + scb->dev_channel = -1; + scb->dev_target = -1; + + // put scb in the free pool + list_add_tail(&scb->list, &adapter->uscb_pool); + } + + adp.unique_id = adapter->unique_id; + adp.drvr_type = DRVRTYPE_MBOX; + adp.drvr_data = (unsigned long)adapter; + adp.pdev = adapter->pdev; + adp.issue_uioc = megaraid_mbox_mm_handler; + adp.timeout = 30; + adp.max_kioc = MBOX_MAX_USER_CMDS; + + if ((rval = mraid_mm_register_adp(&adp)) != 0) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: did not register with CMM\n")); + + kfree(adapter->uscb_list); + } + + return rval; +} + + +/** + * megaraid_cmm_unregister - un-register with the mangement module + * @param adapter : HBA soft state + * + * Un-register with the management module. + * FIXME: mgmt module must return failure for unregister if it has pending + * commands in LLD + */ +static int +megaraid_cmm_unregister(adapter_t *adapter) +{ + kfree(adapter->uscb_list); + mraid_mm_unregister_adp(adapter->unique_id); + return 0; +} + + +/** + * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD + * @param drvr_data : LLD specific data + * @param kioc : CMM interface packet + * @param action : command action + * + * This routine is invoked whenever the Common Mangement Module (CMM) has a + * command for us. The 'action' parameter specifies if this is a new command + * or otherwise. + */ +static int +megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action) +{ + adapter_t *adapter; + + if (action != IOCTL_ISSUE) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: unsupported management action:%#2x\n", + action)); + return (-ENOTSUPP); + } + + adapter = (adapter_t *)drvr_data; + + // make sure this adapter is not being detached right now. + if (atomic_read(&adapter->being_detached)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: reject management request, detaching\n")); + return (-ENODEV); + } + + switch (kioc->opcode) { + + case GET_ADAP_INFO: + + kioc->status = gather_hbainfo(adapter, (mraid_hba_info_t *) + (unsigned long)kioc->buf_vaddr); + + kioc->done(kioc); + + return kioc->status; + + case MBOX_CMD: + + return megaraid_mbox_mm_command(adapter, kioc); + + default: + kioc->status = (-EINVAL); + kioc->done(kioc); + return (-EINVAL); + } + + return 0; // not reached +} + +/** + * megaraid_mbox_mm_command - issues commands routed through CMM + * @param adapter : HBA soft state + * @param kioc : management command packet + * + * Issues commands, which are routed through the management module. + */ +static int +megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc) +{ + struct list_head *head = &adapter->uscb_pool; + mbox64_t *mbox64; + uint8_t *raw_mbox; + scb_t *scb; + mbox_ccb_t *ccb; + unsigned long flags; + + // detach one scb from free pool + spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); + + if (list_empty(head)) { // should never happen because of CMM + + con_log(CL_ANN, (KERN_WARNING + "megaraid mbox: bug in cmm handler, lost resources\n")); + + spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); + + return (-EINVAL); + } + + scb = list_entry(head->next, scb_t, list); + list_del_init(&scb->list); + + spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); + + scb->state = SCB_ACTIVE; + scb->dma_type = MRAID_DMA_NONE; + + ccb = (mbox_ccb_t *)scb->ccb; + mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; + raw_mbox = (uint8_t *)&mbox64->mbox32; + + memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t)); + + scb->gp = (unsigned long)kioc; + + /* + * If it is a logdrv random delete operation, we have to wait till + * there are no outstanding cmds at the fw and then issue it directly + */ + if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { + + if (wait_till_fw_empty(adapter)) { + con_log(CL_ANN, (KERN_NOTICE + "megaraid mbox: LD delete, timed out\n")); + + kioc->status = -ETIME; + + scb->status = -1; + + megaraid_mbox_mm_done(adapter, scb); + + return (-ETIME); + } + + INIT_LIST_HEAD(&scb->list); + + scb->state = SCB_ISSUED; + if (mbox_post_cmd(adapter, scb) != 0) { + + con_log(CL_ANN, (KERN_NOTICE + "megaraid mbox: LD delete, mailbox busy\n")); + + kioc->status = -EBUSY; + + scb->status = -1; + + megaraid_mbox_mm_done(adapter, scb); + + return (-EBUSY); + } + + return 0; + } + + // put the command on the pending list and execute + megaraid_mbox_runpendq(adapter, scb); + + return 0; +} + + +static int +wait_till_fw_empty(adapter_t *adapter) +{ + unsigned long flags = 0; + int i; + + + /* + * Set the quiescent flag to stop issuing cmds to FW. + */ + spin_lock_irqsave(adapter->host_lock, flags); + adapter->quiescent++; + spin_unlock_irqrestore(adapter->host_lock, flags); + + /* + * Wait till there are no more cmds outstanding at FW. Try for at most + * 60 seconds + */ + for (i = 0; i < 60 && adapter->outstanding_cmds; i++) { + con_log(CL_DLEVEL1, (KERN_INFO + "megaraid: FW has %d pending commands\n", + adapter->outstanding_cmds)); + + msleep(1000); + } + + return adapter->outstanding_cmds; +} + + +/** + * megaraid_mbox_mm_done - callback for CMM commands + * @adapter : HBA soft state + * @scb : completed command + * + * Callback routine for internal commands originated from the management + * module. + */ +static void +megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) +{ + uioc_t *kioc; + mbox64_t *mbox64; + uint8_t *raw_mbox; + unsigned long flags; + + kioc = (uioc_t *)scb->gp; + kioc->status = 0; + mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; + mbox64->mbox32.status = scb->status; + raw_mbox = (uint8_t *)&mbox64->mbox32; + + + // put scb in the free pool + scb->state = SCB_FREE; + scb->scp = NULL; + + spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); + + list_add(&scb->list, &adapter->uscb_pool); + + spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); + + // if a delete logical drive operation succeeded, restart the + // controller + if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { + + adapter->quiescent--; + + megaraid_mbox_runpendq(adapter, NULL); + } + + kioc->done(kioc); + + return; +} + + +/** + * gather_hbainfo - HBA characteristics for the applications + * @param adapter : HBA soft state + * @param hinfo : pointer to the caller's host info strucuture + */ +static int +gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) +{ + uint8_t dmajor; + + dmajor = megaraid_mbox_version[0]; + + hinfo->pci_vendor_id = adapter->pdev->vendor; + hinfo->pci_device_id = adapter->pdev->device; + hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor; + hinfo->subsys_device_id = adapter->pdev->subsystem_device; + + hinfo->pci_bus = adapter->pdev->bus->number; + hinfo->pci_dev_fn = adapter->pdev->devfn; + hinfo->pci_slot = PCI_SLOT(adapter->pdev->devfn); + hinfo->irq = adapter->host->irq; + hinfo->baseport = ADAP2RAIDDEV(adapter)->baseport; + + hinfo->unique_id = (hinfo->pci_bus << 8) | adapter->pdev->devfn; + hinfo->host_no = adapter->host->host_no; + + return 0; +} + +/* + * END: Interface for the common management module + */ + + +/* + * END: Mailbox Low Level Driver + */ +module_init(megaraid_init); +module_exit(megaraid_exit); + +/* vim: set ts=8 sw=8 tw=78 ai si: */ diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h new file mode 100644 index 000000000..2f195abc6 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -0,0 +1,268 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : megaraid_mbox.h + */ + +#ifndef _MEGARAID_H_ +#define _MEGARAID_H_ + + +#include "mega_common.h" +#include "mbox_defs.h" +#include "megaraid_ioctl.h" + + +#define MEGARAID_VERSION "2.20.4.0" +#define MEGARAID_EXT_VERSION "(Release Date: Mon Sep 27 22:15:07 EDT 2004)" + + +/* + * Define some PCI values here until they are put in the kernel + */ +#define PCI_DEVICE_ID_PERC4_DI_DISCOVERY 0x000E +#define PCI_SUBSYS_ID_PERC4_DI_DISCOVERY 0x0123 + +#define PCI_DEVICE_ID_PERC4_SC 0x1960 +#define PCI_SUBSYS_ID_PERC4_SC 0x0520 + +#define PCI_DEVICE_ID_PERC4_DC 0x1960 +#define PCI_SUBSYS_ID_PERC4_DC 0x0518 + +#define PCI_DEVICE_ID_PERC4_QC 0x0407 +#define PCI_SUBSYS_ID_PERC4_QC 0x0531 + +#define PCI_DEVICE_ID_PERC4_DI_EVERGLADES 0x000F +#define PCI_SUBSYS_ID_PERC4_DI_EVERGLADES 0x014A + +#define PCI_DEVICE_ID_PERC4E_SI_BIGBEND 0x0013 +#define PCI_SUBSYS_ID_PERC4E_SI_BIGBEND 0x016c + +#define PCI_DEVICE_ID_PERC4E_DI_KOBUK 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_KOBUK 0x016d + +#define PCI_DEVICE_ID_PERC4E_DI_CORVETTE 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_CORVETTE 0x016e + +#define PCI_DEVICE_ID_PERC4E_DI_EXPEDITION 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION 0x016f + +#define PCI_DEVICE_ID_PERC4E_DI_GUADALUPE 0x0013 +#define PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE 0x0170 + +#define PCI_DEVICE_ID_PERC4E_DC_320_2E 0x0408 +#define PCI_SUBSYS_ID_PERC4E_DC_320_2E 0x0002 + +#define PCI_DEVICE_ID_PERC4E_SC_320_1E 0x0408 +#define PCI_SUBSYS_ID_PERC4E_SC_320_1E 0x0001 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0 0xA520 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1 0x0520 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2 0x0518 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0x 0x0407 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x 0x0530 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2x 0x0407 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x 0x0532 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_4x 0x0407 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x 0x0531 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1E 0x0408 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E 0x0001 + +#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2E 0x0408 +#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E 0x0002 + +#define PCI_DEVICE_ID_MEGARAID_I4_133_RAID 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_I4_133_RAID 0x0522 + +#define PCI_DEVICE_ID_MEGARAID_SATA_150_4 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SATA_150_4 0x4523 + +#define PCI_DEVICE_ID_MEGARAID_SATA_150_6 0x1960 +#define PCI_SUBSYS_ID_MEGARAID_SATA_150_6 0x0523 + +#define PCI_DEVICE_ID_MEGARAID_SATA_300_4x 0x0409 +#define PCI_SUBSYS_ID_MEGARAID_SATA_300_4x 0x3004 + +#define PCI_DEVICE_ID_MEGARAID_SATA_300_8x 0x0409 +#define PCI_SUBSYS_ID_MEGARAID_SATA_300_8x 0x3008 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCU42X 0x0407 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42X 0x0532 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCS16 0x1960 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCS16 0x0523 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCU42E 0x0408 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42E 0x0002 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCZCRX 0x0407 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX 0x0530 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCS28X 0x0409 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCS28X 0x3008 + +#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF 0x0408 +#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF 0x3431 + +#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH 0x0408 +#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH 0x3499 + +#define PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x1960 +#define PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x0520 + +#define PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB 0x0408 +#define PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB 0x1065 + +#define PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E 0x0408 +#define PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E 0x004D + +#define PCI_SUBSYS_ID_PERC3_QC 0x0471 +#define PCI_SUBSYS_ID_PERC3_DC 0x0493 +#define PCI_SUBSYS_ID_PERC3_SC 0x0475 + +#ifndef PCI_SUBSYS_ID_FSC +#define PCI_SUBSYS_ID_FSC 0x1734 +#endif + +#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel +#define MBOX_MAX_USER_CMDS 32 // number of cmds for applications +#define MBOX_DEF_CMD_PER_LUN 64 // default commands per lun +#define MBOX_DEFAULT_SG_SIZE 26 // default sg size supported by all fw +#define MBOX_MAX_SG_SIZE 32 // maximum scatter-gather list size +#define MBOX_MAX_SECTORS 128 // maximum sectors per IO +#define MBOX_TIMEOUT 30 // timeout value for internal cmds +#define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox +#define MBOX_RESET_WAIT 180 // wait these many seconds in reset +#define MBOX_RESET_EXT_WAIT 120 // extended wait reset + +/* + * maximum transfer that can happen through the firmware commands issued + * internnaly from the driver. + */ +#define MBOX_IBUF_SIZE 4096 + + +/** + * mbox_ccb_t - command control block specific to mailbox based controllers + * @raw_mbox : raw mailbox pointer + * @mbox : mailbox + * @mbox64 : extended mailbox + * @mbox_dma_h : maibox dma address + * @sgl64 : 64-bit scatter-gather list + * @sgl32 : 32-bit scatter-gather list + * @sgl_dma_h : dma handle for the scatter-gather list + * @pthru : passthru structure + * @pthru_dma_h : dma handle for the passthru structure + * @epthru : extended passthru structure + * @epthru_dma_h : dma handle for extended passthru structure + * @buf_dma_h : dma handle for buffers w/o sg list + * + * command control block specific to the mailbox based controllers + */ +typedef struct { + uint8_t *raw_mbox; + mbox_t *mbox; + mbox64_t *mbox64; + dma_addr_t mbox_dma_h; + mbox_sgl64 *sgl64; + mbox_sgl32 *sgl32; + dma_addr_t sgl_dma_h; + mraid_passthru_t *pthru; + dma_addr_t pthru_dma_h; + mraid_epassthru_t *epthru; + dma_addr_t epthru_dma_h; + dma_addr_t buf_dma_h; +} mbox_ccb_t; + + +/** + * mraid_device_t - adapter soft state structure for mailbox controllers + * @param una_mbox64 : 64-bit mbox - unaligned + * @param una_mbox64_dma : mbox dma addr - unaligned + * @param mbox : 32-bit mbox - aligned + * @param mbox64 : 64-bit mbox - aligned + * @param mbox_dma : mbox dma addr - aligned + * @param mailbox_lock : exclusion lock for the mailbox + * @param baseport : base port of hba memory + * @param baseaddr : mapped addr of hba memory + * @param mbox_pool : pool of mailboxes + * @param mbox_pool_handle : handle for the mailbox pool memory + * @param epthru_pool : a pool for extended passthru commands + * @param epthru_pool_handle : handle to the pool above + * @param sg_pool : pool of scatter-gather lists for this driver + * @param sg_pool_handle : handle to the pool above + * @param ccb_list : list of our command control blocks + * @param uccb_list : list of cmd control blocks for mgmt module + * @param umbox64 : array of mailbox for user commands (cmm) + * @param pdrv_state : array for state of each physical drive. + * @param last_disp : flag used to show device scanning + * @param hw_error : set if FW not responding + * @param fast_load : If set, skip physical device scanning + * @channel_class : channel class, RAID or SCSI + * + * Initialization structure for mailbox controllers: memory based and IO based + * All the fields in this structure are LLD specific and may be discovered at + * init() or start() time. + * + * NOTE: The fields of this structures are placed to minimize cache misses + */ +typedef struct { + mbox64_t *una_mbox64; + dma_addr_t una_mbox64_dma; + mbox_t *mbox; + mbox64_t *mbox64; + dma_addr_t mbox_dma; + spinlock_t mailbox_lock; + unsigned long baseport; + unsigned long baseaddr; + struct mraid_pci_blk mbox_pool[MBOX_MAX_SCSI_CMDS]; + struct dma_pool *mbox_pool_handle; + struct mraid_pci_blk epthru_pool[MBOX_MAX_SCSI_CMDS]; + struct dma_pool *epthru_pool_handle; + struct mraid_pci_blk sg_pool[MBOX_MAX_SCSI_CMDS]; + struct dma_pool *sg_pool_handle; + mbox_ccb_t ccb_list[MBOX_MAX_SCSI_CMDS]; + mbox_ccb_t uccb_list[MBOX_MAX_USER_CMDS]; + mbox64_t umbox64[MBOX_MAX_USER_CMDS]; + + uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES]; + uint32_t last_disp; + int hw_error; + int fast_load; + uint8_t channel_class; +} mraid_device_t; + +// route to raid device from adapter +#define ADAP2RAIDDEV(adp) ((mraid_device_t *)((adp)->raid_device)) + +#define MAILBOX_LOCK(rdev) (&(rdev)->mailbox_lock) + +// Find out if this channel is a RAID or SCSI +#define IS_RAID_CH(rdev, ch) (((rdev)->channel_class >> (ch)) & 0x01) + + +#define RDINDOOR(rdev) readl((rdev)->baseaddr + 0x20) +#define RDOUTDOOR(rdev) readl((rdev)->baseaddr + 0x2C) +#define WRINDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x20) +#define WROUTDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x2C) + +#endif // _MEGARAID_H_ + +// vim: set ts=8 sw=8 tw=78: diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c new file mode 100644 index 000000000..8a6bc9391 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -0,0 +1,1160 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : megaraid_mm.c + * Version : v2.20.2.0 (August 19 2004) + * + * Common management module + */ + +#include "megaraid_mm.h" + + +// Entry points for char node driver +static int mraid_mm_open(struct inode *, struct file *); +static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long); + + +// routines to convert to and from the old the format +static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *); +static int kioc_to_mimd(uioc_t *, mimd_t __user *); + + +// Helper functions +static int handle_drvrcmd(void __user *, uint8_t, int *); +static int lld_ioctl(mraid_mmadp_t *, uioc_t *); +static void ioctl_done(uioc_t *); +static void lld_timedout(unsigned long); +static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *); +static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *); +static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *); +static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *); +static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int); +static int mraid_mm_setup_dma_pools(mraid_mmadp_t *); +static void mraid_mm_free_adp_resources(mraid_mmadp_t *); +static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *); + +#ifdef CONFIG_COMPAT +static int mraid_mm_compat_ioctl(unsigned int, unsigned int, unsigned long, + struct file *); +#endif + +MODULE_AUTHOR("LSI Logic Corporation"); +MODULE_DESCRIPTION("LSI Logic Management Module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(LSI_COMMON_MOD_VERSION); + +static int dbglevel = CL_ANN; +module_param_named(dlevel, dbglevel, int, 0); +MODULE_PARM_DESC(dlevel, "Debug level (default=0)"); + +EXPORT_SYMBOL(mraid_mm_register_adp); +EXPORT_SYMBOL(mraid_mm_unregister_adp); + +static int majorno; +static uint32_t drvr_ver = 0x02200100; + +static int adapters_count_g; +static struct list_head adapters_list_g; + +wait_queue_head_t wait_q; + +static struct file_operations lsi_fops = { + .open = mraid_mm_open, + .ioctl = mraid_mm_ioctl, + .owner = THIS_MODULE, +}; + +/** + * mraid_mm_open - open routine for char node interface + * @inod : unused + * @filep : unused + * + * allow ioctl operations by apps only if they superuser privilege + */ +static int +mraid_mm_open(struct inode *inode, struct file *filep) +{ + /* + * Only allow superuser to access private ioctl interface + */ + if (!capable(CAP_SYS_ADMIN)) return (-EACCES); + + return 0; +} + +/** + * mraid_mm_ioctl - module entry-point for ioctls + * @inode : inode (ignored) + * @filep : file operations pointer (ignored) + * @cmd : ioctl command + * @arg : user ioctl packet + */ +static int +mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + uioc_t *kioc; + char signature[EXT_IOCTL_SIGN_SZ] = {0}; + int rval; + mraid_mmadp_t *adp; + uint8_t old_ioctl; + int drvrcmd_rval; + void __user *argp = (void __user *)arg; + + /* + * Make sure only USCSICMD are issued through this interface. + * MIMD application would still fire different command. + */ + + if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) { + return (-EINVAL); + } + + /* + * Look for signature to see if this is the new or old ioctl format. + */ + if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: copy from usr addr failed\n")); + return (-EFAULT); + } + + if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0) + old_ioctl = 0; + else + old_ioctl = 1; + + /* + * At present, we don't support the new ioctl packet + */ + if (!old_ioctl ) + return (-EINVAL); + + /* + * If it is a driver ioctl (as opposed to fw ioctls), then we can + * handle the command locally. rval > 0 means it is not a drvr cmd + */ + rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval); + + if (rval < 0) + return rval; + else if (rval == 0) + return drvrcmd_rval; + + rval = 0; + if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) { + return rval; + } + + /* + * The following call will block till a kioc is available + */ + kioc = mraid_mm_alloc_kioc(adp); + + /* + * User sent the old mimd_t ioctl packet. Convert it to uioc_t. + */ + if ((rval = mimd_to_kioc(argp, adp, kioc))) { + mraid_mm_dealloc_kioc(adp, kioc); + return rval; + } + + kioc->done = ioctl_done; + + /* + * Issue the IOCTL to the low level driver + */ + if ((rval = lld_ioctl(adp, kioc))) { + mraid_mm_dealloc_kioc(adp, kioc); + return rval; + } + + /* + * Convert the kioc back to user space + */ + rval = kioc_to_mimd(kioc, argp); + + /* + * Return the kioc to free pool + */ + mraid_mm_dealloc_kioc(adp, kioc); + + return rval; +} + + +/** + * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet + * @umimd : User space mimd_t ioctl packet + * @adapter : pointer to the adapter (OUT) + */ +static mraid_mmadp_t * +mraid_mm_get_adapter(mimd_t __user *umimd, int *rval) +{ + mraid_mmadp_t *adapter; + mimd_t mimd; + uint32_t adapno; + int iterator; + + + if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) { + *rval = -EFAULT; + return NULL; + } + + adapno = GETADAP(mimd.ui.fcs.adapno); + + if (adapno >= adapters_count_g) { + *rval = -ENODEV; + return NULL; + } + + adapter = NULL; + iterator = 0; + + list_for_each_entry(adapter, &adapters_list_g, list) { + if (iterator++ == adapno) break; + } + + if (!adapter) { + *rval = -ENODEV; + return NULL; + } + + return adapter; +} + +/* + * handle_drvrcmd - This routine checks if the opcode is a driver + * cmd and if it is, handles it. + * @arg : packet sent by the user app + * @old_ioctl : mimd if 1; uioc otherwise + */ +static int +handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval) +{ + mimd_t __user *umimd; + mimd_t kmimd; + uint8_t opcode; + uint8_t subopcode; + + if (old_ioctl) + goto old_packet; + else + goto new_packet; + +new_packet: + return (-ENOTSUPP); + +old_packet: + *rval = 0; + umimd = arg; + + if (copy_from_user(&kmimd, umimd, sizeof(mimd_t))) + return (-EFAULT); + + opcode = kmimd.ui.fcs.opcode; + subopcode = kmimd.ui.fcs.subopcode; + + /* + * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or + * GET_NUMADP, then we can handle. Otherwise we should return 1 to + * indicate that we cannot handle this. + */ + if (opcode != 0x82) + return 1; + + switch (subopcode) { + + case MEGAIOC_QDRVRVER: + + if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t))) + return (-EFAULT); + + return 0; + + case MEGAIOC_QNADAP: + + *rval = adapters_count_g; + + if (copy_to_user(kmimd.data, &adapters_count_g, + sizeof(uint32_t))) + return (-EFAULT); + + return 0; + + default: + /* cannot handle */ + return 1; + } + + return 0; +} + + +/** + * mimd_to_kioc - Converter from old to new ioctl format + * + * @umimd : user space old MIMD IOCTL + * @kioc : kernel space new format IOCTL + * + * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The + * new packet is in kernel space so that driver can perform operations on it + * freely. + */ + +static int +mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc) +{ + mbox64_t *mbox64; + mbox_t *mbox; + mraid_passthru_t *pthru32; + uint32_t adapno; + uint8_t opcode; + uint8_t subopcode; + mimd_t mimd; + + if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) + return (-EFAULT); + + /* + * Applications are not allowed to send extd pthru + */ + if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) || + (mimd.mbox[0] == MBOXCMD_EXTPTHRU)) + return (-EINVAL); + + opcode = mimd.ui.fcs.opcode; + subopcode = mimd.ui.fcs.subopcode; + adapno = GETADAP(mimd.ui.fcs.adapno); + + if (adapno >= adapters_count_g) + return (-ENODEV); + + kioc->adapno = adapno; + kioc->mb_type = MBOX_LEGACY; + kioc->app_type = APPTYPE_MIMD; + + switch (opcode) { + + case 0x82: + + if (subopcode == MEGAIOC_QADAPINFO) { + + kioc->opcode = GET_ADAP_INFO; + kioc->data_dir = UIOC_RD; + kioc->xferlen = sizeof(mraid_hba_info_t); + + if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) + return (-ENOMEM); + } + else { + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: Invalid subop\n")); + return (-EINVAL); + } + + break; + + case 0x81: + + kioc->opcode = MBOX_CMD; + kioc->xferlen = mimd.ui.fcs.length; + kioc->user_data_len = kioc->xferlen; + kioc->user_data = mimd.ui.fcs.buffer; + + if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) + return (-ENOMEM); + + if (mimd.outlen) kioc->data_dir = UIOC_RD; + if (mimd.inlen) kioc->data_dir |= UIOC_WR; + + break; + + case 0x80: + + kioc->opcode = MBOX_CMD; + kioc->xferlen = (mimd.outlen > mimd.inlen) ? + mimd.outlen : mimd.inlen; + kioc->user_data_len = kioc->xferlen; + kioc->user_data = mimd.data; + + if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) + return (-ENOMEM); + + if (mimd.outlen) kioc->data_dir = UIOC_RD; + if (mimd.inlen) kioc->data_dir |= UIOC_WR; + + break; + + default: + return (-EINVAL); + } + + /* + * If driver command, nothing else to do + */ + if (opcode == 0x82) + return 0; + + /* + * This is a mailbox cmd; copy the mailbox from mimd + */ + mbox64 = (mbox64_t *)((unsigned long)kioc->cmdbuf); + mbox = &mbox64->mbox32; + memcpy(mbox, mimd.mbox, 14); + + if (mbox->cmd != MBOXCMD_PASSTHRU) { // regular DCMD + + mbox->xferaddr = (uint32_t)kioc->buf_paddr; + + if (kioc->data_dir & UIOC_WR) { + if (copy_from_user(kioc->buf_vaddr, kioc->user_data, + kioc->xferlen)) { + return (-EFAULT); + } + } + + return 0; + } + + /* + * This is a regular 32-bit pthru cmd; mbox points to pthru struct. + * Just like in above case, the beginning for memblk is treated as + * a mailbox. The passthru will begin at next 1K boundary. And the + * data will start 1K after that. + */ + pthru32 = kioc->pthru32; + kioc->user_pthru = &umimd->pthru; + mbox->xferaddr = (uint32_t)kioc->pthru32_h; + + if (copy_from_user(pthru32, kioc->user_pthru, + sizeof(mraid_passthru_t))) { + return (-EFAULT); + } + + pthru32->dataxferaddr = kioc->buf_paddr; + if (kioc->data_dir & UIOC_WR) { + if (copy_from_user(kioc->buf_vaddr, kioc->user_data, + pthru32->dataxferlen)) { + return (-EFAULT); + } + } + + return 0; +} + +/** + * mraid_mm_attch_buf - Attach a free dma buffer for required size + * + * @adp : Adapter softstate + * @kioc : kioc that the buffer needs to be attached to + * @xferlen : required length for buffer + * + * First we search for a pool with smallest buffer that is >= @xferlen. If + * that pool has no free buffer, we will try for the next bigger size. If none + * is available, we will try to allocate the smallest buffer that is >= + * @xferlen and attach it the pool. + */ +static int +mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen) +{ + mm_dmapool_t *pool; + int right_pool = -1; + unsigned long flags; + int i; + + kioc->pool_index = -1; + kioc->buf_vaddr = NULL; + kioc->buf_paddr = 0; + kioc->free_buf = 0; + + /* + * We need xferlen amount of memory. See if we can get it from our + * dma pools. If we don't get exact size, we will try bigger buffer + */ + + for (i = 0; i < MAX_DMA_POOLS; i++) { + + pool = &adp->dma_pool_list[i]; + + if (xferlen > pool->buf_size) + continue; + + if (right_pool == -1) + right_pool = i; + + spin_lock_irqsave(&pool->lock, flags); + + if (!pool->in_use) { + + pool->in_use = 1; + kioc->pool_index = i; + kioc->buf_vaddr = pool->vaddr; + kioc->buf_paddr = pool->paddr; + + spin_unlock_irqrestore(&pool->lock, flags); + return 0; + } + else { + spin_unlock_irqrestore(&pool->lock, flags); + continue; + } + } + + /* + * If xferlen doesn't match any of our pools, return error + */ + if (right_pool == -1) + return -EINVAL; + + /* + * We did not get any buffer from the preallocated pool. Let us try + * to allocate one new buffer. NOTE: This is a blocking call. + */ + pool = &adp->dma_pool_list[right_pool]; + + spin_lock_irqsave(&pool->lock, flags); + + kioc->pool_index = right_pool; + kioc->free_buf = 1; + kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, + &kioc->buf_paddr); + spin_unlock_irqrestore(&pool->lock, flags); + + if (!kioc->buf_vaddr) + return -ENOMEM; + + return 0; +} + +/** + * mraid_mm_alloc_kioc - Returns a uioc_t from free list + * @adp : Adapter softstate for this module + * + * The kioc_semaphore is initialized with number of kioc nodes in the + * free kioc pool. If the kioc pool is empty, this function blocks till + * a kioc becomes free. + */ +static uioc_t * +mraid_mm_alloc_kioc(mraid_mmadp_t *adp) +{ + uioc_t *kioc; + struct list_head* head; + unsigned long flags; + + down(&adp->kioc_semaphore); + + spin_lock_irqsave(&adp->kioc_pool_lock, flags); + + head = &adp->kioc_pool; + + if (list_empty(head)) { + up(&adp->kioc_semaphore); + spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); + + con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n")); + return NULL; + } + + kioc = list_entry(head->next, uioc_t, list); + list_del_init(&kioc->list); + + spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); + + memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t)); + memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t)); + + kioc->buf_vaddr = NULL; + kioc->buf_paddr = 0; + kioc->pool_index =-1; + kioc->free_buf = 0; + kioc->user_data = NULL; + kioc->user_data_len = 0; + kioc->user_pthru = NULL; + + return kioc; +} + +/** + * mraid_mm_dealloc_kioc - Return kioc to free pool + * + * @adp : Adapter softstate + * @kioc : uioc_t node to be returned to free pool + */ +static void +mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc) +{ + mm_dmapool_t *pool; + unsigned long flags; + + pool = &adp->dma_pool_list[kioc->pool_index]; + + /* This routine may be called in non-isr context also */ + spin_lock_irqsave(&pool->lock, flags); + + /* + * While attaching the dma buffer, if we didn't get the required + * buffer from the pool, we would have allocated it at the run time + * and set the free_buf flag. We must free that buffer. Otherwise, + * just mark that the buffer is not in use + */ + if (kioc->free_buf == 1) + pci_pool_free(pool->handle, kioc->buf_vaddr, kioc->buf_paddr); + else + pool->in_use = 0; + + spin_unlock_irqrestore(&pool->lock, flags); + + /* Return the kioc to the free pool */ + spin_lock_irqsave(&adp->kioc_pool_lock, flags); + list_add(&kioc->list, &adp->kioc_pool); + spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); + + /* increment the free kioc count */ + up(&adp->kioc_semaphore); + + return; +} + +/** + * lld_ioctl - Routine to issue ioctl to low level drvr + * + * @adp : The adapter handle + * @kioc : The ioctl packet with kernel addresses + */ +static int +lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc) +{ + int rval; + struct timer_list timer; + struct timer_list *tp = NULL; + + kioc->status = -ENODATA; + rval = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE); + + if (rval) return rval; + + /* + * Start the timer + */ + if (adp->timeout > 0) { + tp = &timer; + init_timer(tp); + + tp->function = lld_timedout; + tp->data = (unsigned long)kioc; + tp->expires = jiffies + adp->timeout * HZ; + + add_timer(tp); + } + + /* + * Wait till the low level driver completes the ioctl. After this + * call, the ioctl either completed successfully or timedout. + */ + wait_event(wait_q, (kioc->status != -ENODATA)); + if (tp) { + del_timer_sync(tp); + } + + return kioc->status; +} + + +/** + * ioctl_done - callback from the low level driver + * + * @kioc : completed ioctl packet + */ +static void +ioctl_done(uioc_t *kioc) +{ + /* + * When the kioc returns from driver, make sure it still doesn't + * have ENODATA in status. Otherwise, driver will hang on wait_event + * forever + */ + if (kioc->status == -ENODATA) { + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: lld didn't change status!\n")); + + kioc->status = -EINVAL; + } + + wake_up(&wait_q); +} + + +/* + * lld_timedout : callback from the expired timer + * + * @ptr : ioctl packet that timed out + */ +static void +lld_timedout(unsigned long ptr) +{ + uioc_t *kioc = (uioc_t *)ptr; + + kioc->status = -ETIME; + + con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n")); + + wake_up(&wait_q); +} + + +/** + * kioc_to_mimd : Converter from new back to old format + * + * @kioc : Kernel space IOCTL packet (successfully issued) + * @mimd : User space MIMD packet + */ +static int +kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd) +{ + mimd_t kmimd; + uint8_t opcode; + uint8_t subopcode; + + mbox64_t *mbox64; + mraid_passthru_t __user *upthru32; + mraid_passthru_t *kpthru32; + mcontroller_t cinfo; + mraid_hba_info_t *hinfo; + + + if (copy_from_user(&kmimd, mimd, sizeof(mimd_t))) + return (-EFAULT); + + opcode = kmimd.ui.fcs.opcode; + subopcode = kmimd.ui.fcs.subopcode; + + if (opcode == 0x82) { + switch (subopcode) { + + case MEGAIOC_QADAPINFO: + + hinfo = (mraid_hba_info_t *)(unsigned long) + kioc->buf_vaddr; + + hinfo_to_cinfo(hinfo, &cinfo); + + if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo))) + return (-EFAULT); + + return 0; + + default: + return (-EINVAL); + } + + return 0; + } + + mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; + + if (kioc->user_pthru) { + + upthru32 = kioc->user_pthru; + kpthru32 = kioc->pthru32; + + if (copy_to_user(&upthru32->scsistatus, + &kpthru32->scsistatus, + sizeof(uint8_t))) { + return (-EFAULT); + } + } + + if (kioc->user_data) { + if (copy_to_user(kioc->user_data, kioc->buf_vaddr, + kioc->user_data_len)) { + return (-EFAULT); + } + } + + if (copy_to_user(&mimd->mbox[17], + &mbox64->mbox32.status, sizeof(uint8_t))) { + return (-EFAULT); + } + + return 0; +} + + +/** + * hinfo_to_cinfo - Convert new format hba info into old format + * + * @hinfo : New format, more comprehensive adapter info + * @cinfo : Old format adapter info to support mimd_t apps + */ +static void +hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo) +{ + if (!hinfo || !cinfo) + return; + + cinfo->base = hinfo->baseport; + cinfo->irq = hinfo->irq; + cinfo->numldrv = hinfo->num_ldrv; + cinfo->pcibus = hinfo->pci_bus; + cinfo->pcidev = hinfo->pci_slot; + cinfo->pcifun = PCI_FUNC(hinfo->pci_dev_fn); + cinfo->pciid = hinfo->pci_device_id; + cinfo->pcivendor = hinfo->pci_vendor_id; + cinfo->pcislot = hinfo->pci_slot; + cinfo->uid = hinfo->unique_id; +} + + +/* + * mraid_mm_register_adp - Registration routine for low level drvrs + * + * @adp : Adapter objejct + */ +int +mraid_mm_register_adp(mraid_mmadp_t *lld_adp) +{ + mraid_mmadp_t *adapter; + mbox64_t *mbox_list; + uioc_t *kioc; + uint32_t rval; + int i; + + + if (lld_adp->drvr_type != DRVRTYPE_MBOX) + return (-EINVAL); + + adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); + + if (!adapter) { + rval = -ENOMEM; + goto memalloc_error; + } + + memset(adapter, 0, sizeof(mraid_mmadp_t)); + + adapter->unique_id = lld_adp->unique_id; + adapter->drvr_type = lld_adp->drvr_type; + adapter->drvr_data = lld_adp->drvr_data; + adapter->pdev = lld_adp->pdev; + adapter->issue_uioc = lld_adp->issue_uioc; + adapter->timeout = lld_adp->timeout; + adapter->max_kioc = lld_adp->max_kioc; + + /* + * Allocate single blocks of memory for all required kiocs, + * mailboxes and passthru structures. + */ + adapter->kioc_list = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc, + GFP_KERNEL); + adapter->mbox_list = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc, + GFP_KERNEL); + adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool", + adapter->pdev, + sizeof(mraid_passthru_t), + 16, 0); + + if (!adapter->kioc_list || !adapter->mbox_list || + !adapter->pthru_dma_pool) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: out of memory, %s %d\n", __FUNCTION__, + __LINE__)); + + rval = (-ENOMEM); + + goto memalloc_error; + } + + /* + * Slice kioc_list and make a kioc_pool with the individiual kiocs + */ + INIT_LIST_HEAD(&adapter->kioc_pool); + spin_lock_init(&adapter->kioc_pool_lock); + sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc); + + mbox_list = (mbox64_t *)adapter->mbox_list; + + for (i = 0; i < lld_adp->max_kioc; i++) { + + kioc = adapter->kioc_list + i; + kioc->cmdbuf = (uint64_t)(unsigned long)(mbox_list + i); + kioc->pthru32 = pci_pool_alloc(adapter->pthru_dma_pool, + GFP_KERNEL, &kioc->pthru32_h); + + if (!kioc->pthru32) { + + con_log(CL_ANN, (KERN_WARNING + "megaraid cmm: out of memory, %s %d\n", + __FUNCTION__, __LINE__)); + + rval = (-ENOMEM); + + goto pthru_dma_pool_error; + } + + list_add_tail(&kioc->list, &adapter->kioc_pool); + } + + // Setup the dma pools for data buffers + if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) { + goto dma_pool_error; + } + + list_add_tail(&adapter->list, &adapters_list_g); + + adapters_count_g++; + + return 0; + +dma_pool_error: + /* Do nothing */ + +pthru_dma_pool_error: + + for (i = 0; i < lld_adp->max_kioc; i++) { + kioc = adapter->kioc_list + i; + if (kioc->pthru32) { + pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32, + kioc->pthru32_h); + } + } + +memalloc_error: + + if (adapter->kioc_list) + kfree(adapter->kioc_list); + + if (adapter->mbox_list) + kfree(adapter->mbox_list); + + if (adapter->pthru_dma_pool) + pci_pool_destroy(adapter->pthru_dma_pool); + + if (adapter) + kfree(adapter); + + return rval; +} + +/** + * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter + * + * @adp : Adapter softstate + * + * We maintain a pool of dma buffers per each adapter. Each pool has one + * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers. + * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We + * dont' want to waste too much memory by allocating more buffers per each + * pool. + */ +static int +mraid_mm_setup_dma_pools(mraid_mmadp_t *adp) +{ + mm_dmapool_t *pool; + int bufsize; + int i; + + /* + * Create MAX_DMA_POOLS number of pools + */ + bufsize = MRAID_MM_INIT_BUFF_SIZE; + + for (i = 0; i < MAX_DMA_POOLS; i++){ + + pool = &adp->dma_pool_list[i]; + + pool->buf_size = bufsize; + spin_lock_init(&pool->lock); + + pool->handle = pci_pool_create("megaraid mm data buffer", + adp->pdev, bufsize, 16, 0); + + if (!pool->handle) { + goto dma_pool_setup_error; + } + + pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, + &pool->paddr); + + if (!pool->vaddr) + goto dma_pool_setup_error; + + bufsize = bufsize * 2; + } + + return 0; + +dma_pool_setup_error: + + mraid_mm_teardown_dma_pools(adp); + return (-ENOMEM); +} + + +/* + * mraid_mm_unregister_adp - Unregister routine for low level drivers + * Assume no outstanding ioctls to llds. + * + * @unique_id : UID of the adpater + */ +int +mraid_mm_unregister_adp(uint32_t unique_id) +{ + mraid_mmadp_t *adapter; + mraid_mmadp_t *tmp; + + list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) { + + + if (adapter->unique_id == unique_id) { + + adapters_count_g--; + + list_del_init(&adapter->list); + + mraid_mm_free_adp_resources(adapter); + + kfree(adapter); + + con_log(CL_ANN, ( + "megaraid cmm: Unregistered one adapter:%#x\n", + unique_id)); + + return 0; + } + } + + return (-ENODEV); +} + +/** + * mraid_mm_free_adp_resources - Free adapter softstate + * + * @adp : Adapter softstate + */ +static void +mraid_mm_free_adp_resources(mraid_mmadp_t *adp) +{ + uioc_t *kioc; + int i; + + mraid_mm_teardown_dma_pools(adp); + + for (i = 0; i < adp->max_kioc; i++) { + + kioc = adp->kioc_list + i; + + pci_pool_free(adp->pthru_dma_pool, kioc->pthru32, + kioc->pthru32_h); + } + + kfree(adp->kioc_list); + + kfree(adp->mbox_list); + + pci_pool_destroy(adp->pthru_dma_pool); + + + return; +} + + +/** + * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers + * + * @adp : Adapter softstate + */ +static void +mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp) +{ + int i; + mm_dmapool_t *pool; + + for (i = 0; i < MAX_DMA_POOLS; i++) { + + pool = &adp->dma_pool_list[i]; + + if (pool->handle) { + + if (pool->vaddr) + pci_pool_free(pool->handle, pool->vaddr, + pool->paddr); + + pci_pool_destroy(pool->handle); + pool->handle = NULL; + } + } + + return; +} + +/** + * mraid_mm_init : Module entry point + */ +static int __init +mraid_mm_init(void) +{ + // Announce the driver version + con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n", + LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION)); + + majorno = register_chrdev(0, "megadev", &lsi_fops); + + if (majorno < 0) { + con_log(CL_ANN, ("megaraid cmm: cannot get major\n")); + return majorno; + } + + init_waitqueue_head(&wait_q); + + INIT_LIST_HEAD(&adapters_list_g); + +#ifdef CONFIG_COMPAT + register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl); +#endif + + return 0; +} + + +/** + * mraid_mm_compat_ioctl : 32bit to 64bit ioctl conversion routine + */ +#ifdef CONFIG_COMPAT +static int +mraid_mm_compat_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filep) +{ + struct inode *inode = filep->f_dentry->d_inode; + + return mraid_mm_ioctl(inode, filep, cmd, arg); +} +#endif + +/** + * mraid_mm_exit : Module exit point + */ +static void __exit +mraid_mm_exit(void) +{ + con_log(CL_DLEVEL1 , ("exiting common mod\n")); + + unregister_chrdev(majorno, "megadev"); + unregister_ioctl32_conversion(MEGAIOCCMD); +} + +module_init(mraid_mm_init); +module_exit(mraid_mm_exit); + +/* vi: set ts=8 sw=8 tw=78: */ diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h new file mode 100644 index 000000000..effc23a63 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_mm.h @@ -0,0 +1,102 @@ +/* + * + * Linux MegaRAID device driver + * + * Copyright (c) 2003-2004 LSI Logic Corporation. + * + * 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. + * + * FILE : megaraid_mm.h + */ + +#ifndef MEGARAID_MM_H +#define MEGARAID_MM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mbox_defs.h" +#include "megaraid_ioctl.h" + + +#define LSI_COMMON_MOD_VERSION "2.20.2.0" +#define LSI_COMMON_MOD_EXT_VERSION \ + "(Release Date: Thu Aug 19 09:58:33 EDT 2004)" + + +#define LSI_DBGLVL dbglevel + +// The smallest dma pool +#define MRAID_MM_INIT_BUFF_SIZE 4096 + +/** + * mimd_t : Old style ioctl packet structure (deprecated) + * + * @inlen : + * @outlen : + * @fca : + * @opcode : + * @subopcode : + * @adapno : + * @buffer : + * @pad : + * @length : + * @mbox : + * @pthru : + * @data : + * @pad : + * + * Note : This structure is DEPRECATED. New applications must use + * : uioc_t structure instead. All new hba drivers use the new + * : format. If we get this mimd packet, we will convert it into + * : new uioc_t format and send it to the hba drivers. + */ + +typedef struct mimd { + + uint32_t inlen; + uint32_t outlen; + + union { + uint8_t fca[16]; + struct { + uint8_t opcode; + uint8_t subopcode; + uint16_t adapno; +#if BITS_PER_LONG == 32 + uint8_t __user *buffer; + uint8_t pad[4]; +#endif +#if BITS_PER_LONG == 64 + uint8_t __user *buffer; +#endif + uint32_t length; + } __attribute__ ((packed)) fcs; + } __attribute__ ((packed)) ui; + + uint8_t mbox[18]; /* 16 bytes + 2 status bytes */ + mraid_passthru_t pthru; + +#if BITS_PER_LONG == 32 + char __user *data; /* buffer <= 4096 for 0x80 commands */ + char pad[4]; +#endif +#if BITS_PER_LONG == 64 + char __user *data; +#endif + +} __attribute__ ((packed))mimd_t; + +#endif // MEGARAID_MM_H + +// vi: set ts=8 sw=8 tw=78: diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index b43feb93c..9735d05ad 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -267,8 +267,8 @@ static void nsp32_prom_stop (nsp32_hw_data *); static int nsp32_prom_read (nsp32_hw_data *, int); static int nsp32_prom_read_bit (nsp32_hw_data *); static void nsp32_prom_write_bit(nsp32_hw_data *, int); -static inline void nsp32_prom_set (nsp32_hw_data *, int, int); -static inline int nsp32_prom_get (nsp32_hw_data *, int); +static void nsp32_prom_set (nsp32_hw_data *, int, int); +static int nsp32_prom_get (nsp32_hw_data *, int); /* debug/warning/info message */ static void nsp32_message (const char *, int, char *, char *, ...); @@ -3342,7 +3342,7 @@ static int nsp32_prom_read(nsp32_hw_data *data, int romaddr) return val; } -static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) +static void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) { int base = data->BaseAddress; int tmp; @@ -3360,7 +3360,7 @@ static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) udelay(10); } -static inline int nsp32_prom_get(nsp32_hw_data *data, int bit) +static int nsp32_prom_get(nsp32_hw_data *data, int bit) { int base = data->BaseAddress; int tmp, ret; diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index 1c9788e2d..78127896a 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -605,6 +605,7 @@ static int pas16_release(struct Scsi_Host *shost) { if (shost->irq) free_irq(shost->irq, NULL); + NCR5380_exit(shost); if (shost->dma_channel != 0xff) free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 363d79399..75648dcb6 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1528,7 +1528,7 @@ nsp_proc_info( thislength = pos - (buffer + offset); if(thislength < 0) { - *start = 0; + *start = NULL; return 0; } diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 917a208d1..c4820cfde 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4,7 +4,7 @@ * QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver * Copyright (C) 2000 Qlogic Corporation (www.qlogic.com) * Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc. -* Copyright (C) 2003 Christoph Hellwig +* Copyright (C) 2003-2004 Christoph Hellwig * * 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 @@ -17,9 +17,12 @@ * General Public License for more details. * ******************************************************************************/ -#define QLA1280_VERSION "3.24.3" +#define QLA1280_VERSION "3.24.4" /***************************************************************************** Revision History: + Rev 3.24.4 June 7, 2004 Christoph Hellwig + - restructure firmware loading, cleanup initialization code + - prepare support for ISP1020/1040 chips Rev 3.24.3 January 19, 2004, Jes Sorensen - Handle PCI DMA mask settings correctly - Correct order of error handling in probe_one, free_irq should not @@ -485,6 +488,14 @@ static inline void scsi_host_put(struct Scsi_Host *h) #define ia64_platform_is(foo) (!strcmp(x, platform_name)) #endif + +#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020) +#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \ + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240) +#define IS_ISP1x160(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160 || \ + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160) + + static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *); static void qla1280_remove_one(struct pci_dev *); @@ -501,9 +512,7 @@ static int qla1280_setup(char *s) __init; /* * QLogic ISP1280 Hardware Support Function Prototypes. */ -static int qla1280_isp_firmware(struct scsi_qla_host *); -static int qla1280_chip_diag(struct scsi_qla_host *); -static int qla1280_setup_chip(struct scsi_qla_host *); +static int qla1280_load_firmware(struct scsi_qla_host *); static int qla1280_init_rings(struct scsi_qla_host *); static int qla1280_nvram_config(struct scsi_qla_host *); static int qla1280_mailbox_command(struct scsi_qla_host *, @@ -1384,16 +1393,10 @@ qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct nvram *nv; - int is1x160, status; + int status; nv = &ha->nvram; - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) - is1x160 = 1; - else - is1x160 = 0; - mr = BIT_3 | BIT_2 | BIT_1 | BIT_0; /* Set Target Parameters. */ @@ -1403,17 +1406,16 @@ qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) mb[2] = (nv->bus[bus].target[target].parameter.c << 8); - if (is1x160) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - - if (is1x160) { + if (IS_ISP1x160(ha)) { mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - mb[6] = nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8; - mb[6] |= nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; + mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) | + nv->bus[bus].target[target].sync_period; + mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | + nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; mr |= BIT_6; + } else { + mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) | + nv->bus[bus].target[target].sync_period; } status = qla1280_mailbox_command(ha, mr, &mb[0]); @@ -1476,8 +1478,7 @@ qla1280_slave_configure(struct scsi_device *device) (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) nv->bus[bus].target[target].parameter.f.enable_wide = 0; - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) { + if (IS_ISP1x160(ha)) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && (~driver_setup.ppr_mask & (1 << target)))) @@ -1802,17 +1803,8 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) */ spin_lock_irqsave(HOST_LOCK, flags); #endif - /* If firmware needs to be loaded */ - if (qla1280_isp_firmware(ha)) { - if (!(status = qla1280_chip_diag(ha))) { - status = qla1280_setup_chip(ha); - } - } else { - printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", - ha->host_no); - status = 1; - } + status = qla1280_load_firmware(ha); if (status) { printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n", ha->host_no); @@ -1823,36 +1815,24 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) dprintk(1, "scsi(%ld): Configure NVRAM parameters\n", ha->host_no); qla1280_nvram_config(ha); - if (!ha->flags.disable_host_adapter && !qla1280_init_rings(ha)) { - /* Issue SCSI reset. */ - /* dg 03/13 if we can't reset twice then bus is dead */ - for (bus = 0; bus < ha->ports; bus++) { - if (!ha->bus_settings[bus].disable_scsi_reset){ - if (qla1280_bus_reset(ha, bus)) { - if (qla1280_bus_reset(ha, bus)) { - ha->bus_settings[bus].scsi_bus_dead = 1; - } - } - } - } + if (ha->flags.disable_host_adapter) { + status = 1; + goto out; + } - /* - * qla1280_bus_reset() will take care of issueing markers, - * no need to do that here as well! - */ -#if 0 - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports; bus++) { - ha->bus_settings[bus].reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, MK_SYNC_ALL); - } -#endif + status = qla1280_init_rings(ha); + if (status) + goto out; - ha->flags.online = 1; - } else - status = 1; + /* Issue SCSI reset, if we can't reset twice then bus is dead */ + for (bus = 0; bus < ha->ports; bus++) { + if (!ha->bus_settings[bus].disable_scsi_reset && + qla1280_bus_reset(ha, bus) && + qla1280_bus_reset(ha, bus)) + ha->bus_settings[bus].scsi_bus_dead = 1; + } + ha->flags.online = 1; out: #if LINUX_VERSION_CODE >= 0x020500 spin_unlock_irqrestore(HOST_LOCK, flags); @@ -1945,13 +1925,13 @@ qla1280_chip_diag(struct scsi_qla_host *ha) int status = 0; int cnt; uint16_t data; - dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", ®->id_l); dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no); /* Soft reset chip and wait for it to finish. */ WRT_REG_WORD(®->ictrl, ISP_RESET); + /* * We can't do a traditional PCI write flush here by reading * back the register. The card will not respond once the reset @@ -1969,145 +1949,138 @@ qla1280_chip_diag(struct scsi_qla_host *ha) data = RD_REG_WORD(®->ictrl); } - if (cnt) { - /* Reset register cleared by chip reset. */ - dprintk(3, "qla1280_chip_diag: reset register cleared by " - "chip reset\n"); + if (!cnt) + goto fail; - WRT_REG_WORD(®->cfg_1, 0); + /* Reset register cleared by chip reset. */ + dprintk(3, "qla1280_chip_diag: reset register cleared by chip reset\n"); - /* Reset RISC and disable BIOS which - allows RISC to execute out of RAM. */ -#if 0 - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); -#else - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | - HC_RELEASE_RISC | HC_DISABLE_BIOS); -#endif - RD_REG_WORD(®->id_l); /* Flush PCI write */ - data = qla1280_debounce_register(®->mailbox0); - /* - * I *LOVE* this code! - */ - for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { - udelay(5); - data = RD_REG_WORD(®->mailbox0); - } + WRT_REG_WORD(®->cfg_1, 0); - if (cnt) { - /* Check product ID of chip */ - dprintk(3, "qla1280_chip_diag: Checking product " - "ID of chip\n"); - - if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || - (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && - RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || - RD_REG_WORD(®->mailbox3) != PROD_ID_3 || - RD_REG_WORD(®->mailbox4) != PROD_ID_4) { - printk(KERN_INFO "qla1280: Wrong product ID = " - "0x%x,0x%x,0x%x,0x%x\n", - RD_REG_WORD(®->mailbox1), - RD_REG_WORD(®->mailbox2), - RD_REG_WORD(®->mailbox3), - RD_REG_WORD(®->mailbox4)); - status = 1; - } else { - /* - * Enable ints early!!! - */ - qla1280_enable_intrs(ha); - - dprintk(1, "qla1280_chip_diag: Checking " - "mailboxes of chip\n"); - /* Wrap Incoming Mailboxes Test. */ - mb[0] = MBC_MAILBOX_REGISTER_TEST; - mb[1] = 0xAAAA; - mb[2] = 0x5555; - mb[3] = 0xAA55; - mb[4] = 0x55AA; - mb[5] = 0xA5A5; - mb[6] = 0x5A5A; - mb[7] = 0x2525; - if (!(status = qla1280_mailbox_command(ha, - 0xff, - &mb - [0]))) { - if (mb[1] != 0xAAAA || - mb[2] != 0x5555 || - mb[3] != 0xAA55 || - mb[4] != 0x55AA || - mb[5] != 0xA5A5 || - mb[6] != 0x5A5A || - mb[7] != 0x2525) { - status = 1; - printk(KERN_INFO "qla1280: " - "Failed mbox check\n"); - } - } - } - } else - status = 1; - } else - status = 1; + /* Reset RISC and disable BIOS which + allows RISC to execute out of RAM. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | + HC_RELEASE_RISC | HC_DISABLE_BIOS); + RD_REG_WORD(®->id_l); /* Flush PCI write */ + data = qla1280_debounce_register(®->mailbox0); + + /* + * I *LOVE* this code! + */ + for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { + udelay(5); + data = RD_REG_WORD(®->mailbox0); + } + + if (!cnt) + goto fail; + + /* Check product ID of chip */ + dprintk(3, "qla1280_chip_diag: Checking product ID of chip\n"); + + if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®->mailbox3) != PROD_ID_3 || + RD_REG_WORD(®->mailbox4) != PROD_ID_4) { + printk(KERN_INFO "qla1280: Wrong product ID = " + "0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®->mailbox1), + RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3), + RD_REG_WORD(®->mailbox4)); + goto fail; + } + + /* + * Enable ints early!!! + */ + qla1280_enable_intrs(ha); + + dprintk(1, "qla1280_chip_diag: Checking mailboxes of chip\n"); + /* Wrap Incoming Mailboxes Test. */ + mb[0] = MBC_MAILBOX_REGISTER_TEST; + mb[1] = 0xAAAA; + mb[2] = 0x5555; + mb[3] = 0xAA55; + mb[4] = 0x55AA; + mb[5] = 0xA5A5; + mb[6] = 0x5A5A; + mb[7] = 0x2525; + + status = qla1280_mailbox_command(ha, 0xff, mb); if (status) - dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); - else - dprintk(3, "qla1280_chip_diag: exiting normally\n"); + goto fail; + + if (mb[1] != 0xAAAA || mb[2] != 0x5555 || mb[3] != 0xAA55 || + mb[4] != 0x55AA || mb[5] != 0xA5A5 || mb[6] != 0x5A5A || + mb[7] != 0x2525) { + printk(KERN_INFO "qla1280: Failed mbox check\n"); + goto fail; + } + dprintk(3, "qla1280_chip_diag: exiting normally\n"); + return 0; + fail: + dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); return status; } -/* - * Setup chip - * Load and start RISC firmware. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - */ -#define DUMP_IT_BACK 0 /* for debug of RISC loading */ static int -qla1280_setup_chip(struct scsi_qla_host *ha) +qla1280_load_firmware_pio(struct scsi_qla_host *ha) { - int status = 0; - uint16_t risc_address; - uint16_t *risc_code_address; - int risc_code_size; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t cnt; - int num, i; -#if DUMP_IT_BACK - uint8_t *sp; - uint8_t *tbuf; - dma_addr_t p_tbuf; -#endif + uint16_t risc_address, *risc_code_address, risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT], i; + int err; - ENTER("qla1280_setup_chip"); + /* Load RISC code. */ + risc_address = *ql1280_board_tbl[ha->devnum].fwstart; + risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; + risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; + + for (i = 0; i < risc_code_size; i++) { + mb[0] = MBC_WRITE_RAM_WORD; + mb[1] = risc_address + i; + mb[2] = risc_code_address[i]; + + err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb); + if (err) { + printk(KERN_ERR "scsi(%li): Failed to load firmware\n", + ha->host_no); + return err; + } + } - dprintk(1, "scsi(%ld): Setup chip\n", ha->host_no); + return 0; +} +#define DUMP_IT_BACK 0 /* for debug of RISC loading */ +static int +qla1280_load_firmware_dma(struct scsi_qla_host *ha) +{ + uint16_t risc_address, *risc_code_address, risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT], cnt; + int err = 0, num, i; #if DUMP_IT_BACK - /* get consistent memory allocated for setup_chip */ + uint8_t *sp, *tbuf; + dma_addr_t p_tbuf; + tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); + if (!tbuf) + return -ENOMEM; #endif /* Load RISC code. */ risc_address = *ql1280_board_tbl[ha->devnum].fwstart; risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; - risc_code_size = (int) *ql1280_board_tbl[ha->devnum].fwlen; + risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; - dprintk(1, "qla1280_setup_chip: DMA RISC code (%i) words\n", - risc_code_size); + dprintk(1, "%s: DMA RISC code (%i) words\n", + __FUNCTION__, risc_code_size); num = 0; - while (risc_code_size > 0 && !status) { + while (risc_code_size > 0) { int warn __attribute__((unused)) = 0; cnt = 2000 >> 1; @@ -2129,15 +2102,16 @@ qla1280_setup_chip(struct scsi_qla_host *ha) mb[2] = (ha->request_dma >> 16) & 0xffff; mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; mb[6] = pci_dma_hi32(ha->request_dma) >> 16; - dprintk(2, "qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x," - "0x%4x,0x%4x\n", mb[0], (void *)(long)ha->request_dma, - mb[6], mb[7], mb[2], mb[3]); - if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | - BIT_2 | BIT_1 | BIT_0, - &mb[0]))) { + dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n", + __FUNCTION__, mb[0], + (void *)(long)ha->request_dma, + mb[6], mb[7], mb[2], mb[3]); + err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | + BIT_1 | BIT_0, mb); + if (err) { printk(KERN_ERR "scsi(%li): Failed to load partial " "segment of f\n", ha->host_no); - break; + goto out; } #if DUMP_IT_BACK @@ -2149,22 +2123,22 @@ qla1280_setup_chip(struct scsi_qla_host *ha) mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; mb[6] = pci_dma_hi32(p_tbuf) >> 16; - if ((status = qla1280_mailbox_command(ha, - BIT_4 | BIT_3 | BIT_2 | - BIT_1 | BIT_0, - &mb[0]))) { + err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | + BIT_1 | BIT_0, mb); + if (err) { printk(KERN_ERR "Failed to dump partial segment of f/w\n"); - break; + goto out; } sp = (uint8_t *)ha->request_ring; for (i = 0; i < (cnt << 1); i++) { if (tbuf[i] != sp[i] && warn++ < 10) { - printk(KERN_ERR "qla1280_setup_chip: FW " - "compare error @ byte(0x%x) loop#=%x\n", - i, num); - printk(KERN_ERR "setup_chip: FWbyte=%x " - "FWfromChip=%x\n", sp[i], tbuf[i]); + printk(KERN_ERR "%s: FW compare error @ " + "byte(0x%x) loop#=%x\n", + __FUNCTION__, i, num); + printk(KERN_ERR "%s: FWbyte=%x " + "FWfromChip=%x\n", + __FUNCTION__, sp[i], tbuf[i]); /*break; */ } } @@ -2175,37 +2149,69 @@ qla1280_setup_chip(struct scsi_qla_host *ha) num++; } + out: +#if DUMP_IT_BACK + pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); +#endif + return err; +} + +static int +qla1280_start_firmware(struct scsi_qla_host *ha) +{ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int err; + + dprintk(1, "%s: Verifying checksum of loaded RISC code.\n", + __FUNCTION__); + /* Verify checksum of loaded RISC code. */ - if (!status) { - dprintk(1, "qla1280_setup_chip: Verifying checksum of " - "loaded RISC code.\n"); - mb[0] = MBC_VERIFY_CHECKSUM; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + mb[0] = MBC_VERIFY_CHECKSUM; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); + if (err) { + printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no); + return err; + } - if (!(status = - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { - /* Start firmware execution. */ - dprintk(1, - "qla1280_setup_chip: start firmware running.\n"); - mb[0] = MBC_EXECUTE_FIRMWARE; - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - } else - printk(KERN_ERR "scsi(%li): qla1280_setup_chip: " - "Failed checksum\n", ha->host_no); + /* Start firmware execution. */ + dprintk(1, "%s: start firmware running.\n", __FUNCTION__); + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + if (err) { + printk(KERN_ERR "scsi(%li): Failed to start firmware\n", + ha->host_no); } -#if DUMP_IT_BACK - /* free consistent memory allocated for setup_chip */ - pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); -#endif + return err; +} - if (status) - dprintk(2, "qla1280_setup_chip: **** FAILED ****\n"); +static int +qla1280_load_firmware(struct scsi_qla_host *ha) +{ + int err = -ENODEV; - LEAVE("qla1280_setup_chip"); - return status; + /* If firmware needs to be loaded */ + if (!qla1280_isp_firmware(ha)) { + printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", + ha->host_no); + goto out; + } + + err = qla1280_chip_diag(ha); + if (err) + goto out; + if (IS_ISP1040(ha)) + err = qla1280_load_firmware_pio(ha); + else + err = qla1280_load_firmware_dma(ha); + if (err) + goto out; + err = qla1280_start_firmware(ha); + out: + return err; } /* @@ -2271,123 +2277,9 @@ qla1280_init_rings(struct scsi_qla_host *ha) return status; } -/* - * NVRAM configuration. - * - * Input: - * ha = adapter block pointer. - * ha->request_ring = request ring virtual address - * - * Output: - * host adapters parameters in host adapter block - * - * Returns: - * 0 = success. - */ -static int -qla1280_nvram_config(struct scsi_qla_host *ha) +static void +qla1280_print_settings(struct nvram *nv) { - struct device_reg *reg = ha->iobase; - struct nvram *nv; - int is1x160, status = 0; - int bus, target, lun; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t mask; - - ENTER("qla1280_nvram_config"); - - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) - is1x160 = 1; - else - is1x160 = 0; - - nv = &ha->nvram; - if (!ha->nvram_valid) { - dprintk(1, "Using defaults for NVRAM: \n"); - memset(nv, 0, sizeof(struct nvram)); - - /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ - nv->firmware_feature.f.enable_fast_posting = 1; - nv->firmware_feature.f.disable_synchronous_backoff = 1; - - nv->termination.f.scsi_bus_0_control = 3; - nv->termination.f.scsi_bus_1_control = 3; - nv->termination.f.auto_term_support = 1; - - /* - * Set default FIFO magic - What appropriate values - * would be here is unknown. This is what I have found - * testing with 12160s. - * Now, I would love the magic decoder ring for this one, - * the header file provided by QLogic seems to be bogus - * or incomplete at best. - */ - nv->isp_config.c = 0x44; - - if (is1x160) - nv->isp_parameter = 0x01; - - for (bus = 0; bus < MAX_BUSES; bus++) { - nv->bus[bus].config_1.initiator_id = 7; - nv->bus[bus].bus_reset_delay = 5; - /* 8 = 5.0 clocks */ - nv->bus[bus].config_2.async_data_setup_time = 8; - nv->bus[bus].config_2.req_ack_active_negation = 1; - nv->bus[bus].config_2.data_line_active_negation = 1; - nv->bus[bus].selection_timeout = 250; - nv->bus[bus].max_queue_depth = 256; - - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. - renegotiate_on_error = 1; - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - tag_queuing = 1; - nv->bus[bus].target[target].parameter.f. - enable_sync = 1; -#if 1 /* Some SCSI Processors do not seem to like this */ - nv->bus[bus].target[target].parameter.f. - enable_wide = 1; -#endif - nv->bus[bus].target[target].parameter.f. - parity_checking = 1; - nv->bus[bus].target[target].parameter.f. - disconnect_allowed = 1; - nv->bus[bus].target[target].execution_throttle= - nv->bus[bus].max_queue_depth - 1; - if (is1x160) { - nv->bus[bus].target[target].flags. - flags1x160.device_enable = 1; - nv->bus[bus].target[target].flags. - flags1x160.sync_offset = 0x0e; - nv->bus[bus].target[target]. - sync_period = 9; - nv->bus[bus].target[target]. - ppr_1x160.flags.enable_ppr = 1; - nv->bus[bus].target[target].ppr_1x160. - flags.ppr_options = 2; - nv->bus[bus].target[target].ppr_1x160. - flags.ppr_bus_width = 1; - } else { - nv->bus[bus].target[target].flags. - flags1x80.device_enable = 1; - nv->bus[bus].target[target].flags. - flags1x80.sync_offset = 0x8; - nv->bus[bus].target[target]. - sync_period = 10; - } - } - } - } else { - /* Always force AUTO sense for LINUX SCSI */ - for (bus = 0; bus < MAX_BUSES; bus++) - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - } - } dprintk(1, "qla1280 : initiator scsi id bus[0]=%d\n", nv->bus[0].config_1.initiator_id); dprintk(1, "qla1280 : initiator scsi id bus[1]=%d\n", @@ -2433,36 +2325,264 @@ qla1280_nvram_config(struct scsi_qla_host *ha) nv->bus[0].max_queue_depth); dprintk(1, "qla1280 : max queue depth[1]=%d\n", nv->bus[1].max_queue_depth); +} + +static void +qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target) +{ + struct nvram *nv = &ha->nvram; + + nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1; + nv->bus[bus].target[target].parameter.f.auto_request_sense = 1; + nv->bus[bus].target[target].parameter.f.tag_queuing = 1; + nv->bus[bus].target[target].parameter.f.enable_sync = 1; +#if 1 /* Some SCSI Processors do not seem to like this */ + nv->bus[bus].target[target].parameter.f.enable_wide = 1; +#endif + if (!IS_ISP1040(ha)) + nv->bus[bus].target[target].parameter.f.parity_checking = 1; + + nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1; + nv->bus[bus].target[target].execution_throttle = + nv->bus[bus].max_queue_depth - 1; + + if (IS_ISP1x160(ha)) { + nv->bus[bus].target[target].flags.flags1x160.device_enable = 1; + nv->bus[bus].target[target].flags.flags1x160.sync_offset = 0x0e; + nv->bus[bus].target[target].sync_period = 9; + nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1; + nv->bus[bus].target[target].ppr_1x160.flags.ppr_options = 2; + nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width = 1; + } else { + nv->bus[bus].target[target].flags.flags1x80.device_enable = 1; + nv->bus[bus].target[target].flags.flags1x80.sync_offset = 12; + nv->bus[bus].target[target].sync_period = 10; + } +} + +static void +qla1280_set_defaults(struct scsi_qla_host *ha) +{ + struct nvram *nv = &ha->nvram; + int bus, target; + + dprintk(1, "Using defaults for NVRAM: \n"); + memset(nv, 0, sizeof(struct nvram)); + + /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ + nv->firmware_feature.f.enable_fast_posting = 1; + nv->firmware_feature.f.disable_synchronous_backoff = 1; + nv->termination.f.scsi_bus_0_control = 3; + nv->termination.f.scsi_bus_1_control = 3; + nv->termination.f.auto_term_support = 1; + + /* + * Set default FIFO magic - What appropriate values would be here + * is unknown. This is what I have found testing with 12160s. + * + * Now, I would love the magic decoder ring for this one, the + * header file provided by QLogic seems to be bogus or incomplete + * at best. + */ + nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128; + if (IS_ISP1x160(ha)) + nv->isp_parameter = 0x01; /* fast memory enable */ + + for (bus = 0; bus < MAX_BUSES; bus++) { + nv->bus[bus].config_1.initiator_id = 7; + nv->bus[bus].config_2.req_ack_active_negation = 1; + nv->bus[bus].config_2.data_line_active_negation = 1; + nv->bus[bus].selection_timeout = 250; + nv->bus[bus].max_queue_depth = 256; + + if (IS_ISP1040(ha)) { + nv->bus[bus].bus_reset_delay = 3; + nv->bus[bus].config_2.async_data_setup_time = 6; + nv->bus[bus].retry_delay = 1; + } else { + nv->bus[bus].bus_reset_delay = 5; + nv->bus[bus].config_2.async_data_setup_time = 8; + } + + for (target = 0; target < MAX_TARGETS; target++) + qla1280_set_target_defaults(ha, bus, target); + } +} + +static int +qla1280_config_target(struct scsi_qla_host *ha, int bus, int target) +{ + struct nvram *nv = &ha->nvram; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int status, lun; + + /* Set Target Parameters. */ + mb[0] = MBC_SET_TARGET_PARAMETERS; + mb[1] = (uint16_t) (bus ? target | BIT_7 : target); + mb[1] <<= 8; + + /* + * Do not enable wide, sync, and ppr for the initial + * INQUIRY run. We enable this later if we determine + * the target actually supports it. + */ + nv->bus[bus].target[target].parameter.f. + auto_request_sense = 1; + nv->bus[bus].target[target].parameter.f. + stop_queue_on_check = 0; + + if (IS_ISP1x160(ha)) + nv->bus[bus].target[target].ppr_1x160. + flags.enable_ppr = 0; + + /* + * No sync, wide, etc. while probing + */ + mb[2] = (nv->bus[bus].target[target].parameter.c << 8) & + ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); + + if (IS_ISP1x160(ha)) + mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; + else + mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; + mb[3] |= nv->bus[bus].target[target].sync_period; + + status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]); + + /* Save Tag queuing enable flag. */ + mb[0] = BIT_0 << target; + if (nv->bus[bus].target[target].parameter.f.tag_queuing) + ha->bus_settings[bus].qtag_enables |= mb[0]; + + /* Save Device enable flag. */ + if (IS_ISP1x160(ha)) { + if (nv->bus[bus].target[target].flags.flags1x160.device_enable) + ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].lun_disables |= 0; + } else { + if (nv->bus[bus].target[target].flags.flags1x80.device_enable) + ha->bus_settings[bus].device_enables |= mb[0]; + /* Save LUN disable flag. */ + if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) + ha->bus_settings[bus].lun_disables |= mb[0]; + } + + /* Set Device Queue Parameters. */ + for (lun = 0; lun < MAX_LUNS; lun++) { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)(bus ? target | BIT_7 : target); + mb[1] = mb[1] << 8 | lun; + mb[2] = nv->bus[bus].max_queue_depth; + mb[3] = nv->bus[bus].target[target].execution_throttle; + status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]); + } + + return status; +} + +static int +qla1280_config_bus(struct scsi_qla_host *ha, int bus) +{ + struct nvram *nv = &ha->nvram; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int target, status; + + /* SCSI Reset Disable. */ + ha->bus_settings[bus].disable_scsi_reset = + nv->bus[bus].config_1.scsi_reset_disable; + + /* Initiator ID. */ + ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; + mb[0] = MBC_SET_INITIATOR_ID; + mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : + ha->bus_settings[bus].id; + status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + + /* Reset Delay. */ + ha->bus_settings[bus].bus_reset_delay = + nv->bus[bus].bus_reset_delay; + + /* Command queue depth per device. */ + ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; + + /* Set target parameters. */ + for (target = 0; target < MAX_TARGETS; target++) + status |= qla1280_config_target(ha, bus, target); + + return status; +} + +static int +qla1280_nvram_config(struct scsi_qla_host *ha) +{ + struct device_reg *reg = ha->iobase; + struct nvram *nv = &ha->nvram; + int bus, target, status = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint16_t mask; + + ENTER("qla1280_nvram_config"); + + if (ha->nvram_valid) { + /* Always force AUTO sense for LINUX SCSI */ + for (bus = 0; bus < MAX_BUSES; bus++) + for (target = 0; target < MAX_TARGETS; target++) { + nv->bus[bus].target[target].parameter.f. + auto_request_sense = 1; + } + } else { + qla1280_set_defaults(ha); + } + + qla1280_print_settings(nv); /* Disable RISC load of firmware. */ ha->flags.disable_risc_code_load = nv->cntr_flags_1.disable_loading_risc_code; - /* Set ISP hardware DMA burst */ - mb[0] = nv->isp_config.c; - /* Enable DMA arbitration on dual channel controllers */ - if (ha->ports > 1) - mb[0] |= BIT_13; - WRT_REG_WORD(®->cfg_1, mb[0]); - -#if 1 /* Is this safe? */ - /* Set SCSI termination. */ - WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); - mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); - WRT_REG_WORD(®->gpio_data, mb[0]); -#endif + if (IS_ISP1040(ha)) { + uint16_t hwrev, cfg1, cdma_conf, ddma_conf; + + hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK; + + cfg1 = RD_REG_WORD(®->cfg_1); + cdma_conf = RD_REG_WORD(®->cdma_cfg); + ddma_conf = RD_REG_WORD(®->ddma_cfg); + + /* Busted fifo, says mjacob. */ + if (hwrev == ISP_CFG0_1040A) + WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64); + else + WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB); + + WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB); + WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB); + } else { + /* Set ISP hardware DMA burst */ + mb[0] = nv->isp_config.c; + /* Enable DMA arbitration on dual channel controllers */ + if (ha->ports > 1) + mb[0] |= BIT_13; + WRT_REG_WORD(®->cfg_1, mb[0]); + + /* Set SCSI termination. */ + WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); + mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); + WRT_REG_WORD(®->gpio_data, mb[0]); + } /* ISP parameter word. */ mb[0] = MBC_SET_SYSTEM_PARAMETER; mb[1] = nv->isp_parameter; status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); -#if 0 - /* clock rate - for qla1240 and older, only */ - mb[0] = MBC_SET_CLOCK_RATE; - mb[1] = 0x50; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); -#endif + if (IS_ISP1x40(ha)) { + /* clock rate - for qla1240 and older, only */ + mb[0] = MBC_SET_CLOCK_RATE; + mb[1] = 40; + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); + } + /* Firmware feature word. */ mb[0] = MBC_SET_FIRMWARE_FEATURES; mask = BIT_5 | BIT_1 | BIT_0; @@ -2515,112 +2635,18 @@ qla1280_nvram_config(struct scsi_qla_host *ha) mb[2] = 2; /* Command DMA Channel Burst Enable */ status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + mb[0] = MBC_SET_TAG_AGE_LIMIT; + mb[1] = 8; + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + /* Selection timeout. */ mb[0] = MBC_SET_SELECTION_TIMEOUT; mb[1] = nv->bus[0].selection_timeout; mb[2] = nv->bus[1].selection_timeout; status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); - for (bus = 0; bus < ha->ports; bus++) { - /* SCSI Reset Disable. */ - ha->bus_settings[bus].disable_scsi_reset = - nv->bus[bus].config_1.scsi_reset_disable; - - /* Initiator ID. */ - ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; - mb[0] = MBC_SET_INITIATOR_ID; - mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : - ha->bus_settings[bus].id; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - - /* Reset Delay. */ - ha->bus_settings[bus].bus_reset_delay = - nv->bus[bus].bus_reset_delay; - - /* Command queue depth per device. */ - ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; - - /* Set target parameters. */ - for (target = 0; target < MAX_TARGETS; target++) { - uint8_t mr = BIT_2 | BIT_1 | BIT_0; - - /* Set Target Parameters. */ - mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - /* - * Do not enable wide, sync, and ppr for the initial - * INQUIRY run. We enable this later if we determine - * the target actually supports it. - */ - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - stop_queue_on_check = 0; - - if (is1x160) - nv->bus[bus].target[target].ppr_1x160. - flags.enable_ppr = 0; - /* - * No sync, wide, etc. while probing - */ - mb[2] = (nv->bus[bus].target[target].parameter.c << 8)& - ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); - - if (is1x160) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - mr |= BIT_3; - - /* - * We don't want to enable ppr etc. before we have - * determined that the target actually supports it - */ -#if 0 - if (is1x160) { - mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - - mb[6] = nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8; - mb[6] |= nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; - mr |= BIT_6; - } -#endif - - status = qla1280_mailbox_command(ha, mr, &mb[0]); - - /* Save Tag queuing enable flag. */ - mb[0] = BIT_0 << target; - if (nv->bus[bus].target[target].parameter.f.tag_queuing) - ha->bus_settings[bus].qtag_enables |= mb[0]; - - /* Save Device enable flag. */ - if (is1x160) { - if (nv->bus[bus].target[target].flags.flags1x160.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; - ha->bus_settings[bus].lun_disables |= 0; - } else { - if (nv->bus[bus].target[target].flags.flags1x80.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; - /* Save LUN disable flag. */ - if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) - ha->bus_settings[bus].lun_disables |= mb[0]; - } - - - /* Set Device Queue Parameters. */ - for (lun = 0; lun < MAX_LUNS; lun++) { - mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)(bus ? target | BIT_7 : target); - mb[1] = mb[1] << 8 | lun; - mb[2] = nv->bus[bus].max_queue_depth; - mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, - &mb[0]); - } - } - } + for (bus = 0; bus < ha->ports; bus++) + status |= qla1280_config_bus(ha, bus); if (status) dprintk(2, "qla1280_nvram_config: **** FAILED ****\n"); @@ -4231,6 +4257,7 @@ qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt, static int qla1280_abort_isp(struct scsi_qla_host *ha) { + struct device_reg *reg = ha->iobase; struct srb *sp; int status = 0; int cnt; @@ -4238,69 +4265,53 @@ qla1280_abort_isp(struct scsi_qla_host *ha) ENTER("qla1280_abort_isp"); - if (!ha->flags.abort_isp_active && ha->flags.online) { - struct device_reg *reg = ha->iobase; - ha->flags.abort_isp_active = 1; - - /* Disable ISP interrupts. */ - qla1280_disable_intrs(ha); - WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); - RD_REG_WORD(®->id_l); + if (ha->flags.abort_isp_active || !ha->flags.online) + goto out; + + ha->flags.abort_isp_active = 1; - printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", - ha->host_no); - /* Dequeue all commands in outstanding command list. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - struct scsi_cmnd *cmd; - sp = ha->outstanding_cmds[cnt]; - if (sp) { + /* Disable ISP interrupts. */ + qla1280_disable_intrs(ha); + WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); + RD_REG_WORD(®->id_l); - cmd = sp->cmd; - CMD_RESULT(cmd) = DID_RESET << 16; + printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", + ha->host_no); + /* Dequeue all commands in outstanding command list. */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + struct scsi_cmnd *cmd; + sp = ha->outstanding_cmds[cnt]; + if (sp) { - sp->cmd = NULL; - ha->outstanding_cmds[cnt] = NULL; + cmd = sp->cmd; + CMD_RESULT(cmd) = DID_RESET << 16; - (*cmd->scsi_done)(cmd); + sp->cmd = NULL; + ha->outstanding_cmds[cnt] = NULL; - sp->flags = 0; - } - } + (*cmd->scsi_done)(cmd); - /* If firmware needs to be loaded */ - if (qla1280_isp_firmware (ha)) { - if (!(status = qla1280_chip_diag(ha))) - status = qla1280_setup_chip(ha); + sp->flags = 0; } + } - if (!status) { - /* Setup adapter based on NVRAM parameters. */ - qla1280_nvram_config (ha); + status = qla1280_load_firmware(ha); + if (status) + goto out; - if (!(status = qla1280_init_rings(ha))) { - /* Issue SCSI reset. */ - for (bus = 0; bus < ha->ports; bus++) { - qla1280_bus_reset(ha, bus); - } - /* - * qla1280_bus_reset() will do the marker - * dance - no reason to repeat here! - */ -#if 0 - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports; bus++) { - ha->bus_settings[bus]. - reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, - MK_SYNC_ALL); - } -#endif - ha->flags.abort_isp_active = 0; - } - } - } + /* Setup adapter based on NVRAM parameters. */ + qla1280_nvram_config (ha); + status = qla1280_init_rings(ha); + if (status) + goto out; + + /* Issue SCSI reset. */ + for (bus = 0; bus < ha->ports; bus++) + qla1280_bus_reset(ha, bus); + + ha->flags.abort_isp_active = 0; + out: if (status) { printk(KERN_WARNING "qla1280: ISP error recovery failed, board disabled"); @@ -4936,6 +4947,7 @@ module_exit(qla1280_exit); MODULE_AUTHOR("Qlogic & Jes Sorensen"); MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA1280_VERSION); /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 0027485bf..5dc7ca3da 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -62,6 +62,7 @@ #define WRT_REG_WORD(addr, data) writew(data, addr) #else /* MEMORY_MAPPED_IO */ #define RD_REG_WORD(addr) inw((unsigned long)addr) +#define RD_REG_WORD_dmasync(addr) RD_REG_WORD(addr) #define WRT_REG_WORD(addr, data) outw(data, (unsigned long)addr) #endif /* MEMORY_MAPPED_IO */ @@ -126,7 +127,20 @@ struct device_reg { uint16_t id_l; /* ID low */ uint16_t id_h; /* ID high */ uint16_t cfg_0; /* Configuration 0 */ +#define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */ +#define ISP_CFG0_1020 BIT_0 /* ISP1020 */ +#define ISP_CFG0_1020A BIT_1 /* ISP1020A */ +#define ISP_CFG0_1040 BIT_2 /* ISP1040 */ +#define ISP_CFG0_1040A BIT_3 /* ISP1040A */ +#define ISP_CFG0_1040B BIT_4 /* ISP1040B */ +#define ISP_CFG0_1040C BIT_5 /* ISP1040C */ uint16_t cfg_1; /* Configuration 1 */ +#define ISP_CFG1_F128 BIT_6 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F64 BIT_4|BIT_5 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F32 BIT_5 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F16 BIT_4 /* 128-byte FIFO threshold */ +#define ISP_CFG1_BENAB BIT_2 /* Global Bus burst enable */ +#define ISP_CFG1_SXP BIT_0 /* SXP register select */ uint16_t ictrl; /* Interface control */ #define ISP_RESET BIT_0 /* ISP soft reset */ #define ISP_EN_INT BIT_1 /* ISP enable interrupts. */ @@ -147,7 +161,42 @@ struct device_reg { uint16_t flash_data; /* Flash BIOS data */ uint16_t flash_address; /* Flash BIOS address */ - uint16_t unused_1[0x2e]; /* 0x14-0x6f Gap */ + uint16_t unused_1[0x06]; + + /* cdma_* and ddma_* are 1040 only */ + uint16_t cdma_cfg; +#define CDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ +#define CDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ +#define CDMA_CONF_BENAB BIT_1 /* Bus burst enable */ +#define CDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ + uint16_t cdma_ctrl; + uint16_t cdma_status; + uint16_t cdma_fifo_status; + uint16_t cdma_count; + uint16_t cdma_reserved; + uint16_t cdma_address_count_0; + uint16_t cdma_address_count_1; + uint16_t cdma_address_count_2; + uint16_t cdma_address_count_3; + + uint16_t unused_2[0x06]; + + uint16_t ddma_cfg; +#define DDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ +#define DDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ +#define DDMA_CONF_BENAB BIT_1 /* Bus burst enable */ +#define DDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ + uint16_t ddma_ctrl; + uint16_t ddma_status; + uint16_t ddma_fifo_status; + uint16_t ddma_xfer_count_low; + uint16_t ddma_xfer_count_high; + uint16_t ddma_addr_count_0; + uint16_t ddma_addr_count_1; + uint16_t ddma_addr_count_2; + uint16_t ddma_addr_count_3; + + uint16_t unused_3[0x0e]; uint16_t mailbox0; /* Mailbox 0 */ uint16_t mailbox1; /* Mailbox 1 */ @@ -158,18 +207,18 @@ struct device_reg { uint16_t mailbox6; /* Mailbox 6 */ uint16_t mailbox7; /* Mailbox 7 */ - uint16_t unused_2[0x20];/* 0x80-0xbf Gap */ + uint16_t unused_4[0x20];/* 0x80-0xbf Gap */ uint16_t host_cmd; /* Host command and control */ #define HOST_INT BIT_7 /* host interrupt bit */ #define BIOS_ENABLE BIT_0 - uint16_t unused_6[0x5]; /* 0xc2-0xcb Gap */ + uint16_t unused_5[0x5]; /* 0xc2-0xcb Gap */ uint16_t gpio_data; uint16_t gpio_enable; - uint16_t unused_7[0x11]; /* d0-f0 */ + uint16_t unused_6[0x11]; /* d0-f0 */ uint16_t scsiControlPins; /* f2 */ }; diff --git a/drivers/scsi/qla2xxx/ql2100.c b/drivers/scsi/qla2xxx/ql2100.c index 77de0f4f9..ea136a61a 100644 --- a/drivers/scsi/qla2xxx/ql2100.c +++ b/drivers/scsi/qla2xxx/ql2100.c @@ -89,3 +89,4 @@ module_exit(qla2100_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP21xx FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/ql2200.c b/drivers/scsi/qla2xxx/ql2200.c index c254daaa0..2f5698d52 100644 --- a/drivers/scsi/qla2xxx/ql2200.c +++ b/drivers/scsi/qla2xxx/ql2200.c @@ -89,3 +89,4 @@ module_exit(qla2200_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP22xx FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/ql2300.c b/drivers/scsi/qla2xxx/ql2300.c index 177aa3617..1f6fc895c 100644 --- a/drivers/scsi/qla2xxx/ql2300.c +++ b/drivers/scsi/qla2xxx/ql2300.c @@ -100,3 +100,4 @@ module_exit(qla2300_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP2300 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/ql2322.c b/drivers/scsi/qla2xxx/ql2322.c index ebbb51ea6..70b6d75ed 100644 --- a/drivers/scsi/qla2xxx/ql2322.c +++ b/drivers/scsi/qla2xxx/ql2322.c @@ -105,3 +105,4 @@ module_exit(qla2322_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP2322 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/ql6312.c b/drivers/scsi/qla2xxx/ql6312.c index 6c0720da8..c6b08a6e2 100644 --- a/drivers/scsi/qla2xxx/ql6312.c +++ b/drivers/scsi/qla2xxx/ql6312.c @@ -87,3 +87,4 @@ module_exit(qla6312_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP6312 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/ql6322.c b/drivers/scsi/qla2xxx/ql6322.c index ce651454d..75fb9b266 100644 --- a/drivers/scsi/qla2xxx/ql6322.c +++ b/drivers/scsi/qla2xxx/ql6322.c @@ -105,3 +105,4 @@ module_exit(qla6322_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic ISP6322 FC-SCSI Host Bus Adapter driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e31b5fe3e..23a854528 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -783,7 +783,6 @@ qla2x00_init_response_q_entries(scsi_qla_host_t *ha) static void qla2x00_update_fw_options(scsi_qla_host_t *ha) { - /* Setup seriallink options */ uint16_t swing, emphasis; memset(ha->fw_options, 0, sizeof(ha->fw_options)); @@ -807,7 +806,6 @@ qla2x00_update_fw_options(scsi_qla_host_t *ha) emphasis = ha->fw_seriallink_options[0] & (BIT_4 | BIT_3); emphasis >>= 3; ha->fw_options[10] = (emphasis << 14) | (swing << 8) | 0x3; - /* 2G settings */ swing = ha->fw_seriallink_options[0] & (BIT_7 | BIT_6 | BIT_5); swing >>= 5; @@ -818,7 +816,7 @@ qla2x00_update_fw_options(scsi_qla_host_t *ha) /* Return command IOCBs without waiting for an ABTS to complete. */ ha->fw_options[3] |= BIT_13; - /* Update Serial Link options. */ + /* Update firmware options. */ qla2x00_set_fw_options(ha, ha->fw_options); } @@ -843,7 +841,7 @@ qla2x00_init_rings(scsi_qla_host_t *ha) /* Clear outstanding commands array. */ for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) - ha->outstanding_cmds[cnt] = 0; + ha->outstanding_cmds[cnt] = NULL; ha->current_outstanding_cmd = 0; @@ -869,15 +867,15 @@ qla2x00_init_rings(scsi_qla_host_t *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Update any ISP specific firmware options before initialization. */ + qla2x00_update_fw_options(ha); + DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); rval = qla2x00_init_firmware(ha, sizeof(init_cb_t)); if (rval) { DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n", ha->host_no)); } else { - /* Update any ISP specific firmware options. */ - qla2x00_update_fw_options(ha); - DEBUG3(printk("scsi(%ld): Init firmware -- success.\n", ha->host_no)); } @@ -4133,7 +4131,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = ha->outstanding_cmds[cnt]; if (sp) { - ha->outstanding_cmds[cnt] = 0; + ha->outstanding_cmds[cnt] = NULL; if (ha->actthreads) ha->actthreads--; sp->lun_queue->out_cnt--; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 710a88d67..ebbae6059 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -22,6 +22,8 @@ #include #include +#include + static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); @@ -337,6 +339,7 @@ qla2x00_start_scsi(srb_t *sp) uint16_t req_cnt; uint16_t tot_dsds; device_reg_t *reg; + char tag[2]; /* Setup device pointers. */ ret = 0; @@ -415,14 +418,17 @@ qla2x00_start_scsi(srb_t *sp) cmd_pkt->lun = cpu_to_le16(fclun->lun); /* Update tagged queuing modifier */ - cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG); - if (cmd->device->tagged_supported) { - switch (cmd->tag) { - case HEAD_OF_QUEUE_TAG: + if (scsi_populate_tag_msg(cmd, tag)) { + switch (tag[0]) { + case MSG_SIMPLE_TAG: + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_SIMPLE_TAG); + break; + case MSG_HEAD_TAG: cmd_pkt->control_flags = __constant_cpu_to_le16(CF_HEAD_TAG); break; - case ORDERED_QUEUE_TAG: + case MSG_ORDERED_TAG: cmd_pkt->control_flags = __constant_cpu_to_le16(CF_ORDERED_TAG); break; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index dd5aaba4e..591f1d5a5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1663,7 +1663,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) goto out; /* Waiting for our command in done_queue to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(ha)) + if (!qla2x00_eh_wait_for_pending_commands(ha)) rval = FAILED; out: @@ -1784,7 +1784,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) ql2xmaxqdepth = queue_depth; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + scsi_activate_tcq(sdev, queue_depth); qla_printk(KERN_INFO, ha, "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue " @@ -3590,7 +3590,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha) { srb_t *sp; - sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); + sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); if (sp) atomic_set(&sp->ref_count, 1); return (sp); @@ -4517,3 +4517,4 @@ module_exit(qla2x00_module_exit); MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 1dc4c9594..9ee334ec7 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -19,9 +19,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.00.00b14-k" +#define QLA2XXX_VERSION "8.00.00b15-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 0 #define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 14 +#define QLA_DRIVER_BETA_VER 15 diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c49ca7f2f..91aaf50c7 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -987,7 +987,7 @@ const char *qlogicpti_info(struct Scsi_Host *host) static char buf[80]; struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %lx", + sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %p", __irq_itoa(qpti->qhost->irq), qpti->qregs); return buf; } diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h index a40ff75ca..6cd1c0771 100644 --- a/drivers/scsi/qlogicpti.h +++ b/drivers/scsi/qlogicpti.h @@ -335,7 +335,7 @@ struct scsi_cmnd; /* Software state for the driver. */ struct qlogicpti { /* These are the hot elements in the cache, so they come first. */ - unsigned long qregs; /* Adapter registers */ + void __iomem *qregs; /* Adapter registers */ struct pti_queue_entry *res_cpu; /* Ptr to RESPONSE bufs (CPU) */ struct pti_queue_entry *req_cpu; /* Ptr to REQUEST bufs (CPU) */ @@ -370,7 +370,7 @@ struct qlogicpti { struct host_param host_param; struct dev_param dev_param[MAX_TARGETS]; - unsigned long sreg; + void __iomem *sreg; #define SREG_TPOWER 0x80 /* State of termpwr */ #define SREG_FUSE 0x40 /* State of on board fuse */ #define SREG_PDISAB 0x20 /* Disable state for power on */ diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 29248d608..aef957b52 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -20,6 +20,10 @@ * If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * + * 0.03 + * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using + * mmio_base, which is only set for the CK804/MCP04 case. + * * 0.02 * - Added support for CK804 SATA controller. * @@ -40,13 +44,12 @@ #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "0.02" +#define DRV_VERSION "0.03" #define NV_PORTS 2 #define NV_PIO_MASK 0x1f +#define NV_MWDMA_MASK 0x07 #define NV_UDMA_MASK 0x7f -#define NV_PORT0_BMDMA_REG_OFFSET 0x00 -#define NV_PORT1_BMDMA_REG_OFFSET 0x08 #define NV_PORT0_SCR_REG_OFFSET 0x00 #define NV_PORT1_SCR_REG_OFFSET 0x40 @@ -177,11 +180,12 @@ static struct pci_driver nv_pci_driver = { static Scsi_Host_Template nv_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = ATA_MAX_PRD, + .sg_tablesize = LIBATA_MAX_PRD, .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, @@ -194,13 +198,14 @@ static Scsi_Host_Template nv_sht = { static struct ata_port_operations nv_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .exec_command = ata_exec_command_pio, - .check_status = ata_check_status_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -213,6 +218,18 @@ static struct ata_port_operations nv_ops = { .host_stop = nv_host_stop, }; +static struct ata_port_info nv_port_info = { + .sht = &nv_sht, + .host_flags = ATA_FLAG_SATA | + ATA_FLAG_SATA_RESET | + ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_ops, +}; + MODULE_AUTHOR("NVIDIA"); MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller"); MODULE_LICENSE("GPL"); @@ -293,6 +310,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; struct nv_host *host; + struct ata_port_info *ppi; struct ata_probe_ent *probe_ent = NULL; int rc; @@ -314,7 +332,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &nv_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; @@ -328,39 +347,6 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) host->host_desc = &nv_device_tbl[ent->driver_data]; - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); - - probe_ent->pdev = pdev; - probe_ent->sht = &nv_sht; - probe_ent->host_flags = ATA_FLAG_SATA | - ATA_FLAG_SATA_RESET | - ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY; - - probe_ent->port_ops = &nv_ops; - probe_ent->n_ports = NV_PORTS; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - probe_ent->pio_mask = NV_PIO_MASK; - probe_ent->udma_mask = NV_UDMA_MASK; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = - pci_resource_start(pdev, 4) | NV_PORT0_BMDMA_REG_OFFSET; - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = - pci_resource_start(pdev, 4) | NV_PORT1_BMDMA_REG_OFFSET; - probe_ent->private_data = host; if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) { @@ -369,7 +355,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); if (probe_ent->mmio_base == NULL) - goto err_out_free_ent; + goto err_out_iounmap; base = (unsigned long)probe_ent->mmio_base; @@ -393,12 +379,16 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) rc = ata_device_add(probe_ent); if (rc != NV_PORTS) - goto err_out_free_ent; + goto err_out_iounmap; kfree(probe_ent); return 0; +err_out_iounmap: + if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) + iounmap(probe_ent->mmio_base); + err_out_free_ent: kfree(probe_ent); @@ -415,33 +405,33 @@ static void nv_enable_hotplug(struct ata_probe_ent *probe_ent) u8 intr_mask; outb(NV_INT_STATUS_HOTPLUG, - (unsigned long)probe_ent->mmio_base + NV_INT_STATUS); + probe_ent->port[0].scr_addr + NV_INT_STATUS); - intr_mask = inb((unsigned long)probe_ent->mmio_base + NV_INT_ENABLE); + intr_mask = inb(probe_ent->port[0].scr_addr + NV_INT_ENABLE); intr_mask |= NV_INT_ENABLE_HOTPLUG; - outb(intr_mask, (unsigned long)probe_ent->mmio_base + NV_INT_ENABLE); + outb(intr_mask, probe_ent->port[0].scr_addr + NV_INT_ENABLE); } static void nv_disable_hotplug(struct ata_host_set *host_set) { u8 intr_mask; - intr_mask = inb((unsigned long)host_set->mmio_base + NV_INT_ENABLE); + intr_mask = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); - outb(intr_mask, (unsigned long)host_set->mmio_base + NV_INT_ENABLE); + outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); } static void nv_check_hotplug(struct ata_host_set *host_set) { u8 intr_status; - intr_status = inb((unsigned long)host_set->mmio_base + NV_INT_STATUS); + intr_status = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); // Clear interrupt status. - outb(0xff, (unsigned long)host_set->mmio_base + NV_INT_STATUS); + outb(0xff, host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); if (intr_status & NV_INT_STATUS_HOTPLUG) { if (intr_status & NV_INT_STATUS_PDEV_ADDED) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index a2eefb6bc..67bdfb910 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -74,7 +74,6 @@ struct pdc_port_priv { static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); @@ -83,14 +82,13 @@ static void pdc_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -109,9 +107,10 @@ static Scsi_Host_Template pdc_sata_sht = { static struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, .phy_reset = pdc_phy_reset, .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, @@ -130,7 +129,8 @@ static struct ata_port_info pdc_port_info[] = { .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -140,7 +140,8 @@ static struct ata_port_info pdc_port_info[] = { .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -269,26 +270,26 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) VPRINTK("ENTER\n"); - ata_qc_prep(qc); - - i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + ata_qc_prep(qc); + /* fall through */ - if (qc->tf.flags & ATA_TFLAG_LBA48) - i = pdc_prep_lba48(&qc->tf, pp->pkt, i); - else - i = pdc_prep_lba28(&qc->tf, pp->pkt, i); + case ATA_PROT_NODATA: + i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, + qc->dev->devno, pp->pkt); - pdc_pkt_footer(&qc->tf, pp->pkt, i); -} + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, pp->pkt, i); + else + i = pdc_prep_lba28(&qc->tf, pp->pkt, i); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; + pdc_pkt_footer(&qc->tf, pp->pkt, i); + break; - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); + default: + break; + } } static void pdc_eng_timeout(struct ata_port *ap) @@ -315,17 +316,9 @@ static void pdc_eng_timeout(struct ata_port *ap) switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -358,13 +351,8 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap, switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_complete(ap, qc, have_err); - handled = 1; - break; - - case ATA_PROT_NODATA: /* command completion, but no data xfer */ - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + case ATA_PROT_NODATA: + status = ata_wait_idle(ap); if (have_err) status |= ATA_ERR; ata_qc_complete(qc, status); @@ -440,7 +428,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r return IRQ_RETVAL(handled); } -static inline void pdc_dma_start(struct ata_queued_cmd *qc) +static inline void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; @@ -462,7 +450,8 @@ static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_start(qc); + case ATA_PROT_NODATA: + pdc_packet_start(qc); return 0; case ATA_PROT_ATAPI_DMA: @@ -478,15 +467,17 @@ static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - WARN_ON (tf->protocol == ATA_PROT_DMA); - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - WARN_ON (tf->protocol == ATA_PROT_DMA); - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command(ap, tf); } @@ -539,8 +530,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) writel(tmp, mmio + PDC_TBG_MODE); readl(mmio + PDC_TBG_MODE); /* flush */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(10) + 1); + msleep(10); /* adjust slew rate control register. */ tmp = readl(mmio + PDC_SLEW_CTL); @@ -601,6 +591,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 72a89d1be..9a349a9be 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -6,7 +6,7 @@ * on emails. * * Copyright 2003 Red Hat, Inc. - * Copyright 2003 Benjamin Herrenschmidt + * Copyright 2003 Benjamin Herrenschmidt * * The contents of this file are subject to the Open * Software License version 1.1 that can be found at @@ -106,6 +106,7 @@ static struct pci_driver sil_pci_driver = { static Scsi_Host_Template sil_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -124,14 +125,15 @@ static Scsi_Host_Template sil_sht = { static struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, - .tf_load = ata_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, - .exec_command = ata_exec_command_mmio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, .post_set_mode = sil_post_set_mode, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -149,7 +151,8 @@ static struct ata_port_info sil_port_info[] = { .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, /* sil_3114 */ @@ -157,7 +160,8 @@ static struct ata_port_info sil_port_info[] = { .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, @@ -363,6 +367,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->sht = sil_port_info[ent->driver_data].sht; probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2; probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask; + probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask; probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index 88b7a02ea..17eb7ed5a 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -76,6 +76,7 @@ static struct pci_driver sis_pci_driver = { static Scsi_Host_Template sis_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -93,13 +94,14 @@ static Scsi_Host_Template sis_sht = { static struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -111,6 +113,16 @@ static struct ata_port_operations sis_ops = { .port_stop = ata_port_stop, }; +static struct ata_port_info sis_port_info = { + .sht = &sis_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, + .mwdma_mask = 0x7, + .udma_mask = 0x7f, + .port_ops = &sis_ops, +}; + MODULE_AUTHOR("Uwe Koziolek"); MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller"); @@ -184,6 +196,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_probe_ent *probe_ent = NULL; int rc; u32 genctl; + struct ata_port_info *ppi; rc = pci_enable_device(pdev); if (rc) @@ -200,20 +213,13 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &sis_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - probe_ent->pdev = pdev; - INIT_LIST_HEAD(&probe_ent->node); - - probe_ent->sht = &sis_sht; - probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | - ATA_FLAG_NO_LEGACY; - /* check and see if the SCRs are in IO space or PCI cfg space */ pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) @@ -230,31 +236,12 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->host_flags |= SIS_FLAG_CFGSCR; } - probe_ent->pio_mask = 0x03; - probe_ent->udma_mask = 0x7f; - probe_ent->port_ops = &sis_ops; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) + if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) { probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) probe_ent->port[1].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64; - - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; + } pci_set_master(pdev); pci_enable_intx(pdev); @@ -284,6 +271,6 @@ static void __exit sis_exit(void) pci_unregister_driver(&sis_pci_driver); } - module_init(sis_init); module_exit(sis_exit); + diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 398f24f27..fd01225a7 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -148,7 +148,73 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) } } +/** + * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) + * @qc: Info associated with this ATA transaction. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ + +void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + void *mmio = (void *) ap->ioaddr.bmdma_addr; + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = readb(mmio + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + writeb(dmactl, mmio + ATA_DMA_CMD); + + /* issue r/w command if this is not a ATA DMA command*/ + if (qc->tf.protocol != ATA_PROT_DMA) + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) + * @qc: Info associated with this ATA transaction. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ + +void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void *mmio = (void *) ap->ioaddr.bmdma_addr; + u8 dmactl; + + /* start host DMA transaction */ + dmactl = readb(mmio + ATA_DMA_CMD); + writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); + /* There is a race condition in certain SATA controllers that can + be seen when the r/w command is given to the controller before the + host DMA is started. On a Read command, the controller would initiate + the command to the drive even before it sees the DMA start. When there + are very fast drives connected to the controller, or when the data request + hits in the drive cache, there is the possibility that the drive returns a part + or all of the requested data to the controller before the DMA start is issued. + In this case, the controller would become confused as to what to do with the data. + In the worst case when all the data is returned back to the controller, the + controller could hang. In other cases it could return partial data returning + in data corruption. This problem has been seen in PPC systems and can also appear + on an system with very fast disks, where the SATA controller is sitting behind a + number of bridges, and hence there is significant latency between the r/w command + and the start command. */ + /* issue r/w command if the access is to ATA*/ + if (qc->tf.protocol == ATA_PROT_DMA) + ap->ops->exec_command(ap, &qc->tf); +} + static u8 k2_stat_check_status(struct ata_port *ap) { return readl((void *) ap->ioaddr.status_addr); @@ -205,6 +271,7 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start, static Scsi_Host_Template k2_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -229,10 +296,11 @@ static struct ata_port_operations k2_sata_ops = { .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, - .exec_command = ata_exec_command_mmio, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, + .bmdma_setup = k2_bmdma_setup_mmio, + .bmdma_start = k2_bmdma_start_mmio, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -343,6 +411,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ @@ -371,6 +440,8 @@ err_out: static struct pci_device_id k2_sata_pci_tbl[] = { { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { } }; @@ -388,6 +459,7 @@ static int __init k2_sata_init(void) return pci_module_init(&k2_sata_pci_driver); } + static void __exit k2_sata_exit(void) { pci_unregister_driver(&k2_sata_pci_driver); diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index b54fd87e3..8da761487 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -146,8 +146,6 @@ struct pdc_host_priv { static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc20621_dma_setup(struct ata_queued_cmd *qc); -static void pdc20621_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); @@ -157,8 +155,6 @@ static void pdc20621_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, @@ -172,11 +168,13 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -195,14 +193,13 @@ static Scsi_Host_Template pdc_sata_sht = { static struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, .phy_reset = pdc_20621_phy_reset, - .bmdma_setup = pdc20621_dma_setup, - .bmdma_start = pdc20621_dma_start, .qc_prep = pdc20621_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_issue = pdc20621_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, @@ -217,7 +214,8 @@ static struct ata_port_info pdc_port_info[] = { .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_20621_ops, }, @@ -377,7 +375,10 @@ static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf, /* dimm dma S/G, and next-pkt */ dw = i >> 2; - buf32[dw] = cpu_to_le32(dimm_sg); + if (tf->protocol == ATA_PROT_NODATA) + buf32[dw] = 0; + else + buf32[dw] = cpu_to_le32(dimm_sg); buf32[dw + 1] = 0; i += 8; @@ -437,7 +438,7 @@ static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf, buf32[dw + 3]); } -static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +static void pdc20621_dma_prep(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -449,8 +450,7 @@ static void pdc20621_qc_prep(struct ata_queued_cmd *qc) unsigned int i, last, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; - if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; + assert(qc->flags & ATA_QCFLAG_DMAMAP); VPRINTK("ata%u: ENTER\n", ap->id); @@ -501,6 +501,56 @@ static void pdc20621_qc_prep(struct ata_queued_cmd *qc) VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } +static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + void *mmio = ap->host_set->mmio_base; + struct pdc_host_priv *hpriv = ap->host_set->private_data; + void *dimm_mmio = hpriv->dimm_mmio; + unsigned int portno = ap->port_no; + unsigned int i; + + VPRINTK("ata%u: ENTER\n", ap->id); + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno); + + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i); + else + i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i); + + pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i); + + /* copy three S/G tables and two packets to DIMM MMIO window */ + memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP), + &pp->dimm_buf, PDC_DIMM_HEADER_SZ); + + /* force host FIFO dump */ + writel(0x00000001, mmio + PDC_20621_GENERAL_CTL); + + readl(dimm_mmio); /* MMIO PCI posting flush */ + + VPRINTK("ata pkt buf ofs %u, mmio copied\n", i); +} + +static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pdc20621_dma_prep(qc); + break; + case ATA_PROT_NODATA: + pdc20621_nodata_prep(qc); + break; + default: + break; + } +} + static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, unsigned int seq, u32 pkt_ofs) @@ -576,13 +626,7 @@ static void pdc20621_dump_hdma(struct ata_queued_cmd *qc) static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { } #endif /* ATA_VERBOSE_DEBUG */ -static void pdc20621_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc20621_dma_start(struct ata_queued_cmd *qc) +static void pdc20621_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; @@ -590,24 +634,21 @@ static void pdc20621_dma_start(struct ata_queued_cmd *qc) void *mmio = host_set->mmio_base; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); - unsigned int doing_hdma = 0, port_ofs; + unsigned int port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->id); + wmb(); /* flush PRD, pkt writes */ + port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no); /* if writing, we (1) DMA to DIMM, then (2) do ATA command */ - if (rw) { - doing_hdma = 1; + if (rw && qc->tf.protocol == ATA_PROT_DMA) { seq += 4; - } - - wmb(); /* flush PRD, pkt writes */ - if (doing_hdma) { pdc20621_dump_hdma(qc); pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT); VPRINTK("queued ofs 0x%x (%u), seq %u\n", @@ -628,6 +669,25 @@ static void pdc20621_dma_start(struct ata_queued_cmd *qc) } } +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc20621_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static inline unsigned int pdc20621_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, @@ -648,7 +708,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, if (doing_hdma) { VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } @@ -685,7 +746,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, else { VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } handled = 1; @@ -779,16 +841,6 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re return IRQ_RETVAL(handled); } -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); -} - static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; @@ -813,17 +865,9 @@ static void pdc_eng_timeout(struct ata_port *ap) switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -842,15 +886,17 @@ out: static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command(ap, tf); } @@ -1384,6 +1430,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; @@ -1394,21 +1441,11 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * probe_ent->private_data = hpriv; base += PDC_CHIP0_OFS; + probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); - - /* notice 4-port boards */ - switch (board_idx) { - case board_20621: - probe_ent->n_ports = 4; - - pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); - break; - default: - BUG(); - break; - } + pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 993edfc99..44ffa9b90 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -81,6 +81,7 @@ static struct pci_driver svia_pci_driver = { static Scsi_Host_Template svia_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -99,15 +100,16 @@ static Scsi_Host_Template svia_sht = { static struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -123,6 +125,15 @@ static struct ata_port_operations svia_sata_ops = { .port_stop = ata_port_stop, }; +static struct ata_port_info svia_port_info = { + .sht = &svia_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + .port_ops = &svia_sata_ops, +}; + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); MODULE_LICENSE("GPL"); @@ -156,6 +167,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int printed_version; unsigned int i; int rc; + struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; u8 tmp8; @@ -196,41 +208,17 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &svia_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(pdev)); rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); - probe_ent->pdev = pdev; - probe_ent->sht = &svia_sht; - probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY; - probe_ent->port_ops = &svia_sata_ops; - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + probe_ent->port[0].scr_addr = svia_scr_addr(pci_resource_start(pdev, 5), 0); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; probe_ent->port[1].scr_addr = svia_scr_addr(pci_resource_start(pdev, 5), 1); diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index d63a339cc..880f7f115 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -190,6 +190,7 @@ irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *reg static Scsi_Host_Template vsc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -210,11 +211,12 @@ static struct ata_port_operations vsc_sata_ops = { .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, - .exec_command = ata_exec_command_mmio, - .check_status = ata_check_status_mmio, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -320,6 +322,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 17dce6657..481bea6a4 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -897,15 +897,16 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) */ if (tags <= 0) return; - /* - * Limit max queue depth on a single lun to 256 for now. Remember, - * we allocate a struct scsi_command for each of these and keep it - * around forever. Too deep of a depth just wastes memory. - */ - if (tags > 256) - return; spin_lock_irqsave(&device_request_lock, flags); + spin_lock(sdev->request_queue->queue_lock); + + /* Check to see if the queue is managed by the block layer + * if it is, and we fail to adjust the depth, exit */ + if (blk_queue_tagged(sdev->request_queue) && + blk_queue_resize_tags(sdev->request_queue, tags) != 0) + goto out; + sdev->queue_depth = tags; switch (tagged) { case MSG_ORDERED_TAG: @@ -926,6 +927,8 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) sdev->queue_depth = tags; break; } + out: + spin_unlock(sdev->request_queue->queue_lock); spin_unlock_irqrestore(&device_request_lock, flags); } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 288f2fde9..617412e06 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -42,8 +42,8 @@ * These should *probably* be handled by the host itself. * Since it is allowed to sleep, it probably should. */ -#define BUS_RESET_SETTLE_TIME (10*HZ) -#define HOST_RESET_SETTLE_TIME (10*HZ) +#define BUS_RESET_SETTLE_TIME (10) +#define HOST_RESET_SETTLE_TIME (10) /* called with shost->host_lock held */ void scsi_eh_wakeup(struct Scsi_Host *shost) @@ -643,15 +643,13 @@ static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, * Notes: * This has the unfortunate side effect that if a shost adapter does * not automatically request sense information, that we end up shutting - * it down before we request it. All shosts should be doing this - * anyways, so for now all I have to say is tough noogies if you end up - * in here. On second thought, this is probably a good idea. We - * *really* want to give authors an incentive to automatically request - * this. + * it down before we request it. * - * In 2.5 this capability will be going away. + * All drivers should request sense information internally these days, + * so for now all I have to say is tough noogies if you end up in here. * - * Really? --hch + * XXX: Long term this code should go away, but that needs an audit of + * all LLDDs first. **/ static int scsi_eh_get_sense(struct list_head *work_q, struct list_head *done_q) @@ -1044,7 +1042,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) if (rtn == SUCCESS) { if (!scmd->device->host->hostt->skip_settle_delay) - scsi_sleep(BUS_RESET_SETTLE_TIME); + ssleep(BUS_RESET_SETTLE_TIME); spin_lock_irqsave(scmd->device->host->host_lock, flags); scsi_report_bus_reset(scmd->device->host, scmd->device->channel); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); @@ -1076,7 +1074,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd) if (rtn == SUCCESS) { if (!scmd->device->host->hostt->skip_settle_delay) - scsi_sleep(HOST_RESET_SETTLE_TIME); + ssleep(HOST_RESET_SETTLE_TIME); spin_lock_irqsave(scmd->device->host->host_lock, flags); scsi_report_bus_reset(scmd->device->host, scmd->device->channel); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); @@ -1215,43 +1213,6 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q, return; } -/** - * scsi_sleep_done - timer function for scsi_sleep - * @sem: semphore to signal - * - **/ -static void scsi_sleep_done(unsigned long data) -{ - struct semaphore *sem = (struct semaphore *)data; - - if (sem) - up(sem); -} - -/** - * scsi_sleep - sleep for specified timeout - * @timeout: timeout value - * - **/ -void scsi_sleep(int timeout) -{ - DECLARE_MUTEX_LOCKED(sem); - struct timer_list timer; - - init_timer(&timer); - timer.data = (unsigned long)&sem; - timer.expires = jiffies + timeout; - timer.function = (void (*)(unsigned long))scsi_sleep_done; - - SCSI_LOG_ERROR_RECOVERY(5, printk("sleeping for timer tics %d\n", - timeout)); - - add_timer(&timer); - - down(&sem); - del_timer(&timer); -} - /** * scsi_decide_disposition - Disposition a cmd on return from LLD. * @scmd: SCSI cmd to examine. @@ -1639,8 +1600,6 @@ int scsi_error_handler(void *data) int rtn; DECLARE_MUTEX_LOCKED(sem); - lock_kernel(); - /* * Flush resources */ @@ -1652,8 +1611,6 @@ int scsi_error_handler(void *data) shost->eh_wait = &sem; shost->ehandler = current; - unlock_kernel(); - /* * Wake up the thread that created us. */ diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index bc5869b10..e26addada 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -391,6 +391,21 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; + /* Check for deprecated ioctls ... all the ioctls which don't + * follow the new unique numbering scheme are deprecated */ + switch (cmd) { + case SCSI_IOCTL_SEND_COMMAND: + case SCSI_IOCTL_TEST_UNIT_READY: + case SCSI_IOCTL_BENCHMARK_COMMAND: + case SCSI_IOCTL_SYNC: + case SCSI_IOCTL_START_UNIT: + case SCSI_IOCTL_STOP_UNIT: + printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); + break; + default: + break; + } + switch (cmd) { case SCSI_IOCTL_GET_IDLUN: if (verify_area(VERIFY_WRITE, arg, sizeof(struct scsi_idlun))) @@ -417,12 +432,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) case SCSI_IOCTL_DOORUNLOCK: return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = 0; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 0; - return ioctl_internal_command(sdev, scsi_cmd, - IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); + return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT, + NORMAL_RETRIES); case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e30d3f2bf..ac16f21dc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -954,6 +954,22 @@ static int scsi_init_io(struct scsi_cmnd *cmd) return BLKPREP_KILL; } +static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct scsi_device *sdev = q->queuedata; + struct scsi_driver *drv; + + if (sdev->sdev_state != SDEV_RUNNING) + return -ENXIO; + + drv = *(struct scsi_driver **) disk->private_data; + if (drv->issue_flush) + return drv->issue_flush(&sdev->sdev_gendev, error_sector); + + return -EOPNOTSUPP; +} + static int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device *sdev = q->queuedata; @@ -1335,7 +1351,8 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); - + blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); return q; @@ -1555,6 +1572,34 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, return ret; } +int +scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) +{ + struct scsi_request *sreq; + char cmd[] = { + TEST_UNIT_READY, 0, 0, 0, 0, 0, + }; + int result; + + sreq = scsi_allocate_request(sdev, GFP_KERNEL); + if (!sreq) + return -ENOMEM; + + sreq->sr_data_direction = DMA_NONE; + scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + + if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && + (sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION && + sdev->removable) { + sdev->changed = 1; + sreq->sr_result = 0; + } + result = sreq->sr_result; + scsi_release_request(sreq); + return result; +} +EXPORT_SYMBOL(scsi_test_unit_ready); + /** * scsi_device_set_state - Take the given device through the device * state model. diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 166cb9ab3..9d4d3ce9e 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -200,7 +200,7 @@ static void print_inquiry(unsigned char *inq_result) * scsi_Device pointer, or NULL on failure. **/ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, - uint channel, uint id, uint lun) + uint channel, uint id, uint lun, void *hostdata) { struct scsi_device *sdev, *device; unsigned long flags; @@ -224,6 +224,8 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, INIT_LIST_HEAD(&sdev->starved_entry); spin_lock_init(&sdev->list_lock); + /* usually NULL and set by ->slave_alloc instead */ + sdev->hostdata = hostdata; /* if the device needs this changing, it may do so in the * slave_configure function */ @@ -697,7 +699,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) **/ static int scsi_probe_and_add_lun(struct Scsi_Host *host, uint channel, uint id, uint lun, int *bflagsp, - struct scsi_device **sdevp, int rescan) + struct scsi_device **sdevp, int rescan, void *hostdata) { struct scsi_device *sdev; struct scsi_request *sreq; @@ -726,7 +728,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host, } } - sdev = scsi_alloc_sdev(host, channel, id, lun); + sdev = scsi_alloc_sdev(host, channel, id, lun, hostdata); if (!sdev) goto out; sreq = scsi_allocate_request(sdev, GFP_ATOMIC); @@ -874,7 +876,7 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel, */ for (lun = 1; lun < max_dev_lun; ++lun) if ((scsi_probe_and_add_lun(shost, channel, id, lun, - NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) && + NULL, NULL, rescan, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun) return; } @@ -1085,7 +1087,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, int res; res = scsi_probe_and_add_lun(sdev->host, sdev->channel, - sdev->id, lun, NULL, NULL, rescan); + sdev->id, lun, NULL, NULL, rescan, NULL); if (res == SCSI_SCAN_NO_RESPONSE) { /* * Got some results, but now none, abort. @@ -1111,14 +1113,15 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, return 0; } -struct scsi_device *scsi_add_device(struct Scsi_Host *shost, - uint channel, uint id, uint lun) +struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, + uint id, uint lun, void *hostdata) { struct scsi_device *sdev; int res; down(&shost->scan_mutex); - res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1); + res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, + &sdev, 1, hostdata); if (res != SCSI_SCAN_LUN_PRESENT) sdev = ERR_PTR(-ENODEV); up(&shost->scan_mutex); @@ -1178,7 +1181,7 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel, * Scan for a specific host/chan/id/lun. */ scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL, - rescan); + rescan, NULL); return; } @@ -1187,7 +1190,7 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel, * would not configure LUN 0 until all LUNs are scanned. */ res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev, - rescan); + rescan, NULL); if (res == SCSI_SCAN_LUN_PRESENT) { if (scsi_report_lun_scan(sdev, bflags, rescan) != 0) /* @@ -1316,7 +1319,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) { struct scsi_device *sdev; - sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0); + sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0, NULL); if (sdev) { sdev->borken = 0; } diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index 9da2db4ee..37231932e 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -69,11 +69,9 @@ EXPORT_SYMBOL(scsi_track_queue_full); EXPORT_SYMBOL(scsi_get_host_dev); EXPORT_SYMBOL(scsi_free_host_dev); -EXPORT_SYMBOL(scsi_sleep); - EXPORT_SYMBOL(scsi_io_completion); -EXPORT_SYMBOL(scsi_add_device); +EXPORT_SYMBOL(__scsi_add_device); EXPORT_SYMBOL(scsi_remove_device); EXPORT_SYMBOL(scsi_device_cancel); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index a8855d324..3c567e144 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -525,8 +525,11 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) **/ void scsi_remove_device(struct scsi_device *sdev) { + struct Scsi_Host *shost = sdev->host; + + down(&shost->scan_mutex); if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) - return; + goto out; class_device_unregister(&sdev->sdev_classdev); if (sdev->transport_classdev.class) @@ -538,6 +541,9 @@ void scsi_remove_device(struct scsi_device *sdev) if (sdev->host->transportt->cleanup) sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); + +out: + up(&shost->scan_mutex); } int scsi_register_driver(struct device_driver *drv) diff --git a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c index 89b957673..bc6907943 100644 --- a/drivers/scsi/scsiiom.c +++ b/drivers/scsi/scsiiom.c @@ -213,8 +213,17 @@ dc390_dma_intr (struct dc390_acb* pACB) } #endif + +static void __inline__ +dc390_InvalidCmd(struct dc390_acb* pACB) +{ + if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ | SRB_MSGOUT)) + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); +} + + static irqreturn_t __inline__ -DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct dc390_acb *pACB, *pACB2; struct dc390_dcb *pDCB; @@ -594,7 +603,7 @@ dc390_MsgIn_reject (struct dc390_acb* pACB, struct dc390_srb* pSRB) } /* abort command */ -static void __inline__ +static void dc390_EnableMsgOut_Abort ( struct dc390_acb* pACB, struct dc390_srb* pSRB ) { pSRB->MsgOutBuf[0] = ABORT; @@ -890,14 +899,22 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) if (pSRB == pACB->pTmpSRB) { - if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", - pDCB->TargetID, pDCB->TargetLUN); - else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); - - pSRB->pSRBDCB = pDCB; - dc390_EnableMsgOut_Abort (pACB, pSRB); - if (pDCB) pDCB->DCBFlag |= ABORT_DEV; - return; + if (pDCB) + printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); + else + printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); + + /* Try to recover - some broken disks react badly to tagged INQUIRY */ + if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) { + pSRB = pDCB->pGoingSRB; + pDCB->pActiveSRB = pSRB; + } else { + pSRB->pSRBDCB = pDCB; + dc390_EnableMsgOut_Abort(pACB, pSRB); + if (pDCB) + pDCB->DCBFlag |= ABORT_DEV; + return; + } } if( pSRB->SGIndex < pSRB->SGcount ) @@ -1138,7 +1155,7 @@ dc390_Disconnect( struct dc390_acb* pACB ) } DC390_write8 (ScsiCmd, EN_SEL_RESEL); pSRB = pDCB->pActiveSRB; - pACB->pActiveDCB = 0; + pACB->pActiveDCB = NULL; pSRB->ScsiPhase = SCSI_NOP0; if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { @@ -1158,7 +1175,7 @@ dc390_Disconnect( struct dc390_acb* pACB ) dc390_Free_insert (pACB, pSRB); pSRB = psrb; } - pDCB->pGoingSRB = 0; + pDCB->pGoingSRB = NULL; dc390_Waiting_process (pACB); } else @@ -1187,7 +1204,7 @@ dc390_Disconnect( struct dc390_acb* pACB ) { disc1: dc390_freetag (pDCB, pSRB); - pDCB->pActiveSRB = 0; + pDCB->pActiveSRB = NULL; pSRB->SRBState = SRB_FREE; dc390_SRBdone( pACB, pDCB, pSRB); } @@ -1325,6 +1342,35 @@ dc390_add_dev (struct dc390_acb* pACB, struct dc390_dcb* pDCB, PSCSI_INQDATA ptr } +static void __inline__ +dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB) +{ + struct scsi_cmnd *pcmd; + + pcmd = pSRB->pcmd; + + REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense(Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN)); + + pSRB->SRBFlag |= AUTO_REQSENSE; + pSRB->SavedSGCount = pcmd->use_sg; + pSRB->SavedTotXLen = pSRB->TotalXferredLen; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ + + /* We are called from SRBdone, original PCI mapping has been removed + * already, new one is set up from StartSCSI */ + pSRB->SGIndex = 0; + + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if (dc390_StartSCSI(pACB, pDCB, pSRB)) { + dc390_Going_to_Waiting(pDCB, pSRB); + dc390_waiting_timer(pACB, HZ/5); + } +} + + static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ) { @@ -1352,26 +1398,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; pSRB->TargetStatus = CHECK_CONDITION << 1; -#ifdef DC390_REMOVABLEDEBUG - switch (pcmd->sense_buffer[2] & 0x0f) - { - case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, - status, pACB->scan_devices); break; - } -#endif + //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status); if (status == (CHECK_CONDITION << 1)) { @@ -1525,23 +1552,6 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pDCB->Inquiry7 = ptr->Flags; ckc_e: - if( pACB->scan_devices ) - { - if( pcmd->cmnd[0] == TEST_UNIT_READY || - pcmd->cmnd[0] == INQUIRY) - { -#ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: %s: result: %08x", - (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"), - pcmd->result); - if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n", - pcmd->sense_buffer[0], pcmd->sense_buffer[1], - pcmd->sense_buffer[2], pcmd->sense_buffer[3]); - else printk ("\n"); -#endif - } - } - if( pcmd->cmnd[0] == INQUIRY && (pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) ) { @@ -1586,18 +1596,6 @@ dc390_DoingSRB_Done(struct dc390_acb* pACB, struct scsi_cmnd *cmd) psrb2 = psrb->pNextSRB; pcmd = psrb->pcmd; dc390_Free_insert (pACB, psrb); -#ifndef USE_NEW_EH - /* New EH will crash on being given timed out cmnds */ - if (pcmd == cmd) - pcmd->result = MK_RES(0,DID_ABORT,0,0); - else - pcmd->result = MK_RES(0,DID_RESET,0,0); - -/* ReleaseSRB( pDCB, pSRB ); */ - - DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid)); - pcmd->scsi_done( pcmd ); -#endif psrb = psrb2; } pdcb->GoingSRBCnt = 0; @@ -1646,7 +1644,7 @@ dc390_ScsiRstDetect( struct dc390_acb* pACB ) pACB->ACBFlag |= RESET_DETECT; dc390_ResetDevParam( pACB ); - dc390_DoingSRB_Done( pACB, 0 ); + dc390_DoingSRB_Done( pACB, NULL ); //dc390_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; @@ -1654,51 +1652,3 @@ dc390_ScsiRstDetect( struct dc390_acb* pACB ) } return; } - - -static void __inline__ -dc390_RequestSense( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ) -{ - struct scsi_cmnd *pcmd; - - pcmd = pSRB->pcmd; - - REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN)); - - pSRB->SRBFlag |= AUTO_REQSENSE; - //pSRB->Segment0[0] = (u32) pSRB->CmdBlock[0]; - //pSRB->Segment0[1] = (u32) pSRB->CmdBlock[4]; - //pSRB->Segment1[0] = ((u32)(pcmd->cmd_len) << 8) + pSRB->SGcount; - //pSRB->Segment1[1] = pSRB->TotalXferredLen; - pSRB->SavedSGCount = pcmd->use_sg; - pSRB->SavedTotXLen = pSRB->TotalXferredLen; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ - - /* We are called from SRBdone, original PCI mapping has been removed - * already, new one is set up from StartSCSI */ - pSRB->SGIndex = 0; - - //pSRB->CmdBlock[0] = REQUEST_SENSE; - //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; - //(u16) pSRB->CmdBlock[2] = 0; - //(u16) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - //pSRB->ScsiCmdLen = 6; - - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { - dc390_Going_to_Waiting ( pDCB, pSRB ); - dc390_waiting_timer (pACB, HZ/5); - } -} - - - -static void __inline__ -dc390_InvalidCmd( struct dc390_acb* pACB ) -{ - if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); -} diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8fd459060..f44e96df0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,18 @@ #include "scsi_logging.h" - /* - * Remaining dev_t-handling stuff + * More than enough for everybody ;) The huge number of majors + * is a leftover from 16bit dev_t days, we don't really need that + * much numberspace. */ #define SD_MAJORS 16 -#define SD_DISKS 32768 /* anything between 256 and 262144 */ + +/* + * This is limited by the naming scheme enforced in sd_probe, + * add another character to it if you really need more disks. + */ +#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) /* * Time out in seconds for disks and Magneto-opticals (which are slower). @@ -96,8 +103,7 @@ struct scsi_disk { unsigned RCD : 1; /* state of disk RCD bit, unused */ }; - -static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; +static DEFINE_IDR(sd_index_idr); static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; /* This semaphore is used to mediate the 0->1 reference get in the @@ -113,6 +119,7 @@ static int sd_remove(struct device *); static void sd_shutdown(struct device *dev); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); +static int sd_issue_flush(struct device *, sector_t *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer); @@ -126,9 +133,11 @@ static struct scsi_driver sd_template = { }, .rescan = sd_rescan, .init_command = sd_init_command, + .issue_flush = sd_issue_flush, }; -/* Device no to disk mapping: +/* + * Device no to disk mapping: * * major disc2 disc p1 * |............|.............|....|....| <- dev_t @@ -141,7 +150,6 @@ static struct scsi_driver sd_template = { * As we stay compatible with our numbering scheme, we can reuse * the well-know SCSI majors 8, 65--71, 136--143. */ - static int sd_major(int major_idx) { switch (major_idx) { @@ -157,14 +165,6 @@ static int sd_major(int major_idx) } } -static unsigned int make_sd_dev(unsigned int sd_nr, unsigned int part) -{ - return (part & 0xf) | ((sd_nr & 0xf) << 4) | - (sd_major((sd_nr & 0xf0) >> 4) << 20) | (sd_nr & 0xfff00); -} - -/* reverse mapping dev -> (sd_nr, part) not currently needed */ - #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref) static inline struct scsi_disk *scsi_disk(struct gendisk *disk) @@ -180,16 +180,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); @@ -200,7 +198,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); } @@ -648,7 +646,7 @@ static int sd_media_changed(struct gendisk *disk) */ retval = -ENODEV; if (scsi_block_when_processing_errors(sdp)) - retval = scsi_ioctl(sdp, SCSI_IOCTL_TEST_UNIT_READY, NULL); + retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); /* * Unable to test, unit probably not ready. This usually @@ -676,6 +674,62 @@ not_present: return 1; } +static int sd_sync_cache(struct scsi_device *sdp) +{ + struct scsi_request *sreq; + int retries, res; + + if (!scsi_device_online(sdp)) + return -ENODEV; + + sreq = scsi_allocate_request(sdp, GFP_KERNEL); + if (!sreq) { + printk("FAILED\n No memory for request\n"); + return -ENOMEM; + } + + sreq->sr_data_direction = DMA_NONE; + for (retries = 3; retries > 0; --retries) { + unsigned char cmd[10] = { 0 }; + + cmd[0] = SYNCHRONIZE_CACHE; + /* + * Leave the rest of the command zero to indicate + * flush everything. + */ + scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); + if (sreq->sr_result == 0) + break; + } + + res = sreq->sr_result; + if (res) { + printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + scsi_print_req_sense("sd", sreq); + } + + scsi_release_request(sreq); + return res; +} + +static int sd_issue_flush(struct device *dev, sector_t *error_sector) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + if (!sdkp) + return -ENODEV; + + if (!sdkp->WCE) + return 0; + + return sd_sync_cache(sdp); +} + static void sd_rescan(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); @@ -1347,7 +1401,7 @@ static int sd_probe(struct device *dev) struct scsi_disk *sdkp; struct gendisk *gd; u32 index; - int error, devno; + int error; error = -ENODEV; if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) @@ -1362,27 +1416,23 @@ static int sd_probe(struct device *dev) goto out; memset (sdkp, 0, sizeof(*sdkp)); - kref_init(&sdkp->kref, scsi_disk_release); - - /* Note: We can accomodate 64 partitions, but the genhd code - * assumes partitions allocate consecutive minors, which they don't. - * So for now stay with max 16 partitions and leave two spare bits. - * Later, we may change the genhd code and the alloc_disk() call - * and the ->minors assignment here. KG, 2004-02-10 - */ + kref_init(&sdkp->kref); + gd = alloc_disk(16); if (!gd) goto out_free; + if (!idr_pre_get(&sd_index_idr, GFP_KERNEL)) + goto out_put; + spin_lock(&sd_index_lock); - index = find_first_zero_bit(sd_index_bits, SD_DISKS); - if (index == SD_DISKS) { - spin_unlock(&sd_index_lock); + error = idr_get_new(&sd_index_idr, NULL, &index); + spin_unlock(&sd_index_lock); + + if (index >= SD_MAX_DISKS) error = -EBUSY; + if (error) goto out_put; - } - __set_bit(index, sd_index_bits); - spin_unlock(&sd_index_lock); sdkp->device = sdp; sdkp->driver = &sd_template; @@ -1397,15 +1447,14 @@ static int sd_probe(struct device *dev) sdp->timeout = SD_MOD_TIMEOUT; } - devno = make_sd_dev(index, 0); - gd->major = MAJOR(devno); - gd->first_minor = MINOR(devno); + gd->major = sd_major((index & 0xf0) >> 4); + gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); gd->minors = 16; gd->fops = &sd_fops; if (index < 26) { sprintf(gd->disk_name, "sd%c", 'a' + index % 26); - } else if (index < (26*27)) { + } else if (index < (26 + 1) * 26) { sprintf(gd->disk_name, "sd%c%c", 'a' + index / 26 - 1,'a' + index % 26); } else { @@ -1464,7 +1513,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; @@ -1485,7 +1534,7 @@ static void scsi_disk_release(struct kref *kref) struct gendisk *disk = sdkp->disk; spin_lock(&sd_index_lock); - clear_bit(sdkp->index, sd_index_bits); + idr_remove(&sd_index_idr, sdkp->index); spin_unlock(&sd_index_lock); disk->private_data = NULL; @@ -1503,52 +1552,17 @@ static void scsi_disk_release(struct kref *kref) static void sd_shutdown(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); - struct scsi_disk *sdkp; - struct scsi_request *sreq; - int retries, res; + struct scsi_disk *sdkp = dev_get_drvdata(dev); - sdkp = dev_get_drvdata(dev); if (!sdkp) - return; /* this can happen */ + return; /* this can happen */ - if (!scsi_device_online(sdp) || !sdkp->WCE) + if (!sdkp->WCE) return; - printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ", + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", sdkp->disk->disk_name); - - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk("FAILED\n No memory for request\n"); - return; - } - - sreq->sr_data_direction = DMA_NONE; - for (retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; - - cmd[0] = SYNCHRONIZE_CACHE; - /* - * Leave the rest of the command zero to indicate - * flush everything. - */ - scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); - if (sreq->sr_result == 0) - break; - } - - res = sreq->sr_result; - if (res) { - printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " - "host = %d, driver = %02x\n ", - status_byte(res), msg_byte(res), - host_byte(res), driver_byte(res)); - if (driver_byte(res) & DRIVER_SENSE) - scsi_print_req_sense("sd", sreq); - } - - scsi_release_request(sreq); - printk("\n"); + sd_sync_cache(sdp); } /** diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7b0665d8b..ed80392b0 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -47,8 +47,9 @@ static int sg_version_num = 30531; /* 2 digits for each component */ #include #include #include - #include +#include + #include "scsi.h" #include #include @@ -205,8 +206,6 @@ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request *sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); -static int sg_ms_to_jif(unsigned int msecs); -static inline unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static Sg_device *sg_get_dev(int dev); @@ -611,7 +610,7 @@ sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, return -EBUSY; /* reserve buffer already being used */ } } - timeout = sg_ms_to_jif(srp->header.timeout); + timeout = msecs_to_jiffies(srp->header.timeout); if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) { sg_remove_request(sfp, srp); return -EMSGSIZE; @@ -719,19 +718,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return 0; } -static inline unsigned -sg_jif_to_ms(int jifs) -{ - if (jifs <= 0) - return 0U; - else { - unsigned int j = (unsigned int) jifs; - return (j < - (UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) * - 1000); - } -} - static int sg_ioctl(struct inode *inode, struct file *filp, unsigned int cmd_in, unsigned long arg) @@ -941,7 +927,7 @@ sg_ioctl(struct inode *inode, struct file *filp, srp->header.driver_status; rinfo[val].duration = srp->done ? srp->header.duration : - sg_jif_to_ms( + jiffies_to_msecs( jiffies - srp->header.duration); rinfo[val].orphan = srp->orphan; rinfo[val].sg_io_owned = srp->sg_io_owned; @@ -1263,7 +1249,7 @@ sg_cmd_done(Scsi_Cmnd * SCpnt) srp->header.resid = SCpnt->resid; /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = - sg_jif_to_ms(jiffies - (int) srp->header.duration); + jiffies_to_msecs(jiffies - srp->header.duration); if (0 != SRpnt->sr_result) { memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof (srp->sense_b)); @@ -1547,7 +1533,7 @@ sg_remove(struct class_device *cl_dev) } if (delay) - scsi_sleep(2); /* dirty detach so delay device destruction */ + msleep(10); /* dirty detach so delay device destruction */ } /* Set 'perm' (4th argument) to 0 to disable module_param's definition @@ -2587,17 +2573,6 @@ sg_page_free(char *buff, int size) free_pages((unsigned long) buff, order); } -static int -sg_ms_to_jif(unsigned int msecs) -{ - if ((UINT_MAX / 2U) < msecs) - return INT_MAX; /* special case, set largest possible */ - else - return ((int) msecs < - (INT_MAX / 1000)) ? (((int) msecs * HZ) / 1000) - : (((int) msecs / 1000) * HZ); -} - static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE, INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, MODE_SENSE, MODE_SENSE_10, LOG_SENSE @@ -2960,7 +2935,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " "(res)sgat=%d low_dma=%d\n", k + 1, - sg_jif_to_ms(fp->timeout), + jiffies_to_msecs(fp->timeout), fp->reserve.bufflen, (int) fp->reserve.k_use_sg, (int) fp->low_dma); @@ -2996,8 +2971,8 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " dur=%d", hp->duration); else seq_printf(s, " t_o/elap=%d/%d", - new_interface ? hp->timeout : sg_jif_to_ms(fp->timeout), - sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); + new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout), + jiffies_to_msecs(hp->duration ? (jiffies - hp->duration) : 0)); seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b80aa283c..b6c76b568 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); } @@ -183,7 +181,7 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot) return -EINVAL; } - retval = scsi_ioctl(cd->device, SCSI_IOCTL_TEST_UNIT_READY, NULL); + retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES); if (retval) { /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, @@ -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/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 7d24b57c2..1ddb5f27a 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -131,7 +132,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); if (retries++ < 10) { /* sleep 2 sec and try again */ - scsi_sleep(2 * HZ); + ssleep(2); goto retry; } else { /* 20 secs are enough? */ diff --git a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h index 1241104b6..09f861a03 100644 --- a/drivers/scsi/sym53c8xx_2/sym_defs.h +++ b/drivers/scsi/sym53c8xx_2/sym_defs.h @@ -53,6 +53,9 @@ #ifndef SYM_DEFS_H #define SYM_DEFS_H +#define SYM_VERSION "2.1.18j" +#define SYM_DRIVER_NAME "sym-" SYM_VERSION + /* * Vendor. */ diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 22238315d..0d9d1b42b 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -142,13 +142,6 @@ m_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m) return b; } -/* - * Driver host data structure. - */ -struct host_data { - struct sym_hcb *ncb; -}; - /* * Used by the eh thread to wait for command completion. * It is allocated on the eh thread stack. @@ -220,47 +213,12 @@ static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) return use_sg; } -static void __sync_scsi_data_for_cpu(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - int dma_dir = cmd->sc_data_direction; - - switch(SYM_UCMD_PTR(cmd)->data_mapped) { - case 2: - pci_dma_sync_sg_for_cpu(pdev, cmd->buffer, cmd->use_sg, dma_dir); - break; - case 1: - pci_dma_sync_single_for_cpu(pdev, SYM_UCMD_PTR(cmd)->data_mapping, - cmd->request_bufflen, dma_dir); - break; - } -} - -static void __sync_scsi_data_for_device(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - int dma_dir = cmd->sc_data_direction; - - switch(SYM_UCMD_PTR(cmd)->data_mapped) { - case 2: - pci_dma_sync_sg_for_device(pdev, cmd->buffer, cmd->use_sg, dma_dir); - break; - case 1: - pci_dma_sync_single_for_device(pdev, SYM_UCMD_PTR(cmd)->data_mapping, - cmd->request_bufflen, dma_dir); - break; - } -} - #define unmap_scsi_data(np, cmd) \ __unmap_scsi_data(np->s.device, cmd) #define map_scsi_single_data(np, cmd) \ __map_scsi_single_data(np->s.device, cmd) #define map_scsi_sg_data(np, cmd) \ __map_scsi_sg_data(np->s.device, cmd) -#define sync_scsi_data_for_cpu(np, cmd) \ - __sync_scsi_data_for_cpu(np->s.device, cmd) -#define sync_scsi_data_for_device(np, cmd) \ - __sync_scsi_data_for_device(np->s.device, cmd) - /* * Complete a pending CAM CCB. */ @@ -416,27 +374,6 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid) } -/* - * Called on successfull INQUIRY response. - */ -void sym_sniff_inquiry(struct sym_hcb *np, struct scsi_cmnd *cmd, int resid) -{ - int retv; - - if (!cmd || cmd->use_sg) - return; - - sync_scsi_data_for_cpu(np, cmd); - retv = __sym_sniff_inquiry(np, cmd->device->id, cmd->device->lun, - (u_char *) cmd->request_buffer, - cmd->request_bufflen - resid); - sync_scsi_data_for_device(np, cmd); - if (retv < 0) - return; - else if (retv) - sym_update_trans_settings(np, &np->target[cmd->device->id]); -} - /* * Build the scatter/gather array for an I/O. */ @@ -730,14 +667,15 @@ void sym_log_bus_error(struct sym_hcb *np) */ static void sym_requeue_awaiting_cmds(struct sym_hcb *np) { - struct scsi_cmnd *cmd; - struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); + struct sym_ucmd *ucp; SYM_QUEHEAD tmp_cmdq; int sts; sym_que_move(&np->s.wait_cmdq, &tmp_cmdq); while ((ucp = (struct sym_ucmd *) sym_remque_head(&tmp_cmdq)) != 0) { + struct scsi_cmnd *cmd; + sym_insque_tail(&ucp->link_cmdq, &np->s.busy_cmdq); cmd = SYM_SCMD_PTR(ucp); sts = sym_queue_command(np, cmd); @@ -1118,12 +1056,7 @@ static int sym53c8xx_slave_configure(struct scsi_device *device) np = ((struct host_data *) host->hostdata)->ncb; tp = &np->target[device->id]; - - /* - * Get user settings for transfer parameters. - */ - tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16); - sym_update_trans_settings(np, tp); + tp->sdev = device; /* * Allocate the LCB if not yet. @@ -2283,6 +2216,7 @@ static int sym_detach(struct sym_hcb *np) } MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(SYM_VERSION); /* * Driver host template. @@ -2383,13 +2317,6 @@ static void sym2_set_offset(struct scsi_device *sdev, int offset) struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; - if (tp->tinfo.curr.options & PPR_OPT_DT) { - if (offset > np->maxoffs_dt) - offset = np->maxoffs_dt; - } else { - if (offset > np->maxoffs) - offset = np->maxoffs; - } tp->tinfo.goal.offset = offset; } @@ -2407,23 +2334,11 @@ static void sym2_set_period(struct scsi_device *sdev, int period) struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; - if (period <= 9 && np->minsync_dt) { - if (period < np->minsync_dt) - period = np->minsync_dt; - tp->tinfo.goal.options = PPR_OPT_DT; - tp->tinfo.goal.period = period; - if (!tp->tinfo.curr.offset || - tp->tinfo.curr.offset > np->maxoffs_dt) - tp->tinfo.goal.offset = np->maxoffs_dt; - } else { - if (period < np->minsync) - period = np->minsync; - tp->tinfo.goal.options = 0; - tp->tinfo.goal.period = period; - if (!tp->tinfo.curr.offset || - tp->tinfo.curr.offset > np->maxoffs) - tp->tinfo.goal.offset = np->maxoffs; - } + /* have to have DT for these transfers */ + if (period <= np->minsync) + tp->tinfo.goal.options |= PPR_OPT_DT; + + tp->tinfo.goal.period = period; } static void sym2_get_width(struct scsi_device *sdev) @@ -2439,6 +2354,10 @@ static void sym2_set_width(struct scsi_device *sdev, int width) struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; + /* It is illegal to have DT set on narrow transfers */ + if (width == 0) + tp->tinfo.goal.options &= ~PPR_OPT_DT; + tp->tinfo.goal.width = width; } @@ -2455,17 +2374,10 @@ static void sym2_set_dt(struct scsi_device *sdev, int dt) struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; - if (!dt) { - /* if clearing DT, then we may need to reduce the - * period and the offset */ - if (tp->tinfo.curr.period < np->minsync) - tp->tinfo.goal.period = np->minsync; - if (tp->tinfo.curr.offset > np->maxoffs) - tp->tinfo.goal.offset = np->maxoffs; - tp->tinfo.goal.options &= ~PPR_OPT_DT; - } else { + if (dt) tp->tinfo.goal.options |= PPR_OPT_DT; - } + else + tp->tinfo.goal.options &= ~PPR_OPT_DT; } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h index 60d48b750..5dd15fc0f 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.h +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h @@ -90,7 +90,6 @@ #define SYM_OPT_HANDLE_DIR_UNKNOWN #define SYM_OPT_HANDLE_DEVICE_QUEUEING #define SYM_OPT_NVRAM_PRE_READ -#define SYM_OPT_SNIFF_INQUIRY #define SYM_OPT_LIMIT_COMMAND_REORDERING #define SYM_OPT_ANNOUNCE_TRANSFER_RATE @@ -289,32 +288,32 @@ typedef struct scsi_cmnd *cam_scsiio_p;/* SCSI I/O */ * MEMORY mapped IO input / output */ -#define INB_OFF(o) readb((char *)np->s.mmio_va + sym_offb(o)) -#define OUTB_OFF(o, val) writeb((val), (char *)np->s.mmio_va + sym_offb(o)) +#define INB_OFF(o) readb(np->s.mmio_va + sym_offb(o)) +#define OUTB_OFF(o, val) writeb((val), np->s.mmio_va + sym_offb(o)) #if defined(__BIG_ENDIAN) && !defined(SYM_CONF_CHIP_BIG_ENDIAN) -#define INW_OFF(o) readw_l2b((char *)np->s.mmio_va + sym_offw(o)) -#define INL_OFF(o) readl_l2b((char *)np->s.mmio_va + (o)) +#define INW_OFF(o) readw_l2b(np->s.mmio_va + sym_offw(o)) +#define INL_OFF(o) readl_l2b(np->s.mmio_va + (o)) -#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->s.mmio_va + sym_offw(o)) -#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->s.mmio_va + (o)) +#define OUTW_OFF(o, val) writew_b2l((val), np->s.mmio_va + sym_offw(o)) +#define OUTL_OFF(o, val) writel_b2l((val), np->s.mmio_va + (o)) #elif defined(__LITTLE_ENDIAN) && defined(SYM_CONF_CHIP_BIG_ENDIAN) -#define INW_OFF(o) readw_b2l((char *)np->s.mmio_va + sym_offw(o)) -#define INL_OFF(o) readl_b2l((char *)np->s.mmio_va + (o)) +#define INW_OFF(o) readw_b2l(np->s.mmio_va + sym_offw(o)) +#define INL_OFF(o) readl_b2l(np->s.mmio_va + (o)) -#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->s.mmio_va + sym_offw(o)) -#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->s.mmio_va + (o)) +#define OUTW_OFF(o, val) writew_l2b((val), np->s.mmio_va + sym_offw(o)) +#define OUTL_OFF(o, val) writel_l2b((val), np->s.mmio_va + (o)) #else -#define INW_OFF(o) readw_raw((char *)np->s.mmio_va + sym_offw(o)) -#define INL_OFF(o) readl_raw((char *)np->s.mmio_va + (o)) +#define INW_OFF(o) readw_raw(np->s.mmio_va + sym_offw(o)) +#define INL_OFF(o) readl_raw(np->s.mmio_va + (o)) -#define OUTW_OFF(o, val) writew_raw((val), (char *)np->s.mmio_va + sym_offw(o)) -#define OUTL_OFF(o, val) writel_raw((val), (char *)np->s.mmio_va + (o)) +#define OUTW_OFF(o, val) writew_raw((val), np->s.mmio_va + sym_offw(o)) +#define OUTL_OFF(o, val) writel_raw((val), np->s.mmio_va + (o)) #endif @@ -391,8 +390,8 @@ struct sym_shcb { struct Scsi_Host *host; - void * mmio_va; /* MMIO kernel virtual address */ - void * ram_va; /* RAM kernel virtual address */ + void __iomem * mmio_va; /* MMIO kernel virtual address */ + void __iomem * ram_va; /* RAM kernel virtual address */ u_long io_port; /* IO port address cookie */ u_short io_ws; /* IO window size */ int irq; /* IRQ number */ @@ -424,7 +423,7 @@ struct sym_slot { int irq; /* port and address fields to fit INB, OUTB macros */ u_long io_port; - void * mmio_va; + void __iomem * mmio_va; char inst_name[16]; }; @@ -439,6 +438,13 @@ struct sym_device { u_char host_id; }; +/* + * Driver host data structure. + */ +struct host_data { + struct sym_hcb *ncb; +}; + /* * The driver definitions (sym_hipd.h) must know about a * couple of things related to the memory allocator. diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 25a27f998..dddf88b87 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -49,10 +49,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - -#define SYM_VERSION "2.1.18j" -#define SYM_DRIVER_NAME "sym-" SYM_VERSION - #include "sym_glue.h" #include "sym_nvram.h" @@ -1042,28 +1038,11 @@ static int sym_prepare_setting(hcb_p np, struct sym_nvram *nvram) for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { tcb_p tp = &np->target[i]; - tp->tinfo.user.scsi_version = tp->tinfo.curr.scsi_version= 2; - tp->tinfo.user.spi_version = tp->tinfo.curr.spi_version = 2; - tp->tinfo.user.period = np->minsync; - tp->tinfo.user.offset = np->maxoffs; - tp->tinfo.user.width = np->maxwide ? BUS_16_BIT : BUS_8_BIT; tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); tp->usrtags = SYM_SETUP_MAX_TAG; sym_nvram_setup_target (np, i, nvram); - /* - * Some single-ended devices may crash on receiving a - * PPR negotiation attempt. Only try PPR if we're in - * LVD mode. - */ - if (np->features & FE_ULTRA3) { - tp->tinfo.user.options |= PPR_OPT_DT; - tp->tinfo.user.period = np->minsync_dt; - tp->tinfo.user.offset = np->maxoffs_dt; - tp->tinfo.user.spi_version = 3; - } - if (!tp->usrtags) tp->usrflags &= ~SYM_TAGS_ENABLED; } @@ -1497,6 +1476,55 @@ static void sym_update_dmap_regs(hcb_p np) } #endif +static void sym_check_goals(struct scsi_device *sdev) +{ + struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; + struct sym_trans *st = &np->target[sdev->id].tinfo.goal; + + /* here we enforce all the fiddly SPI rules */ + + if (!scsi_device_wide(sdev)) + st->width = 0; + + if (!scsi_device_sync(sdev)) { + st->options = 0; + st->period = 0; + st->offset = 0; + return; + } + + if (scsi_device_dt(sdev)) { + if (scsi_device_dt_only(sdev)) + st->options |= PPR_OPT_DT; + + if (st->offset == 0) + st->options &= ~PPR_OPT_DT; + } else { + st->options &= ~PPR_OPT_DT; + } + + if (!(np->features & FE_ULTRA3)) + st->options &= ~PPR_OPT_DT; + + if (st->options & PPR_OPT_DT) { + /* all DT transfers must be wide */ + st->width = 1; + if (st->offset > np->maxoffs_dt) + st->offset = np->maxoffs_dt; + if (st->period < np->minsync_dt) + st->period = np->minsync_dt; + if (st->period > np->maxsync_dt) + st->period = np->maxsync_dt; + } else { + if (st->offset > np->maxoffs) + st->offset = np->maxoffs; + if (st->period < np->minsync) + st->period = np->minsync; + if (st->period > np->maxsync) + st->period = np->maxsync; + } +} + /* * Prepare the next negotiation message if needed. * @@ -1508,6 +1536,10 @@ static int sym_prepare_nego(hcb_p np, ccb_p cp, int nego, u_char *msgptr) { tcb_p tp = &np->target[cp->target]; int msglen = 0; + struct scsi_device *sdev = tp->sdev; + + if (likely(sdev)) + sym_check_goals(sdev); /* * Early C1010 chips need a work-around for DT @@ -1518,19 +1550,21 @@ static int sym_prepare_nego(hcb_p np, ccb_p cp, int nego, u_char *msgptr) /* * negotiate using PPR ? */ - if (tp->tinfo.goal.options & PPR_OPT_MASK) + if (scsi_device_dt(sdev)) { nego = NS_PPR; - /* - * negotiate wide transfers ? - */ - else if (tp->tinfo.curr.width != tp->tinfo.goal.width) - nego = NS_WIDE; - /* - * negotiate synchronous transfers? - */ - else if (tp->tinfo.curr.period != tp->tinfo.goal.period || - tp->tinfo.curr.offset != tp->tinfo.goal.offset) - nego = NS_SYNC; + } else { + /* + * negotiate wide transfers ? + */ + if (tp->tinfo.curr.width != tp->tinfo.goal.width) + nego = NS_WIDE; + /* + * negotiate synchronous transfers? + */ + else if (tp->tinfo.curr.period != tp->tinfo.goal.period || + tp->tinfo.curr.offset != tp->tinfo.goal.offset) + nego = NS_SYNC; + } switch (nego) { case NS_SYNC: @@ -3999,7 +4033,6 @@ int sym_compute_residual(hcb_p np, ccb_p cp) static int sym_sync_nego_check(hcb_p np, int req, int target) { - tcb_p tp = &np->target[target]; u_char chg, ofs, per, fak, div; if (DEBUG_FLAGS & DEBUG_NEGO) { @@ -4019,19 +4052,11 @@ sym_sync_nego_check(hcb_p np, int req, int target) if (ofs) { if (ofs > np->maxoffs) {chg = 1; ofs = np->maxoffs;} - if (req) { - if (ofs > tp->tinfo.user.offset) - {chg = 1; ofs = tp->tinfo.user.offset;} - } } if (ofs) { if (per < np->minsync) {chg = 1; per = np->minsync;} - if (req) { - if (per < tp->tinfo.user.period) - {chg = 1; per = tp->tinfo.user.period;} - } } /* @@ -4151,10 +4176,6 @@ sym_ppr_nego_check(hcb_p np, int req, int target) } if (!wide || !(np->features & FE_ULTRA3)) dt &= ~PPR_OPT_DT; - if (req) { - if (wide > tp->tinfo.user.width) - {chg = 1; wide = tp->tinfo.user.width;} - } if (!(np->features & FE_U3EN)) /* Broken U3EN bit not supported */ dt &= ~PPR_OPT_DT; @@ -4168,10 +4189,6 @@ sym_ppr_nego_check(hcb_p np, int req, int target) } else if (ofs > np->maxoffs) {chg = 1; ofs = np->maxoffs;} - if (req) { - if (ofs > tp->tinfo.user.offset) - {chg = 1; ofs = tp->tinfo.user.offset;} - } } if (ofs) { @@ -4181,10 +4198,6 @@ sym_ppr_nego_check(hcb_p np, int req, int target) } else if (per < np->minsync) {chg = 1; per = np->minsync;} - if (req) { - if (per < tp->tinfo.user.period) - {chg = 1; per = tp->tinfo.user.period;} - } } /* @@ -4286,7 +4299,6 @@ reject_it: static int sym_wide_nego_check(hcb_p np, int req, int target) { - tcb_p tp = &np->target[target]; u_char chg, wide; if (DEBUG_FLAGS & DEBUG_NEGO) { @@ -4306,10 +4318,6 @@ sym_wide_nego_check(hcb_p np, int req, int target) chg = 1; wide = np->maxwide; } - if (req) { - if (wide > tp->tinfo.user.width) - {chg = 1; wide = tp->tinfo.user.width;} - } if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_TARGET(np, target); diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index aa246dd0f..04b5411ea 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -69,11 +69,6 @@ * When this option is set, the driver will use a queue per * device and handle QUEUE FULL status requeuing internally. * - * SYM_OPT_SNIFF_INQUIRY - * When this option is set, the driver sniff out successful - * INQUIRY response and performs negotiations accordingly. - * (set for Linux) - * * SYM_OPT_LIMIT_COMMAND_REORDERING * When this option is set, the driver tries to limit tagged * command reordering to some reasonnable value. @@ -82,7 +77,6 @@ #if 0 #define SYM_OPT_HANDLE_DIR_UNKNOWN #define SYM_OPT_HANDLE_DEVICE_QUEUEING -#define SYM_OPT_SNIFF_INQUIRY #define SYM_OPT_LIMIT_COMMAND_REORDERING #endif @@ -364,7 +358,6 @@ struct sym_trans { struct sym_tinfo { struct sym_trans curr; struct sym_trans goal; - struct sym_trans user; #ifdef SYM_OPT_ANNOUNCE_TRANSFER_RATE struct sym_trans prev; #endif @@ -465,18 +458,7 @@ struct sym_tcb { */ u_char usrflags; u_short usrtags; - -#ifdef SYM_OPT_SNIFF_INQUIRY - /* - * Some minimal information from INQUIRY response. - */ - u32 cmdq_map[(SYM_CONF_MAX_LUN+31)/32]; - u_char inq_version; - u_char inq_byte7; - u_char inq_byte56; - u_char inq_byte7_valid; -#endif - + struct scsi_device *sdev; }; /* @@ -1168,26 +1150,6 @@ void sym_clock(hcb_p np); void sym_announce_transfer_rate(hcb_p np, int target); #endif -/* - * Optionnaly, the driver may sniff inquiry data. - */ -#ifdef SYM_OPT_SNIFF_INQUIRY -#define INQ7_CMDQ (0x02) -#define INQ7_SYNC (0x10) -#define INQ7_WIDE16 (0x20) - -#define INQ56_CLOCKING (3<<2) -#define INQ56_ST_ONLY (0<<2) -#define INQ56_DT_ONLY (1<<2) -#define INQ56_ST_DT (3<<2) - -void sym_update_trans_settings(hcb_p np, tcb_p tp); -int -__sym_sniff_inquiry(hcb_p np, u_char tn, u_char ln, - u_char *inq_data, int inq_len); -#endif - - /* * Build a scatter/gather entry. * diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.c b/drivers/scsi/sym53c8xx_2/sym_misc.c index ee2a7b28a..6b3c8b84c 100644 --- a/drivers/scsi/sym53c8xx_2/sym_misc.c +++ b/drivers/scsi/sym53c8xx_2/sym_misc.c @@ -216,121 +216,3 @@ void sym_announce_transfer_rate(hcb_p np, int target) #undef __tprev #undef __tcurr #endif /* SYM_OPT_ANNOUNCE_TRANSFER_RATE */ - - -#ifdef SYM_OPT_SNIFF_INQUIRY -/* - * Update transfer settings according to user settings - * and bits sniffed out from INQUIRY response. - */ -void sym_update_trans_settings(hcb_p np, tcb_p tp) -{ - memcpy(&tp->tinfo.goal, &tp->tinfo.user, sizeof(tp->tinfo.goal)); - - if (tp->inq_version >= 4) { - switch(tp->inq_byte56 & INQ56_CLOCKING) { - case INQ56_ST_ONLY: - tp->tinfo.goal.options = 0; - break; - case INQ56_DT_ONLY: - case INQ56_ST_DT: - default: - break; - } - } - - if (!((tp->inq_byte7 & tp->inq_byte7_valid) & INQ7_WIDE16)) { - tp->tinfo.goal.width = 0; - tp->tinfo.goal.options = 0; - } - - if (!((tp->inq_byte7 & tp->inq_byte7_valid) & INQ7_SYNC)) { - tp->tinfo.goal.offset = 0; - tp->tinfo.goal.options = 0; - } - - if (tp->tinfo.goal.options & PPR_OPT_DT) { - if (tp->tinfo.goal.offset > np->maxoffs_dt) - tp->tinfo.goal.offset = np->maxoffs_dt; - } - else { - if (tp->tinfo.goal.offset > np->maxoffs) - tp->tinfo.goal.offset = np->maxoffs; - } -} - -/* - * Snoop target capabilities from INQUIRY response. - * We only believe device versions >= SCSI-2 that use - * appropriate response data format (2). But it seems - * that some CCS devices also support SYNC (?). - */ -int -__sym_sniff_inquiry(hcb_p np, u_char tn, u_char ln, - u_char *inq_data, int inq_len) -{ - tcb_p tp = &np->target[tn]; - u_char inq_version; - u_char inq_byte7; - u_char inq_byte56; - - if (!inq_data || inq_len < 2) - return -1; - - /* - * Check device type and qualifier. - */ - if ((inq_data[0] & 0xe0) == 0x60) - return -1; - - /* - * Get SPC version. - */ - if (inq_len <= 2) - return -1; - inq_version = inq_data[2] & 0x7; - - /* - * Get SYNC/WIDE16 capabilities. - */ - inq_byte7 = tp->inq_byte7; - if (inq_version >= 2 && (inq_data[3] & 0xf) == 2) { - if (inq_len > 7) - inq_byte7 = inq_data[7]; - } - else if (inq_version == 1 && (inq_data[3] & 0xf) == 1) - inq_byte7 = INQ7_SYNC; - - /* - * Get Tagged Command Queuing capability. - */ - if (inq_byte7 & INQ7_CMDQ) - sym_set_bit(tp->cmdq_map, ln); - else - sym_clr_bit(tp->cmdq_map, ln); - inq_byte7 &= ~INQ7_CMDQ; - - /* - * Get CLOCKING capability. - */ - inq_byte56 = tp->inq_byte56; - if (inq_version >= 4 && inq_len > 56) - inq_byte56 = inq_data[56]; -#if 0 -printf("XXXXXX [%d] inq_version=%x inq_byte7=%x inq_byte56=%x XXXXX\n", - inq_len, inq_version, inq_byte7, inq_byte56); -#endif - /* - * Trigger a negotiation if needed. - */ - if (tp->inq_version != inq_version || - tp->inq_byte7 != inq_byte7 || - tp->inq_byte56 != inq_byte56) { - tp->inq_version = inq_version; - tp->inq_byte7 = inq_byte7; - tp->inq_byte56 = inq_byte56; - return 1; - } - return 0; -} -#endif /* SYM_OPT_SNIFF_INQUIRY */ diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c index 2bb4b3f3e..ca857ffc6 100644 --- a/drivers/scsi/sym53c8xx_2/sym_nvram.c +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c @@ -53,11 +53,6 @@ #include "sym_glue.h" #include "sym_nvram.h" -/* - * Some poor and bogus sync table that refers to Tekram NVRAM layout. - */ -static u_char Tekram_sync[16] = - {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10}; #ifdef SYM_CONF_DEBUG_NVRAM static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; #endif @@ -100,8 +95,6 @@ sym_Symbios_setup_target(struct sym_hcb *np, int target, Symbios_nvram *nvram) struct sym_tcb *tp = &np->target[target]; Symbios_target *tn = &nvram->target[target]; - tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0; - tp->tinfo.user.width = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT; tp->usrtags = (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0; @@ -121,15 +114,6 @@ sym_Tekram_setup_target(struct sym_hcb *np, int target, Tekram_nvram *nvram) { struct sym_tcb *tp = &np->target[target]; struct Tekram_target *tn = &nvram->target[target]; - int i; - - if (tn->flags & TEKRAM_SYNC_NEGO) { - i = tn->sync_index & 0xf; - tp->tinfo.user.period = Tekram_sync[i]; - } - - tp->tinfo.user.width = (tn->flags & TEKRAM_WIDE_NEGO) ? - BUS_16_BIT : BUS_8_BIT; if (tn->flags & TEKRAM_TAGGED_COMMANDS) { tp->usrtags = 2 << nvram->max_tags_index; diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index 7ef1b8c92..7e73fc257 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -284,6 +284,7 @@ static int t128_release(struct Scsi_Host *shost) { if (shost->irq) free_irq(shost->irq, NULL); + NCR5380_exit(shost); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); scsi_unregister(shost); diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 1b324b800..8a1ed11fb 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -240,17 +240,15 @@ #include #include -#if 0 #include #include #include -#else -#include "scsi.h" -#endif #include #include -#include "dc390.h" + +#define DC390_BANNER "Tekram DC390/AM53C974" +#define DC390_VERSION "2.1d 2004-05-27" #define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI @@ -291,20 +289,14 @@ static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struc static void dc390_DoingSRB_Done( struct dc390_acb* pACB, struct scsi_cmnd * cmd); static void dc390_ScsiRstDetect( struct dc390_acb* pACB ); static void dc390_ResetSCSIBus( struct dc390_acb* pACB ); -static void __inline__ dc390_RequestSense( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ); -static void __inline__ dc390_InvalidCmd( struct dc390_acb* pACB ); -static void __inline__ dc390_EnableMsgOut_Abort (struct dc390_acb*, struct dc390_srb*); +static void dc390_EnableMsgOut_Abort(struct dc390_acb*, struct dc390_srb*); static irqreturn_t do_DC390_Interrupt( int, void *, struct pt_regs *); static int dc390_initAdapter(struct Scsi_Host *psh, unsigned long io_port, u8 Irq, u8 index ); static void dc390_updateDCB (struct dc390_acb* pACB, struct dc390_dcb* pDCB); -static int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start, - off_t offset, int length, int inout); - static struct dc390_acb* dc390_pACB_start= NULL; static struct dc390_acb* dc390_pACB_current = NULL; -static unsigned long dc390_lastabortedpid = 0; static u32 dc390_laststatus = 0; static u8 dc390_adapterCnt = 0; @@ -612,16 +604,12 @@ static u8 __devinit dc390_CheckEEpromCheckSum(struct pci_dev *pdev, u8 index) **********************************************************************/ static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun) { - struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return 0; + struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL; while (pDCB->TargetID != id || pDCB->TargetLUN != lun) { pDCB = pDCB->pNextDCB; if (pDCB == pACB->pLinkDCB) - { - DCBDEBUG(printk (KERN_WARNING "DC390: DCB not found (DCB=%p, DCBmap[%2x]=%2x)\n", - pDCB, id, pACB->DCBmap[id])); - return 0; - } + return NULL; } DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \ pDCB, pDCB->TargetID, pDCB->TargetLUN)); @@ -942,8 +930,6 @@ static void dc390_BuildSRB (struct scsi_cmnd *pcmd, struct dc390_dcb* pDCB, stru { pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; - //pSRB->ScsiCmdLen = pcmd->cmd_len; - //memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); pSRB->SGIndex = 0; pSRB->AdaptStatus = 0; @@ -991,28 +977,6 @@ static int DC390_queue_command(struct scsi_cmnd *cmd, struct dc390_srb* pSRB; struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; - DEBUG0(/* if(pACB->scan_devices) */ \ - printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li), buffer=%p\n",\ - cmd->cmnd[0],cmd->device->id,cmd->device->lun,cmd->pid, cmd->buffer)); - - /* TODO: Change the policy: Always accept TEST_UNIT_READY or INQUIRY - * commands and alloc a DCB for the device if not yet there. DCB will - * be removed in dc390_SRBdone if SEL_TIMEOUT */ - if (!(pACB->scan_devices) && !(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun))) { - printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", - cmd->device->id, cmd->device->lun); - goto fail; - } - - /* Should it be: BUG_ON(!pDCB); ? */ - - if (!pDCB) - { /* should never happen */ - printk (KERN_ERR "DC390: no DCB found, target %02x lun %02x\n", - cmd->device->id, cmd->device->lun); - goto fail; - } - pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; @@ -1033,146 +997,8 @@ static int DC390_queue_command(struct scsi_cmnd *cmd, requeue: return 1; - fail: - cmd->result = DID_BAD_TARGET << 16; - done(cmd); - return 0; -} - -/* We ignore mapping problems, as we expect everybody to respect - * valid partition tables. Waiting for complaints ;-) */ - -#ifdef CONFIG_SCSI_DC390T_TRADMAP -/* - * The next function, partsize(), is copied from scsicam.c. - * - * This is ugly code duplication, but I didn't find another way to solve it: - * We want to respect the partition table and if it fails, we apply the - * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do - * the job, because we don't know, whether the values returned are from - * the part. table or determined by setsize(). Unfortunately the setsize() - * values differ from the ones chosen by the DC390 BIOS. - * - * Looking forward to seeing suggestions for a better solution! KG, 98/10/14 - */ -#include - -/* - * Function : static int partsize(unsigned char *buf, unsigned long - * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); - * - * Purpose : to determine the BIOS mapping used to create the partition - * table, storing the results in *cyls, *hds, and *secs - * - * Returns : -1 on failure, 0 on success. - * - */ - -static int partsize(unsigned char *buf, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, unsigned int *secs) { - struct partition *p, *largest = NULL; - int i, largest_cyl; - int cyl, ext_cyl, end_head, end_cyl, end_sector; - unsigned int logical_end, physical_end, ext_physical_end; - - - if (*(unsigned short *) (buf+64) == 0xAA55) { - for (largest_cyl = -1, p = (struct partition *) buf, - i = 0; i < 4; ++i, ++p) { - if (!p->sys_ind) - continue; - cyl = p->cyl + ((p->sector & 0xc0) << 2); - if (cyl > largest_cyl) { - largest_cyl = cyl; - largest = p; - } - } - } - - if (largest) { - end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); - end_head = largest->end_head; - end_sector = largest->end_sector & 0x3f; - - physical_end = end_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; - - /* This is the actual _sector_ number at the end */ - logical_end = get_unaligned(&largest->start_sect) - + get_unaligned(&largest->nr_sects); - - /* This is for >1023 cylinders */ - ext_cyl= (logical_end-(end_head * end_sector + end_sector)) - /(end_head + 1) / end_sector; - ext_physical_end = ext_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; - - if ((logical_end == physical_end) || - (end_cyl==1023 && ext_physical_end==logical_end)) { - *secs = end_sector; - *hds = end_head + 1; - *cyls = capacity / ((end_head + 1) * end_sector); - return 0; - } - } - return -1; } -/*********************************************************************** - * Function: - * DC390_bios_param - * - * Description: - * Return the disk geometry for the given SCSI device. - * Respect the partition table, otherwise try own heuristic - * - * Note: - * In contrary to other externally callable funcs (DC390_), we don't lock - ***********************************************************************/ -static int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - int heads, sectors, cylinders; - struct dc390_acb* pACB = (struct dc390_acb*) sdev->host->hostdata; - int ret_code = -1; - int size = capacity; - unsigned char *buf; - - if ((buf = scsi_bios_ptable(bdev))) - { - /* try to infer mapping from partition table */ - ret_code = partsize (buf, (unsigned long) size, (unsigned int *) geom + 2, - (unsigned int *) geom + 0, (unsigned int *) geom + 1); - kfree (buf); - } - if (ret_code == -1) - { - heads = 64; - sectors = 32; - cylinders = size / (heads * sectors); - - if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) - { - heads = 255; - sectors = 63; - cylinders = size / (heads * sectors); - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - } - - return (0); -} -#else -static int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - return scsicam_bios_param (bdev, capacity, geom); -} -#endif - static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB) { struct pci_dev *pdev; @@ -1219,146 +1045,54 @@ static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, stru } -/*********************************************************************** - * Function : int DC390_abort (struct scsi_cmnd *cmd) - * - * Purpose : Abort an errant SCSI command - * - * Inputs : cmd - command to abort - * - * Returns : 0 on success, -1 on failure. - * - * Status: Buggy ! - ***********************************************************************/ - -static int DC390_abort (struct scsi_cmnd *cmd) +static int DC390_abort(struct scsi_cmnd *cmd) { - struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; - struct dc390_srb *pSRB, *psrb; - u32 count, i; - int status; - //unsigned long sbac; - struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; - - printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n", - cmd->pid, cmd->device->id, cmd->device->lun); - - if( !pDCB ) goto NOT_RUN; - - /* Added 98/07/02 KG */ - /* - pSRB = pDCB->pActiveSRB; - if (pSRB && pSRB->pcmd == cmd ) - goto ON_GOING; - */ - - pSRB = pDCB->pWaitingSRB; - if( !pSRB ) - goto ON_GOING; + struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; + struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; + struct dc390_srb *pSRB, *psrb; - /* Now scan Waiting queue */ - if( pSRB->pcmd == cmd ) - { - pDCB->pWaitingSRB = pSRB->pNextSRB; - goto IN_WAIT; - } - else - { - psrb = pSRB; - if( !(psrb->pNextSRB) ) - goto ON_GOING; - while( psrb->pNextSRB->pcmd != cmd ) - { - psrb = psrb->pNextSRB; - if( !(psrb->pNextSRB) || psrb == pSRB) - goto ON_GOING; - } - pSRB = psrb->pNextSRB; - psrb->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pWaitLast ) - pDCB->pWaitLast = psrb; -IN_WAIT: - dc390_Free_insert (pACB, pSRB); + printk("DC390: Abort command (pid %li, Device %02i-%02i)\n", + cmd->pid, cmd->device->id, cmd->device->lun); + + pSRB = pDCB->pWaitingSRB; + if (!pSRB) + goto on_going; + + /* Now scan Waiting queue */ + if (pSRB->pcmd != cmd) { + psrb = pSRB; + if (!(psrb->pNextSRB)) + goto on_going; + + while (psrb->pNextSRB->pcmd != cmd) { + psrb = psrb->pNextSRB; + if (!(psrb->pNextSRB) || psrb == pSRB) + goto on_going; + } + + pSRB = psrb->pNextSRB; + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pWaitLast) + pDCB->pWaitLast = psrb; + } else + pDCB->pWaitingSRB = pSRB->pNextSRB; + + dc390_Free_insert(pACB, pSRB); pDCB->WaitSRBCnt--; INIT_LIST_HEAD((struct list_head*)&cmd->SCp); - status = SCSI_ABORT_SUCCESS; - goto ABO_X; - } - /* SRB has already been sent ! */ -ON_GOING: - /* abort() is too stupid for already sent commands at the moment. - * If it's called we are in trouble anyway, so let's dump some info - * into the syslog at least. (KG, 98/08/20,99/06/20) */ - dc390_dumpinfo (pACB, pDCB, pSRB); - pSRB = pDCB->pGoingSRB; - pDCB->DCBFlag |= ABORT_DEV_; - /* Now for the hard part: The command is currently processed */ - for( count = pDCB->GoingSRBCnt, i=0; ipcmd != cmd ) - pSRB = pSRB->pNextSRB; - else - { - if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) ) - { - status = SCSI_ABORT_BUSY; - printk ("DC390: Abort current command (pid %li, SRB %p)\n", - cmd->pid, pSRB); - goto ABO_X; - } - else - { - status = SCSI_ABORT_SNOOZE; - goto ABO_X; - } - } - } + return SUCCESS; -NOT_RUN: - status = SCSI_ABORT_NOT_RUNNING; +on_going: + /* abort() is too stupid for already sent commands at the moment. + * If it's called we are in trouble anyway, so let's dump some info + * into the syslog at least. (KG, 98/08/20,99/06/20) */ + dc390_dumpinfo(pACB, pDCB, pSRB); -ABO_X: - cmd->result = DID_ABORT << 16; - printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); -#if 0 - if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */ - { - /* Let's do something to help the bus getting clean again */ - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, DMA_COMMAND); - //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - //DC390_write8 (ScsiCmd, RESET_ATN_CMD); - DC390_write8 (ScsiCmd, NOP_CMD); - //udelay (10000); - //DC390_read8 (INT_Status); - //DC390_write8 (ScsiCmd, EN_SEL_RESEL); - } - sbac = DC390_read32 (DMA_ScsiBusCtrl); - if (sbac & SCSI_BUSY) - { /* clear BSY, SEL and ATN */ - printk (KERN_WARNING "DC390: Reset SCSI device: "); - //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES); - //udelay (250); - //sbac = DC390_read32 (DMA_ScsiBusCtrl); - //printk ("%08lx ", sbac); - //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM)); - //udelay (100); - //sbac = DC390_read32 (DMA_ScsiBusCtrl); - //printk ("%08lx ", sbac); - DC390_write8 (ScsiCmd, RST_DEVICE_CMD); - udelay (250); - DC390_write8 (ScsiCmd, NOP_CMD); - sbac = DC390_read32 (DMA_ScsiBusCtrl); - printk ("%08lx\n", sbac); - } -#endif - dc390_lastabortedpid = cmd->pid; - //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); -#ifndef USE_NEW_EH - if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd); -#endif - return( status ); + pDCB->DCBFlag |= ABORT_DEV_; + printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid); + + return FAILED; } @@ -1385,93 +1119,38 @@ static void dc390_ResetDevParam( struct dc390_acb* pACB ) } -#if 0 -/* Moves all SRBs from Going to Waiting for all DCBs */ -static void dc390_RecoverSRB( struct dc390_acb* pACB ) +static int DC390_bus_reset (struct scsi_cmnd *cmd) { - struct dc390_dcb *pDCB, *pdcb; - struct dc390_srb *psrb, *psrb2; - u32 cnt, i; + struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; + u8 bval; - pDCB = pACB->pLinkDCB; - if( !pDCB ) return; - pdcb = pDCB; - do - { - cnt = pdcb->GoingSRBCnt; - psrb = pdcb->pGoingSRB; - for (i=0; ipNextSRB; -/* dc390_RewaitSRB( pDCB, psrb ); */ - if( pdcb->pWaitingSRB ) - { - psrb2->pNextSRB = pdcb->pWaitingSRB; - pdcb->pWaitingSRB = psrb2; - } - else - { - pdcb->pWaitingSRB = psrb2; - pdcb->pWaitLast = psrb2; - psrb2->pNextSRB = NULL; - } - } - pdcb->GoingSRBCnt = 0; - pdcb->pGoingSRB = NULL; - pdcb->TagMask = 0; - pdcb = pdcb->pNextDCB; - } while( pdcb != pDCB ); -} -#endif - -/*********************************************************************** - * Function : int DC390_reset (struct scsi_cmnd *cmd, ...) - * - * Purpose : perform a hard reset on the SCSI bus - * - * Inputs : cmd - command which caused the SCSI RESET - * resetFlags - how hard to try - * - * Returns : 0 on success. - ***********************************************************************/ - -static int DC390_reset (struct scsi_cmnd *cmd) -{ - u8 bval; - struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; + del_timer (&pACB->Waiting_Timer); - printk(KERN_INFO "DC390: RESET ... "); - - if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); - bval = DC390_read8 (CtrlReg1); - bval |= DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* disable IRQ on bus reset */ + bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST; + DC390_write8(CtrlReg1, bval); /* disable IRQ on bus reset */ - pACB->ACBFlag |= RESET_DEV; - dc390_ResetSCSIBus( pACB ); + pACB->ACBFlag |= RESET_DEV; + dc390_ResetSCSIBus(pACB); - dc390_ResetDevParam( pACB ); - udelay (1000); - pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + dc390_ResetDevParam(pACB); + udelay(1000); + pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - DC390_read8 (INT_Status); /* Reset Pending INT */ + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + DC390_read8(INT_Status); /* Reset Pending INT */ - dc390_DoingSRB_Done( pACB, cmd ); - /* dc390_RecoverSRB (pACB); */ - pACB->pActiveDCB = NULL; + dc390_DoingSRB_Done(pACB, cmd); - pACB->ACBFlag = 0; - bval = DC390_read8 (CtrlReg1); - bval &= ~DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; + + bval = DC390_read8(CtrlReg1) & ~DIS_INT_ON_SCSI_RST; + DC390_write8(CtrlReg1, bval); /* re-enable interrupt */ - dc390_Waiting_process( pACB ); + dc390_Waiting_process(pACB); - printk("done\n"); - return( SCSI_RESET_SUCCESS ); + return SUCCESS; } #include "scsiiom.c" @@ -1548,7 +1227,6 @@ static void dc390_linkSRB( struct dc390_acb* pACB ) static void __devinit dc390_initACB (struct Scsi_Host *psh, unsigned long io_port, u8 Irq, u8 index) { struct dc390_acb* pACB; - u8 i; psh->can_queue = MAX_CMD_QUEUE; psh->cmd_per_lun = MAX_CMD_PER_LUN; @@ -1595,8 +1273,6 @@ static void __devinit dc390_initACB (struct Scsi_Host *psh, unsigned long io_por dc390_linkSRB( pACB ); pACB->pTmpSRB = &pACB->TmpSRB; dc390_initSRB( pACB->pTmpSRB ); - for(i=0; iDCBmap[i] = 0; pACB->sel_timeout = SEL_TIMEOUT; pACB->glitch_cfg = EATER_25NS; pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = 0; @@ -1706,7 +1382,7 @@ static void __devinit dc390_set_pci_cfg (struct pci_dev *pdev) static int dc390_slave_alloc(struct scsi_device *scsi_device) { struct dc390_acb *pACB = (struct dc390_acb*) scsi_device->host->hostdata; - struct dc390_dcb *pDCB, *pDCB2 = 0; + struct dc390_dcb *pDCB, *pDCB2 = NULL; uint id = scsi_device->id; uint lun = scsi_device->lun; @@ -1757,7 +1433,6 @@ static int dc390_slave_alloc(struct scsi_device *scsi_device) pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } - pACB->DCBmap[id] |= (1 << lun); dc390_updateDCB(pACB, pDCB); pACB->scan_devices = 1; @@ -1781,8 +1456,6 @@ static void dc390_slave_destroy(struct scsi_device *scsi_device) BUG_ON(pDCB->GoingSRBCnt > 1); - pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN); - if (pDCB == pACB->pLinkDCB) { if (pACB->pLastDCB == pDCB) { pDCB->pNextDCB = NULL; @@ -1818,15 +1491,13 @@ static int dc390_slave_configure(struct scsi_device *scsi_device) static struct scsi_host_template driver_template = { .module = THIS_MODULE, .proc_name = "tmscsim", - .proc_info = DC390_proc_info, .name = DC390_BANNER " V" DC390_VERSION, .slave_alloc = dc390_slave_alloc, .slave_configure = dc390_slave_configure, .slave_destroy = dc390_slave_destroy, .queuecommand = DC390_queue_command, .eh_abort_handler = DC390_abort, - .eh_bus_reset_handler = DC390_reset, - .bios_param = DC390_bios_param, + .eh_bus_reset_handler = DC390_bus_reset, .can_queue = 42, .this_id = 7, .sg_tablesize = SG_ALL, @@ -1939,152 +1610,6 @@ static void __devexit dc390_remove_one(struct pci_dev *dev) pci_set_drvdata(dev, NULL); } -/******************************************************************** - * Function: DC390_proc_info(char* buffer, char **start, - * off_t offset, int length, int hostno, int inout) - * - * Purpose: return SCSI Adapter/Device Info - * - * Input: buffer: Pointer to a buffer where to write info - * start : - * offset: - * hostno: Host adapter index - * inout : Read (=0) or set(!=0) info - * - * Output: buffer: contains info - * length; length of info in buffer - * - * return value: length - * - ********************************************************************/ - -#undef SPRINTF -#define SPRINTF(args...) pos += sprintf(pos, ## args) - -#define YESNO(YN) \ - if (YN) SPRINTF(" Yes "); \ - else SPRINTF(" No ") - - -static int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start, - off_t offset, int length, int inout) -{ - int dev, spd, spd1; - char *pos = buffer; - struct dc390_acb* pACB; - struct dc390_dcb* pDCB; - - pACB = dc390_pACB_start; - - while(pACB != (struct dc390_acb*)-1) - { - if (shpnt == pACB->pScsiHost) - break; - pACB = pACB->pNextACB; - } - - if (pACB == (struct dc390_acb*)-1) return(-ESRCH); - - if(inout) /* Has data been written to the file ? */ - return -ENOSYS; - - SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, "); - SPRINTF("Driver Version %s\n", DC390_VERSION); - - SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); - SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); - SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); - SPRINTF("IRQ %02i\n", pACB->IRQLevel); - - SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); - SPRINTF("AdapterID %i, SelTimeout %i ms, DelayReset %i s\n", - shpnt->this_id, (pACB->sel_timeout*164)/100, - dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); - - SPRINTF("TagMaxNum %i, Status 0x%02x, ACBFlag 0x%02x, GlitchEater %i ns\n", - pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12); - - SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %i, Out of SRB conds %i\n", - pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); - SPRINTF(" Lost arbitrations %i, Sel. connected %i, Connected: %s\n", - pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No"); - - SPRINTF("Nr of DCBs: %i\n", pACB->DCBCnt); - SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", - pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], - pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]); - - SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd\n"); - - pDCB = pACB->pLinkDCB; - for (dev = 0; dev < pACB->DCBCnt; dev++) - { - SPRINTF("%02i %02i %02i ", dev, pDCB->TargetID, pDCB->TargetLUN); - YESNO(pDCB->DevMode & PARITY_CHK_); - YESNO(pDCB->SyncMode & SYNC_NEGO_DONE); - YESNO(pDCB->DevMode & EN_DISCONNECT_); - YESNO(pDCB->DevMode & SEND_START_); - YESNO(pDCB->SyncMode & EN_TAG_QUEUEING); - if (pDCB->SyncOffset & 0x0f) - { - int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++; - SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2); - spd = 40/(sp); spd1 = 40%(sp); - spd1 = (spd1 * 10 + sp/2) / (sp); - SPRINTF(" %2i.%1i M %02i", spd, spd1, (pDCB->SyncOffset & 0x0f)); - } - else SPRINTF(" (%03i ns) ", (pDCB->NegoPeriod) << 2); - /* Add more info ...*/ - SPRINTF (" %02i\n", pDCB->MaxCommand); - pDCB = pDCB->pNextDCB; - } - if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n"); - else SPRINTF ("\n"); - pDCB = pACB->pLinkDCB; - - for (dev = 0; dev < pACB->DCBCnt; dev++) - { - struct dc390_srb* pSRB; - if (pDCB->WaitSRBCnt) - SPRINTF ("DCB (%02i-%i): Waiting: %i:", pDCB->TargetID, pDCB->TargetLUN, - pDCB->WaitSRBCnt); - for (pSRB = pDCB->pWaitingSRB; pSRB; pSRB = pSRB->pNextSRB) - SPRINTF(" %li", pSRB->pcmd->pid); - if (pDCB->GoingSRBCnt) - SPRINTF ("\nDCB (%02i-%i): Going : %i:", pDCB->TargetID, pDCB->TargetLUN, - pDCB->GoingSRBCnt); - for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB) -#if 0 //def DC390_DEBUGTRACE - SPRINTF(" %s\n ", pSRB->debugtrace); -#else - SPRINTF(" %li", pSRB->pcmd->pid); -#endif - if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt) SPRINTF ("\n"); - pDCB = pDCB->pNextDCB; - } - -#ifdef DC390_DEBUGDCB - SPRINTF ("DCB list for ACB %p:\n", pACB); - pDCB = pACB->pLinkDCB; - SPRINTF ("%p", pDCB); - for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB) - SPRINTF ("->%p", pDCB->pNextDCB); - SPRINTF("\n"); -#endif - - *start = buffer + offset; - - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - else - return length; -} - -#undef YESNO -#undef SPRINTF - static struct pci_driver dc390_driver = { .name = "tmscsim", .id_table = tmscsim_pci_tbl, diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h index 62e9f8791..5cc90e951 100644 --- a/drivers/scsi/tmscsim.h +++ b/drivers/scsi/tmscsim.h @@ -163,7 +163,6 @@ struct dc390_srb *pFreeSRB; struct dc390_srb *pTmpSRB; u8 msgin123[4]; -u8 DCBmap[MAX_SCSI_ID]; u8 Connected; u8 pad; diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 193e40c18..553a5f1e2 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -190,7 +190,6 @@ #include -#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/68328serial.c b/drivers/serial/68328serial.c index 5c499be24..6dd522466 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -435,10 +435,7 @@ static void do_softint(void *private) return; #if 0 if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } #endif } @@ -858,10 +855,7 @@ static void rs_flush_buffer(struct tty_struct *tty) cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1185,11 +1179,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; +#warning "This is not and has never been valid so fix it" +#if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); @@ -1198,6 +1194,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (tty->ldisc.open) (tty->ldisc.open)(tty); } +#endif if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 64e296ad3..cd2d62cd1 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -700,12 +700,8 @@ static void do_softint(void *private_) if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); } @@ -1152,10 +1148,7 @@ static void rs_360_flush_buffer(struct tty_struct *tty) /* There is nothing to "flush", whatever we gave the CPM * is on its way out. */ - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); info->flags &= ~TX_WAKEUP; } @@ -1716,8 +1709,7 @@ static void rs_360_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -2592,7 +2584,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/8250.c b/drivers/serial/8250.c index 4906b5751..2ade801d0 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -130,6 +130,7 @@ struct uart_8250_port { struct timer_list timer; /* "no irq" timer */ struct list_head list; /* ports on this IRQ */ unsigned int capabilities; /* port capabilities */ + unsigned int tx_loadsz; /* transmit fifo load size */ unsigned short rev; unsigned char acr; unsigned char ier; @@ -156,23 +157,23 @@ static struct irq_info irq_lists[NR_IRQS]; /* * Here we define the default xmit fifo size used for each type of UART. */ -static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { - { "unknown", 1, 0 }, - { "8250", 1, 0 }, - { "16450", 1, 0 }, - { "16550", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "Cirrus", 1, 0 }, - { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, - { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "Startech", 1, 0 }, - { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }, - { "XScale", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, +static const struct serial8250_config uart_config[PORT_MAX_8250+1] = { + { "unknown", 1, 1, 0 }, + { "8250", 1, 1, 0 }, + { "16450", 1, 1, 0 }, + { "16550", 1, 1, 0 }, + { "16550A", 16, 16, UART_CAP_FIFO }, + { "Cirrus", 1, 1, 0 }, + { "ST16650", 1, 1, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "ST16650V2", 32, 16, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "TI16750", 64, 64, UART_CAP_FIFO | UART_CAP_SLEEP }, + { "Startech", 1, 1, 0 }, + { "16C950/954", 128, 128, UART_CAP_FIFO }, + { "ST16654", 64, 32, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "XR16850", 128, 128, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, + { "RSA", 2048, 2048, UART_CAP_FIFO }, + { "NS16550A", 16, 16, UART_CAP_FIFO | UART_NATSEMI }, + { "XScale", 32, 32, UART_CAP_FIFO }, }; static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) @@ -187,6 +188,9 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) case UPIO_MEM: return readb(up->port.membase + offset); + case UPIO_MEM32: + return readl(up->port.membase + offset); + default: return inb(up->port.iobase + offset); } @@ -207,6 +211,10 @@ serial_out(struct uart_8250_port *up, int offset, int value) writeb(value, up->port.membase + offset); break; + case UPIO_MEM32: + writel(value, up->port.membase + offset); + break; + default: outb(value, up->port.iobase + offset); } @@ -243,6 +251,41 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) return value; } +/* + * FIFO support. + */ +static inline void serial8250_clear_fifos(struct uart_8250_port *p) +{ + if (p->capabilities & UART_CAP_FIFO) { + serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(p, UART_FCR, 0); + } +} + +/* + * IER sleep support. UARTs which have EFRs need the "extended + * capability" bit enabled. Note that on XR16C850s, we need to + * reset LCR to write to IER. + */ +static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +{ + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { + serial_outp(p, UART_LCR, 0xBF); + serial_outp(p, UART_EFR, UART_EFR_ECB); + serial_outp(p, UART_LCR, 0); + } + serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_outp(p, UART_LCR, 0xBF); + serial_outp(p, UART_EFR, 0); + serial_outp(p, UART_LCR, 0); + } + } +} + #ifdef CONFIG_SERIAL_8250_RSA /* * Attempts to turn on the RSA FIFO. Returns zero on failure. @@ -697,8 +740,9 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) #endif serial_outp(up, UART_LCR, save_lcr); - up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; + up->port.fifosize = uart_config[up->port.type].fifo_size; up->capabilities = uart_config[up->port.type].flags; + up->tx_loadsz = uart_config[up->port.type].tx_loadsz; if (up->port.type == PORT_UNKNOWN) goto out; @@ -711,10 +755,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) serial_outp(up, UART_RSA_FRR, 0); #endif serial_outp(up, UART_MCR, save_mcr); - serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(up, UART_FCR, 0); + serial8250_clear_fifos(up); (void)serial_in(up, UART_RX); serial_outp(up, UART_IER, 0); @@ -923,7 +964,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up) return; } - count = up->port.fifosize; + count = up->tx_loadsz; do { serial_out(up, UART_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -1227,12 +1268,7 @@ static int serial8250_startup(struct uart_port *port) * Clear the FIFO buffers and disable them. * (they will be reeanbled in set_termios()) */ - if (up->capabilities & UART_CLEAR_FIFO) { - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); - } + serial8250_clear_fifos(up); /* * Clear the interrupt registers. @@ -1253,6 +1289,23 @@ static int serial8250_startup(struct uart_port *port) return -ENODEV; } + /* + * For a XR16C850, we need to set the trigger levels + */ + if (up->port.type == PORT_16850) { + unsigned char fctr; + + serial_outp(up, UART_LCR, 0xbf); + + fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_outp(up, UART_TRG, UART_TRG_96); + serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_outp(up, UART_TRG, UART_TRG_96); + + serial_outp(up, UART_LCR, 0); + } + /* * If the "interrupt" for this port doesn't correspond with any * hardware interrupt, we use a timer-based system. The original @@ -1345,10 +1398,7 @@ static void serial8250_shutdown(struct uart_port *port) * Disable break condition and FIFOs */ serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); + serial8250_clear_fifos(up); #ifdef CONFIG_SERIAL_8250_RSA /* @@ -1440,7 +1490,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, up->rev == 0x5201) quot ++; - if (up->capabilities & UART_USE_FIFO) { + if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { if (baud < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; #ifdef CONFIG_SERIAL_8250_RSA @@ -1514,7 +1564,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, serial_out(up, UART_IER, up->ier); - if (up->capabilities & UART_STARTECH) { + if (up->capabilities & UART_CAP_EFR) { serial_outp(up, UART_LCR, 0xBF); serial_outp(up, UART_EFR, termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0); @@ -1554,71 +1604,12 @@ static void serial8250_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_8250_port *up = (struct uart_8250_port *)port; - if (state) { - /* sleep */ - if (up->capabilities & UART_STARTECH) { - /* Arrange to enter sleep mode */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_IER, UART_IERX_SLEEP); - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, 0); - serial_outp(up, UART_LCR, 0); - } - if (up->port.type == PORT_16750) { - /* Arrange to enter sleep mode */ - serial_outp(up, UART_IER, UART_IERX_SLEEP); - } + struct uart_8250_port *p = (struct uart_8250_port *)port; - if (up->pm) - up->pm(port, state, oldstate); - } else { - /* wake */ - if (up->capabilities & UART_STARTECH) { - /* Wake up UART */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - /* - * Turn off LCR == 0xBF so we actually set the IER - * register on the XR16C850 - */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_IER, 0); - /* - * Now reset LCR so we can turn off the ECB bit - */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, 0); - /* - * For a XR16C850, we need to set the trigger levels - */ - if (up->port.type == PORT_16850) { - unsigned char fctr; - - fctr = serial_inp(up, UART_FCTR) & - ~(UART_FCTR_RX | UART_FCTR_TX); - serial_outp(up, UART_FCTR, fctr | - UART_FCTR_TRGD | - UART_FCTR_RX); - serial_outp(up, UART_TRG, UART_TRG_96); - serial_outp(up, UART_FCTR, fctr | - UART_FCTR_TRGD | - UART_FCTR_TX); - serial_outp(up, UART_TRG, UART_TRG_96); - } - serial_outp(up, UART_LCR, 0); - } + serial8250_set_sleep(p, state != 0); - if (up->port.type == PORT_16750) { - /* Wake up UART */ - serial_outp(up, UART_IER, 0); - } - - if (up->pm) - up->pm(port, state, oldstate); - } + if (p->pm) + p->pm(port, state, oldstate); } /* diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index da0ad9b3d..79c036852 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -33,6 +33,20 @@ struct old_serial_port { unsigned short iomem_reg_shift; }; +/* + * This replaces serial_uart_config in include/linux/serial.h + */ +struct serial8250_config { + const char *name; + unsigned int fifo_size; + unsigned int tx_loadsz; + unsigned int flags; +}; + +#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */ +#define UART_CAP_EFR (1 << 9) /* UART has EFR */ +#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */ + #undef SERIAL_DEBUG_PCI #if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 34b367778..55c8aa908 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -83,7 +83,7 @@ struct pci_serial_quirk { struct serial_private { unsigned int nr; - void *remapped_bar[PCI_NUM_BAR_RESOURCES]; + void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES]; struct pci_serial_quirk *quirk; int line[0]; }; @@ -243,7 +243,8 @@ static int __devinit pci_inteli960ni_init(struct pci_dev *dev) */ static int __devinit pci_plx9050_init(struct pci_dev *dev) { - u8 *p, irq_config; + u8 irq_config; + void __iomem *p; if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) { moan_device("no memory in bar 0", dev); @@ -272,12 +273,12 @@ static int __devinit pci_plx9050_init(struct pci_dev *dev) p = ioremap(pci_resource_start(dev, 0), 0x80); if (p == NULL) return -ENOMEM; - writel(irq_config, (unsigned long)p + 0x4c); + writel(irq_config, p + 0x4c); /* * Read the register back to ensure that it took effect. */ - readl((unsigned long)p + 0x4c); + readl(p + 0x4c); iounmap(p); return 0; @@ -397,7 +398,8 @@ static void __devexit sbs_exit(struct pci_dev *dev) static int pci_siig10x_init(struct pci_dev *dev) { - u16 data, *p; + u16 data; + void __iomem *p; switch (dev->device & 0xfff8) { case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ @@ -415,8 +417,8 @@ static int pci_siig10x_init(struct pci_dev *dev) if (p == NULL) return -ENOMEM; - writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28); - readw((unsigned long)p + 0x28); + writew(readw(p + 0x28) & data, p + 0x28); + readw(p + 0x28); iounmap(p); return 0; } @@ -1068,6 +1070,9 @@ enum pci_board_num_t { pbn_computone_6, pbn_computone_8, pbn_sbsxrsio, + pbn_exar_XR17C152, + pbn_exar_XR17C154, + pbn_exar_XR17C158, }; /* @@ -1488,7 +1493,30 @@ static struct pci_board pci_boards[] __devinitdata = { .base_baud = 460800, .uart_offset = 256, .reg_shift = 4, - } + }, + /* + * Exar Corp. XR17C15[248] Dual/Quad/Octal UART + * Only basic 16550A support. + * XR17C15[24] are not tested, but they should work. + */ + [pbn_exar_XR17C152] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_XR17C154] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_XR17C158] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x200, + }, }; /* @@ -2147,6 +2175,22 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b3_8_115200 }, + /* + * Exar Corp. XR17C15[248] Dual/Quad/Octal UART + */ + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C152 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C154 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C158 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 74a0b9cad..6f8984a54 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -450,7 +450,7 @@ config SERIAL_MUX_CONSOLE config PDC_CONSOLE bool "PDC software console support" - depends on PARISC && !SERIAL_MUX + depends on PARISC && !SERIAL_MUX && VT default n help Saying Y here will enable the software based PDC console to be @@ -682,6 +682,7 @@ config SERIAL_SGI_L1_CONSOLE bool "SGI Altix L1 serial console support" depends on IA64_GENERIC || IA64_SGI_SN2 select SERIAL_CORE + select SERIAL_CORE_CONSOLE help If you have an SGI Altix and you would like to use the system controller serial port as your console (you want this!), @@ -714,4 +715,16 @@ config SERIAL_MPC52xx_CONSOLE_BAUD This value is only used if the bootloader doesn't pass in the console baudrate +config SERIAL_ICOM + tristate "IBM Multiport Serial Adapter" + depends on PPC_ISERIES || PPC_PSERIES + select SERIAL_CORE + help + This driver is for a family of multiport serial adapters + including 2 port RVX, 2 port internal modem, 4 port internal + modem and a split 1 port RVX and 1 port internal modem. + + This driver can also be built as a module. If so, the module + will be called icom. + endmenu diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index c91f6b149..69bd7f5ce 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -696,7 +696,6 @@ static int __init pl011_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; - int ret; /* * Check whether an invalid uart number has been specified, and diff --git a/drivers/serial/bast_sio.c b/drivers/serial/bast_sio.c index 698514d16..2b48fab6f 100644 --- a/drivers/serial/bast_sio.c +++ b/drivers/serial/bast_sio.c @@ -1,3 +1,19 @@ +/* linux/drivers/serial/bast_sio.c + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * 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. + * + * Modifications: + * 23-Sep-2004 BJD Added copyright header + * 23-Sep-2004 BJD Added serial port remove code +*/ + #include #include #include @@ -20,10 +36,6 @@ static int __init serial_bast_register(unsigned long port, unsigned int irq) { struct serial_struct serial_req; -#if 0 - printk("BAST: SuperIO serial (%08lx,%d)\n", port, irq); -#endif - serial_req.flags = UPF_AUTOPROBE | UPF_SHARE_IRQ; serial_req.baud_base = BASE_BAUD; serial_req.irq = irq; @@ -37,11 +49,13 @@ static int __init serial_bast_register(unsigned long port, unsigned int irq) #define SERIAL_BASE (S3C2410_CS2 + BAST_PA_SUPERIO) +static int port[2] = { -1, -1 }; + static int __init serial_bast_init(void) { if (machine_is_bast()) { - serial_bast_register(SERIAL_BASE + 0x2f8, IRQ_PCSERIAL1); - serial_bast_register(SERIAL_BASE + 0x3f8, IRQ_PCSERIAL2); + port[0] = serial_bast_register(SERIAL_BASE + 0x2f8, IRQ_PCSERIAL1); + port[1] = serial_bast_register(SERIAL_BASE + 0x3f8, IRQ_PCSERIAL2); } return 0; @@ -49,7 +63,10 @@ static int __init serial_bast_init(void) static void __exit serial_bast_exit(void) { - /* todo -> remove both our ports */ + if (port[0] != -1) + unregister_serial(port[0]); + if (port[1] != -1) + unregister_serial(port[1]); } diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c new file mode 100644 index 000000000..c15c8a0aa --- /dev/null +++ b/drivers/serial/icom.c @@ -0,0 +1,1702 @@ +/* + * icom.c + * + * Copyright (C) 2001 IBM Corporation. All rights reserved. + * + * Serial device driver. + * + * Based on code from serial.c + * + * 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 + * + */ +#define SERIAL_DO_RESTART +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "icom.h" + +/*#define ICOM_TRACE enable port trace capabilities */ + +#define ICOM_DRIVER_NAME "icom" +#define ICOM_VERSION_STR "1.3.1" +#define NR_PORTS 128 +#define ICOM_PORT ((struct icom_port *)port) +#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj) + +static const struct pci_device_id icom_pci_table[] = { + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = ADAPTER_V1, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, + .driver_data = ADAPTER_V2, + }, + {} +}; + +struct lookup_proc_table start_proc[4] = { + {0, ICOM_CONTROL_START_A}, + {0, ICOM_CONTROL_START_B}, + {0, ICOM_CONTROL_START_C}, + {0, ICOM_CONTROL_START_D} +}; + + +struct lookup_proc_table stop_proc[4] = { + {0, ICOM_CONTROL_STOP_A}, + {0, ICOM_CONTROL_STOP_B}, + {0, ICOM_CONTROL_STOP_C}, + {0, ICOM_CONTROL_STOP_D} +}; + +struct lookup_int_table int_mask_tbl[4] = { + {0, ICOM_INT_MASK_PRC_A}, + {0, ICOM_INT_MASK_PRC_B}, + {0, ICOM_INT_MASK_PRC_C}, + {0, ICOM_INT_MASK_PRC_D}, +}; + + +MODULE_DEVICE_TABLE(pci, icom_pci_table); + +static LIST_HEAD(icom_adapter_head); + +/* spinlock for adapter initialization and changing adapter operations */ +static spinlock_t icom_lock; + +#ifdef ICOM_TRACE +static inline void trace(struct icom_port *, char *, unsigned long) {}; +#else +static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; +#endif + +static void msleep(unsigned long msecs) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(MSECS_TO_JIFFIES(msecs)); +} + +static void free_port_memory(struct icom_port *icom_port) +{ + struct pci_dev *dev = icom_port->adapter->pci_dev; + + trace(icom_port, "RET_PORT_MEM", 0); + if (icom_port->recv_buf) { + pci_free_consistent(dev, 4096, icom_port->recv_buf, + icom_port->recv_buf_pci); + icom_port->recv_buf = 0; + } + if (icom_port->xmit_buf) { + pci_free_consistent(dev, 4096, icom_port->xmit_buf, + icom_port->xmit_buf_pci); + icom_port->xmit_buf = 0; + } + if (icom_port->statStg) { + pci_free_consistent(dev, 4096, icom_port->statStg, + icom_port->statStg_pci); + icom_port->statStg = 0; + } + + if (icom_port->xmitRestart) { + pci_free_consistent(dev, 4096, icom_port->xmitRestart, + icom_port->xmitRestart_pci); + icom_port->xmitRestart = 0; + } +} + +static int __init get_port_memory(struct icom_port *icom_port) +{ + int index; + unsigned long stgAddr; + unsigned long startStgAddr; + unsigned long offset; + struct pci_dev *dev = icom_port->adapter->pci_dev; + + icom_port->xmit_buf = + pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci); + if (!icom_port->xmit_buf) { + dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); + return -ENOMEM; + } + + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->xmit_buf); + + icom_port->recv_buf = + pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci); + if (!icom_port->recv_buf) { + dev_err(&dev->dev, "Can not allocate Receive buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->recv_buf); + + icom_port->statStg = + pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci); + if (!icom_port->statStg) { + dev_err(&dev->dev, "Can not allocate Status buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->statStg); + + icom_port->xmitRestart = + pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci); + if (!icom_port->xmitRestart) { + dev_err(&dev->dev, + "Can not allocate xmit Restart buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + + memset(icom_port->statStg, 0, 4096); + + /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that + indicates that frames are to be transmitted + */ + + stgAddr = (unsigned long) icom_port->statStg; + for (index = 0; index < NUM_XBUFFS; index++) { + trace(icom_port, "FOD_ADDR", stgAddr); + stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]); + if (index < (NUM_XBUFFS - 1)) { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + icom_port->statStg->xmit[index].leLengthASD = + (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + trace(icom_port, "FOD_ADDR", stgAddr); + trace(icom_port, "FOD_XBUFF", + (unsigned long) icom_port->xmit_buf); + icom_port->statStg->xmit[index].leBuffer = + cpu_to_le32(icom_port->xmit_buf_pci); + } else if (index == (NUM_XBUFFS - 1)) { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + icom_port->statStg->xmit[index].leLengthASD = + (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + trace(icom_port, "FOD_XBUFF", + (unsigned long) icom_port->xmit_buf); + icom_port->statStg->xmit[index].leBuffer = + cpu_to_le32(icom_port->xmit_buf_pci); + } else { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + } + } + /* FIDs */ + startStgAddr = stgAddr; + + /* fill in every entry, even if no buffer */ + for (index = 0; index < NUM_RBUFFS; index++) { + trace(icom_port, "FID_ADDR", stgAddr); + stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]); + icom_port->statStg->rcv[index].leLength = 0; + icom_port->statStg->rcv[index].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + if (index < (NUM_RBUFFS - 1) ) { + offset = stgAddr - (unsigned long) icom_port->statStg; + icom_port->statStg->rcv[index].leNext = + cpu_to_le32(icom_port-> statStg_pci + offset); + trace(icom_port, "FID_RBUFF", + (unsigned long) icom_port->recv_buf); + icom_port->statStg->rcv[index].leBuffer = + cpu_to_le32(icom_port->recv_buf_pci); + } else if (index == (NUM_RBUFFS -1) ) { + offset = startStgAddr - (unsigned long) icom_port->statStg; + icom_port->statStg->rcv[index].leNext = + cpu_to_le32(icom_port-> statStg_pci + offset); + trace(icom_port, "FID_RBUFF", + (unsigned long) icom_port->recv_buf + 2048); + icom_port->statStg->rcv[index].leBuffer = + cpu_to_le32(icom_port->recv_buf_pci + 2048); + } else { + icom_port->statStg->rcv[index].leNext = 0; + icom_port->statStg->rcv[index].leBuffer = 0; + } + } + + return 0; +} + +static void stop_processor(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + + port = icom_port->port; + if (port == 0 || port == 1) + stop_proc[port].global_control_reg = &icom_port->global_reg->control; + else + stop_proc[port].global_control_reg = &icom_port->global_reg->control_2; + + + if (port < 4) { + temp = readl(stop_proc[port].global_control_reg); + temp = + (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; + writel(temp, stop_proc[port].global_control_reg); + + /* write flush */ + readl(stop_proc[port].global_control_reg); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); +} + +static void start_processor(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + + port = icom_port->port; + if (port == 0 || port == 1) + start_proc[port].global_control_reg = &icom_port->global_reg->control; + else + start_proc[port].global_control_reg = &icom_port->global_reg->control_2; + if (port < 4) { + temp = readl(start_proc[port].global_control_reg); + temp = + (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; + writel(temp, start_proc[port].global_control_reg); + + /* write flush */ + readl(start_proc[port].global_control_reg); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); +} + +static void load_code(struct icom_port *icom_port) +{ + const struct firmware *fw; + char *iram_ptr; + int index; + int status = 0; + char *dram_ptr = (char *) icom_port->dram; + dma_addr_t temp_pci; + unsigned char *new_page = NULL; + unsigned char cable_id = NO_CABLE; + struct pci_dev *dev = icom_port->adapter->pci_dev; + + /* Clear out any pending interrupts */ + writew(0x3FFF, (void *) icom_port->int_reg); + + trace(icom_port, "CLEAR_INTERRUPTS", 0); + + /* Stop processor */ + stop_processor(icom_port); + + /* Zero out DRAM */ + memset_io(dram_ptr, 0, 512); + + /* Load Call Setup into Adapter */ + if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_DCE_IRAM_OFFSET) { + dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + iram_ptr = (char *) icom_port->dram + ICOM_IRAM_OFFSET; + for (index = 0; index < fw->size; index++) + writeb(fw->data[index], &iram_ptr[index]); + + release_firmware(fw); + + /* Load Resident DCE portion of Adapter */ + if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_IRAM_SIZE) { + dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + iram_ptr = (char *) icom_port->dram + ICOM_IRAM_OFFSET; + for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++) + writeb(fw->data[index], &iram_ptr[index]); + + release_firmware(fw); + + /* Set Hardware level */ + if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) + writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); + + /* Start the processor in Adapter */ + start_processor(icom_port); + + writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL), + &(icom_port->dram->HDLCConfigReg)); + writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0x00, &(icom_port->dram->CmdReg)); + writeb(0x10, &(icom_port->dram->async_config3)); + writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC | + ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2)); + + /*Set up data in icom DRAM to indicate where personality + *code is located and its length. + */ + new_page = pci_alloc_consistent(dev, 4096, &temp_pci); + + if (!new_page) { + dev_err(&dev->dev, "Can not allocate DMA buffer\n"); + status = -1; + goto load_code_exit; + } + + if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_DCE_IRAM_OFFSET) { + dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + for (index = 0; index < fw->size; index++) + new_page[index] = fw->data[index]; + + release_firmware(fw); + + writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); + writel(temp_pci, &icom_port->dram->mac_load_addr); + + /*Setting the syncReg to 0x80 causes adapter to start downloading + the personality code into adapter instruction RAM. + Once code is loaded, it will begin executing and, based on + information provided above, will start DMAing data from + shared memory to adapter DRAM. + */ + /* the wait loop below verifies this write operation has been done + and processed + */ + writeb(START_DOWNLOAD, &icom_port->dram->sync); + + /* Wait max 1 Sec for data download and processor to start */ + for (index = 0; index < 10; index++) { + msleep(100); + if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE) + break; + } + + if (index == 10) + status = -1; + + /* + * check Cable ID + */ + cable_id = readb(&icom_port->dram->cable_id); + + if (cable_id & ICOM_CABLE_ID_VALID) { + /* Get cable ID into the lower 4 bits (standard form) */ + cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4; + icom_port->cable_id = cable_id; + } else { + dev_err(&dev->dev,"Invalid or no cable attached\n"); + icom_port->cable_id = NO_CABLE; + } + + load_code_exit: + + if (status != 0) { + /* Clear out any pending interrupts */ + writew(0x3FFF, (void *) icom_port->int_reg); + + /* Turn off port */ + writeb(ICOM_DISABLE, &(icom_port->dram->disable)); + + /* Stop processor */ + stop_processor(icom_port); + + dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n"); + } + + if (new_page != NULL) + pci_free_consistent(dev, 4096, new_page, temp_pci); +} + +static int startup(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned char cable_id, raw_cable_id; + unsigned long flags; + int port; + + trace(icom_port, "STARTUP", 0); + + if (icom_port->dram == 0x00000000) { + /* should NEVER be zero */ + dev_err(&icom_port->adapter->pci_dev->dev, + "Unusable Port, port configuration missing\n"); + return -ENODEV; + } + + /* + * check Cable ID + */ + raw_cable_id = readb(&icom_port->dram->cable_id); + trace(icom_port, "CABLE_ID", raw_cable_id); + + /* Get cable ID into the lower 4 bits (standard form) */ + cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; + + /* Check for valid Cable ID */ + if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || + (cable_id != icom_port->cable_id)) { + + /* reload adapter code, pick up any potential changes in cable id */ + load_code(icom_port); + + /* still no sign of cable, error out */ + raw_cable_id = readb(&icom_port->dram->cable_id); + cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; + if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || + (icom_port->cable_id == NO_CABLE)) + return -EIO; + } + + /* + * Finally, clear and enable interrupts + */ + spin_lock_irqsave(&icom_lock, flags); + port = icom_port->port; + if (port == 0 || port == 1) + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; + else + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; + + if (port == 0 || port == 2) + writew(0x00FF,(void *) icom_port->int_reg); + else + writew(0x3F00,(void *) icom_port->int_reg); + if (port < 4) { + temp = readl(int_mask_tbl[port].global_int_mask); + writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); + + /* write flush */ + readl(int_mask_tbl[port].global_int_mask); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); + return 0; +} + +static void shutdown(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned char cmdReg; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + trace(icom_port, "SHUTDOWN", 0); + + /* + * disable all interrupts + */ + port = icom_port->port; + if (port == 0 || port == 1) + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; + else + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; + + if (port < 4) { + temp = readl(int_mask_tbl[port].global_int_mask); + writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); + + /* write flush */ + readl(int_mask_tbl[port].global_int_mask); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + spin_unlock_irqrestore(&icom_lock, flags); + + /* + * disable break condition + */ + cmdReg = readb(&icom_port->dram->CmdReg); + if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) { + writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); + } +} + +static int icom_write(struct uart_port *port) +{ + unsigned long data_count; + unsigned char cmdReg; + unsigned long offset; + int temp_tail = port->info->xmit.tail; + + trace(ICOM_PORT, "WRITE", 0); + + if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) { + trace(ICOM_PORT, "WRITE_FULL", 0); + return 0; + } + + data_count = 0; + while ((port->info->xmit.head != temp_tail) && + (data_count <= XMIT_BUFF_SZ)) { + + ICOM_PORT->xmit_buf[data_count++] = + port->info->xmit.buf[temp_tail]; + + temp_tail++; + temp_tail &= (UART_XMIT_SIZE - 1); + } + + if (data_count) { + ICOM_PORT->statStg->xmit[0].flags = + cpu_to_le16(SA_FLAGS_READY_TO_XMIT); + ICOM_PORT->statStg->xmit[0].leLength = + cpu_to_le16(data_count); + offset = + (unsigned long) &ICOM_PORT->statStg->xmit[0] - + (unsigned long) ICOM_PORT->statStg; + *ICOM_PORT->xmitRestart = + cpu_to_le32(ICOM_PORT->statStg_pci + offset); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_XMIT_RCV_ENABLE, + &ICOM_PORT->dram->CmdReg); + writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd); + trace(ICOM_PORT, "WRITE_START", data_count); + /* write flush */ + readb(&ICOM_PORT->dram->StartXmitCmd); + } + + return data_count; +} + +static inline void check_modem_status(struct icom_port *icom_port) +{ + static char old_status = 0; + char delta_status; + unsigned char status; + + spin_lock(&icom_port->uart_port.lock); + + /*modem input register */ + status = readb(&icom_port->dram->isr); + trace(icom_port, "CHECK_MODEM", status); + delta_status = status ^ old_status; + if (delta_status) { + if (delta_status & ICOM_RI) + icom_port->uart_port.icount.rng++; + if (delta_status & ICOM_DSR) + icom_port->uart_port.icount.dsr++; + if (delta_status & ICOM_DCD) + uart_handle_dcd_change(&icom_port->uart_port, + delta_status & ICOM_DCD); + if (delta_status & ICOM_CTS) + uart_handle_cts_change(&icom_port->uart_port, + delta_status & ICOM_CTS); + + wake_up_interruptible(&icom_port->uart_port.info-> + delta_msr_wait); + old_status = status; + } + spin_unlock(&icom_port->uart_port.lock); +} + +static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) +{ + unsigned short int count; + int i; + + if (port_int_reg & (INT_XMIT_COMPLETED)) { + trace(icom_port, "XMIT_COMPLETE", 0); + + /* clear buffer in use bit */ + icom_port->statStg->xmit[0].flags &= + cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); + + count = (unsigned short int) + cpu_to_le16(icom_port->statStg->xmit[0].leLength); + icom_port->uart_port.icount.tx += count; + + for (i=0; iuart_port.info->xmit); i++) { + + icom_port->uart_port.info->xmit.tail++; + icom_port->uart_port.info->xmit.tail &= + (UART_XMIT_SIZE - 1); + } + + if (!icom_write(&icom_port->uart_port)) + /* activate write queue */ + uart_write_wakeup(&icom_port->uart_port); + } else + trace(icom_port, "XMIT_DISABLED", 0); +} + +static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) +{ + short int count, rcv_buff; + struct tty_struct *tty = icom_port->uart_port.info->tty; + unsigned short int status; + struct uart_icount *icount; + unsigned long offset; + + trace(icom_port, "RCV_COMPLETE", 0); + rcv_buff = icom_port->next_rcv; + + status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + while (status & SA_FL_RCV_DONE) { + + trace(icom_port, "FID_STATUS", status); + count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); + + trace(icom_port, "RCV_COUNT", count); + if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + trace(icom_port, "REAL_COUNT", count); + + offset = + cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - + icom_port->recv_buf_pci; + + memcpy(tty->flip.char_buf_ptr,(unsigned char *) + ((unsigned long)icom_port->recv_buf + offset), count); + + if (count > 0) { + tty->flip.count += count - 1; + tty->flip.char_buf_ptr += count - 1; + + memset(tty->flip.flag_buf_ptr, 0, count); + tty->flip.flag_buf_ptr += count - 1; + } + + icount = &icom_port->uart_port.icount; + icount->rx += count; + + /* Break detect logic */ + if ((status & SA_FLAGS_FRAME_ERROR) + && (tty->flip.char_buf_ptr[0] == 0x00)) { + status &= ~SA_FLAGS_FRAME_ERROR; + status |= SA_FLAGS_BREAK_DET; + trace(icom_port, "BREAK_DET", 0); + } + + if (status & + (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | + SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { + + if (status & SA_FLAGS_BREAK_DET) + icount->brk++; + if (status & SA_FLAGS_PARITY_ERROR) + icount->parity++; + if (status & SA_FLAGS_FRAME_ERROR) + icount->frame++; + if (status & SA_FLAGS_OVERRUN) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (status & icom_port->ignore_status_mask) { + trace(icom_port, "IGNORE_CHAR", 0); + goto ignore_char; + } + + status &= icom_port->read_status_mask; + + if (status & SA_FLAGS_BREAK_DET) { + *tty->flip.flag_buf_ptr = TTY_BREAK; + } else if (status & SA_FLAGS_PARITY_ERROR) { + trace(icom_port, "PARITY_ERROR", 0); + *tty->flip.flag_buf_ptr = TTY_PARITY; + } else if (status & SA_FLAGS_FRAME_ERROR) + *tty->flip.flag_buf_ptr = TTY_FRAME; + + if (status & SA_FLAGS_OVERRUN) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + icom_port->statStg->rcv[rcv_buff].flags = 0; + icom_port->statStg->rcv[rcv_buff].leLength = 0; + icom_port->statStg->rcv[rcv_buff].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + + rcv_buff++; + if (rcv_buff == NUM_RBUFFS) + rcv_buff = 0; + + status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + } + icom_port->next_rcv = rcv_buff; + tty_flip_buffer_push(tty); +} + +static void process_interrupt(u16 port_int_reg, + struct icom_port *icom_port) +{ + + spin_lock(&icom_port->uart_port.lock); + trace(icom_port, "INTERRUPT", port_int_reg); + + if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) + xmit_interrupt(port_int_reg, icom_port); + + if (port_int_reg & INT_RCV_COMPLETED) + recv_interrupt(port_int_reg, icom_port); + + spin_unlock(&icom_port->uart_port.lock); +} + +static irqreturn_t icom_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + unsigned long int_reg; + u32 adapter_interrupts; + u16 port_int_reg; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; + + /* find icom_port for this interrupt */ + icom_adapter = (struct icom_adapter *) dev_id; + + if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { + int_reg = icom_adapter->base_addr + 0x8024; + + adapter_interrupts = readl((void *) int_reg); + + if (adapter_interrupts & 0x00003FFF) { + /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */ + icom_port = &icom_adapter->port_info[2]; + port_int_reg = (u16) adapter_interrupts; + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + if (adapter_interrupts & 0x3FFF0000) { + /* port 3 interrupt */ + icom_port = &icom_adapter->port_info[3]; + if (icom_port->status == ICOM_PORT_ACTIVE) { + port_int_reg = + (u16) (adapter_interrupts >> 16); + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + } + + /* Clear out any pending interrupts */ + writel(adapter_interrupts, (void *) int_reg); + + int_reg = icom_adapter->base_addr + 0x8004; + } else { + int_reg = icom_adapter->base_addr + 0x4004; + } + + adapter_interrupts = readl((void *) int_reg); + + if (adapter_interrupts & 0x00003FFF) { + /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */ + icom_port = &icom_adapter->port_info[0]; + port_int_reg = (u16) adapter_interrupts; + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + if (adapter_interrupts & 0x3FFF0000) { + /* port 1 interrupt */ + icom_port = &icom_adapter->port_info[1]; + if (icom_port->status == ICOM_PORT_ACTIVE) { + port_int_reg = (u16) (adapter_interrupts >> 16); + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + } + + /* Clear out any pending interrupts */ + writel(adapter_interrupts, (void *) int_reg); + + /* flush the write */ + adapter_interrupts = readl((void *) int_reg); + + return IRQ_HANDLED; +} + +/* + * ------------------------------------------------------------------ + * Begin serial-core API + * ------------------------------------------------------------------ + */ +static unsigned int icom_tx_empty(struct uart_port *port) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) + ret = TIOCSER_TEMT; + else + ret = 0; + + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned char local_osr; + + trace(ICOM_PORT, "SET_MODEM", 0); + local_osr = readb(&ICOM_PORT->dram->osr); + + if (mctrl & TIOCM_RTS) { + trace(ICOM_PORT, "RAISE_RTS", 0); + local_osr |= ICOM_RTS; + } else { + trace(ICOM_PORT, "LOWER_RTS", 0); + local_osr &= ~ICOM_RTS; + } + + if (mctrl & TIOCM_DTR) { + trace(ICOM_PORT, "RAISE_DTR", 0); + local_osr |= ICOM_DTR; + } else { + trace(ICOM_PORT, "LOWER_DTR", 0); + local_osr &= ~ICOM_DTR; + } + + writeb(local_osr, &ICOM_PORT->dram->osr); +} + +static unsigned int icom_get_mctrl(struct uart_port *port) +{ + unsigned char status; + unsigned int result; + + trace(ICOM_PORT, "GET_MODEM", 0); + + status = readb(&ICOM_PORT->dram->isr); + + result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) + | ((status & ICOM_RI) ? TIOCM_RNG : 0) + | ((status & ICOM_DSR) ? TIOCM_DSR : 0) + | ((status & ICOM_CTS) ? TIOCM_CTS : 0); + return result; +} + +static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned char cmdReg; + + if (tty_stop) { + trace(ICOM_PORT, "STOP", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); + } +} + +static void icom_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "START", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) + writeb(cmdReg & ~CMD_HOLD_XMIT, + &ICOM_PORT->dram->CmdReg); + + icom_write(port); +} + +static void icom_send_xchar(struct uart_port *port, char ch) +{ + unsigned char xdata; + int index; + unsigned long flags; + + trace(ICOM_PORT, "SEND_XCHAR", ch); + + /* wait .1 sec to send char */ + for (index = 0; index < 10; index++) { + spin_lock_irqsave(&port->lock, flags); + xdata = readb(&ICOM_PORT->dram->xchar); + if (xdata == 0x00) { + trace(ICOM_PORT, "QUICK_WRITE", 0); + writeb(ch, &ICOM_PORT->dram->xchar); + + /* flush write operation */ + xdata = readb(&ICOM_PORT->dram->xchar); + spin_unlock_irqrestore(&port->lock, flags); + break; + } + spin_unlock_irqrestore(&port->lock, flags); + msleep(10); + } +} + +static void icom_stop_rx(struct uart_port *port) +{ + unsigned char cmdReg; + + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); +} + +static void icom_enable_ms(struct uart_port *port) +{ + /* no-op */ +} + +static void icom_break(struct uart_port *port, int break_state) +{ + unsigned char cmdReg; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + trace(ICOM_PORT, "BREAK", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + if (break_state == -1) { + writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + } else { + writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static int icom_open(struct uart_port *port) +{ + int retval; + + kobject_get(&ICOM_PORT->adapter->kobj); + retval = startup(ICOM_PORT); + + if (retval) { + kobject_put(&ICOM_PORT->adapter->kobj); + trace(ICOM_PORT, "STARTUP_ERROR", 0); + return retval; + } + + return 0; +} + +static void icom_close(struct uart_port *port) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "CLOSE", 0); + + /* stop receiver */ + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE, + &ICOM_PORT->dram->CmdReg); + + shutdown(ICOM_PORT); + + kobject_put(&ICOM_PORT->adapter->kobj); +} + +static void icom_set_termios(struct uart_port *port, + struct termios *termios, + struct termios *old_termios) +{ + int baud; + unsigned cflag, iflag; + int bits; + char new_config2; + char new_config3 = 0; + char tmp_byte; + int index; + int rcv_buff, xmit_buff; + unsigned long offset; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + trace(ICOM_PORT, "CHANGE_SPEED", 0); + + cflag = termios->c_cflag; + iflag = termios->c_iflag; + + new_config2 = ICOM_ACFG_DRIVE1; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: /* 5 bits/char */ + new_config2 |= ICOM_ACFG_5BPC; + bits = 7; + break; + case CS6: /* 6 bits/char */ + new_config2 |= ICOM_ACFG_6BPC; + bits = 8; + break; + case CS7: /* 7 bits/char */ + new_config2 |= ICOM_ACFG_7BPC; + bits = 9; + break; + case CS8: /* 8 bits/char */ + new_config2 |= ICOM_ACFG_8BPC; + bits = 10; + break; + default: + bits = 10; + break; + } + if (cflag & CSTOPB) { + /* 2 stop bits */ + new_config2 |= ICOM_ACFG_2STOP_BIT; + bits++; + } + if (cflag & PARENB) { + /* parity bit enabled */ + new_config2 |= ICOM_ACFG_PARITY_ENAB; + trace(ICOM_PORT, "PARENB", 0); + bits++; + } + if (cflag & PARODD) { + /* odd parity */ + new_config2 |= ICOM_ACFG_PARITY_ODD; + trace(ICOM_PORT, "PARODD", 0); + } + + /* Determine divisor based on baud rate */ + baud = uart_get_baud_rate(port, termios, old_termios, + icom_acfg_baud[0], + icom_acfg_baud[BAUD_TABLE_LIMIT]); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + for (index = 0; index < BAUD_TABLE_LIMIT; index++) { + if (icom_acfg_baud[index] == baud) { + new_config3 = index; + break; + } + } + + uart_update_timeout(port, cflag, baud); + + /* CTS flow control flag and modem status interrupts */ + tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + if (cflag & CRTSCTS) + tmp_byte |= HDLC_HDW_FLOW; + else + tmp_byte &= ~HDLC_HDW_FLOW; + writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + + /* + * Set up parity check flag + */ + ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; + if (iflag & INPCK) + ICOM_PORT->read_status_mask |= + SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR; + + if ((iflag & BRKINT) || (iflag & PARMRK)) + ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET; + + /* + * Characters to ignore + */ + ICOM_PORT->ignore_status_mask = 0; + if (iflag & IGNPAR) + ICOM_PORT->ignore_status_mask |= + SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR; + if (iflag & IGNBRK) { + ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (iflag & IGNPAR) + ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN; + } + + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE; + + /* Turn off Receiver to prepare for reset */ + writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg); + + for (index = 0; index < 10; index++) { + if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) { + break; + } + } + + /* clear all current buffers of data */ + for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) { + ICOM_PORT->statStg->rcv[rcv_buff].flags = 0; + ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0; + ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + } + + for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) { + ICOM_PORT->statStg->xmit[xmit_buff].flags = 0; + } + + /* activate changes and start xmit and receiver here */ + /* Enable the receiver */ + writeb(new_config3, &(ICOM_PORT->dram->async_config3)); + writeb(new_config2, &(ICOM_PORT->dram->async_config2)); + tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL; + writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */ + + /* reset processor */ + writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg); + + for (index = 0; index < 10; index++) { + if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) { + break; + } + } + + /* Enable Transmitter and Reciever */ + offset = + (unsigned long) &ICOM_PORT->statStg->rcv[0] - + (unsigned long) ICOM_PORT->statStg; + writel(ICOM_PORT->statStg_pci + offset, + &ICOM_PORT->dram->RcvStatusAddr); + ICOM_PORT->next_rcv = 0; + ICOM_PORT->put_length = 0; + *ICOM_PORT->xmitRestart = 0; + writel(ICOM_PORT->xmitRestart_pci, + &ICOM_PORT->dram->XmitStatusAddr); + trace(ICOM_PORT, "XR_ENAB", 0); + writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *icom_type(struct uart_port *port) +{ + return "icom"; +} + +static void icom_release_port(struct uart_port *port) +{ +} + +static int icom_request_port(struct uart_port *port) +{ + return 0; +} + +static void icom_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_ICOM; +} + +static struct uart_ops icom_ops = { + .tx_empty = icom_tx_empty, + .set_mctrl = icom_set_mctrl, + .get_mctrl = icom_get_mctrl, + .stop_tx = icom_stop_tx, + .start_tx = icom_start_tx, + .send_xchar = icom_send_xchar, + .stop_rx = icom_stop_rx, + .enable_ms = icom_enable_ms, + .break_ctl = icom_break, + .startup = icom_open, + .shutdown = icom_close, + .set_termios = icom_set_termios, + .type = icom_type, + .release_port = icom_release_port, + .request_port = icom_request_port, + .config_port = icom_config_port, +}; + +#define ICOM_CONSOLE NULL + +static struct uart_driver icom_uart_driver = { + .owner = THIS_MODULE, + .driver_name = ICOM_DRIVER_NAME, + .dev_name = "ttyA", + .major = ICOM_MAJOR, + .minor = ICOM_MINOR_START, + .nr = NR_PORTS, + .cons = ICOM_CONSOLE, +}; + +static int __devinit icom_init_ports(struct icom_adapter *icom_adapter) +{ + u32 subsystem_id = icom_adapter->subsystem_id; + int retval = 0; + int i; + struct icom_port *icom_port; + + if (icom_adapter->version == ADAPTER_V1) { + icom_adapter->numb_ports = 2; + + for (i = 0; i < 2; i++) { + icom_port = &icom_adapter->port_info[i]; + icom_port->port = i; + icom_port->status = ICOM_PORT_ACTIVE; + icom_port->imbed_modem = ICOM_UNKNOWN; + } + } else { + if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) { + icom_adapter->numb_ports = 4; + + for (i = 0; i < 4; i++) { + icom_port = &icom_adapter->port_info[i]; + + icom_port->port = i; + icom_port->status = ICOM_PORT_ACTIVE; + icom_port->imbed_modem = ICOM_IMBED_MODEM; + } + } else { + icom_adapter->numb_ports = 4; + + icom_adapter->port_info[0].port = 0; + icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE; + + if (subsystem_id == + PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) { + icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM; + } else { + icom_adapter->port_info[0].imbed_modem = ICOM_RVX; + } + + icom_adapter->port_info[1].status = ICOM_PORT_OFF; + + icom_adapter->port_info[2].port = 2; + icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE; + icom_adapter->port_info[2].imbed_modem = ICOM_RVX; + icom_adapter->port_info[3].status = ICOM_PORT_OFF; + } + } + + return retval; +} + +static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num) +{ + if (icom_adapter->version == ADAPTER_V1) { + icom_port->global_reg = (struct icom_regs *) ((char *) + icom_adapter->base_addr + 0x4000); + icom_port->int_reg = (unsigned long) icom_adapter->base_addr + + 0x4004 + 2 - 2 * port_num; + } else { + icom_port->global_reg = (struct icom_regs *) ((char *) + icom_adapter->base_addr + 0x8000); + if (icom_port->port < 2) + icom_port->int_reg = (unsigned long) icom_adapter->base_addr + + 0x8004 + 2 - 2 * icom_port->port; + else + icom_port->int_reg = (unsigned long) icom_adapter->base_addr + + 0x8024 + 2 - 2 * (icom_port->port - 2); + } +} +static int __init icom_load_ports(struct icom_adapter *icom_adapter) +{ + struct icom_port *icom_port; + int port_num; + int retval; + + for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) { + + icom_port = &icom_adapter->port_info[port_num]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + icom_port_active(icom_port, icom_adapter, port_num); + icom_port->dram = (struct func_dram *) ((char *) + icom_adapter->base_addr + + 0x2000 * icom_port->port); + + icom_port->adapter = icom_adapter; + + /* get port memory */ + if ((retval = get_port_memory(icom_port)) != 0) { + dev_err(&icom_port->adapter->pci_dev->dev, + "Memory allocation for port FAILED\n"); + } + } + } + return 0; +} + +static int __devinit icom_alloc_adapter(struct icom_adapter + **icom_adapter_ref) +{ + int adapter_count = 0; + struct icom_adapter *icom_adapter; + struct icom_adapter *cur_adapter_entry; + struct list_head *tmp; + + icom_adapter = (struct icom_adapter *) + kmalloc(sizeof(struct icom_adapter), GFP_KERNEL); + + if (!icom_adapter) { + return -ENOMEM; + } + + memset(icom_adapter, 0, sizeof(struct icom_adapter)); + + list_for_each(tmp, &icom_adapter_head) { + cur_adapter_entry = + list_entry(tmp, struct icom_adapter, + icom_adapter_entry); + if (cur_adapter_entry->index != adapter_count) { + break; + } + adapter_count++; + } + + icom_adapter->index = adapter_count; + list_add_tail(&icom_adapter->icom_adapter_entry, tmp); + + *icom_adapter_ref = icom_adapter; + return 0; +} + +static void icom_free_adapter(struct icom_adapter *icom_adapter) +{ + list_del(&icom_adapter->icom_adapter_entry); + kfree(icom_adapter); +} + +static void icom_remove_adapter(struct icom_adapter *icom_adapter) +{ + struct icom_port *icom_port; + int index; + + for (index = 0; index < icom_adapter->numb_ports; index++) { + icom_port = &icom_adapter->port_info[index]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + dev_info(&icom_adapter->pci_dev->dev, + "Device removed\n"); + + uart_remove_one_port(&icom_uart_driver, + &icom_port->uart_port); + + /* be sure that DTR and RTS are dropped */ + writeb(0x00, &icom_port->dram->osr); + + /* Wait 0.1 Sec for simple Init to complete */ + msleep(100); + + /* Stop proccessor */ + stop_processor(icom_port); + + free_port_memory(icom_port); + } + } + + free_irq(icom_adapter->irq_number, (void *) icom_adapter); + iounmap((void *) icom_adapter->base_addr); + icom_free_adapter(icom_adapter); + pci_release_regions(icom_adapter->pci_dev); +} + +static void icom_kobj_release(struct kobject *kobj) +{ + struct icom_adapter *icom_adapter; + + icom_adapter = to_icom_adapter(kobj); + icom_remove_adapter(icom_adapter); +} + +static struct kobj_type icom_kobj_type = { + .release = icom_kobj_release, +}; + +static int __devinit icom_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + int index; + unsigned int command_reg; + int retval; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; + + retval = pci_enable_device(dev); + if (retval) { + dev_err(&dev->dev, "Device enable FAILED\n"); + return retval; + } + + if ( (retval = pci_request_regions(dev, "icom"))) { + dev_err(&dev->dev, "pci_request_region FAILED\n"); + pci_disable_device(dev); + return retval; + } + + pci_set_master(dev); + + if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + dev_err(&dev->dev, "PCI Config read FAILED\n"); + return retval; + } + + pci_write_config_dword(dev, PCI_COMMAND, + command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER + | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + + if (ent->driver_data == ADAPTER_V1) { + pci_write_config_dword(dev, 0x44, 0x8300830A); + } else { + pci_write_config_dword(dev, 0x44, 0x42004200); + pci_write_config_dword(dev, 0x48, 0x42004200); + } + + + retval = icom_alloc_adapter(&icom_adapter); + if (retval) { + dev_err(&dev->dev, "icom_alloc_adapter FAILED\n"); + retval = -EIO; + goto probe_exit0; + } + + icom_adapter->base_addr_pci = pci_resource_start(dev, 0); + icom_adapter->irq_number = dev->irq; + icom_adapter->pci_dev = dev; + icom_adapter->version = ent->driver_data; + icom_adapter->subsystem_id = ent->subdevice; + + + retval = icom_init_ports(icom_adapter); + if (retval) { + dev_err(&dev->dev, "Port configuration failed\n"); + goto probe_exit1; + } + + icom_adapter->base_addr = + (unsigned long) ioremap(icom_adapter->base_addr_pci, + pci_resource_len(dev, 0)); + + if (!icom_adapter->base_addr) + goto probe_exit1; + + /* save off irq and request irq line */ + if ( (retval = request_irq(dev->irq, icom_interrupt, + SA_INTERRUPT | SA_SHIRQ, ICOM_DRIVER_NAME, + (void *) icom_adapter))) { + goto probe_exit2; + } + + retval = icom_load_ports(icom_adapter); + + for (index = 0; index < icom_adapter->numb_ports; index++) { + icom_port = &icom_adapter->port_info[index]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + icom_port->uart_port.irq = icom_port->adapter->irq_number; + icom_port->uart_port.type = PORT_ICOM; + icom_port->uart_port.iotype = UPIO_MEM; + icom_port->uart_port.membase = + (char *) icom_adapter->base_addr_pci; + icom_port->uart_port.fifosize = 16; + icom_port->uart_port.ops = &icom_ops; + icom_port->uart_port.line = + icom_port->port + icom_adapter->index * 4; + if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) { + icom_port->status = ICOM_PORT_OFF; + dev_err(&dev->dev, "Device add failed\n"); + } else + dev_info(&dev->dev, "Device added\n"); + } + } + + kobject_init(&icom_adapter->kobj); + icom_adapter->kobj.ktype = &icom_kobj_type; + return 0; + +probe_exit2: + iounmap((void *) icom_adapter->base_addr); +probe_exit1: + icom_free_adapter(icom_adapter); + +probe_exit0: + pci_release_regions(dev); + pci_disable_device(dev); + + return retval; + + +} + +static void __devexit icom_remove(struct pci_dev *dev) +{ + struct icom_adapter *icom_adapter; + struct list_head *tmp; + + list_for_each(tmp, &icom_adapter_head) { + icom_adapter = list_entry(tmp, struct icom_adapter, + icom_adapter_entry); + if (icom_adapter->pci_dev == dev) { + kobject_put(&icom_adapter->kobj); + return; + } + } + + dev_err(&dev->dev, "Unable to find device to remove\n"); +} + +static struct pci_driver icom_pci_driver = { + .name = ICOM_DRIVER_NAME, + .id_table = icom_pci_table, + .probe = icom_probe, + .remove = __devexit_p(icom_remove), +}; + +static int __init icom_init(void) +{ + int ret; + + spin_lock_init(&icom_lock); + icom_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + + ret = uart_register_driver(&icom_uart_driver); + if (ret) + return ret; + + ret = pci_register_driver(&icom_pci_driver); + + if (ret < 0) + uart_unregister_driver(&icom_uart_driver); + + return ret; +} + +static void __exit icom_exit(void) +{ + pci_unregister_driver(&icom_pci_driver); + uart_unregister_driver(&icom_uart_driver); +} + +module_init(icom_init); +module_exit(icom_exit); + +#ifdef ICOM_TRACE +static inline void trace(struct icom_port *icom_port, char *trace_pt, + unsigned long trace_data) +{ + dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", + icom_port->port, trace_pt, trace_data); +} +#endif + +MODULE_AUTHOR("Michael Anderson "); +MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); +MODULE_SUPPORTED_DEVICE + ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h new file mode 100644 index 000000000..479b52d36 --- /dev/null +++ b/drivers/serial/icom.h @@ -0,0 +1,290 @@ +/* + * icom.h + * + * Copyright (C) 2001 Michael Anderson, IBM Corporation + * + * Serial device driver include file. + * + * 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 + */ + +#include + +#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1) +static int icom_acfg_baud[] = { + 300, + 600, + 900, + 1200, + 1800, + 2400, + 3600, + 4800, + 7200, + 9600, + 14400, + 19200, + 28800, + 38400, + 57600, + 76800, + 115200, + 153600, + 230400, + 307200, + 460800, +}; + +struct icom_regs { + u32 control; /* Adapter Control Register */ + u32 interrupt; /* Adapter Interrupt Register */ + u32 int_mask; /* Adapter Interrupt Mask Reg */ + u32 int_pri; /* Adapter Interrupt Priority r */ + u32 int_reg_b; /* Adapter non-masked Interrupt */ + u32 resvd01; + u32 resvd02; + u32 resvd03; + u32 control_2; /* Adapter Control Register 2 */ + u32 interrupt_2; /* Adapter Interrupt Register 2 */ + u32 int_mask_2; /* Adapter Interrupt Mask 2 */ + u32 int_pri_2; /* Adapter Interrupt Prior 2 */ + u32 int_reg_2b; /* Adapter non-masked 2 */ +}; + +struct func_dram { + u32 reserved[108]; /* 0-1B0 reserved by personality code */ + u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ + u8 RcvStnAddr; /* 1B4 Receive Station Addr */ + u8 IdleState; /* 1B5 Idle State */ + u8 IdleMonitor; /* 1B6 Idle Monitor */ + u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ + u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ + u8 StartXmitCmd; /* 1BC Start Xmit Command */ + u8 HDLCConfigReg; /* 1BD Reserved */ + u8 CauseCode; /* 1BE Cause code for fatal error */ + u8 xchar; /* 1BF High priority send */ + u32 reserved3; /* 1C0-1C3 Reserved */ + u8 PrevCmdReg; /* 1C4 Reserved */ + u8 CmdReg; /* 1C5 Command Register */ + u8 async_config2; /* 1C6 Async Config Byte 2 */ + u8 async_config3; /* 1C7 Async Config Byte 3 */ + u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ + u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ + u8 misc_flags; /* 1DD misc flags */ +#define V2_HARDWARE 0x40 +#define ICOM_HDW_ACTIVE 0x01 + u8 call_length; /* 1DE Phone #/CFI buff ln */ + u8 call_length2; /* 1DF Upper byte (unused) */ + u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ + u16 timer_value; /* 1E4-1E5 general timer value */ + u8 timer_command; /* 1E6 general timer cmd */ + u8 dce_command; /* 1E7 dce command reg */ + u8 dce_cmd_status; /* 1E8 dce command stat */ + u8 x21_r1_ioff; /* 1E9 dce ready counter */ + u8 x21_r0_ioff; /* 1EA dce not ready ctr */ + u8 x21_ralt_ioff; /* 1EB dce CNR counter */ + u8 x21_r1_ion; /* 1EC dce ready I on ctr */ + u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ + u8 ier; /* 1EE Interrupt Enable */ + u8 isr; /* 1EF Input Signal Reg */ + u8 osr; /* 1F0 Output Signal Reg */ + u8 reset; /* 1F1 Reset/Reload Reg */ + u8 disable; /* 1F2 Disable Reg */ + u8 sync; /* 1F3 Sync Reg */ + u8 error_stat; /* 1F4 Error Status */ + u8 cable_id; /* 1F5 Cable ID */ + u8 cs_length; /* 1F6 CS Load Length */ + u8 mac_length; /* 1F7 Mac Load Length */ + u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ + u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ +}; + +/* + * adapter defines and structures + */ +#define ICOM_CONTROL_START_A 0x00000008 +#define ICOM_CONTROL_STOP_A 0x00000004 +#define ICOM_CONTROL_START_B 0x00000002 +#define ICOM_CONTROL_STOP_B 0x00000001 +#define ICOM_CONTROL_START_C 0x00000008 +#define ICOM_CONTROL_STOP_C 0x00000004 +#define ICOM_CONTROL_START_D 0x00000002 +#define ICOM_CONTROL_STOP_D 0x00000001 +#define ICOM_IRAM_OFFSET 0x1000 +#define ICOM_IRAM_SIZE 0x0C00 +#define ICOM_DCE_IRAM_OFFSET 0x0A00 +#define ICOM_CABLE_ID_VALID 0x01 +#define ICOM_CABLE_ID_MASK 0xF0 +#define ICOM_DISABLE 0x80 +#define CMD_XMIT_RCV_ENABLE 0xC0 +#define CMD_XMIT_ENABLE 0x40 +#define CMD_RCV_DISABLE 0x00 +#define CMD_RCV_ENABLE 0x80 +#define CMD_RESTART 0x01 +#define CMD_HOLD_XMIT 0x02 +#define CMD_SND_BREAK 0x04 +#define RS232_CABLE 0x06 +#define V24_CABLE 0x0E +#define V35_CABLE 0x0C +#define V36_CABLE 0x02 +#define NO_CABLE 0x00 +#define START_DOWNLOAD 0x80 +#define ICOM_INT_MASK_PRC_A 0x00003FFF +#define ICOM_INT_MASK_PRC_B 0x3FFF0000 +#define ICOM_INT_MASK_PRC_C 0x00003FFF +#define ICOM_INT_MASK_PRC_D 0x3FFF0000 +#define INT_RCV_COMPLETED 0x1000 +#define INT_XMIT_COMPLETED 0x2000 +#define INT_IDLE_DETECT 0x0800 +#define INT_RCV_DISABLED 0x0400 +#define INT_XMIT_DISABLED 0x0200 +#define INT_RCV_XMIT_SHUTDOWN 0x0100 +#define INT_FATAL_ERROR 0x0080 +#define INT_CABLE_PULL 0x0020 +#define INT_SIGNAL_CHANGE 0x0010 +#define HDLC_PPP_PURE_ASYNC 0x02 +#define HDLC_FF_FILL 0x00 +#define HDLC_HDW_FLOW 0x01 +#define START_XMIT 0x80 +#define ICOM_ACFG_DRIVE1 0x20 +#define ICOM_ACFG_NO_PARITY 0x00 +#define ICOM_ACFG_PARITY_ENAB 0x02 +#define ICOM_ACFG_PARITY_ODD 0x01 +#define ICOM_ACFG_8BPC 0x00 +#define ICOM_ACFG_7BPC 0x04 +#define ICOM_ACFG_6BPC 0x08 +#define ICOM_ACFG_5BPC 0x0C +#define ICOM_ACFG_1STOP_BIT 0x00 +#define ICOM_ACFG_2STOP_BIT 0x10 +#define ICOM_DTR 0x80 +#define ICOM_RTS 0x40 +#define ICOM_RI 0x08 +#define ICOM_DSR 0x80 +#define ICOM_DCD 0x20 +#define ICOM_CTS 0x40 + +#define NUM_XBUFFS 1 +#define NUM_RBUFFS 2 +#define RCV_BUFF_SZ 0x0200 +#define XMIT_BUFF_SZ 0x1000 +struct statusArea { + /**********************************************/ + /* Transmit Status Area */ + /**********************************************/ + struct xmit_status_area{ + u32 leNext; /* Next entry in Little Endian on Adapter */ + u32 leNextASD; + u32 leBuffer; /* Buffer for entry in LE for Adapter */ + u16 leLengthASD; + u16 leOffsetASD; + u16 leLength; /* Length of data in segment */ + u16 flags; +#define SA_FLAGS_DONE 0x0080 /* Done with Segment */ +#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ +#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ +#define SA_FLAGS_READY_TO_XMIT 0x0800 +#define SA_FLAGS_STAT_MASK 0x007F + } xmit[NUM_XBUFFS]; + + /**********************************************/ + /* Receive Status Area */ + /**********************************************/ + struct { + u32 leNext; /* Next entry in Little Endian on Adapter */ + u32 leNextASD; + u32 leBuffer; /* Buffer for entry in LE for Adapter */ + u16 WorkingLength; /* size of segment */ + u16 reserv01; + u16 leLength; /* Length of data in segment */ + u16 flags; +#define SA_FL_RCV_DONE 0x0010 /* Data ready */ +#define SA_FLAGS_OVERRUN 0x0040 +#define SA_FLAGS_PARITY_ERROR 0x0080 +#define SA_FLAGS_FRAME_ERROR 0x0001 +#define SA_FLAGS_FRAME_TRUNC 0x0002 +#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ +#define SA_FLAGS_RCV_MASK 0xFFE6 + } rcv[NUM_RBUFFS]; +}; + +struct icom_adapter; + + +#define ICOM_MAJOR 243 +#define ICOM_MINOR_START 0 + +struct icom_port { + struct uart_port uart_port; + u8 imbed_modem; +#define ICOM_UNKNOWN 1 +#define ICOM_RVX 2 +#define ICOM_IMBED_MODEM 3 + unsigned char cable_id; + unsigned char read_status_mask; + unsigned char ignore_status_mask; + unsigned long int_reg; + struct icom_regs *global_reg; + struct func_dram *dram; + int port; + struct statusArea *statStg; + dma_addr_t statStg_pci; + u32 *xmitRestart; + dma_addr_t xmitRestart_pci; + unsigned char *xmit_buf; + dma_addr_t xmit_buf_pci; + unsigned char *recv_buf; + dma_addr_t recv_buf_pci; + int next_rcv; + int put_length; + int status; +#define ICOM_PORT_ACTIVE 1 /* Port exists. */ +#define ICOM_PORT_OFF 0 /* Port does not exist. */ + int load_in_progress; + struct icom_adapter *adapter; +}; + +struct icom_adapter { + unsigned long base_addr; + unsigned long base_addr_pci; + unsigned char irq_number; + struct pci_dev *pci_dev; + struct icom_port port_info[4]; + int index; + int version; +#define ADAPTER_V1 0x0001 +#define ADAPTER_V2 0x0002 + u32 subsystem_id; +#define FOUR_PORT_MODEL 0x0252 +#define V2_TWO_PORTS_RVX 0x021A +#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 + int numb_ports; + struct list_head icom_adapter_entry; + struct kobject kobj; +}; + +/* prototype */ +extern void iCom_sercons_init(void); + +struct lookup_proc_table { + u32 *global_control_reg; + unsigned long processor_id; +}; + +struct lookup_int_table { + u32 *global_int_mask; + unsigned long processor_id; +}; + +#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000) diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index dfed45204..7f1b9ee7e 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -424,11 +424,7 @@ static void mcfrs_offintr(void *private) tty = info->tty; if (!tty) return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } @@ -835,10 +831,7 @@ static void mcfrs_flush_buffer(struct tty_struct *tty) info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; local_irq_restore(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1232,11 +1225,12 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; info->event = 0; info->tty = 0; +#if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); @@ -1245,6 +1239,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) if (tty->ldisc.open) (tty->ldisc.open)(tty); } +#endif if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index cb6b4f3ec..3a7ab51d2 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -40,6 +40,7 @@ #include #include #include +#include #if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 22a02bd69..70d2f8333 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -26,8 +26,6 @@ #include #include -#include - #if 0 #include #define dbg(x...) llprintk(x) @@ -677,7 +675,7 @@ serial_s3c2410_get_options(struct uart_port *port, int *baud, default: case S3C2410_LCON_PNONE: - /* nothing */ + *parity = 'n'; } /* now calculate the baud rate */ diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 24ef1cbf5..1ac6c9d81 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -107,15 +107,7 @@ static void uart_start(struct tty_struct *tty) static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - struct tty_struct *tty; - - tty = state->info->tty; - if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } + tty_wakeup(state->info->tty); } static inline void @@ -403,7 +395,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else - quot = port->uartclk / (16 * baud); + quot = (port->uartclk + (8 * baud)) / (16 * baud); return quot; } @@ -581,10 +573,7 @@ static void uart_flush_buffer(struct tty_struct *tty) spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1216,7 +1205,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; struct uart_port *port; - + BUG_ON(!kernel_locked()); if (!state || !state->port) @@ -1239,12 +1228,12 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("uart_close: bad serial port count; tty->count is 1, " + printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { - printk("rs_close: bad serial port count for %s: %d\n", + printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", tty->name, state->count); state->count = 0; } @@ -1280,8 +1269,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(state); uart_flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); + tty->closing = 0; state->info->tty = NULL; @@ -1978,6 +1968,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: + case UPIO_MEM32: printk("MMIO 0x%lx", port->mapbase); break; } diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index c3e6eb244..8557ed1ce 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -363,9 +363,10 @@ next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) /*====================================================================*/ -static int simple_config(dev_link_t * link) +static int simple_config(dev_link_t *link) { static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + static int size_table[2] = { 8, 16 }; client_handle_t handle = link->handle; struct serial_info *info = link->priv; tuple_t tuple; @@ -374,6 +375,7 @@ static int simple_config(dev_link_t * link) cistpl_cftable_entry_t *cf = &parse.cftable_entry; config_info_t config; int i, j, try; + int s; /* If the card is already configured, look up the port and irq */ i = pcmcia_get_configuration_info(handle, &config); @@ -399,29 +401,30 @@ static int simple_config(dev_link_t * link) tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ - for (try = 0; try < 2; try++) { - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if (i != CS_SUCCESS) - goto next_entry; - if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && - (cf->io.win[0].base != 0)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = (try == 0) ? - 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); - if (i == CS_SUCCESS) - goto found_port; + for (s = 0; s < 2; s++) { + for (try = 0; try < 2; try++) { + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i != CS_SUCCESS) + goto next_entry; + if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && + (cf->io.win[0].base != 0)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = (try == 0) ? + 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + i = pcmcia_request_io(link->handle, &link->io); + if (i == CS_SUCCESS) + goto found_port; + } +next_entry: + i = next_tuple(handle, &tuple, &parse); } - next_entry: - i = next_tuple(handle, &tuple, &parse); } } - /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 98b96c546..200bbce42 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -80,6 +81,12 @@ #define DEVICE_MAJOR 204 #define DEVICE_MINOR 40 +#ifdef CONFIG_MAGIC_SYSRQ +static char sysrq_serial_str[] = "\eSYS"; +static char *sysrq_serial_ptr = sysrq_serial_str; +static unsigned long sysrq_requested; +#endif /* CONFIG_MAGIC_SYSRQ */ + /* * Port definition - this kinda drives it all */ @@ -532,13 +539,15 @@ sn_debug_printf(const char *fmt, ...) * sn_receive_chars - Grab characters, pass them to tty layer * @port: Port to operate on * @regs: Saved registers (needed by uart_handle_sysrq_char) + * @flags: irq flags * * Note: If we're not registered with the serial core infrastructure yet, * we don't try to send characters to it... * */ static void -sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs) +sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs, + unsigned long flags) { int ch; struct tty_struct *tty; @@ -569,10 +578,34 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs) "obtaining data from the console (0x%0x)\n", ch); break; } -#if defined(CONFIG_SERIAL_SGI_L1_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (uart_handle_sysrq_char(&port->sc_port, ch, regs)) - continue; -#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE && CONFIG_MAGIC_SYSRQ */ +#ifdef CONFIG_MAGIC_SYSRQ + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; + + sysrq_requested = 0; + if (ch && time_before(jiffies, sysrq_timeout)) { + spin_unlock_irqrestore(&port->sc_port.lock, flags); + handle_sysrq(ch, regs, NULL); + spin_lock_irqsave(&port->sc_port.lock, flags); + /* ignore actual sysrq command char */ + continue; + } + } + if (ch == *sysrq_serial_ptr) { + if (!(*++sysrq_serial_ptr)) { + sysrq_requested = jiffies; + sysrq_serial_ptr = sysrq_serial_str; + } + /* + * ignore the whole sysrq string except for the + * leading escape + */ + if (ch != '\e') + continue; + } + else + sysrq_serial_ptr = sysrq_serial_str; +#endif /* CONFIG_MAGIC_SYSRQ */ /* record the character to pass up to the tty layer */ if (tty) { @@ -583,8 +616,6 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs) if (tty->flip.count == TTY_FLIPBUF_SIZE) break; } - else { - } port->sc_port.icount.rx++; } @@ -695,7 +726,7 @@ sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_lock_irqsave(&port->sc_port.lock, flags); if (status & SAL_CONSOLE_INTR_RECV) { - sn_receive_chars(port, regs); + sn_receive_chars(port, regs, flags); } if (status & SAL_CONSOLE_INTR_XMIT) { sn_transmit_chars(port, TRANSMIT_BUFFERED); @@ -714,7 +745,8 @@ sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int sn_sal_connect_interrupt(struct sn_cons_port *port) { - if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, SA_INTERRUPT, + if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, + SA_INTERRUPT | SA_SHIRQ, "SAL console driver", port) >= 0) { return SGI_UART_VECTOR; } @@ -743,7 +775,7 @@ sn_sal_timer_poll(unsigned long data) if (!port->sc_port.irq) { spin_lock_irqsave(&port->sc_port.lock, flags); - sn_receive_chars(port, NULL); + sn_receive_chars(port, NULL, flags); sn_transmit_chars(port, TRANSMIT_RAW); spin_unlock_irqrestore(&port->sc_port.lock, flags); mod_timer(&port->sc_timer, @@ -851,7 +883,6 @@ sn_sal_switch_to_interrupts(struct sn_cons_port *port) * Kernel console definitions */ -#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE static void sn_sal_console_write(struct console *, const char *, unsigned); static int __init sn_sal_console_setup(struct console *, char *); extern struct uart_driver sal_console_uart; @@ -867,9 +898,6 @@ static struct console sal_console = { }; #define SAL_CONSOLE &sal_console -#else -#define SAL_CONSOLE 0 -#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ static struct uart_driver sal_console_uart = { .owner = THIS_MODULE, @@ -895,11 +923,11 @@ sn_sal_module_init(void) { int retval; - printk(KERN_INFO "sn_console: Console driver init\n"); - if (!ia64_platform_is("sn2")) return -ENODEV; + printk(KERN_INFO "sn_console: Console driver init\n"); + if (USE_DYNAMIC_MINOR == 1) { misc.minor = MISC_DYNAMIC_MINOR; misc.name = DEVICE_NAME_DYNAMIC; @@ -969,8 +997,6 @@ sn_sal_module_exit(void) module_init(sn_sal_module_init); module_exit(sn_sal_module_exit); -#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE - /** * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required * @puts_raw : puts function to do the writing @@ -1085,7 +1111,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 */ @@ -1190,5 +1218,3 @@ sn_sal_serial_console_init(void) } console_initcall(sn_sal_serial_console_init); - -#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 494df5557..4c38513b2 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -768,25 +768,6 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0), &up->regs->rw.ccr2); - if (cflag & CRTSCTS) { - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_RTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FCTS, - &up->regs->rw.mode); - up->interrupt_mask1 &= ~SAB82532_IMR1_CSC; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - } else { - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FCTS, - &up->regs->rw.mode); - up->interrupt_mask1 |= SAB82532_IMR1_CSC; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - } writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode); } @@ -940,6 +921,7 @@ static int sunsab_console_setup(struct console *con, char *options) writeb(up->interrupt_mask1, &up->regs->w.imr1); sunsab_convert_to_sab(up, con->cflag, 0, baud); + sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); spin_unlock_irqrestore(&up->port.lock, flags); diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 02586518a..2446dd664 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -98,7 +98,7 @@ struct uart_sunsu_port { unsigned int irq; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -520,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -534,7 +534,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg case 0: #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -994,7 +994,7 @@ static spinlock_t sunsu_serio_lock = SPIN_LOCK_UNLOCKED; static int sunsu_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int lsr; @@ -1014,7 +1014,7 @@ static int sunsu_serio_write(struct serio *serio, unsigned char ch) static int sunsu_serio_open(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int ret; @@ -1031,7 +1031,7 @@ static int sunsu_serio_open(struct serio *serio) static void sunsu_serio_close(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunsu_serio_lock, flags); @@ -1284,54 +1284,58 @@ static struct uart_driver sunsu_reg = { .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(void) +static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) { - struct uart_sunsu_port *up; - int i; + struct serio *serio; - for (i = 0, up = sunsu_ports; i < 2; i++, up++) { - up->port.line = i; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); + up->port.line = channel; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); - if (up->su_type == SU_PORT_KBD) - up->cflag = B1200 | CS8 | CLOCAL | CREAD; - else - up->cflag = B4800 | CS8 | CLOCAL | CREAD; + if (up->su_type == SU_PORT_KBD) + up->cflag = B1200 | CS8 | CLOCAL | CREAD; + else + up->cflag = B4800 | CS8 | CLOCAL | CREAD; - sunsu_autoconfig(up); - if (up->port.type == PORT_UNKNOWN) - continue; + sunsu_autoconfig(up); + if (up->port.type == PORT_UNKNOWN) + return -1; - printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", - i, - up->port.membase, __irq_itoa(up->irq), - sunsu_type(&up->port)); + printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", + channel, + up->port.membase, __irq_itoa(up->irq), + sunsu_type(&up->port)); #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(*serio)); - up->serio.driver = up; + serio->port_data = up; - up->serio.type = SERIO_RS232; + serio->type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "sukbd"; + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "sums"; + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "sums", sizeof(serio->name)); } - up->serio.phys = (i == 0 ? "su/serio0" : "su/serio1"); + strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); - up->serio.write = sunsu_serio_write; - up->serio.open = sunsu_serio_open; - up->serio.close = sunsu_serio_close; + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; - serio_register_port(&up->serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "su%d: not enough memory for serio port\n", + channel); + } #endif - sunsu_startup(&up->port); - } + sunsu_startup(&up->port); return 0; } @@ -1680,10 +1684,12 @@ static int __init sunsu_probe(void) if (scan.msx != -1 && scan.kbx != -1) { sunsu_ports[0].su_type = SU_PORT_MS; sunsu_ports[0].port_node = scan.msnode; + sunsu_kbd_ms_init(&sunsu_ports[0], 0); + sunsu_ports[1].su_type = SU_PORT_KBD; sunsu_ports[1].port_node = scan.kbnode; + sunsu_kbd_ms_init(&sunsu_ports[1], 1); - sunsu_kbd_ms_init(); return 0; } @@ -1715,7 +1721,10 @@ static void __exit sunsu_exit(void) if (up->su_type == SU_PORT_MS || up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } #endif } else if (up->port.type != PORT_UNKNOWN) { uart_remove_one_port(&sunsu_reg, &up->port); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index b38c02593..11ec83d8e 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -107,7 +107,7 @@ struct uart_sunzilog_port { unsigned char prev_status; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -1295,7 +1295,7 @@ static spinlock_t sunzilog_serio_lock = SPIN_LOCK_UNLOCKED; static int sunzilog_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1309,7 +1309,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch) static int sunzilog_serio_open(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; int ret; @@ -1326,7 +1326,7 @@ static int sunzilog_serio_open(struct serio *serio) static void sunzilog_serio_close(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1545,33 +1545,44 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); sunzilog_convert_to_zs(up, up->cflag, 0, brg); + sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + __sunzilog_startup(up); +} #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); +static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) +{ + struct serio *serio; - up->serio.driver = up; + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(*serio)); - up->serio.type = SERIO_RS232; - if (channel == KEYBOARD_LINE) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "zskbd"; - } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "zsms"; - } - up->serio.phys = (channel == KEYBOARD_LINE ? - "zs/serio0" : "zs/serio1"); + serio->port_data = up; - up->serio.write = sunzilog_serio_write; - up->serio.open = sunzilog_serio_open; - up->serio.close = sunzilog_serio_close; + serio->type = SERIO_RS232; + if (channel == KEYBOARD_LINE) { + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); + } else { + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "zsms", sizeof(serio->name)); + } + strlcpy(serio->phys, + (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); - serio_register_port(&up->serio); -#endif + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; - sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - __sunzilog_startup(up); + serio_register_port(serio); + } else { + printk(KERN_WARNING "zs%d: not enough memory for serio port\n", + channel); + } } +#endif static void __init sunzilog_init_hw(void) { @@ -1615,6 +1626,11 @@ static void __init sunzilog_init_hw(void) } spin_unlock_irqrestore(&up->port.lock, flags); + +#ifdef CONFIG_SERIO + if (i == KEYBOARD_LINE || i == MOUSE_LINE) + sunzilog_register_serio(up, i); +#endif } } @@ -1732,10 +1748,15 @@ static void __exit sunzilog_exit(void) for (i = 0; i < NUM_CHANNELS; i++) { struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) - continue; - - uart_remove_one_port(&sunzilog_reg, &up->port); + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); } uart_unregister_driver(&sunzilog_reg); diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 7391ae649..c5befc9af 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -211,10 +211,6 @@ static void probe_sccs(void); static void change_speed(struct dec_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -683,10 +679,7 @@ static void do_softint(void *private_) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } @@ -706,7 +699,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 /* @@ -950,16 +943,16 @@ static int rs_write(struct tty_struct * tty, int from_user, save_flags(flags); while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; if (from_user) { down(&tmp_buf_sem); copy_from_user(tmp_buf, buf, c); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); up(&tmp_buf_sem); } else @@ -1010,10 +1003,7 @@ static void rs_flush_buffer(struct tty_struct *tty) cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -1356,7 +1346,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 +1361,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; } @@ -1407,8 +1397,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -1446,7 +1435,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (char_time == 0) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(char_time); @@ -1531,7 +1520,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 +1554,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 +1565,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 +1731,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 +1881,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 1d0a2e1a7..59a6515e7 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 ad23b28e6..143818a56 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/class/audio.c b/drivers/usb/class/audio.c index 42f60fa37..17a6dd747 100644 --- a/drivers/usb/class/audio.c +++ b/drivers/usb/class/audio.c @@ -1954,9 +1954,9 @@ static int usb_audio_open_mixdev(struct inode *inode, struct file *file) struct usb_audio_state *s; down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) { + list_for_each(mdevs, &s->mixerlist) { ms = list_entry(mdevs, struct usb_mixerdev, list); if (ms->dev_mixer == minor) goto mixer_found; @@ -2640,9 +2640,9 @@ static int usb_audio_open(struct inode *inode, struct file *file) for (;;) { down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) { + list_for_each(adevs, &s->audiolist) { as = list_entry(adevs, struct usb_audiodev, list); if (!((as->dev_audio ^ minor) & ~0xf)) goto device_found; @@ -3831,7 +3831,7 @@ static void usb_audio_disconnect(struct usb_interface *intf) usb_set_intfdata (intf, NULL); /* deregister all audio and mixer devices, so no new processes can open this device */ - for(list = s->audiolist.next; list != &s->audiolist; list = list->next) { + list_for_each(list, &s->audiolist) { as = list_entry(list, struct usb_audiodev, list); usbin_disc(as); usbout_disc(as); @@ -3843,7 +3843,7 @@ static void usb_audio_disconnect(struct usb_interface *intf) } as->dev_audio = -1; } - for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) { + list_for_each(list, &s->mixerlist) { ms = list_entry(list, struct usb_mixerdev, list); if (ms->dev_mixer >= 0) { unregister_sound_mixer(ms->dev_mixer); diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c index 2e8f5200c..4d8e01895 100644 --- a/drivers/usb/class/bluetty.c +++ b/drivers/usb/class/bluetty.c @@ -988,21 +988,13 @@ static void bluetooth_write_bulk_callback (struct urb *urb, struct pt_regs *regs static void bluetooth_softint(void *private) { struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__); - struct tty_struct *tty; dbg("%s", __FUNCTION__); - if (!bluetooth) { + if (!bluetooth) return; - } - - tty = bluetooth->tty; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg("%s - write wakeup call.", __FUNCTION__); - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); + tty_wakeup(bluetooth->tty); } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3fae8a6e4..a929a5212 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -142,7 +142,7 @@ static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs) case ACM_IRQ_LINE_STATE: - newctrl = le16_to_cpu(get_unaligned((__u16 *) data)); + newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); @@ -248,16 +248,11 @@ out: static void acm_softint(void *private) { struct acm *acm = private; - struct tty_struct *tty = acm->tty; dbg("Entering acm_softint.\n"); if (!ACM_READY(acm)) return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); + tty_wakeup(acm->tty); } /* @@ -367,7 +362,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c acm->writeurb->dev = acm->dev; acm->ready_for_write = 0; - stat = usb_submit_urb(acm->writeurb, GFP_NOIO); + stat = usb_submit_urb(acm->writeurb, from_user ? GFP_KERNEL : GFP_ATOMIC); if (stat < 0) { dbg("usb_submit_urb(write bulk) failed"); acm->ready_for_write = 1; @@ -583,19 +578,25 @@ next_desc: } if (!union_header) { - dev_dbg(&intf->dev,"No union descriptor, giving up\n"); - return -ENODEV; - } - - control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev,"no interfaces\n"); - return -ENODEV; + if (call_interface_num > 0) { + dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); + control_interface = intf; + } else { + dev_dbg(&intf->dev,"No union descriptor, giving up\n"); + return -ENODEV; + } + } else { + control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); + if (!control_interface || !data_interface) { + dev_dbg(&intf->dev,"no interfaces\n"); + return -ENODEV; + } } - if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); + if (data_interface_num != call_interface_num) + dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); if (usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev,"The data interface isn't available\n"); diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index bf72f278b..cc26d9517 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -70,7 +70,7 @@ */ struct acm_line { - __u32 speed; + __le32 speed; __u8 stopbits; __u8 parity; __u8 databits; diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c index 6a6dbac49..a9dc047a0 100644 --- a/drivers/usb/class/usb-midi.c +++ b/drivers/usb/class/usb-midi.c @@ -55,39 +55,39 @@ /* ------------------------------------------------------------------------- */ static int singlebyte = 0; -MODULE_PARM(singlebyte,"i"); +module_param(singlebyte, int, 0); MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet"); static int maxdevices = 4; -MODULE_PARM(maxdevices,"i"); +module_param(maxdevices, int, 0); MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device"); static int uvendor = -1; -MODULE_PARM(uvendor,"i"); +module_param(uvendor, int, 0); MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface"); static int uproduct = -1; -MODULE_PARM(uproduct,"i"); +module_param(uproduct, int, 0); MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface"); static int uinterface = -1; -MODULE_PARM(uinterface,"i"); +module_param(uinterface, int, 0); MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface"); static int ualt = -1; -MODULE_PARM(ualt,"i"); +module_param(ualt, int, 0); MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface"); static int umin = -1; -MODULE_PARM(umin,"i"); +module_param(umin, int, 0); MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface"); static int umout = -1; -MODULE_PARM(umout,"i"); +module_param(umout, int, 0); MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface"); static int ucable = -1; -MODULE_PARM(ucable,"i"); +module_param(ucable, int, 0); MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface"); /** Note -- the usb_string() returns only Latin-1 characters. @@ -95,7 +95,7 @@ MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface") * unicode16LE-to-JIS routine is needed to wrap around usb_get_string(). **/ static unsigned short ulangid = 0x0409; /** 0x0411 for Japanese **/ -MODULE_PARM(ulangid,"h"); +module_param(ulangid, ushort, 0); MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices"); MODULE_AUTHOR("NAGANO Daisuke "); @@ -817,9 +817,9 @@ static int usb_midi_open(struct inode *inode, struct file *file) for(;;) { down(&open_sem); - for (devs = mididevs.next; devs != &mididevs; devs = devs->next) { + list_for_each(devs, &mididevs) { s = list_entry(devs, struct usb_midi_state, mididev); - for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) { + list_for_each(mdevs, &s->midiDevList) { m = list_entry(mdevs, struct usb_mididev, list); if ( !((m->dev_midi ^ minor) & ~0xf) ) goto device_found; @@ -2012,7 +2012,7 @@ static void usb_midi_disconnect(struct usb_interface *intf) s->usbdev = NULL; usb_set_intfdata (intf, NULL); - for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) { + list_for_each(list, &s->midiDevList) { m = list_entry(list, struct usb_mididev, list); wake_up(&(m->min.ep->wait)); wake_up(&(m->mout.ep->wait)); diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index b6da40067..da91bbd67 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -221,7 +221,7 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol); static int usblp_cache_device_id_string(struct usblp *usblp); /* forward reference to make our lives easier */ -extern struct usb_driver usblp_driver; +static struct usb_driver usblp_driver; /* * Functions for usblp control messages. @@ -397,10 +397,6 @@ static void usblp_cleanup (struct usblp *usblp) { info("usblp%d: removed", usblp->minor); - usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, - usblp->writebuf, usblp->writeurb->transfer_dma); - usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, - usblp->readbuf, usblp->readurb->transfer_dma); kfree (usblp->device_id_string); kfree (usblp->statusbuf); usb_free_urb(usblp->writeurb); @@ -1129,7 +1125,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp) /* First two bytes are length in big-endian. * They count themselves, and we copy them into * the user's buffer. */ - length = be16_to_cpu(*((u16 *)usblp->device_id_string)); + length = be16_to_cpu(*((__be16 *)usblp->device_id_string)); if (length < 2) length = 2; else if (length >= USBLP_DEVICE_ID_SIZE) @@ -1159,6 +1155,10 @@ static void usblp_disconnect(struct usb_interface *intf) usb_set_intfdata (intf, NULL); usblp_unlink_urbs(usblp); + usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, + usblp->writebuf, usblp->writeurb->transfer_dma); + usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, + usblp->readbuf, usblp->readurb->transfer_dma); if (!usblp->used) usblp_cleanup (usblp); @@ -1208,6 +1208,6 @@ module_exit(usblp_exit); MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_PARM(proto_bias, "i"); +module_param(proto_bias, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 050b078e3..1a9ff6184 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -60,3 +60,40 @@ config USB_DYNAMIC_MINORS If you are unsure about this, say N here. +config USB_SUSPEND + bool "USB suspend/resume (EXPERIMENTAL)" + depends on USB && PM && EXPERIMENTAL + help + If you say Y here, you can use driver calls or the sysfs + "power/state" file to suspend or resume individual USB + peripherals. There are many related features, such as + remote wakeup and driver-specific suspend processing, that + may not yet work as expected. + + If you are unsure about this, say N here. + + +config USB_OTG + bool + depends on USB && EXPERIMENTAL + select USB_SUSPEND + default n + + +config USB_OTG_WHITELIST + bool "Rely on OTG Targeted Peripherals List" + depends on USB_OTG + default y + help + If you say Y here, the "otg_whitelist.h" file will be used as a + product whitelist, so USB peripherals not listed there will be + rejected during enumeration. This behavior is required by the + USB OTG specification for all devices not on your product's + "Targeted Peripherals List". + + Otherwise, peripherals not listed there will only generate a + warning and enumeration will continue. That's more like what + normal Linux-USB hosts do (other than the warning), and is + convenient for many stages of product development. + + diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index ae7ec7405..33c51714f 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/devices.c b/drivers/usb/core/devices.c index 5541363b6..8e535789f 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -283,9 +283,8 @@ static char *usb_dump_interface( /* TBD: * 0. TBDs - * 1. marking active config and ifaces (code lists all, but should mark + * 1. marking active interface altsettings (code lists all, but should mark * which ones are active, if any) - * 2. add status to each endpoint line */ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active) @@ -584,7 +583,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte /* enumerate busses */ down (&usb_bus_list_lock); - for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { + list_for_each(buslist, &usb_bus_list) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6f969a4da..776c1bf0d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -72,6 +72,8 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); } while (0) +#define MAX_USBFS_BUFFER_SIZE 16384 + static inline int connected (struct usb_device *dev) { return dev->state != USB_STATE_NOTATTACHED; @@ -555,8 +557,10 @@ static int proc_control(struct dev_state *ps, void __user *arg) snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); + up(&dev->serialize); i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + down(&dev->serialize); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); @@ -584,8 +588,10 @@ static int proc_control(struct dev_state *ps, void __user *arg) printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } + up(&dev->serialize); i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + down(&dev->serialize); } free_page((unsigned long)tbuf); if (i<0) { @@ -619,6 +625,8 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; + if (len1 > MAX_USBFS_BUFFER_SIZE) + return -EINVAL; if (!(tbuf = kmalloc(len1, GFP_KERNEL))) return -ENOMEM; tmo = (bulk.timeout * HZ + 999) / 1000; @@ -627,7 +635,9 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) kfree(tbuf); return -EINVAL; } + up(&dev->serialize); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + down(&dev->serialize); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); @@ -641,7 +651,9 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) return -EFAULT; } } + up(&dev->serialize); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + down(&dev->serialize); } kfree(tbuf); if (i < 0) { @@ -849,7 +861,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) case USBDEVFS_URB_TYPE_BULK: uurb.number_of_packets = 0; - if (uurb.buffer_length > 16384) + if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; @@ -891,7 +903,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) interval = 1 << min (15, ep_desc->bInterval - 1); else interval = ep_desc->bInterval; - if (uurb.buffer_length > 16384) + if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index e7a7ba513..5fdaae079 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -65,7 +65,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) { struct hc_driver *driver; unsigned long resource, len; - void *base; + void __iomem *base; struct usb_hcd *hcd; int retval, region; char buf [8], *bufp = buf; @@ -121,7 +121,7 @@ clean_1: dev_dbg (&dev->dev, "no i/o regions available\n"); return -EBUSY; } - base = (void *) resource; + base = (void __iomem *) resource; } // driver->reset(), later on, will transfer device from diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cd2268ad1..d970e2c0c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -708,6 +708,7 @@ int usb_register_bus(struct usb_bus *bus) bus->busnum = busnum; } else { printk (KERN_ERR "%s: too many buses\n", usbcore_name); + up(&usb_bus_list_lock); return -E2BIG; } @@ -790,6 +791,8 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64; retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { + usb_dev->bus->root_hub = NULL; + up (&usb_bus_list_lock); dev_dbg (parent_dev, "can't read %s device descriptor %d\n", usb_dev->dev.bus_id, retval); return (retval < 0) ? retval : -EMSGSIZE; @@ -1311,13 +1314,10 @@ static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) rescan: /* (re)block new requests, as best we can */ - if (endpoint & USB_DIR_IN) { - usb_endpoint_halt (udev, epnum, 0); + if (endpoint & USB_DIR_IN) udev->epmaxpacketin [epnum] = 0; - } else { - usb_endpoint_halt (udev, epnum, 1); + else udev->epmaxpacketout [epnum] = 0; - } /* then kill any current requests */ spin_lock (&hcd_data_lock); @@ -1407,6 +1407,45 @@ static int hcd_hub_resume (struct usb_bus *bus) /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_OTG + +/** + * usb_bus_start_enum - start immediate enumeration (for OTG) + * @bus: the bus (must use hcd framework) + * @port: 1-based number of port; usually bus->otg_port + * Context: in_interrupt() + * + * Starts enumeration, with an immediate reset followed later by + * khubd identifying and possibly configuring the device. + * This is needed by OTG controller drivers, where it helps meet + * HNP protocol timing requirements for starting a port reset. + */ +int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) +{ + struct usb_hcd *hcd; + int status = -EOPNOTSUPP; + + /* NOTE: since HNP can't start by grabbing the bus's address0_sem, + * boards with root hubs hooked up to internal devices (instead of + * just the OTG port) may need more attention to resetting... + */ + hcd = container_of (bus, struct usb_hcd, self); + if (port_num && hcd->driver->start_port_reset) + status = hcd->driver->start_port_reset(hcd, port_num); + + /* run khubd shortly after (first) root port reset finishes; + * it may issue others, until at least 50 msecs have passed. + */ + if (status == 0) + mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10)); + return status; +} +EXPORT_SYMBOL (usb_bus_start_enum); + +#endif + +/*-------------------------------------------------------------------------*/ + /* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup. * we're guaranteed that the device is fully quiesced. also, that each * endpoint has been hcd_endpoint_disabled. diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 89b6fc2e3..340977b72 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -77,7 +77,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ unsigned can_wakeup:1; /* hw supports wakeup? */ unsigned remote_wakeup:1;/* sw should use wakeup? */ int irq; /* irq allocated */ - void *regs; /* device memory/io */ + void __iomem *regs; /* device memory/io */ #ifdef CONFIG_PCI int region; /* pci region for regs */ @@ -212,6 +212,7 @@ struct hc_driver { char *buf, u16 wLength); int (*hub_suspend)(struct usb_hcd *); int (*hub_resume)(struct usb_hcd *); + int (*start_port_reset)(struct usb_hcd *, unsigned port_num); }; extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); @@ -376,8 +377,6 @@ extern void usb_bus_put (struct usb_bus *bus); extern int usb_find_interface_driver (struct usb_device *dev, struct usb_interface *interface); -#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) - #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) /* diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b13fe4040..7f72ee96c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -36,7 +36,7 @@ #include "hcd.h" #include "hub.h" -/* Protect all struct usb_device state members */ +/* Protect struct usb_device state and children members */ static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED; /* Wakes up khubd */ @@ -143,7 +143,7 @@ static void led_work (void *__hub) unsigned changed = 0; int cursor = -1; - if (hdev->state != USB_STATE_CONFIGURED) + if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing) return; for (i = 0; i < hub->descriptor->bNbrPorts; i++) { @@ -269,6 +269,9 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs) spin_unlock(&hub_event_lock); resubmit: + if (hub->quiescing) + return; + if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) dev_err (&hub->intf->dev, "resubmit --> %d\n", status); @@ -623,6 +626,33 @@ fail: static unsigned highspeed_hubs; +static void hub_quiesce(struct usb_hub *hub) +{ + /* stop khubd and related activity */ + hub->quiescing = 1; + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work(&hub->leds); + if (hub->has_indicators || hub->tt.hub) + flush_scheduled_work(); +} + +#ifdef CONFIG_USB_SUSPEND + +static void hub_reactivate(struct usb_hub *hub) +{ + int status; + + hub->quiescing = 0; + status = usb_submit_urb(hub->urb, GFP_NOIO); + if (status < 0) + dev_err(&hub->intf->dev, "reactivate --> %d\n", status); + if (hub->has_indicators && blinkenlights) + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +} + +#endif + static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -637,22 +667,14 @@ static void hub_disconnect(struct usb_interface *intf) usb_set_intfdata (intf, NULL); - if (hub->urb) { - usb_kill_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } + hub_quiesce(hub); + usb_free_urb(hub->urb); + hub->urb = NULL; spin_lock_irq(&hub_event_lock); list_del_init(&hub->event_list); spin_unlock_irq(&hub_event_lock); - /* assuming we used keventd, it must quiesce too */ - if (hub->has_indicators) - cancel_delayed_work (&hub->leds); - if (hub->has_indicators || hub->tt.hub) - flush_scheduled_work (); - if (hub->descriptor) { kfree(hub->descriptor); hub->descriptor = NULL; @@ -772,6 +794,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) } } +/* caller has locked the hub and must own the device lock */ static int hub_reset(struct usb_hub *hub) { struct usb_device *hdev = hub->hdev; @@ -789,7 +812,7 @@ static int hub_reset(struct usb_hub *hub) else return -1; - if (usb_reset_device(hdev)) + if (__usb_reset_device(hdev)) return -1; hub->urb->dev = hdev; @@ -801,6 +824,7 @@ static int hub_reset(struct usb_hub *hub) return 0; } +/* caller has locked the hub */ /* FIXME! This routine should be subsumed into hub_reset */ static void hub_start_disconnect(struct usb_device *hdev) { @@ -832,12 +856,65 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) udev->state = USB_STATE_NOTATTACHED; } +/* grab device/port lock, returning index of that port (zero based). + * protects the upstream link used by this device from concurrent + * tree operations like suspend, resume, reset, and disconnect, which + * apply to everything downstream of a given port. + */ +static int locktree(struct usb_device *udev) +{ + int t; + struct usb_device *hdev; + + if (!udev) + return -ENODEV; + + /* root hub is always the first lock in the series */ + hdev = udev->parent; + if (!hdev) { + down(&udev->serialize); + return 0; + } + + /* on the path from root to us, lock everything from + * top down, dropping parent locks when not needed + * + * NOTE: if disconnect were to ignore the locking, we'd need + * to get extra refcounts to everything since hdev->children + * and udev->parent could be invalidated while we work... + */ + t = locktree(hdev); + if (t < 0) + return t; + spin_lock_irq(&device_state_lock); + for (t = 0; t < hdev->maxchild; t++) { + if (hdev->children[t] == udev) { + /* everything is fail-fast once disconnect + * processing starts + */ + if (udev->state == USB_STATE_NOTATTACHED) + break; + + /* when everyone grabs locks top->bottom, + * non-overlapping work may be concurrent + */ + spin_unlock_irq(&device_state_lock); + down(&udev->serialize); + up(&hdev->serialize); + return t; + } + } + spin_unlock_irq(&device_state_lock); + up(&hdev->serialize); + return -ENODEV; +} + /** * usb_set_device_state - change a device's current state (usbcore-internal) * @udev: pointer to device whose state should be changed * @new_state: new state value to be stored * - * udev->state is _not_ protected by the udev->serialize semaphore. This + * udev->state is _not_ protected by the device lock. This * is so that devices can be marked as disconnected as soon as possible, * without having to wait for the semaphore to be released. Instead, * changes to the state must be protected by the device_state_lock spinlock. @@ -897,7 +974,7 @@ static void release_address(struct usb_device *udev) /** * usb_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected + * @pdev: pointer to device being disconnected, into a locked hub * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. @@ -921,7 +998,8 @@ void usb_disconnect(struct usb_device **pdev) } /* mark the device as inactive, so any further urb submissions for - * this device will fail. + * this device (and any of its children) will fail immediately. + * this quiesces everyting except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); @@ -940,6 +1018,7 @@ void usb_disconnect(struct usb_device **pdev) /* deallocate hcd/hardware state ... nuking all pending urbs and * cleaning up all state associated with the current configuration + * so that the hardware is now fully quiesced. */ usb_disable_device(udev, 0); @@ -952,7 +1031,7 @@ void usb_disconnect(struct usb_device **pdev) usbfs_remove_device(udev); usb_remove_sysfs_dev_files(udev); - /* Avoid races with recursively_mark_NOTATTACHED() */ + /* Avoid races with recursively_mark_NOTATTACHED() and locktree() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); @@ -1016,6 +1095,10 @@ static inline void show_string(struct usb_device *udev, char *id, int index) {} #endif +#ifdef CONFIG_USB_OTG +#include "otg_whitelist.h" +#endif + /** * usb_new_device - perform initial device setup (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) @@ -1065,6 +1148,79 @@ int usb_new_device(struct usb_device *udev) show_string(udev, "SerialNumber", udev->descriptor.iSerialNumber); +#ifdef CONFIG_USB_OTG + /* + * OTG-aware devices on OTG-capable root hubs may be able to use SRP, + * to wake us after we've powered off VBUS; and HNP, switching roles + * "host" to "peripheral". The OTG descriptor helps figure this out. + */ + if (!udev->bus->is_b_host + && udev->config + && udev->parent == udev->bus->root_hub) { + struct usb_otg_descriptor *desc = 0; + struct usb_bus *bus = udev->bus; + + /* descriptor may appear anywhere in config */ + if (__usb_get_extra_descriptor (udev->rawdescriptors[0], + udev->config[0].desc.wTotalLength, + USB_DT_OTG, (void **) &desc) == 0) { + if (desc->bmAttributes & USB_OTG_HNP) { + unsigned port; + struct usb_device *root = udev->parent; + + for (port = 0; port < root->maxchild; port++) { + if (root->children[port] == udev) + break; + } + port++; + + dev_info(&udev->dev, + "Dual-Role OTG device on %sHNP port\n", + (port == bus->otg_port) + ? "" : "non-"); + + /* enable HNP before suspend, it's simpler */ + if (port == bus->otg_port) + bus->b_hnp_enable = 1; + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + bus->b_hnp_enable + ? USB_DEVICE_B_HNP_ENABLE + : USB_DEVICE_A_ALT_HNP_SUPPORT, + 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + if (err < 0) { + /* OTG MESSAGE: report errors here, + * customize to match your product. + */ + dev_info(&udev->dev, + "can't set HNP mode; %d\n", + err); + bus->b_hnp_enable = 0; + } + } + } + } + + if (!is_targeted(udev)) { + + /* Maybe it can talk to us, though we can't talk to it. + * (Includes HNP test device.) + */ + if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { + static int __usb_suspend_device (struct usb_device *, + int port, u32 state); + err = __usb_suspend_device(udev, + udev->bus->otg_port - 1, + PM_SUSPEND_MEM); + if (err < 0) + dev_dbg(&udev->dev, "HNP fail, %d\n", err); + } + err = -ENODEV; + goto fail; + } +#endif + /* put device-specific files into sysfs */ err = device_add (&udev->dev); if (err) { @@ -1203,6 +1359,7 @@ static int hub_port_reset(struct usb_device *hdev, int port, if (status == -ENOTCONN || status == 0) { clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_RESET); + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); @@ -1226,9 +1383,11 @@ static int hub_port_disable(struct usb_device *hdev, int port) { int ret; - if (hdev->children[port]) + if (hdev->children[port]) { + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(hdev->children[port], USB_STATE_NOTATTACHED); + } ret = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_ENABLE); if (ret) dev_err(hubdev(hdev), "cannot disable port %d (err = %d)\n", @@ -1239,7 +1398,490 @@ static int hub_port_disable(struct usb_device *hdev, int port) #ifdef CONFIG_USB_SUSPEND - /* no USB_SUSPEND yet! */ +/* + * Selective port suspend reduces power; most suspended devices draw + * less than 500 uA. It's also used in OTG, along with remote wakeup. + * All devices below the suspended port are also suspended. + * + * Devices leave suspend state when the host wakes them up. Some devices + * also support "remote wakeup", where the device can activate the USB + * tree above them to deliver data, such as a keypress or packet. In + * some cases, this wakes the USB host. + */ +static int hub_port_suspend(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "suspend port %d\n", port); + + /* enable remote wakeup when appropriate; this lets the device + * wake up the upstream hub (including maybe the root hub). + * + * NOTE: OTG devices may issue remote wakeup (or SRP) even when + * we don't explicitly enable it here. + */ + if (udev->actconfig + // && FIXME (remote wakeup enabled on this bus) + // ... currently assuming it's always appropriate + && (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP) != 0) { + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) + dev_dbg(&udev->dev, + "won't remote wakeup, status %d\n", + status); + } + + /* see 7.1.7.6 */ + status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(hubdev(hdev), + "can't suspend port %d, status %d\n", + port, status); + /* paranoia: "should not happen" */ + (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + /* device has up to 10 msec to fully suspend */ + dev_dbg(&udev->dev, "usb suspend\n"); + udev->state = USB_STATE_SUSPENDED; + msleep(10); + } + return status; +} + +/* + * Devices on USB hub ports have only one "suspend" state, corresponding + * to ACPI D2 (PM_SUSPEND_MEM), "may cause the device to lose some context". + * State transitions include: + * + * - suspend, resume ... when the VBUS power link stays live + * - suspend, disconnect ... VBUS lost + * + * Once VBUS drop breaks the circuit, the port it's using has to go through + * normal re-enumeration procedures, starting with enabling VBUS power. + * Other than re-initializing the hub (plug/unplug, except for root hubs), + * Linux (2.6) currently has NO mechanisms to initiate that: no khubd + * timer, no SRP, no requests through sysfs. + */ +static int __usb_suspend_device (struct usb_device *udev, int port, u32 state) +{ + int status; + + if (port < 0) + return port; + + /* NOTE: udev->serialize released on all real returns! */ + + if (state <= udev->dev.power.power_state + || state < PM_SUSPEND_MEM + || udev->state == USB_STATE_SUSPENDED + || udev->state == USB_STATE_NOTATTACHED) { + up(&udev->serialize); + return 0; + } + + /* suspend interface drivers; if this is a hub, it + * suspends the child devices + */ + if (udev->actconfig) { + int i; + + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (state <= intf->dev.power.power_state) + continue; + if (!intf->dev.driver) + continue; + driver = to_usb_driver(intf->dev.driver); + + if (driver->suspend) { + status = driver->suspend(intf, state); + if (intf->dev.power.power_state != state + || status) + dev_err(&intf->dev, + "suspend %d fail, code %d\n", + state, status); + } + + /* only drivers with suspend() can ever resume(); + * and after power loss, even they won't. + * bus_rescan_devices() can rebind drivers later. + * + * FIXME the PM core self-deadlocks when unbinding + * drivers during suspend/resume ... everything grabs + * dpm_sem (not a spinlock, ugh). we want to unbind, + * since we know every driver's probe/disconnect works + * even for drivers that can't suspend. + */ + if (!driver->suspend || state > PM_SUSPEND_MEM) { +#if 1 + dev_warn(&intf->dev, "resume is unsafe!\n"); +#else + down_write(&usb_bus_type.rwsem); + device_release_driver(&intf->dev); + up_write(&usb_bus_type.rwsem); +#endif + } + } + } + + /* + * FIXME this needs port power off call paths too, to help force + * USB into the "generic" PM model. At least for devices on + * ports that aren't using ganged switching (usually root hubs). + * + * NOTE: SRP-capable links should adopt more aggressive poweroff + * policies (when HNP doesn't apply) once we have mechanisms to + * turn power back on! (Likely not before 2.7...) + */ + if (state > PM_SUSPEND_MEM) { + dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); + state = PM_SUSPEND_MEM; + } + + /* "global suspend" of the HC-to-USB interface (root hub), or + * "selective suspend" of just one hub-device link. + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_suspend) + status = bus->op->hub_suspend (bus); + else + status = -EOPNOTSUPP; + } else + status = hub_port_suspend(udev->parent, port + 1); + + if (status == 0) + udev->dev.power.power_state = state; + up(&udev->serialize); + return status; +} + +/** + * usb_suspend_device - suspend a usb device + * @udev: device that's no longer in active use + * @state: PM_SUSPEND_MEM to suspend + * Context: must be able to sleep; device not locked + * + * Suspends a USB device that isn't in active use, conserving power. + * Devices may wake out of a suspend, if anything important happens, + * using the remote wakeup mechanism. They may also be taken out of + * suspend by the host, using usb_resume_device(). It's also routine + * to disconnect devices while they are suspended. + * + * Suspending OTG devices may trigger HNP, if that's been enabled + * between a pair of dual-role devices. That will change roles, such + * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. + * + * Returns 0 on success, else negative errno. + */ +int usb_suspend_device(struct usb_device *udev, u32 state) +{ + return __usb_suspend_device(udev, locktree(udev), state); +} + +/* + * hardware resume signaling is finished, either because of selective + * resume (by host) or remote wakeup (by device) ... now see what changed + * in the tree that's rooted at this device. + */ +static int finish_port_resume(struct usb_device *udev) +{ + int status; + u16 devstatus; + + /* caller owns udev->serialize */ + dev_dbg(&udev->dev, "usb resume\n"); + udev->dev.power.power_state = PM_SUSPEND_ON; + + /* usb ch9 identifies four variants of SUSPENDED, based on what + * state the device resumes to. Linux currently won't see the + * first two on the host side; they'd be inside hub_port_init() + * during many timeouts, but khubd can't suspend until later. + */ + udev->state = udev->actconfig + ? USB_STATE_CONFIGURED + : USB_STATE_ADDRESS; + + /* 10.5.4.5 says be sure devices in the tree are still there. + * For now let's assume the device didn't go crazy on resume, + * and device drivers will know about any resume quirks. + */ + status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); + if (status < 0) + dev_dbg(&udev->dev, + "gone after usb resume? status %d\n", + status); + else if (udev->actconfig) { + unsigned i; + + le16_to_cpus(&devstatus); + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) { + dev_dbg(&udev->dev, "disable remote " + "wakeup, status %d\n", status); + status = 0; + } + } + + /* resume interface drivers; if this is a hub, it + * resumes the child devices + */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (intf->dev.power.power_state == PM_SUSPEND_ON) + continue; + if (!intf->dev.driver) { + /* FIXME maybe force to alt 0 */ + continue; + } + driver = to_usb_driver(intf->dev.driver); + + /* bus_rescan_devices() may rebind drivers */ + if (!driver->resume) + continue; + + /* can we do better than just logging errors? */ + status = driver->resume(intf); + if (intf->dev.power.power_state != PM_SUSPEND_ON + || status) + dev_dbg(&intf->dev, + "resume fail, state %d code %d\n", + intf->dev.power.power_state, status); + } + status = 0; + + } else if (udev->devnum <= 0) { + dev_dbg(&udev->dev, "bogus resume!\n"); + status = -EINVAL; + } + return status; +} + +static int +hub_port_resume(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "resume port %d\n", port); + + /* see 7.1.7.7; affects power usage, but not budgeting */ + status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "can't resume port %d, status %d\n", + port, status); + } else { + u16 devstatus; + u16 portchange; + + /* drive resume for at least 20 msec */ + dev_dbg(&udev->dev, "RESUME\n"); + msleep(25); + +#define LIVE_FLAGS ( USB_PORT_STAT_POWER \ + | USB_PORT_STAT_ENABLE \ + | USB_PORT_STAT_CONNECTION) + + /* Virtual root hubs can trigger on GET_PORT_STATUS to + * stop resume signaling. Then finish the resume + * sequence. + */ + devstatus = portchange = 0; + status = hub_port_status(hdev, port - 1, + &devstatus, &portchange); + if (status < 0 + || (devstatus & LIVE_FLAGS) != LIVE_FLAGS + || (devstatus & USB_PORT_STAT_SUSPEND) != 0 + ) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "port %d status %04x.%04x after resume, %d\n", + port, portchange, devstatus, status); + } else { + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + } + if (status < 0) + status = hub_port_disable(hdev, port); + + return status; +} + +static int hub_resume (struct usb_interface *intf); + +/** + * usb_resume_device - re-activate a suspended usb device + * @udev: device to re-activate + * Context: must be able to sleep; device not locked + * + * This will re-activate the suspended device, increasing power usage + * while letting drivers communicate again with its endpoints. + * USB resume explicitly guarantees that the power session between + * the host and the device is the same as it was when the device + * suspended. + * + * Returns 0 on success, else negative errno. + */ +int usb_resume_device(struct usb_device *udev) +{ + int port, status; + + port = locktree(udev); + if (port < 0) + return port; + + /* "global resume" of the HC-to-USB interface (root hub), or + * selective resume of one hub-to-device port + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_resume) + status = bus->op->hub_resume (bus); + else + status = -EOPNOTSUPP; + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + status = hub_resume (bus->root_hub + ->actconfig->interface[0]); + } + } else if (udev->state == USB_STATE_SUSPENDED) { + status = hub_port_resume(udev->parent, port + 1); + } else { + status = 0; + udev->dev.power.power_state = PM_SUSPEND_ON; + } + if (status < 0) { + dev_dbg(&udev->dev, "can't resume, status %d\n", + status); + } + + up(&udev->serialize); + + /* rebind drivers that had no suspend() */ + bus_rescan_devices(&usb_bus_type); + + return status; +} + +static int remote_wakeup(struct usb_device *udev) +{ + int status = 0; + + /* don't repeat RESUME sequence if this device + * was already woken up by some other task + */ + down(&udev->serialize); + if (udev->state == USB_STATE_SUSPENDED) { + dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + up(&udev->serialize); + return status; +} + +static int hub_suspend(struct usb_interface *intf, u32 state) +{ + struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_device *hdev = hub->hdev; + unsigned port; + int status; + + /* stop khubd and related activity */ + hub_quiesce(hub); + + /* then suspend every port */ + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + + udev = hdev->children [port]; + if (!udev) + continue; + down(&udev->serialize); + status = __usb_suspend_device(udev, port, state); + if (status < 0) + dev_dbg(&intf->dev, "suspend port %d --> %d\n", + port, status); + } + + intf->dev.power.power_state = state; + return 0; +} + +static int hub_resume(struct usb_interface *intf) +{ + struct usb_device *hdev = interface_to_usbdev(intf); + struct usb_hub *hub = usb_get_intfdata (intf); + unsigned port; + int status; + + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + u16 portstat, portchange; + + udev = hdev->children [port]; + status = hub_port_status(hdev, port, &portstat, &portchange); + if (status == 0) { + if (portchange & USB_PORT_STAT_C_SUSPEND) { + clear_port_feature(hdev, port + 1, + USB_PORT_FEAT_C_SUSPEND); + portchange &= ~USB_PORT_STAT_C_SUSPEND; + } + + /* let khubd handle disconnects etc */ + if (portchange) + continue; + } + + if (!udev) + continue; + down (&udev->serialize); + if (portstat & USB_PORT_STAT_SUSPEND) + status = hub_port_resume(hdev, port + 1); + else { + status = finish_port_resume(udev); + if (status < 0) + status = hub_port_disable(hdev, port); + if (status < 0) + dev_dbg(&intf->dev, "resume port %d --> %d\n", + port, status); + } + up(&udev->serialize); + } + intf->dev.power.power_state = PM_SUSPEND_ON; + + hub_reactivate(hub); + return 0; +} #else /* !CONFIG_USB_SUSPEND */ @@ -1369,6 +2011,10 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port) hdev->bus->b_hnp_enable = 0; } + retval = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (retval < 0 && retval != -EPIPE) + dev_dbg(&udev->dev, "can't clear suspend; %d\n", retval); + /* Some low speed devices have problems with the quick delay, so */ /* be a bit pessimistic with those devices. RHbug #23670 */ if (oldspeed == USB_SPEED_LOW) @@ -1479,8 +2125,6 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port) != udev->descriptor.bMaxPacketSize0)) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - usb_endpoint_running(udev, 0, 1); - usb_endpoint_running(udev, 0, 0); udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0; udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0; } @@ -1574,6 +2218,7 @@ hub_power_remaining (struct usb_hub *hub) * a port enable-change occurs (often caused by EMI); * usb_reset_device() encounters changed descriptors (as from * a firmware download) + * caller already locked the hub */ static void hub_port_connect_change(struct usb_hub *hub, int port, u16 portstatus, u16 portchange) @@ -1596,6 +2241,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port, usb_disconnect(&hdev->children[port]); clear_bit(port, hub->change_bits); +#ifdef CONFIG_USB_OTG + /* during HNP, don't repeat the debounce */ + if (hdev->bus->is_b_host) + portchange &= ~USB_PORT_STAT_C_CONNECTION; +#endif + if (portchange & USB_PORT_STAT_C_CONNECTION) { status = hub_port_debounce(hdev, port); if (status < 0) { @@ -1780,7 +2431,8 @@ static void hub_events(void) /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ - down(&hdev->serialize); + if (locktree(hdev) < 0) + break; if (hdev->state != USB_STATE_CONFIGURED || !hdev->actconfig || hub != usb_get_intfdata( @@ -2034,7 +2686,7 @@ static int config_descriptors_changed(struct usb_device *udev) } /** - * usb_reset_devce - perform a USB port reset to reinitialize a device + * usb_reset_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) * * WARNING - don't reset any device unless drivers for all of its @@ -2123,7 +2775,7 @@ int __usb_reset_device(struct usb_device *udev) struct usb_interface *intf = udev->actconfig->interface[i]; struct usb_interface_descriptor *desc; - /* set_interface resets host side toggle and halt status even + /* set_interface resets host side toggle even * for altsetting zero. the interface may have no driver. */ desc = &intf->cur_altsetting->desc; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 9e81738fd..7ace2d24d 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -60,8 +60,8 @@ * See USB 2.0 spec Table 11-19 and Table 11-20 */ struct usb_port_status { - __u16 wPortStatus; - __u16 wPortChange; + __le16 wPortStatus; + __le16 wPortChange; } __attribute__ ((packed)); /* @@ -103,8 +103,8 @@ struct usb_port_status { #define HUB_CHAR_PORTIND 0x0080 /* D7 */ struct usb_hub_status { - __u16 wHubStatus; - __u16 wHubChange; + __le16 wHubStatus; + __le16 wHubChange; } __attribute__ ((packed)); /* @@ -190,8 +190,8 @@ struct usb_hub { struct usb_device *hdev; struct urb *urb; /* for interrupt polling pipe */ - /* buffer for urb ... 1 bit each for hub and children, rounded up */ - char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8]; + /* buffer for urb ... with extra space in case of babble */ + char (*buffer)[8]; dma_addr_t buffer_dma; /* DMA address for buffer */ union { struct usb_hub_status hub; @@ -214,6 +214,8 @@ struct usb_hub { u8 power_budget; /* in 2mA units; or zero */ + unsigned quiescing:1; + unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; struct work_struct leds; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index d73c3ad45..c9f57e334 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -345,30 +345,13 @@ static int usbfs_unlink (struct inode *dir, struct dentry *dentry) return 0; } -static void d_unhash(struct dentry *dentry) -{ - dget(dentry); - spin_lock(&dcache_lock); - switch (atomic_read(&dentry->d_count)) { - default: - spin_unlock(&dcache_lock); - shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); - if (atomic_read(&dentry->d_count) != 2) - break; - case 2: - __d_drop(dentry); - } - spin_unlock(&dcache_lock); -} - static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) { int error = -ENOTEMPTY; struct inode * inode = dentry->d_inode; down(&inode->i_sem); - d_unhash(dentry); + dentry_unhash(dentry); if (usbfs_empty(dentry)) { dentry->d_inode->i_nlink -= 2; dput(dentry); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index e0eacc28a..98695c68d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -248,7 +248,7 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs) * unlink pending urbs so they won't rx/tx bad data. */ for (i = 0, found = 0; i < io->entries; i++) { - if (!io->urbs [i]) + if (!io->urbs [i] || !io->urbs [i]->dev) continue; if (found) { status = usb_unlink_urb (io->urbs [i]); @@ -337,7 +337,7 @@ int usb_sg_init ( if (io->entries <= 0) return io->entries; - io->count = 0; + io->count = io->entries; io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); if (!io->urbs) goto nomem; @@ -347,7 +347,7 @@ int usb_sg_init ( if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; - for (i = 0; i < io->entries; i++, io->count = i) { + for (i = 0; i < io->entries; i++) { unsigned len; io->urbs [i] = usb_alloc_urb (0, mem_flags); @@ -477,24 +477,19 @@ void usb_sg_wait (struct usb_sg_request *io) /* fail any uncompleted urbs */ default: - spin_lock_irq (&io->lock); - io->count -= entries - i; - if (io->status == -EINPROGRESS) - io->status = retval; - if (io->count == 0) - complete (&io->complete); - spin_unlock_irq (&io->lock); - - io->urbs[i]->dev = NULL; + io->urbs [i]->dev = NULL; io->urbs [i]->status = retval; dev_dbg (&io->dev->dev, "%s, submit --> %d\n", __FUNCTION__, retval); usb_sg_cancel (io); } spin_lock_irq (&io->lock); - if (retval && io->status == -ECONNRESET) + if (retval && (io->status == 0 || io->status == -ECONNRESET)) io->status = retval; } + io->count -= entries - i; + if (io->count == 0) + complete (&io->complete); spin_unlock_irq (&io->lock); /* OK, yes, this could be packaged as non-blocking. @@ -577,8 +572,13 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, HZ * USB_CTRL_GET_TIMEOUT); - if (!(result == 0 || result == -EPIPE)) - break; + if (result == 0 || result == -EPIPE) + continue; + if (result > 1 && ((u8 *)buf)[1] != type) { + result = -EPROTO; + continue; + } + break; } return result; } @@ -854,9 +854,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * the copy in usb-storage, for as long as we need two copies. */ - /* toggle was reset by the clear, then ep was reactivated */ + /* toggle was reset by the clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); return 0; } @@ -870,9 +869,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * Deallocates hcd/hardware state for this endpoint ... and nukes all * pending urbs. * - * If the HCD hasn't registered a disable() function, this marks the - * endpoint as halted and sets its maxpacket size to 0 to prevent - * further submissions. + * If the HCD hasn't registered a disable() function, this sets the + * endpoint's maxpacket size to 0 to prevent further submissions. */ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) { @@ -881,13 +879,10 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) else { unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - if (usb_endpoint_out(epaddr)) { - usb_endpoint_halt(dev, epnum, 1); + if (usb_endpoint_out(epaddr)) dev->epmaxpacketout[epnum] = 0; - } else { - usb_endpoint_halt(dev, epnum, 0); + else dev->epmaxpacketin[epnum] = 0; - } } } @@ -930,7 +925,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) usb_disable_endpoint(dev, i + USB_DIR_IN); } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -966,9 +960,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * @dev: the device whose interface is being enabled * @epd: pointer to the endpoint descriptor * - * Marks the endpoint as running, resets its toggle, and stores - * its maxpacket value. For control endpoints, both the input - * and output sides are handled. + * Resets the endpoint toggle and stores its maxpacket value. + * For control endpoints, both the input and output sides are handled. */ void usb_enable_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *epd) @@ -980,12 +973,10 @@ void usb_enable_endpoint(struct usb_device *dev, USB_ENDPOINT_XFER_CONTROL); if (usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 1); usb_settoggle(dev, epnum, 1, 0); dev->epmaxpacketout[epnum] = maxsize; } if (!usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 0); usb_settoggle(dev, epnum, 0, 0); dev->epmaxpacketin[epnum] = maxsize; } @@ -1048,6 +1039,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) int ret; int manual = 0; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + iface = usb_ifnum_to_if(dev, interface); if (!iface) { dev_dbg(&dev->dev, "selecting invalid interface %d\n", @@ -1145,6 +1139,9 @@ int usb_reset_configuration(struct usb_device *dev) int i, retval; struct usb_host_config *config; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + /* caller must own dev->serialize (config won't change) * and the usb bus readlock (so driver bindings are stable); * so calls during probe() are fine @@ -1166,7 +1163,6 @@ int usb_reset_configuration(struct usb_device *dev) } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { @@ -1195,7 +1191,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); } @@ -1258,6 +1254,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ n = nintf = 0; diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h new file mode 100644 index 000000000..8bf4e8111 --- /dev/null +++ b/drivers/usb/core/otg_whitelist.h @@ -0,0 +1,112 @@ +/* + * drivers/usb/core/otg_whitelist.h + * + * Copyright (C) 2004 Texas Instruments + * + * 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 OTG Whitelist is the OTG "Targeted Peripheral List". It should + * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries.. + * + * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! + */ + +static struct usb_device_id whitelist_table [] = { + +/* hubs are optional in OTG, but very handy ... */ +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), }, + +#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */ +/* FIXME actually, printers are NOT supposed to use device classes; + * they're supposed to use interface classes... + */ +{ USB_DEVICE_INFO(7, 1, 1) }, +{ USB_DEVICE_INFO(7, 1, 2) }, +{ USB_DEVICE_INFO(7, 1, 3) }, +#endif + +#ifdef CONFIG_USB_CDCETHER +/* Linux-USB CDC Ethernet gadget */ +{ USB_DEVICE(0x0525, 0xa4a1), }, +/* Linux-USB CDC Ethernet + RNDIS gadget */ +{ USB_DEVICE(0x0525, 0xa4a2), }, +#endif + +#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE) +/* gadget zero, for testing */ +{ USB_DEVICE(0x0525, 0xa4a0), }, +#endif + +{ } /* Terminating entry */ +}; + +static int is_targeted(struct usb_device *dev) +{ + struct usb_device_id *id = whitelist_table; + + /* possible in developer configs only! */ + if (!dev->bus->otg_port) + return 1; + + /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ + if (dev->descriptor.idVendor == 0x1a0a + && dev->descriptor.idProduct == 0xbadd) + return 0; + + /* NOTE: can't use usb_match_id() since interface caches + * aren't set up yet. this is cut/paste from that code. + */ + for (id = whitelist_table; id->match_flags; id++) { + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + id->idVendor != dev->descriptor.idVendor) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && + id->idProduct != dev->descriptor.idProduct) + continue; + + /* No need to test id->bcdDevice_lo != 0, since 0 is never + greater than any unsigned number. */ + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && + (id->bcdDevice_lo > dev->descriptor.bcdDevice)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && + (id->bcdDevice_hi < dev->descriptor.bcdDevice)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && + (id->bDeviceClass != dev->descriptor.bDeviceClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && + (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) + continue; + + return 1; + } + + /* add other match criteria here ... */ + + + /* OTG MESSAGE: report errors here, customize to match your product */ + dev_err(&dev->dev, "device v%04x p%04x is not supported\n", + dev->descriptor.idVendor, + dev->descriptor.idProduct); +#ifdef CONFIG_USB_OTG_WHITELIST + return 0; +#else + return 1; +#endif +} + diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 777f34ea6..3c14361bb 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); } /** @@ -256,13 +256,6 @@ int usb_submit_urb(struct urb *urb, int mem_flags) if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; - /* (actually HCDs may need to duplicate this, endpoint might yet - * stall due to queued bulk/intr transactions that complete after - * we check) - */ - if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out)) - return -EPIPE; - /* FIXME there should be a sharable lock protecting us against * config/altsetting changes and disconnects, kicking in here. * (here == before maxpacket, and eventually endpoint type, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 324e16caf..de2edfb08 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -93,6 +93,8 @@ int usb_probe_interface(struct device *dev) if (!driver->probe) return error; + if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; id = usb_match_id (intf, driver->id_table); if (id) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 7d978af3a..f1dff4f4d 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/Kconfig b/drivers/usb/gadget/Kconfig index 9189fb0da..decbca335 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -135,6 +135,18 @@ config USB_SA1100 depends on USB_GADGET_SA1100 default USB_GADGET +config USB_GADGET_LH7A40X + boolean "LH7A40X" + depends on ARCH_LH7A40X + help + This driver provides USB Device Controller driver for LH7A40x + +config USB_LH7A40X + tristate + depends on USB_GADGET_LH7A40X + default USB_GADGET + + config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" depends on USB && EXPERIMENTAL @@ -163,6 +175,41 @@ config USB_DUMMY_HCD depends on USB_GADGET_DUMMY_HCD default USB_GADGET +config USB_GADGET_OMAP + boolean "OMAP USB Device Controller" + depends on ARCH_OMAP + select ISP1301_OMAP if MACH_OMAP_H2 + help + Many Texas Instruments OMAP processors have flexible full + speed USB device controllers, with support for up to 30 + endpoints (plus endpoint zero). This driver supports the + controller in the OMAP 1611, and should work with controllers + in other OMAP processors too, given minor tweaks. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "omap_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_OMAP + tristate + depends on USB_GADGET_OMAP + default USB_GADGET + +config USB_OTG + boolean "OTG Support" + depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD + help + The most notable feature of USB OTG is support for a + "Dual-Role" device, which can act as either a device + or a host. The initial role choice can be changed + later, when two dual-role devices talk to each other. + + Select this only if your OMAP board has a Mini-AB connector. + +config USB_OMAP_PROC + boolean "/proc/driver/udc file" + depends on USB_GADGET_OMAP + endchoice config USB_GADGET_DUALSPEED @@ -275,7 +322,7 @@ config USB_GADGETFS dynamically linked module called "gadgetfs". config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEVELOPMENT)" + tristate "File-backed Storage Gadget" # we don't support the SA1100 because of its limitations depends on USB_GADGET_SA1100 = n help @@ -288,7 +335,7 @@ config USB_FILE_STORAGE dynamically linked module called "g_file_storage". config USB_FILE_STORAGE_TEST - bool "File-backed Storage Gadget test version" + bool "File-backed Storage Gadget testing version" depends on USB_FILE_STORAGE default n help diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 645d15cf5..03c639bfd 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -5,13 +5,15 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o +obj-$(CONFIG_USB_OMAP) += omap_udc.o +obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o # # USB gadget drivers # g_zero-objs := zero.o usbstring.o config.o epautoconf.o g_ether-objs := ether.o usbstring.o config.o epautoconf.o -g_serial-objs := serial.o usbstring.o +g_serial-objs := serial.o usbstring.o epautoconf.o gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4c1b157cf..91e878642 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -596,14 +596,13 @@ static const struct usb_gadget_ops dummy_ops = { /* "function" sysfs attribute */ static ssize_t -show_function (struct device *_dev, char *buf) +show_function (struct device *dev, char *buf) { - struct dummy *dum = the_controller; + struct dummy *dum = gadget_dev_to_dummy (dev); - if (!dum->driver->function - || strlen (dum->driver->function) > PAGE_SIZE) + if (!dum->driver || !dum->driver->function) return 0; - return snprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); + return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } DEVICE_ATTR (function, S_IRUGO, show_function, NULL); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 174afd47b..763d05521 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -63,6 +63,7 @@ /* * Ethernet gadget driver -- with CDC and non-CDC options + * Builds on hardware support for a full duplex link. * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB. Real hardware tends to use the same framing protocol but look @@ -242,6 +243,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif +#ifdef CONFIG_USB_GADGET_LH7A40X +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_SA1100 /* use non-CDC for backwards compatibility */ #define DEV_CONFIG_SUBSET @@ -855,7 +860,7 @@ static char product_desc [40] = DRIVER_DESC; static char ethaddr [2 * ETH_ALEN + 1]; #endif -/* static strings, in iso 8859/1 */ +/* static strings, in UTF-8 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, product_desc, }, @@ -897,9 +902,9 @@ config_buf (enum usb_device_speed speed, if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#define which_fn(t) (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function) +#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) #else -#define which_fn(t) (& fs_ ## t ## _function) +#define which_fn(t) (fs_ ## t ## _function) #endif if (index >= device_desc.bNumConfigurations) @@ -911,14 +916,12 @@ config_buf (enum usb_device_speed speed, */ if (device_desc.bNumConfigurations == 2 && index == 0) { config = &rndis_config; - function = (const struct usb_descriptor_header **) - which_fn (rndis); + function = which_fn (rndis); } else #endif { config = ð_config; - function = (const struct usb_descriptor_header **) - which_fn (eth); + function = which_fn (eth); } /* for now, don't advertise srp-only devices */ @@ -2329,6 +2332,8 @@ eth_bind (struct usb_gadget *gadget) device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); } else if (gadget_is_omap (gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else if (gadget_is_lh7a40x(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); } else { /* can't assume CDC works. don't want to default to * anything less functional on CDC-capable hardware, diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 9b978911e..6e8008fa4 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -46,17 +46,16 @@ * * Backing storage is provided by a regular file or a block device, specified * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. + * setting the optional "ro" module parameter. The gadget will indicate that + * it has removable media if the optional "removable" module parameter is set. * * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected * by the optional "transport" module parameter. It also supports the * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. For testing purposes the - * gadget will indicate that it has removable media if the optional - * "removable" module parameter is set. In addition, the default Vendor ID, - * Product ID, and release number can be overridden. + * the optional "protocol" module parameter. In addition, the default + * Vendor ID, Product ID, and release number can be overridden. * * There is support for multiple logical units (LUNs), each of which has * its own backing file. The number of LUNs can be set using the optional @@ -79,13 +78,13 @@ * the files or block devices used for * backing storage * ro=b[,b...] Default false, booleans for read-only access + * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; * also 1 - 6) - * removable Default false, boolean for removable media * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID * release=0xRRRR Override the USB release number (bcdDevice) @@ -97,16 +96,16 @@ * boolean to permit the driver to halt * bulk endpoints * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro" - * options are available; default values are used for everything else. + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", + * "removable", and "luns" options are available; default values are used + * for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun subdirectory of the - * gadget's sysfs directory. If CONFIG_USB_FILE_STORAGE_TEST and the - * "removable" option are both set, writing to these files will simulate - * ejecting/loading the medium (writing an empty line means eject) and - * adjusting a write-enable tab. Changes to the ro setting are not allowed - * when the medium is loaded. + * gadget's sysfs directory. If the "removable" option is set, writing to + * these files will simulate ejecting/loading the medium (writing an empty + * line means eject) and adjusting a write-enable tab. Changes to the ro + * setting are not allowed when the medium is loaded. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. */ @@ -178,7 +177,10 @@ * Bulk-only specification requires a stall. In such cases the driver * will halt the endpoint and set a flag indicating that it should clear * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. + * will permit everything to work correctly. Furthermore, although the + * specification allows the bulk-out endpoint to halt when the host sends + * too much data, implementing this would cause an unavoidable race. + * The driver will always use the "no-stall" approach for OUT transfers. * * One subtle point concerns sending status-stage responses for ep0 * requests. Some of these requests, such as device reset, can involve @@ -246,7 +248,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "21 March 2004" +#define DRIVER_VERSION "28 July 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -371,14 +373,17 @@ MODULE_PARM_DESC(file, "names of backing files or devices"); module_param_array(ro, bool, mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); +module_param_named(luns, mod_data.nluns, uint, S_IRUGO); +MODULE_PARM_DESC(luns, "number of LUNs"); -/* In the non-TEST version, only the file and ro module parameters +module_param_named(removable, mod_data.removable, bool, S_IRUGO); +MODULE_PARM_DESC(removable, "true to simulate removable media"); + + +/* In the non-TEST version, only the module parameters listed above * are available. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); @@ -386,9 +391,6 @@ module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " "8070, or SCSI)"); -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); MODULE_PARM_DESC(vendor, "USB Vendor ID"); @@ -525,11 +527,6 @@ struct interrupt_data { * parts of the driver that aren't used in the non-TEST version. Even gcc * can recognize when a test of a constant expression yields a dead code * path. - * - * Also, in the non-TEST version, open_backing_file() is only used during - * initialization and the sysfs attribute store_xxx routines aren't used - * at all. We will define NORMALLY_INIT to mark them as __init so they - * don't occupy kernel code space unnecessarily. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -537,16 +534,12 @@ struct interrupt_data { #define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) #define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) #define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) -#define backing_file_is_open(curlun) ((curlun)->filp != NULL) -#define NORMALLY_INIT #else #define transport_is_bbb() 1 #define transport_is_cbi() 0 #define protocol_is_scsi() 1 -#define backing_file_is_open(curlun) 1 -#define NORMALLY_INIT __init #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -567,6 +560,8 @@ struct lun { struct device dev; }; +#define backing_file_is_open(curlun) ((curlun)->filp != NULL) + static inline struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); @@ -659,6 +654,7 @@ struct fsg_dev { unsigned long atomic_bitflags; #define REGISTERED 0 #define CLEAR_BULK_HALTS 1 +#define SUSPENDED 2 struct usb_ep *bulk_in; struct usb_ep *bulk_out; @@ -1041,8 +1037,6 @@ static int populate_config_buf(enum usb_device_speed speed, function = fs_function; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - if (len < 0) - return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len; } @@ -1172,9 +1166,10 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) wakeup_thread(fsg); } + +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; @@ -1190,17 +1185,21 @@ static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + /*-------------------------------------------------------------------------*/ /* Ep0 class-specific handlers. These always run in_irq. */ +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct usb_request *req = fsg->ep0req; static u8 cbi_reset_cmnd[6] = { SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; @@ -1238,9 +1237,13 @@ static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + static int class_setup_req(struct fsg_dev *fsg, const struct usb_ctrlrequest *ctrl) @@ -1465,8 +1468,8 @@ static int fsg_setup(struct usb_gadget *gadget, /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < ctrl->wLength - && (rc % gadget->ep0->maxpacket) == 0; + fsg->ep0req->zero = (rc < ctrl->wLength && + (rc % gadget->ep0->maxpacket) == 0); fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); @@ -2443,14 +2446,19 @@ static int finish_reply(struct fsg_dev *fsg) rc = -EINTR; } - /* We haven't processed all the incoming data. If we are - * allowed to stall, halt the bulk-out endpoint and cancel - * any outstanding requests. */ + /* We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. */ +#if 0 else if (mod_data.can_stall) { fsg_set_halt(fsg, fsg->bulk_out); raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); rc = -EINTR; } +#endif /* We can't stall. Read in the excess data and throw it * all away. */ @@ -2513,7 +2521,7 @@ static int send_status(struct fsg_dev *fsg) } else if (mod_data.transport_type == USB_PR_CB) { - /* Control-Bulk transport has no status stage! */ + /* Control-Bulk transport has no status phase! */ return 0; } else { // USB_PR_CBI @@ -2603,8 +2611,10 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, fsg->residue = fsg->usb_amount_left = fsg->data_size; /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) - goto phase_error; + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { + fsg->phase_error = 1; + return -EINVAL; + } /* Verify the length of the command itself */ if (cmnd_size != fsg->cmnd_size) { @@ -2613,8 +2623,10 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, * with cbw->Length == 12 (it should be 6). */ if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) cmnd_size = fsg->cmnd_size; - else - goto phase_error; + else { + fsg->phase_error = 1; + return -EINVAL; + } } /* Check that the LUN values are oonsistent */ @@ -2674,10 +2686,6 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, } return 0; - -phase_error: - fsg->phase_error = 1; - return -EINVAL; } @@ -3424,8 +3432,7 @@ static int fsg_main_thread(void *fsg_) /* If the next two routines are called while the gadget is registered, * the caller must own fsg->filesem for writing. */ -static int NORMALLY_INIT open_backing_file(struct lun *curlun, - const char *filename) +static int open_backing_file(struct lun *curlun, const char *filename) { int ro; struct file *filp = NULL; @@ -3550,8 +3557,7 @@ static ssize_t show_file(struct device *dev, char *buf) } -ssize_t NORMALLY_INIT store_ro(struct device *dev, const char *buf, - size_t count) +ssize_t store_ro(struct device *dev, const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3575,8 +3581,7 @@ ssize_t NORMALLY_INIT store_ro(struct device *dev, const char *buf, return rc; } -ssize_t NORMALLY_INIT store_file(struct device *dev, const char *buf, - size_t count) +ssize_t store_file(struct device *dev, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); @@ -3708,6 +3713,8 @@ static int __init check_parameters(struct fsg_dev *fsg) mod_data.release = __constant_cpu_to_le16(0x0307); else if (gadget_is_omap(fsg->gadget)) mod_data.release = __constant_cpu_to_le16(0x0308); + else if (gadget_is_lh7a40x(gadget)) + mod_data.release = __constant_cpu_to_le16 (0x0309); else { WARN(fsg, "controller '%s' not recognized\n", fsg->gadget->name); @@ -3805,9 +3812,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) goto out; } - /* Create the LUNs and open their backing files. We can't register - * the LUN devices until the gadget itself is registered, which - * doesn't happen until after fsg_bind() returns. */ + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); if (!fsg->luns) { rc = -ENOMEM; @@ -3825,6 +3831,15 @@ static int __init fsg_bind(struct usb_gadget *gadget) snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); + if ((rc = device_register(&curlun->dev)) != 0) + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + else { + curlun->registered = 1; + curlun->dev.release = lun_release; + device_create_file(&curlun->dev, &dev_attr_ro); + device_create_file(&curlun->dev, &dev_attr_file); + } + if (file[i] && *file[i]) { if ((rc = open_backing_file(curlun, file[i])) != 0) goto out; @@ -3972,6 +3987,25 @@ out: } +/*-------------------------------------------------------------------------*/ + +static void fsg_suspend(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "suspend\n"); + set_bit(SUSPENDED, &fsg->atomic_bitflags); +} + +static void fsg_resume(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "resume\n"); + clear_bit(SUSPENDED, &fsg->atomic_bitflags); +} + + /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { @@ -3985,6 +4019,8 @@ static struct usb_gadget_driver fsg_driver = { .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, + .suspend = fsg_suspend, + .resume = fsg_resume, .driver = { .name = (char *) shortname, @@ -4024,8 +4060,6 @@ static int __init fsg_init(void) { int rc; struct fsg_dev *fsg; - int i; - struct lun *curlun; if ((rc = fsg_alloc()) != 0) return rc; @@ -4036,19 +4070,6 @@ static int __init fsg_init(void) } set_bit(REGISTERED, &fsg->atomic_bitflags); - /* Register the LUN devices and their attribute files */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if ((rc = device_register(&curlun->dev)) != 0) - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - else { - curlun->registered = 1; - curlun->dev.release = lun_release; - device_create_file(&curlun->dev, &dev_attr_ro); - device_create_file(&curlun->dev, &dev_attr_file); - } - } - /* Tell the thread to start working */ complete(&fsg->thread_notifier); return 0; diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 3093bceb9..e24e2f9ad 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -44,6 +44,12 @@ #define gadget_is_sa1100(g) 0 #endif +#ifdef CONFIG_USB_GADGET_LH7A40X +#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name) +#else +#define gadget_is_lh7a40x(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_MQ11XX #define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) #else diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index c746ecbe1..f5e146225 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1,7 +1,7 @@ /* * inode.c -- user mode filesystem api for usb gadget controllers * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * Copyright (C) 2003 Agilent Technologies * * This program is free software; you can redistribute it and/or modify @@ -71,7 +71,7 @@ */ #define DRIVER_DESC "USB Gadget filesystem" -#define DRIVER_VERSION "18 Nov 2003" +#define DRIVER_VERSION "24 Aug 2004" static const char driver_desc [] = DRIVER_DESC; static const char shortname [] = "gadgetfs"; @@ -229,37 +229,12 @@ static void put_ep (struct ep_data *data) /*----------------------------------------------------------------------*/ /* most "how to use the hardware" policy choices are in userspace: - * mapping endpoint roles the driver needs to the capabilities that - * the usb controller exposes. + * mapping endpoint roles (which the driver needs) to the capabilities + * which the usb controller has. most of those capabilities are exposed + * implicitly, starting with the driver name and then endpoint names. */ -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -/* act (mostly) like a net2280 */ -#define CONFIG_USB_GADGET_NET2280 -#endif - -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define HIGHSPEED -#endif - -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx_udc" -/* earlier hardware doesn't have UDCCFR, races set_{config,interface} */ -#warning works best with pxa255 or newer -#endif - -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku_udc" -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define CHIP "omap_udc" -#endif - -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#endif +static const char *CHIP; /*----------------------------------------------------------------------*/ @@ -558,7 +533,7 @@ struct kiocb_priv { static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) { - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; struct ep_data *epdata; int value; @@ -577,10 +552,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; + struct kiocb_priv *priv = iocb->private; + 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); @@ -589,6 +564,7 @@ static long ep_aio_read_retry(struct kiocb *iocb) else status = priv->actual; kfree(priv->buf); + kfree(priv); aio_put_req(iocb); return status; } @@ -596,7 +572,7 @@ static long ep_aio_read_retry(struct kiocb *iocb) static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) { struct kiocb *iocb = req->context; - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; struct ep_data *epdata = priv->epdata; /* lock against disconnect (and ideally, cancel) */ @@ -607,6 +583,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) || unlikely(0 == req->actual) || unlikely(kiocbIsCancelled(iocb))) { kfree(req->buf); + kfree(priv); + iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ if (unlikely(kiocbIsCancelled(iocb))) aio_put_req(iocb); @@ -631,17 +609,33 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) } static ssize_t -ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) +ep_aio_rwtail( + struct kiocb *iocb, + char *buf, + size_t len, + struct ep_data *epdata, + char __user *ubuf +) { struct kiocb_priv *priv = (void *) &iocb->private; struct usb_request *req; ssize_t value; - value = get_ready_ep(iocb->ki_filp->f_flags, epdata); - if (unlikely(value < 0)) { + priv = kmalloc(sizeof *priv, GFP_KERNEL); + if (!priv) { + value = -ENOMEM; +fail: kfree(buf); return value; } + iocb->private = priv; + priv->ubuf = ubuf; + + value = get_ready_ep(iocb->ki_filp->f_flags, epdata); + if (unlikely(value < 0)) { + kfree(priv); + goto fail; + } iocb->ki_cancel = ep_aio_cancel; get_ep(epdata); @@ -671,9 +665,10 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) up(&epdata->lock); - if (unlikely(value)) + if (unlikely(value)) { + kfree(priv); put_ep(epdata); - else + } else value = -EIOCBQUEUED; return value; } @@ -681,7 +676,6 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) static ssize_t ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) { - struct kiocb_priv *priv = (void *) &iocb->private; struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; @@ -691,8 +685,7 @@ ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) if (unlikely(!buf)) return -ENOMEM; iocb->ki_retry = ep_aio_read_retry; - priv->ubuf = ubuf; - return ep_aio_rwtail(iocb, buf, len, epdata); + return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); } static ssize_t @@ -710,7 +703,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) kfree(buf); return -EFAULT; } - return ep_aio_rwtail(iocb, buf, len, epdata); + return ep_aio_rwtail(iocb, buf, len, epdata, NULL); } /*----------------------------------------------------------------------*/ @@ -718,6 +711,8 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) /* used after endpoint configuration */ static struct file_operations ep_io_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ep_read, .write = ep_write, .ioctl = ep_ioctl, @@ -874,6 +869,8 @@ ep_open (struct inode *inode, struct file *fd) /* used before endpoint configuration */ static struct file_operations ep_config_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .open = ep_open, .write = ep_config, .release = ep_release, @@ -980,6 +977,18 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) retval = usb_ep_queue (ep, req, GFP_ATOMIC); dev->state = STATE_CONNECTED; + /* assume that was SET_CONFIGURATION */ + if (dev->current_config) { + unsigned power; +#ifdef HIGHSPEED + if (dev->gadget->speed == USB_SPEED_HIGH) + power = dev->hs_config->bMaxPower; + else +#endif + power = dev->config->bMaxPower; + usb_gadget_vbus_draw(dev->gadget, 2 * power); + } + } else { /* collect OUT data */ if ((fd->f_flags & O_NONBLOCK) != 0 && !dev->setup_out_ready) { @@ -1230,6 +1239,8 @@ static int dev_ioctl (struct inode *inode, struct file *fd, /* used after device configuration */ static struct file_operations ep0_io_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ep0_read, .write = ep0_write, .fasync = ep0_fasync, @@ -1406,19 +1417,25 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (0 == (u8) ctrl->wValue) { value = 0; dev->current_config = 0; + usb_gadget_vbus_draw(gadget, 8 /* mA */ ); // user mode expected to disable endpoints } else { - u8 config; + u8 config, power; #ifdef HIGHSPEED - if (gadget->speed == USB_SPEED_HIGH) + if (gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; - else + power = dev->hs_config->bMaxPower; + } else #endif + { config = dev->config->bConfigurationValue; + power = dev->config->bMaxPower; + } if (config == (u8) ctrl->wValue) { value = 0; dev->current_config = config; + usb_gadget_vbus_draw(gadget, 2 * power); } } @@ -1636,8 +1653,8 @@ gadgetfs_bind (struct usb_gadget *gadget) if (!dev) return -ESRCH; if (0 != strcmp (CHIP, gadget->name)) { - printk (KERN_ERR "%s expected " CHIP " controller not %s\n", - shortname, gadget->name); + printk (KERN_ERR "%s expected %s controller not %s\n", + shortname, CHIP, gadget->name); return -ENODEV; } @@ -1727,6 +1744,26 @@ static struct usb_gadget_driver gadgetfs_driver = { /*----------------------------------------------------------------------*/ +static void gadgetfs_nop(struct usb_gadget *arg) { } + +static int gadgetfs_probe (struct usb_gadget *gadget) +{ + CHIP = gadget->name; + return -EISNAM; +} + +static struct usb_gadget_driver probe_driver = { + .speed = USB_SPEED_HIGH, + .bind = gadgetfs_probe, + .unbind = gadgetfs_nop, + .setup = (void *)gadgetfs_nop, + .disconnect = gadgetfs_nop, + .driver = { + .name = "nop", + }, +}; + + /* DEVICE INITIALIZATION * * fd = open ("/dev/gadget/$CHIP", O_RDWR) @@ -1763,6 +1800,7 @@ static int is_valid_config (struct usb_config_descriptor *config) && config->bConfigurationValue != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; + /* FIXME if gadget->is_otg, _must_ include an otg descriptor */ /* FIXME check lengths: walk to end */ } @@ -1881,6 +1919,8 @@ dev_open (struct inode *inode, struct file *fd) static struct file_operations dev_init_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .open = dev_open, .write = dev_config, .fasync = ep0_fasync, @@ -1976,6 +2016,11 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) if (the_device) return -ESRCH; + /* fake probe to determine $CHIP */ + (void) usb_gadget_register_driver (&probe_driver); + if (!CHIP) + return -ENODEV; + /* superblock */ sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c new file mode 100644 index 000000000..772627e97 --- /dev/null +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -0,0 +1,2168 @@ +/* + * linux/drivers/usb/gadget/lh7a40x_udc.c + * Sharp LH7A40x on-chip full speed USB device controllers + * + * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID + * Copyright (C) 2004 Bo Henriksen, Nordic ID + * + * 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 + * + */ + +#include "lh7a40x_udc.h" + +//#define DEBUG printk +//#define DEBUG_EP0 printk +//#define DEBUG_SETUP printk + +#ifndef DEBUG_EP0 +# define DEBUG_EP0(fmt,args...) +#endif +#ifndef DEBUG_SETUP +# define DEBUG_SETUP(fmt,args...) +#endif +#ifndef DEBUG +# define NO_STATES +# define DEBUG(fmt,args...) +#endif + +#define DRIVER_DESC "LH7A40x USB Device Controller" +#define DRIVER_VERSION __DATE__ + +#ifndef _BIT /* FIXME - what happended to _BIT in 2.6.7bk18? */ +#define _BIT(x) (1<<(x)) +#endif + +struct lh7a40x_udc *the_controller; + +static const char driver_name[] = "lh7a40x_udc"; +static const char driver_desc[] = DRIVER_DESC; +static const char ep0name[] = "ep0-control"; + +/* + Local definintions. +*/ +#define UDC_PROC_FILE + +#ifndef NO_STATES +static char *state_names[] = { + "WAIT_FOR_SETUP", + "DATA_STATE_XMIT", + "DATA_STATE_NEED_ZLP", + "WAIT_FOR_OUT_STATUS", + "DATA_STATE_RECV" +}; +#endif + +/* + Local declarations. +*/ +static int lh7a40x_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *); +static int lh7a40x_ep_disable(struct usb_ep *ep); +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, int); +static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); +static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *, + int); +static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t, + unsigned); +static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, int); +static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); +static int lh7a40x_set_halt(struct usb_ep *ep, int); +static int lh7a40x_fifo_status(struct usb_ep *ep); +static int lh7a40x_fifo_status(struct usb_ep *ep); +static void lh7a40x_fifo_flush(struct usb_ep *ep); +static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep); +static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr); + +static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, + int status); +static void pio_irq_enable(int bEndpointAddress); +static void pio_irq_disable(int bEndpointAddress); +static void stop_activity(struct lh7a40x_udc *dev, + struct usb_gadget_driver *driver); +static void flush(struct lh7a40x_ep *ep); +static void udc_enable(struct lh7a40x_udc *dev); +static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address); + +static struct usb_ep_ops lh7a40x_ep_ops = { + .enable = lh7a40x_ep_enable, + .disable = lh7a40x_ep_disable, + + .alloc_request = lh7a40x_alloc_request, + .free_request = lh7a40x_free_request, + + .alloc_buffer = lh7a40x_alloc_buffer, + .free_buffer = lh7a40x_free_buffer, + + .queue = lh7a40x_queue, + .dequeue = lh7a40x_dequeue, + + .set_halt = lh7a40x_set_halt, + .fifo_status = lh7a40x_fifo_status, + .fifo_flush = lh7a40x_fifo_flush, +}; + +/* Inline code */ + +static __inline__ int write_packet(struct lh7a40x_ep *ep, + struct lh7a40x_request *req, int max) +{ + u8 *buf; + int length, count; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + buf = req->req.buf + req->req.actual; + prefetch(buf); + + length = req->req.length - req->req.actual; + length = min(length, max); + req->req.actual += length; + + DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); + + count = length; + while (count--) { + *fifo = *buf++; + } + + return length; +} + +static __inline__ void usb_set_index(u32 ep) +{ + *(volatile u32 *)io_p2v(USB_INDEX) = ep; +} + +static __inline__ u32 usb_read(u32 port) +{ + return *(volatile u32 *)io_p2v(port); +} + +static __inline__ void usb_write(u32 val, u32 port) +{ + *(volatile u32 *)io_p2v(port) = val; +} + +static __inline__ void usb_set(u32 val, u32 port) +{ + volatile u32 *ioport = (volatile u32 *)io_p2v(port); + u32 after = (*ioport) | val; + *ioport = after; +} + +static __inline__ void usb_clear(u32 val, u32 port) +{ + volatile u32 *ioport = (volatile u32 *)io_p2v(port); + u32 after = (*ioport) & ~val; + *ioport = after; +} + +/*-------------------------------------------------------------------------*/ + +#define GPIO_PORTC_DR (0x80000E08) +#define GPIO_PORTC_DDR (0x80000E18) +#define GPIO_PORTC_PDR (0x80000E70) + +/* get port C pin data register */ +#define get_portc_pdr(bit) ((usb_read(GPIO_PORTC_PDR) & _BIT(bit)) != 0) +/* get port C data direction register */ +#define get_portc_ddr(bit) ((usb_read(GPIO_PORTC_DDR) & _BIT(bit)) != 0) +/* set port C data register */ +#define set_portc_dr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DR) : usb_clear(_BIT(bit), GPIO_PORTC_DR)) +/* set port C data direction register */ +#define set_portc_ddr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DDR) : usb_clear(_BIT(bit), GPIO_PORTC_DDR)) + +/* + * LPD7A404 GPIO's: + * Port C bit 1 = USB Port 1 Power Enable + * Port C bit 2 = USB Port 1 Data Carrier Detect + */ +#define is_usb_connected() get_portc_pdr(2) + +#ifdef UDC_PROC_FILE + +static const char proc_node_name[] = "driver/udc"; + +static int +udc_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *_dev) +{ + char *buf = page; + struct lh7a40x_udc *dev = _dev; + char *next = buf; + unsigned size = count; + unsigned long flags; + int t; + + if (off != 0) + return 0; + + local_irq_save(flags); + + /* basic device status */ + t = scnprintf(next, size, + DRIVER_DESC "\n" + "%s version: %s\n" + "Gadget driver: %s\n" + "Host: %s\n\n", + driver_name, DRIVER_VERSION, + dev->driver ? dev->driver->driver.name : "(none)", + is_usb_connected()? "full speed" : "disconnected"); + size -= t; + next += t; + + t = scnprintf(next, size, + "GPIO:\n" + " Port C bit 1: %d, dir %d\n" + " Port C bit 2: %d, dir %d\n\n", + get_portc_pdr(1), get_portc_ddr(1), + get_portc_pdr(2), get_portc_ddr(2) + ); + size -= t; + next += t; + + t = scnprintf(next, size, + "DCP pullup: %d\n\n", + (usb_read(USB_PM) & PM_USB_DCP) != 0); + size -= t; + next += t; + + local_irq_restore(flags); + *eof = 1; + return count - size; +} + +#define create_proc_files() create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) +#define remove_proc_files() remove_proc_entry(proc_node_name, NULL) + +#else /* !UDC_PROC_FILE */ + +#define create_proc_files() do {} while (0) +#define remove_proc_files() do {} while (0) + +#endif /* UDC_PROC_FILE */ + +/* + * udc_disable - disable USB device controller + */ +static void udc_disable(struct lh7a40x_udc *dev) +{ + DEBUG("%s, %p\n", __FUNCTION__, dev); + + udc_set_address(dev, 0); + + /* Disable interrupts */ + usb_write(0, USB_IN_INT_EN); + usb_write(0, USB_OUT_INT_EN); + usb_write(0, USB_INT_EN); + + /* Disable the USB */ + usb_write(0, USB_PM); + +#ifdef CONFIG_ARCH_LH7A404 + /* Disable USB power */ + set_portc_dr(1, 0); +#endif + + /* if hardware supports it, disconnect from usb */ + /* make_usb_disappear(); */ + + dev->ep0state = WAIT_FOR_SETUP; + dev->gadget.speed = USB_SPEED_UNKNOWN; + dev->usb_address = 0; +} + +/* + * udc_reinit - initialize software state + */ +static void udc_reinit(struct lh7a40x_udc *dev) +{ + u32 i; + + DEBUG("%s, %p\n", __FUNCTION__, dev); + + /* device/ep0 records init */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + dev->ep0state = WAIT_FOR_SETUP; + + /* basic endpoint records init */ + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct lh7a40x_ep *ep = &dev->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->desc = 0; + ep->stopped = 0; + INIT_LIST_HEAD(&ep->queue); + ep->pio_irqs = 0; + } + + /* the rest was statically initialized, and is read-only */ +} + +#define BYTES2MAXP(x) (x / 8) +#define MAXP2BYTES(x) (x * 8) + +/* until it's enabled, this UDC should be completely invisible + * to any USB host. + */ +static void udc_enable(struct lh7a40x_udc *dev) +{ + int ep; + + DEBUG("%s, %p\n", __FUNCTION__, dev); + + dev->gadget.speed = USB_SPEED_UNKNOWN; + +#ifdef CONFIG_ARCH_LH7A404 + /* Set Port C bit 1 & 2 as output */ + set_portc_ddr(1, 1); + set_portc_ddr(2, 1); + + /* Enable USB power */ + set_portc_dr(1, 0); +#endif + + /* + * C.f Chapter 18.1.3.1 Initializing the USB + */ + + /* Disable the USB */ + usb_clear(PM_USB_ENABLE, USB_PM); + + /* Reset APB & I/O sides of the USB */ + usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET); + mdelay(5); + usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET); + + /* Set MAXP values for each */ + for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) { + struct lh7a40x_ep *ep_reg = &dev->ep[ep]; + u32 csr; + + usb_set_index(ep); + + switch (ep_reg->ep_type) { + case ep_bulk_in: + case ep_interrupt: + usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET, + ep_reg->csr2); + /* Fall through */ + case ep_control: + usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), + USB_IN_MAXP); + break; + case ep_bulk_out: + usb_clear(USB_OUT_CSR2_USB_DMA_EN | + USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2); + usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), + USB_OUT_MAXP); + break; + } + + /* Read & Write CSR1, just in case */ + csr = usb_read(ep_reg->csr1); + usb_write(csr, ep_reg->csr1); + + flush(ep_reg); + } + + /* Disable interrupts */ + usb_write(0, USB_IN_INT_EN); + usb_write(0, USB_OUT_INT_EN); + usb_write(0, USB_INT_EN); + + /* Enable interrupts */ + usb_set(USB_IN_INT_EP0, USB_IN_INT_EN); + usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN); + /* Dont enable rest of the interrupts */ + /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN); + usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */ + + /* Enable SUSPEND */ + usb_set(PM_ENABLE_SUSPEND, USB_PM); + + /* Enable the USB */ + usb_set(PM_USB_ENABLE, USB_PM); + +#ifdef CONFIG_ARCH_LH7A404 + /* NOTE: DOES NOT WORK! */ + /* Let host detect UDC: + * Software must write a 0 to the PMR:DCP_CTRL bit to turn this + * transistor on and pull the USBDP pin HIGH. + */ + /* usb_clear(PM_USB_DCP, USB_PM); + usb_set(PM_USB_DCP, USB_PM); */ +#endif +} + +/* + Register entry point for the peripheral controller driver. +*/ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct lh7a40x_udc *dev = the_controller; + int retval; + + DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name); + + if (!driver + || driver->speed != USB_SPEED_FULL + || !driver->bind + || !driver->unbind || !driver->disconnect || !driver->setup) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + /* first hook up the driver ... */ + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + + device_add(&dev->gadget.dev); + retval = driver->bind(&dev->gadget); + if (retval) { + printk("%s: bind to driver %s --> error %d\n", dev->gadget.name, + driver->driver.name, retval); + device_del(&dev->gadget.dev); + + dev->driver = 0; + dev->gadget.dev.driver = 0; + return retval; + } + + /* ... then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + * NOTE: this shouldn't power up until later. + */ + printk("%s: registered gadget driver '%s'\n", dev->gadget.name, + driver->driver.name); + + udc_enable(dev); + + return 0; +} + +EXPORT_SYMBOL(usb_gadget_register_driver); + +/* + Unregister entry point for the peripheral controller driver. +*/ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct lh7a40x_udc *dev = the_controller; + unsigned long flags; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + dev->driver = 0; + stop_activity(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + driver->unbind(&dev->gadget); + device_del(&dev->gadget.dev); + + udc_disable(dev); + + DEBUG("unregistered gadget driver '%s'\n", driver->driver.name); + return 0; +} + +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/*-------------------------------------------------------------------------*/ + +/** Write request to FIFO (max write == maxp size) + * Return: 0 = still running, 1 = completed, negative = errno + * NOTE: INDEX register must be set for EP + */ +static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 max; + u32 csr; + + max = le16_to_cpu(ep->desc->wMaxPacketSize); + + csr = usb_read(ep->csr1); + DEBUG("CSR: %x %d\n", csr, csr & USB_IN_CSR1_FIFO_NOT_EMPTY); + + if (!(csr & USB_IN_CSR1_FIFO_NOT_EMPTY)) { + unsigned count; + int is_last, is_short; + + count = write_packet(ep, req, max); + usb_set(USB_IN_CSR1_IN_PKT_RDY, ep->csr1); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = is_short = 1; + else { + if (likely(req->req.length != req->req.actual) + || req->req.zero) + is_last = 0; + else + is_last = 1; + /* interrupt/iso maxpacket may not fill the fifo */ + is_short = unlikely(max < ep_maxpacket(ep)); + } + + DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, + ep->ep.name, count, + is_last ? "/L" : "", is_short ? "/S" : "", + req->req.length - req->req.actual, req); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue)) { + pio_irq_disable(ep_index(ep)); + } + return 1; + } + } else { + DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); + } + + return 0; +} + +/** Read to request from FIFO (max read == bytes in fifo) + * Return: 0 = still running, 1 = completed, negative = errno + * NOTE: INDEX register must be set for EP + */ +static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 csr; + u8 *buf; + unsigned bufferspace, count, is_short; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + /* make sure there's a packet in the FIFO. */ + csr = usb_read(ep->csr1); + if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) { + DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); + return -EINVAL; + } + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + count = usb_read(USB_OUT_FIFO_WC1); + req->req.actual += min(count, bufferspace); + + is_short = (count < ep->ep.maxpacket); + DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, csr, count, + is_short ? "/S" : "", req, req->req.actual, req->req.length); + + while (likely(count-- != 0)) { + u8 byte = (u8) (*fifo & 0xff); + + if (unlikely(bufferspace == 0)) { + /* this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + printk("%s overflow %d\n", ep->ep.name, count); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + bufferspace--; + } + } + + usb_clear(USB_OUT_CSR1_OUT_PKT_RDY, ep->csr1); + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); + + if (list_empty(&ep->queue)) + pio_irq_disable(ep_index(ep)); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/* + * done - retire a request; caller blocked irqs + * INDEX register is preserved to keep same + */ +static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status) +{ + unsigned int stopped = ep->stopped; + u32 index; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + list_del_init(&req->queue); + + if (likely(req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + DEBUG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + /* Read current index (completion may modify it) */ + index = usb_read(USB_INDEX); + + spin_unlock(&ep->dev->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->dev->lock); + + /* Restore index */ + usb_set_index(index); + ep->stopped = stopped; +} + +/** Enable EP interrupt */ +static void pio_irq_enable(int ep) +{ + DEBUG("%s: %d\n", __FUNCTION__, ep); + + switch (ep) { + case 1: + usb_set(USB_IN_INT_EP1, USB_IN_INT_EN); + break; + case 2: + usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); + break; + case 3: + usb_set(USB_IN_INT_EP3, USB_IN_INT_EN); + break; + default: + DEBUG("Unknown endpoint: %d\n", ep); + break; + } +} + +/** Disable EP interrupt */ +static void pio_irq_disable(int ep) +{ + DEBUG("%s: %d\n", __FUNCTION__, ep); + + switch (ep) { + case 1: + usb_clear(USB_IN_INT_EP1, USB_IN_INT_EN); + break; + case 2: + usb_clear(USB_OUT_INT_EP2, USB_OUT_INT_EN); + break; + case 3: + usb_clear(USB_IN_INT_EP3, USB_IN_INT_EN); + break; + default: + DEBUG("Unknown endpoint: %d\n", ep); + break; + } +} + +/* + * nuke - dequeue ALL requests + */ +void nuke(struct lh7a40x_ep *ep, int status) +{ + struct lh7a40x_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + /* Flush FIFO */ + flush(ep); + + /* called with irqs blocked */ + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + done(ep, req, status); + } + + /* Disable IRQ if EP is enabled (has decriptor) */ + if (ep->desc) + pio_irq_disable(ep_index(ep)); +} + +/* +void nuke_all(struct lh7a40x_udc *dev) +{ + int n; + for(n=0; nep[n]; + usb_set_index(n); + nuke(ep, 0); + } +}*/ + +/* +static void flush_all(struct lh7a40x_udc *dev) +{ + int n; + for (n = 0; n < UDC_MAX_ENDPOINTS; n++) + { + struct lh7a40x_ep *ep = &dev->ep[n]; + flush(ep); + } +} +*/ + +/** Flush EP + * NOTE: INDEX register must be set before this call + */ +static void flush(struct lh7a40x_ep *ep) +{ + DEBUG("%s, %p\n", __FUNCTION__, ep); + + switch (ep->ep_type) { + case ep_control: + /* check, by implication c.f. 15.1.2.11 */ + break; + + case ep_bulk_in: + case ep_interrupt: + /* if(csr & USB_IN_CSR1_IN_PKT_RDY) */ + usb_set(USB_IN_CSR1_FIFO_FLUSH, ep->csr1); + break; + + case ep_bulk_out: + /* if(csr & USB_OUT_CSR1_OUT_PKT_RDY) */ + usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); + break; + } +} + +/** + * lh7a40x_in_epn - handle IN interrupt + */ +static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) +{ + u32 csr; + struct lh7a40x_ep *ep = &dev->ep[ep_idx]; + struct lh7a40x_request *req; + + usb_set_index(ep_idx); + + csr = usb_read(ep->csr1); + DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); + + if (csr & USB_IN_CSR1_SENT_STALL) { + DEBUG("USB_IN_CSR1_SENT_STALL\n"); + usb_set(USB_IN_CSR1_SENT_STALL /*|USB_IN_CSR1_SEND_STALL */ , + ep->csr1); + return; + } + + if (!ep->desc) { + DEBUG("%s: NO EP DESC\n", __FUNCTION__); + return; + } + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + + DEBUG("req: %p\n", req); + + if (!req) + return; + + write_fifo(ep, req); +} + +/* ********************************************************************************************* */ +/* Bulk OUT (recv) + */ + +static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) +{ + struct lh7a40x_ep *ep = &dev->ep[ep_idx]; + struct lh7a40x_request *req; + + DEBUG("%s: %d\n", __FUNCTION__, ep_idx); + + usb_set_index(ep_idx); + + if (ep->desc) { + u32 csr; + csr = usb_read(ep->csr1); + + while ((csr = + usb_read(ep-> + csr1)) & (USB_OUT_CSR1_OUT_PKT_RDY | + USB_OUT_CSR1_SENT_STALL)) { + DEBUG("%s: %x\n", __FUNCTION__, csr); + + if (csr & USB_OUT_CSR1_SENT_STALL) { + DEBUG("%s: stall sent, flush fifo\n", + __FUNCTION__); + /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ + flush(ep); + } else if (csr & USB_OUT_CSR1_OUT_PKT_RDY) { + if (list_empty(&ep->queue)) + req = 0; + else + req = + list_entry(ep->queue.next, + struct lh7a40x_request, + queue); + + if (!req) { + printk("%s: NULL REQ %d\n", + __FUNCTION__, ep_idx); + flush(ep); + break; + } else { + read_fifo(ep, req); + } + } + + } + + } else { + /* Throw packet away.. */ + printk("%s: No descriptor?!?\n", __FUNCTION__); + flush(ep); + } +} + +static void stop_activity(struct lh7a40x_udc *dev, + struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect drivers more than once */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = 0; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct lh7a40x_ep *ep = &dev->ep[i]; + ep->stopped = 1; + + usb_set_index(i); + nuke(ep, -ESHUTDOWN); + } + + /* report disconnect; the driver is already quiesced */ + if (driver) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } + + /* re-init driver-visible data structures */ + udc_reinit(dev); +} + +/** Handle USB RESET interrupt + */ +static void lh7a40x_reset_intr(struct lh7a40x_udc *dev) +{ +#if 0 /* def CONFIG_ARCH_LH7A404 */ + /* Does not work always... */ + + DEBUG("%s: %d\n", __FUNCTION__, dev->usb_address); + + if (!dev->usb_address) { + /*usb_set(USB_RESET_IO, USB_RESET); + mdelay(5); + usb_clear(USB_RESET_IO, USB_RESET); */ + return; + } + /* Put the USB controller into reset. */ + usb_set(USB_RESET_IO, USB_RESET); + + /* Set Device ID to 0 */ + udc_set_address(dev, 0); + + /* Let PLL2 settle down */ + mdelay(5); + + /* Release the USB controller from reset */ + usb_clear(USB_RESET_IO, USB_RESET); + + /* Re-enable UDC */ + udc_enable(dev); + +#endif + dev->gadget.speed = USB_SPEED_FULL; +} + +/* + * lh7a40x usb client interrupt handler. + */ +static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev, struct pt_regs *r) +{ + struct lh7a40x_udc *dev = _dev; + + DEBUG("\n\n"); + + spin_lock(&dev->lock); + + for (;;) { + u32 intr_in = usb_read(USB_IN_INT); + u32 intr_out = usb_read(USB_OUT_INT); + u32 intr_int = usb_read(USB_INT); + + /* Test also against enable bits.. (lh7a40x errata).. Sigh.. */ + u32 in_en = usb_read(USB_IN_INT_EN); + u32 out_en = usb_read(USB_OUT_INT_EN); + + if (!intr_out && !intr_in && !intr_int) + break; + + DEBUG("%s (on state %s)\n", __FUNCTION__, + state_names[dev->ep0state]); + DEBUG("intr_out = %x\n", intr_out); + DEBUG("intr_in = %x\n", intr_in); + DEBUG("intr_int = %x\n", intr_int); + + if (intr_in) { + usb_write(intr_in, USB_IN_INT); + + if ((intr_in & USB_IN_INT_EP1) + && (in_en & USB_IN_INT_EP1)) { + DEBUG("USB_IN_INT_EP1\n"); + lh7a40x_in_epn(dev, 1, intr_in); + } + if ((intr_in & USB_IN_INT_EP3) + && (in_en & USB_IN_INT_EP3)) { + DEBUG("USB_IN_INT_EP3\n"); + lh7a40x_in_epn(dev, 3, intr_in); + } + if (intr_in & USB_IN_INT_EP0) { + DEBUG("USB_IN_INT_EP0 (control)\n"); + lh7a40x_handle_ep0(dev, intr_in); + } + } + + if (intr_out) { + usb_write(intr_out, USB_OUT_INT); + + if ((intr_out & USB_OUT_INT_EP2) + && (out_en & USB_OUT_INT_EP2)) { + DEBUG("USB_OUT_INT_EP2\n"); + lh7a40x_out_epn(dev, 2, intr_out); + } + } + + if (intr_int) { + usb_write(intr_int, USB_INT); + + if (intr_int & USB_INT_RESET_INT) { + lh7a40x_reset_intr(dev); + } + + if (intr_int & USB_INT_RESUME_INT) { + DEBUG("USB resume\n"); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->resume + && is_usb_connected()) { + dev->driver->resume(&dev->gadget); + } + } + + if (intr_int & USB_INT_SUSPEND_INT) { + DEBUG("USB suspend%s\n", + is_usb_connected()? "" : "+disconnect"); + if (!is_usb_connected()) { + stop_activity(dev, dev->driver); + } else if (dev->gadget.speed != + USB_SPEED_UNKNOWN && dev->driver + && dev->driver->suspend) { + dev->driver->suspend(&dev->gadget); + } + } + + } + } + + spin_unlock(&dev->lock); + + return IRQ_HANDLED; +} + +static int lh7a40x_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct lh7a40x_ep *ep; + struct lh7a40x_udc *dev; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) { + DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); + return -EINVAL; + } + + /* xfer types must match, except that interrupt ~= bulk */ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); + return -EINVAL; + } + + /* hardware _could_ do smaller, but driver doesn't */ + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep)) + || !desc->wMaxPacketSize) { + DEBUG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); + return -ERANGE; + } + + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + DEBUG("%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&ep->dev->lock, flags); + + ep->stopped = 0; + ep->desc = desc; + ep->pio_irqs = 0; + ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + + /* Reset halt state (does flush) */ + lh7a40x_set_halt(_ep, 0); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); + return 0; +} + +/** Disable EP + * NOTE: Sets INDEX register + */ +static int lh7a40x_ep_disable(struct usb_ep *_ep) +{ + struct lh7a40x_ep *ep; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep || !ep->desc) { + DEBUG("%s, %s not enabled\n", __FUNCTION__, + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->dev->lock, flags); + + usb_set_index(ep_index(ep)); + + /* Nuke all pending requests (does flush) */ + nuke(ep, -ESHUTDOWN); + + /* Disable ep IRQ */ + pio_irq_disable(ep_index(ep)); + + ep->desc = 0; + ep->stopped = 1; + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); + return 0; +} + +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, + int gfp_flags) +{ + struct lh7a40x_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + req = kmalloc(sizeof *req, gfp_flags); + if (!req) + return 0; + + memset(req, 0, sizeof *req); + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) +{ + struct lh7a40x_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + req = container_of(_req, struct lh7a40x_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + +static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, + dma_addr_t * dma, int gfp_flags) +{ + char *retval; + + DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags); + + retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM)); + if (retval) + *dma = virt_to_bus(retval); + return retval; +} + +static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, + unsigned bytes) +{ + DEBUG("%s, %p\n", __FUNCTION__, ep); + kfree(buf); +} + +/** Queue one request + * Kickstart transfer if needed + * NOTE: Sets INDEX register + */ +static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, + int gfp_flags) +{ + struct lh7a40x_request *req; + struct lh7a40x_ep *ep; + struct lh7a40x_udc *dev; + unsigned long flags; + + DEBUG("\n\n\n%s, %p\n", __FUNCTION__, _ep); + + req = container_of(_req, struct lh7a40x_request, req); + if (unlikely + (!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue))) { + DEBUG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + dev = ep->dev; + if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); + return -ESHUTDOWN; + } + + DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, + _req->buf); + + spin_lock_irqsave(&dev->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* kickstart this i/o queue? */ + DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), + ep->stopped); + if (list_empty(&ep->queue) && likely(!ep->stopped)) { + u32 csr; + + if (unlikely(ep_index(ep) == 0)) { + /* EP0 */ + list_add_tail(&req->queue, &ep->queue); + lh7a40x_ep0_kick(dev, ep); + req = 0; + } else if (ep_is_in(ep)) { + /* EP1 & EP3 */ + usb_set_index(ep_index(ep)); + csr = usb_read(ep->csr1); + pio_irq_enable(ep_index(ep)); + if ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) == 0) { + if (write_fifo(ep, req) == 1) + req = 0; + } + } else { + /* EP2 */ + usb_set_index(ep_index(ep)); + csr = usb_read(ep->csr1); + pio_irq_enable(ep_index(ep)); + if (!(csr & USB_OUT_CSR1_FIFO_FULL)) { + if (read_fifo(ep, req) == 1) + req = 0; + } + } + } + + /* pio or dma irq handler advances the queue. */ + if (likely(req != 0)) + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* dequeue JUST ONE request */ +static int lh7a40x_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct lh7a40x_ep *ep; + struct lh7a40x_request *req; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep || ep->ep.name == ep0name) + return -EINVAL; + + spin_lock_irqsave(&ep->dev->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->dev->lock, flags); + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + return 0; +} + +/** Halt specific EP + * Return 0 if success + * NOTE: Sets INDEX register to EP ! + */ +static int lh7a40x_set_halt(struct usb_ep *_ep, int value) +{ + struct lh7a40x_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + usb_set_index(ep_index(ep)); + + DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); + + spin_lock_irqsave(&ep->dev->lock, flags); + + if (ep_index(ep) == 0) { + /* EP0 */ + usb_set(EP0_SEND_STALL, ep->csr1); + } else if (ep_is_in(ep)) { + u32 csr = usb_read(ep->csr1); + if (value && ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) + || !list_empty(&ep->queue))) { + /* + * Attempts to halt IN endpoints will fail (returning -EAGAIN) + * if any transfer requests are still queued, or if the controller + * FIFO still holds bytes that the host hasnÂ’t collected. + */ + spin_unlock_irqrestore(&ep->dev->lock, flags); + DEBUG + ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", + (csr & USB_IN_CSR1_FIFO_NOT_EMPTY), + !list_empty(&ep->queue)); + return -EAGAIN; + } + flush(ep); + if (value) + usb_set(USB_IN_CSR1_SEND_STALL, ep->csr1); + else { + usb_clear(USB_IN_CSR1_SEND_STALL, ep->csr1); + usb_set(USB_IN_CSR1_CLR_DATA_TOGGLE, ep->csr1); + } + + } else { + + flush(ep); + if (value) + usb_set(USB_OUT_CSR1_SEND_STALL, ep->csr1); + else { + usb_clear(USB_OUT_CSR1_SEND_STALL, ep->csr1); + usb_set(USB_OUT_CSR1_CLR_DATA_REG, ep->csr1); + } + } + + if (value) { + ep->stopped = 1; + } else { + ep->stopped = 0; + } + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); + + return 0; +} + +/** Return bytes in EP FIFO + * NOTE: Sets INDEX register to EP + */ +static int lh7a40x_fifo_status(struct usb_ep *_ep) +{ + u32 csr; + int count = 0; + struct lh7a40x_ep *ep; + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (!_ep) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -ENODEV; + } + + DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); + + /* LPD can't report unclaimed bytes from IN fifos */ + if (ep_is_in(ep)) + return -EOPNOTSUPP; + + usb_set_index(ep_index(ep)); + + csr = usb_read(ep->csr1); + if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || + csr & USB_OUT_CSR1_OUT_PKT_RDY) { + count = usb_read(USB_OUT_FIFO_WC1); + } + + return count; +} + +/** Flush EP FIFO + * NOTE: Sets INDEX register to EP + */ +static void lh7a40x_fifo_flush(struct usb_ep *_ep) +{ + struct lh7a40x_ep *ep; + + ep = container_of(_ep, struct lh7a40x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return; + } + + usb_set_index(ep_index(ep)); + flush(ep); +} + +/****************************************************************/ +/* End Point 0 related functions */ +/****************************************************************/ + +/* return: 0 = still running, 1 = completed, negative = errno */ +static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 max; + unsigned count; + int is_last; + + max = ep_maxpacket(ep); + + DEBUG_EP0("%s\n", __FUNCTION__); + + count = write_packet(ep, req, max); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = 1; + else { + if (likely(req->req.length != req->req.actual) || req->req.zero) + is_last = 0; + else + is_last = 1; + } + + DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, + ep->ep.name, count, + is_last ? "/L" : "", req->req.length - req->req.actual, req); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + return 1; + } + + return 0; +} + +static __inline__ int lh7a40x_fifo_read(struct lh7a40x_ep *ep, + unsigned char *cp, int max) +{ + int bytes; + int count = usb_read(USB_OUT_FIFO_WC1); + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + if (count > max) + count = max; + bytes = count; + while (count--) + *cp++ = *fifo & 0xFF; + return bytes; +} + +static __inline__ void lh7a40x_fifo_write(struct lh7a40x_ep *ep, + unsigned char *cp, int count) +{ + volatile u32 *fifo = (volatile u32 *)ep->fifo; + DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count); + while (count--) + *fifo = *cp++; +} + +static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req) +{ + u32 csr; + u8 *buf; + unsigned bufferspace, count, is_short; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + + DEBUG_EP0("%s\n", __FUNCTION__); + + csr = usb_read(USB_EP0_CSR); + if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) + return 0; + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + if (likely(csr & EP0_OUT_PKT_RDY)) { + count = usb_read(USB_OUT_FIFO_WC1); + req->req.actual += min(count, bufferspace); + } else /* zlp */ + count = 0; + + is_short = (count < ep->ep.maxpacket); + DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, csr, count, + is_short ? "/S" : "", req, req->req.actual, req->req.length); + + while (likely(count-- != 0)) { + u8 byte = (u8) (*fifo & 0xff); + + if (unlikely(bufferspace == 0)) { + /* this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + DEBUG_EP0("%s overflow %d\n", ep->ep.name, + count); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + bufferspace--; + } + } + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/** + * udc_set_address - set the USB address for this device + * @address: + * + * Called from control endpoint function after it decodes a set address setup packet. + */ +static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address) +{ + DEBUG_EP0("%s: %d\n", __FUNCTION__, address); + /* c.f. 15.1.2.2 Table 15-4 address will be used after DATA_END is set */ + dev->usb_address = address; + usb_set((address & USB_FA_FUNCTION_ADDR), USB_FA); + usb_set(USB_FA_ADDR_UPDATE | (address & USB_FA_FUNCTION_ADDR), USB_FA); + /* usb_read(USB_FA); */ +} + +/* + * DATA_STATE_RECV (OUT_PKT_RDY) + * - if error + * set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits + * - else + * set EP0_CLR_OUT bit + if last set EP0_DATA_END bit + */ +static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr) +{ + struct lh7a40x_request *req; + struct lh7a40x_ep *ep = &dev->ep[0]; + int ret; + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + + if (req) { + + if (req->req.length == 0) { + DEBUG_EP0("ZERO LENGTH OUT!\n"); + usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + return; + } + ret = read_fifo_ep0(ep, req); + if (ret) { + /* Done! */ + DEBUG_EP0("%s: finished, waiting for status\n", + __FUNCTION__); + + usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + } else { + /* Not done yet.. */ + DEBUG_EP0("%s: not finished\n", __FUNCTION__); + usb_set(EP0_CLR_OUT, USB_EP0_CSR); + } + } else { + DEBUG_EP0("NO REQ??!\n"); + } +} + +/* + * DATA_STATE_XMIT + */ +static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr) +{ + struct lh7a40x_request *req; + struct lh7a40x_ep *ep = &dev->ep[0]; + int ret, need_zlp = 0; + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct lh7a40x_request, queue); + + if (!req) { + DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); + return 0; + } + + if (req->req.length == 0) { + + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + return 1; + } + + if (req->req.length - req->req.actual == EP0_PACKETSIZE) { + /* Next write will end with the packet size, */ + /* so we need Zero-length-packet */ + need_zlp = 1; + } + + ret = write_fifo_ep0(ep, req); + + if (ret == 1 && !need_zlp) { + /* Last packet */ + DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); + + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; + } else { + DEBUG_EP0("%s: not finished\n", __FUNCTION__); + usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR); + } + + if (need_zlp) { + DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); + usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR); + dev->ep0state = DATA_STATE_NEED_ZLP; + } + + return 1; +} + +static int lh7a40x_handle_get_status(struct lh7a40x_udc *dev, + struct usb_ctrlrequest *ctrl) +{ + struct lh7a40x_ep *ep0 = &dev->ep[0]; + struct lh7a40x_ep *qep; + int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); + u16 val = 0; + + if (reqtype == USB_RECIP_INTERFACE) { + /* This is not supported. + * And according to the USB spec, this one does nothing.. + * Just return 0 + */ + DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); + } else if (reqtype == USB_RECIP_DEVICE) { + DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); + val |= (1 << 0); /* Self powered */ + /*val |= (1<<1); *//* Remote wakeup */ + } else if (reqtype == USB_RECIP_ENDPOINT) { + int ep_num = (ctrl->wIndex & ~USB_DIR_IN); + + DEBUG_SETUP + ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", + ep_num, ctrl->wLength); + + if (ctrl->wLength > 2 || ep_num > 3) + return -EOPNOTSUPP; + + qep = &dev->ep[ep_num]; + if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) + && ep_index(qep) != 0) { + return -EOPNOTSUPP; + } + + usb_set_index(ep_index(qep)); + + /* Return status on next IN token */ + switch (qep->ep_type) { + case ep_control: + val = + (usb_read(qep->csr1) & EP0_SEND_STALL) == + EP0_SEND_STALL; + break; + case ep_bulk_in: + case ep_interrupt: + val = + (usb_read(qep->csr1) & USB_IN_CSR1_SEND_STALL) == + USB_IN_CSR1_SEND_STALL; + break; + case ep_bulk_out: + val = + (usb_read(qep->csr1) & USB_OUT_CSR1_SEND_STALL) == + USB_OUT_CSR1_SEND_STALL; + break; + } + + /* Back to EP0 index */ + usb_set_index(0); + + DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, + ctrl->wIndex, val); + } else { + DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); + return -EOPNOTSUPP; + } + + /* Clear "out packet ready" */ + usb_set((EP0_CLR_OUT), USB_EP0_CSR); + /* Put status to FIFO */ + lh7a40x_fifo_write(ep0, (u8 *) & val, sizeof(val)); + /* Issue "In packet ready" */ + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + + return 0; +} + +/* + * WAIT_FOR_SETUP (OUT_PKT_RDY) + * - read data packet from EP0 FIFO + * - decode command + * - if error + * set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits + * - else + * set EP0_CLR_OUT | EP0_DATA_END bits + */ +static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr) +{ + struct lh7a40x_ep *ep = &dev->ep[0]; + struct usb_ctrlrequest ctrl; + int i, bytes, is_in; + + DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); + + /* Nuke all previous transfers */ + nuke(ep, -EPROTO); + + /* read control req from fifo (8 bytes) */ + bytes = lh7a40x_fifo_read(ep, (unsigned char *)&ctrl, 8); + + DEBUG_SETUP("Read CTRL REQ %d bytes\n", bytes); + DEBUG_SETUP("CTRL.bRequestType = %d (is_in %d)\n", ctrl.bRequestType, + ctrl.bRequestType == USB_DIR_IN); + DEBUG_SETUP("CTRL.bRequest = %d\n", ctrl.bRequest); + DEBUG_SETUP("CTRL.wLength = %d\n", ctrl.wLength); + DEBUG_SETUP("CTRL.wValue = %d (%d)\n", ctrl.wValue, ctrl.wValue >> 8); + DEBUG_SETUP("CTRL.wIndex = %d\n", ctrl.wIndex); + + /* Set direction of EP0 */ + if (likely(ctrl.bRequestType & USB_DIR_IN)) { + ep->bEndpointAddress |= USB_DIR_IN; + is_in = 1; + } else { + ep->bEndpointAddress &= ~USB_DIR_IN; + is_in = 0; + } + + dev->req_pending = 1; + + /* Handle some SETUP packets ourselves */ + switch (ctrl.bRequest) { + case USB_REQ_SET_ADDRESS: + if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + + DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); + udc_set_address(dev, ctrl.wValue); + usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); + return; + + case USB_REQ_GET_STATUS:{ + if (lh7a40x_handle_get_status(dev, &ctrl) == 0) + return; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { + struct lh7a40x_ep *qep; + int ep_num = (ctrl.wIndex & 0x0f); + + /* Support only HALT feature */ + if (ctrl.wValue != 0 || ctrl.wLength != 0 + || ep_num > 3 || ep_num < 1) + break; + + qep = &dev->ep[ep_num]; + if (ctrl.bRequest == USB_REQ_SET_FEATURE) { + DEBUG_SETUP("SET_FEATURE (%d)\n", + ep_num); + lh7a40x_set_halt(&qep->ep, 1); + } else { + DEBUG_SETUP("CLR_FEATURE (%d)\n", + ep_num); + lh7a40x_set_halt(&qep->ep, 0); + } + usb_set_index(0); + + /* Reply with a ZLP on next IN token */ + usb_set((EP0_CLR_OUT | EP0_DATA_END), + USB_EP0_CSR); + return; + } + break; + } + + default: + break; + } + + if (likely(dev->driver)) { + /* device-2-host (IN) or no data setup command, process immediately */ + spin_unlock(&dev->lock); + i = dev->driver->setup(&dev->gadget, &ctrl); + spin_lock(&dev->lock); + + if (i < 0) { + /* setup processing failed, force stall */ + DEBUG_SETUP + (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", + i); + usb_set_index(0); + usb_set((EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL), + USB_EP0_CSR); + + /* ep->stopped = 1; */ + dev->ep0state = WAIT_FOR_SETUP; + } + } +} + +/* + * DATA_STATE_NEED_ZLP + */ +static void lh7a40x_ep0_in_zlp(struct lh7a40x_udc *dev, u32 csr) +{ + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + /* c.f. Table 15-14 */ + usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); + dev->ep0state = WAIT_FOR_SETUP; +} + +/* + * handle ep0 interrupt + */ +static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr) +{ + struct lh7a40x_ep *ep = &dev->ep[0]; + u32 csr; + + /* Set index 0 */ + usb_set_index(0); + csr = usb_read(USB_EP0_CSR); + + DEBUG_EP0("%s: csr = %x\n", __FUNCTION__, csr); + + /* + * For overview of what we should be doing see c.f. Chapter 18.1.2.4 + * We will follow that outline here modified by our own global state + * indication which provides hints as to what we think should be + * happening.. + */ + + /* + * if SENT_STALL is set + * - clear the SENT_STALL bit + */ + if (csr & EP0_SENT_STALL) { + DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __FUNCTION__, csr); + usb_clear((EP0_SENT_STALL | EP0_SEND_STALL), USB_EP0_CSR); + nuke(ep, -ECONNABORTED); + dev->ep0state = WAIT_FOR_SETUP; + return; + } + + /* + * if a transfer is in progress && IN_PKT_RDY and OUT_PKT_RDY are clear + * - fill EP0 FIFO + * - if last packet + * - set IN_PKT_RDY | DATA_END + * - else + * set IN_PKT_RDY + */ + if (!(csr & (EP0_IN_PKT_RDY | EP0_OUT_PKT_RDY))) { + DEBUG_EP0("%s: IN_PKT_RDY and OUT_PKT_RDY are clear\n", + __FUNCTION__); + + switch (dev->ep0state) { + case DATA_STATE_XMIT: + DEBUG_EP0("continue with DATA_STATE_XMIT\n"); + lh7a40x_ep0_in(dev, csr); + return; + case DATA_STATE_NEED_ZLP: + DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); + lh7a40x_ep0_in_zlp(dev, csr); + return; + default: + /* Stall? */ + DEBUG_EP0("Odd state!! state = %s\n", + state_names[dev->ep0state]); + dev->ep0state = WAIT_FOR_SETUP; + /* nuke(ep, 0); */ + /* usb_set(EP0_SEND_STALL, ep->csr1); */ + break; + } + } + + /* + * if SETUP_END is set + * - abort the last transfer + * - set SERVICED_SETUP_END_BIT + */ + if (csr & EP0_SETUP_END) { + DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __FUNCTION__, csr); + + usb_set(EP0_CLR_SETUP_END, USB_EP0_CSR); + + nuke(ep, 0); + dev->ep0state = WAIT_FOR_SETUP; + } + + /* + * if EP0_OUT_PKT_RDY is set + * - read data packet from EP0 FIFO + * - decode command + * - if error + * set SERVICED_OUT_PKT_RDY | DATA_END bits | SEND_STALL + * - else + * set SERVICED_OUT_PKT_RDY | DATA_END bits + */ + if (csr & EP0_OUT_PKT_RDY) { + + DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, + csr); + + switch (dev->ep0state) { + case WAIT_FOR_SETUP: + DEBUG_EP0("WAIT_FOR_SETUP\n"); + lh7a40x_ep0_setup(dev, csr); + break; + + case DATA_STATE_RECV: + DEBUG_EP0("DATA_STATE_RECV\n"); + lh7a40x_ep0_out(dev, csr); + break; + + default: + /* send stall? */ + DEBUG_EP0("strange state!! 2. send stall? state = %d\n", + dev->ep0state); + break; + } + } +} + +static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep) +{ + u32 csr; + + usb_set_index(0); + csr = usb_read(USB_EP0_CSR); + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + /* Clear "out packet ready" */ + usb_set(EP0_CLR_OUT, USB_EP0_CSR); + + if (ep_is_in(ep)) { + dev->ep0state = DATA_STATE_XMIT; + lh7a40x_ep0_in(dev, csr); + } else { + dev->ep0state = DATA_STATE_RECV; + lh7a40x_ep0_out(dev, csr); + } +} + +/* --------------------------------------------------------------------------- + * device-scoped parts of the api to the usb controller hardware + * --------------------------------------------------------------------------- + */ + +static int lh7a40x_udc_get_frame(struct usb_gadget *_gadget) +{ + u32 frame1 = usb_read(USB_FRM_NUM1); /* Least significant 8 bits */ + u32 frame2 = usb_read(USB_FRM_NUM2); /* Most significant 3 bits */ + DEBUG("%s, %p\n", __FUNCTION__, _gadget); + return ((frame2 & 0x07) << 8) | (frame1 & 0xff); +} + +static int lh7a40x_udc_wakeup(struct usb_gadget *_gadget) +{ + /* host may not have enabled remote wakeup */ + /*if ((UDCCS0 & UDCCS0_DRWF) == 0) + return -EHOSTUNREACH; + udc_set_mask_UDCCR(UDCCR_RSM); */ + return -ENOTSUPP; +} + +static const struct usb_gadget_ops lh7a40x_udc_ops = { + .get_frame = lh7a40x_udc_get_frame, + .wakeup = lh7a40x_udc_wakeup, + /* current versions must always be self-powered */ +}; + +static void nop_release(struct device *dev) +{ + DEBUG("%s %s\n", __FUNCTION__, dev->bus_id); +} + +static struct lh7a40x_udc memory = { + .usb_address = 0, + + .gadget = { + .ops = &lh7a40x_udc_ops, + .ep0 = &memory.ep[0].ep, + .name = driver_name, + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + /* control endpoint */ + .ep[0] = { + .ep = { + .name = ep0name, + .ops = &lh7a40x_ep_ops, + .maxpacket = EP0_PACKETSIZE, + }, + .dev = &memory, + + .bEndpointAddress = 0, + .bmAttributes = 0, + + .ep_type = ep_control, + .fifo = io_p2v(USB_EP0_FIFO), + .csr1 = USB_EP0_CSR, + .csr2 = USB_EP0_CSR, + }, + + /* first group of endpoints */ + .ep[1] = { + .ep = { + .name = "ep1in-bulk", + .ops = &lh7a40x_ep_ops, + .maxpacket = 64, + }, + .dev = &memory, + + .bEndpointAddress = USB_DIR_IN | 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + + .ep_type = ep_bulk_in, + .fifo = io_p2v(USB_EP1_FIFO), + .csr1 = USB_IN_CSR1, + .csr2 = USB_IN_CSR2, + }, + + .ep[2] = { + .ep = { + .name = "ep2out-bulk", + .ops = &lh7a40x_ep_ops, + .maxpacket = 64, + }, + .dev = &memory, + + .bEndpointAddress = 2, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + + .ep_type = ep_bulk_out, + .fifo = io_p2v(USB_EP2_FIFO), + .csr1 = USB_OUT_CSR1, + .csr2 = USB_OUT_CSR2, + }, + + .ep[3] = { + .ep = { + .name = "ep3in-int", + .ops = &lh7a40x_ep_ops, + .maxpacket = 64, + }, + .dev = &memory, + + .bEndpointAddress = USB_DIR_IN | 3, + .bmAttributes = USB_ENDPOINT_XFER_INT, + + .ep_type = ep_interrupt, + .fifo = io_p2v(USB_EP3_FIFO), + .csr1 = USB_IN_CSR1, + .csr2 = USB_IN_CSR2, + }, +}; + +/* + * probe - binds to the platform device + */ +static int lh7a40x_udc_probe(struct device *_dev) +{ + struct lh7a40x_udc *dev = &memory; + int retval; + + DEBUG("%s: %p\n", __FUNCTION__, _dev); + + spin_lock_init(&dev->lock); + dev->dev = _dev; + + device_initialize(&dev->gadget.dev); + dev->gadget.dev.parent = _dev; + + the_controller = dev; + dev_set_drvdata(_dev, dev); + + udc_disable(dev); + udc_reinit(dev); + + /* irq setup after old hardware state is cleaned up */ + retval = + request_irq(IRQ_USBINTR, lh7a40x_udc_irq, SA_INTERRUPT, driver_name, + dev); + if (retval != 0) { + DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, + IRQ_USBINTR, retval); + return -EBUSY; + } + + create_proc_files(); + + return retval; +} + +static int lh7a40x_udc_remove(struct device *_dev) +{ + struct lh7a40x_udc *dev = _dev->driver_data; + + DEBUG("%s: %p\n", __FUNCTION__, dev); + + udc_disable(dev); + remove_proc_files(); + usb_gadget_unregister_driver(dev->driver); + + free_irq(IRQ_USBINTR, dev); + + dev_set_drvdata(_dev, 0); + + the_controller = 0; + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct device_driver udc_driver = { + .name = (char *)driver_name, + .bus = &platform_bus_type, + .probe = lh7a40x_udc_probe, + .remove = lh7a40x_udc_remove + /* FIXME power management support */ + /* .suspend = ... disable UDC */ + /* .resume = ... re-enable UDC */ +}; + +static int __init udc_init(void) +{ + DEBUG("%s: %s version %s\n", __FUNCTION__, driver_name, DRIVER_VERSION); + return driver_register(&udc_driver); +} + +static void __exit udc_exit(void) +{ + driver_unregister(&udc_driver); +} + +module_init(udc_init); +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Mikko Lahteenmaki, Bo Henriksen"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h new file mode 100644 index 000000000..1bb455c04 --- /dev/null +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -0,0 +1,261 @@ +/* + * linux/drivers/usb/gadget/lh7a40x_udc.h + * Sharp LH7A40x on-chip full speed USB device controllers + * + * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID + * Copyright (C) 2004 Bo Henriksen, Nordic ID + * + * 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 + * + */ + +#ifndef __LH7A40X_H_ +#define __LH7A40X_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Memory map + */ + +#define USB_FA 0x80000200 // function address register +#define USB_PM 0x80000204 // power management register + +#define USB_IN_INT 0x80000208 // IN interrupt register bank (EP0-EP3) +#define USB_OUT_INT 0x80000210 // OUT interrupt register bank (EP2) +#define USB_INT 0x80000218 // interrupt register bank + +#define USB_IN_INT_EN 0x8000021C // IN interrupt enable register bank +#define USB_OUT_INT_EN 0x80000224 // OUT interrupt enable register bank +#define USB_INT_EN 0x8000022C // USB interrupt enable register bank + +#define USB_FRM_NUM1 0x80000230 // Frame number1 register +#define USB_FRM_NUM2 0x80000234 // Frame number2 register +#define USB_INDEX 0x80000238 // index register + +#define USB_IN_MAXP 0x80000240 // IN MAXP register +#define USB_IN_CSR1 0x80000244 // IN CSR1 register/EP0 CSR register +#define USB_EP0_CSR 0x80000244 // IN CSR1 register/EP0 CSR register +#define USB_IN_CSR2 0x80000248 // IN CSR2 register +#define USB_OUT_MAXP 0x8000024C // OUT MAXP register + +#define USB_OUT_CSR1 0x80000250 // OUT CSR1 register +#define USB_OUT_CSR2 0x80000254 // OUT CSR2 register +#define USB_OUT_FIFO_WC1 0x80000258 // OUT FIFO write count1 register +#define USB_OUT_FIFO_WC2 0x8000025C // OUT FIFO write count2 register + +#define USB_RESET 0x8000044C // USB reset register + +#define USB_EP0_FIFO 0x80000280 +#define USB_EP1_FIFO 0x80000284 +#define USB_EP2_FIFO 0x80000288 +#define USB_EP3_FIFO 0x8000028c + +/* + * USB reset register + */ +#define USB_RESET_APB (1<<1) //resets USB APB control side WRITE +#define USB_RESET_IO (1<<0) //resets USB IO side WRITE + +/* + * USB function address register + */ +#define USB_FA_ADDR_UPDATE (1<<7) +#define USB_FA_FUNCTION_ADDR (0x7F) + +/* + * Power Management register + */ +#define PM_USB_DCP (1<<5) +#define PM_USB_ENABLE (1<<4) +#define PM_USB_RESET (1<<3) +#define PM_UC_RESUME (1<<2) +#define PM_SUSPEND_MODE (1<<1) +#define PM_ENABLE_SUSPEND (1<<0) + +/* + * IN interrupt register + */ +#define USB_IN_INT_EP3 (1<<3) +#define USB_IN_INT_EP1 (1<<1) +#define USB_IN_INT_EP0 (1<<0) + +/* + * OUT interrupt register + */ +#define USB_OUT_INT_EP2 (1<<2) + +/* + * USB interrupt register + */ +#define USB_INT_RESET_INT (1<<2) +#define USB_INT_RESUME_INT (1<<1) +#define USB_INT_SUSPEND_INT (1<<0) + +/* + * USB interrupt enable register + */ +#define USB_INT_EN_USB_RESET_INTER (1<<2) +#define USB_INT_EN_RESUME_INTER (1<<1) +#define USB_INT_EN_SUSPEND_INTER (1<<0) + +/* + * INCSR1 register + */ +#define USB_IN_CSR1_CLR_DATA_TOGGLE (1<<6) +#define USB_IN_CSR1_SENT_STALL (1<<5) +#define USB_IN_CSR1_SEND_STALL (1<<4) +#define USB_IN_CSR1_FIFO_FLUSH (1<<3) +#define USB_IN_CSR1_FIFO_NOT_EMPTY (1<<1) +#define USB_IN_CSR1_IN_PKT_RDY (1<<0) + +/* + * INCSR2 register + */ +#define USB_IN_CSR2_AUTO_SET (1<<7) +#define USB_IN_CSR2_USB_DMA_EN (1<<4) + +/* + * OUT CSR1 register + */ +#define USB_OUT_CSR1_CLR_DATA_REG (1<<7) +#define USB_OUT_CSR1_SENT_STALL (1<<6) +#define USB_OUT_CSR1_SEND_STALL (1<<5) +#define USB_OUT_CSR1_FIFO_FLUSH (1<<4) +#define USB_OUT_CSR1_FIFO_FULL (1<<1) +#define USB_OUT_CSR1_OUT_PKT_RDY (1<<0) + +/* + * OUT CSR2 register + */ +#define USB_OUT_CSR2_AUTO_CLR (1<<7) +#define USB_OUT_CSR2_USB_DMA_EN (1<<4) + +/* + * EP0 CSR + */ +#define EP0_CLR_SETUP_END (1<<7) /* Clear "Setup Ends" Bit (w) */ +#define EP0_CLR_OUT (1<<6) /* Clear "Out packet ready" Bit (w) */ +#define EP0_SEND_STALL (1<<5) /* Send STALL Handshake (rw) */ +#define EP0_SETUP_END (1<<4) /* Setup Ends (r) */ + +#define EP0_DATA_END (1<<3) /* Data end (rw) */ +#define EP0_SENT_STALL (1<<2) /* Sent Stall Handshake (r) */ +#define EP0_IN_PKT_RDY (1<<1) /* In packet ready (rw) */ +#define EP0_OUT_PKT_RDY (1<<0) /* Out packet ready (r) */ + +/* general CSR */ +#define OUT_PKT_RDY (1<<0) +#define IN_PKT_RDY (1<<0) + +/* + * IN/OUT MAXP register + */ +#define USB_OUT_MAXP_MAXP (0xF) +#define USB_IN_MAXP_MAXP (0xF) + +// Max packet size +//#define EP0_PACKETSIZE 0x10 +#define EP0_PACKETSIZE 0x8 +#define EP0_MAXPACKETSIZE 0x10 + +#define UDC_MAX_ENDPOINTS 4 + +#define WAIT_FOR_SETUP 0 +#define DATA_STATE_XMIT 1 +#define DATA_STATE_NEED_ZLP 2 +#define WAIT_FOR_OUT_STATUS 3 +#define DATA_STATE_RECV 4 + +/* ********************************************************************************************* */ +/* IO + */ + +typedef enum ep_type { + ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt +} ep_type_t; + +struct lh7a40x_ep { + struct usb_ep ep; + struct lh7a40x_udc *dev; + + const struct usb_endpoint_descriptor *desc; + struct list_head queue; + unsigned long pio_irqs; + + u8 stopped; + u8 bEndpointAddress; + u8 bmAttributes; + + ep_type_t ep_type; + u32 fifo; + u32 csr1; + u32 csr2; +}; + +struct lh7a40x_request { + struct usb_request req; + struct list_head queue; +}; + +struct lh7a40x_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct device *dev; + spinlock_t lock; + + int ep0state; + struct lh7a40x_ep ep[UDC_MAX_ENDPOINTS]; + + unsigned char usb_address; + + unsigned req_pending:1, req_std:1, req_config:1; +}; + +extern struct lh7a40x_udc *the_controller; + +#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN) +#define ep_index(EP) ((EP)->bEndpointAddress&0xF) +#define ep_maxpacket(EP) ((EP)->ep.maxpacket) + +#endif diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 880b1f799..d28de0b8c 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -7,13 +7,9 @@ * * CODE STATUS HIGHLIGHTS * - * Used with a gadget driver like "zero.c" this enumerates fine to Windows - * or Linux hosts; handles disconnect, reconnect, and reset, for full or - * high speed operation; and passes USB-IF "chapter 9" tests. - * - * Handles standard stress loads from the Linux "usbtest" driver, with - * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}. Testing - * with "ttcp" (and the "ether.c" driver) behaves nicely too. + * This driver should work well with most "gadget" drivers, including + * the File Storage, Serial, and Ethernet/RNDIS gadget drivers + * as well as Gadget Zero and Gadgetfs. * * DMA is enabled by default. Drivers using transfer queues might use * DMA chaining to remove IRQ latencies between transfers. (Except when @@ -257,7 +253,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) return 0; } -static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -276,7 +272,7 @@ static int handshake (u32 *ptr, u32 mask, u32 done, int usec) static struct usb_ep_ops net2280_ep_ops; -static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep) +static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) { u32 tmp; @@ -307,14 +303,16 @@ static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep) /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) */ - writel ( (1 << SET_NAK_OUT_PACKETS_MODE) + tmp = (1 << SET_NAK_OUT_PACKETS_MODE) | (1 << SET_NAK_OUT_PACKETS) | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE) - | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - | (1 << CLEAR_ENDPOINT_TOGGLE) - | (1 << CLEAR_ENDPOINT_HALT) - , &ep->regs->ep_rsp); + | (1 << CLEAR_INTERRUPT_MODE); + + if (ep->num != 0) { + tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) + | (1 << CLEAR_ENDPOINT_HALT); + } + writel (tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ writel ( (1 << TIMEOUT) @@ -517,7 +515,7 @@ net2280_free_buffer ( static void write_fifo (struct net2280_ep *ep, struct usb_request *req) { - struct net2280_ep_regs *regs = ep->regs; + struct net2280_ep_regs __iomem *regs = ep->regs; u8 *buf; u32 tmp; unsigned count, total; @@ -577,7 +575,8 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) */ static void out_flush (struct net2280_ep *ep) { - u32 *statp, tmp; + u32 __iomem *statp; + u32 tmp; ASSERT_OUT_NAKING (ep); @@ -610,7 +609,7 @@ static void out_flush (struct net2280_ep *ep) static int read_fifo (struct net2280_ep *ep, struct net2280_request *req) { - struct net2280_ep_regs *regs = ep->regs; + struct net2280_ep_regs __iomem *regs = ep->regs; u8 *buf = req->req.buf + req->req.actual; unsigned count, tmp, is_short; unsigned cleanup = 0, prevent = 0; @@ -678,7 +677,7 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) } if (count) { tmp = readl (®s->ep_data); - cpu_to_le32s (&tmp); + /* LE conversion is implicit here: */ do { *buf++ = (u8) tmp; tmp >>= 8; @@ -737,12 +736,12 @@ static const u32 dmactl_default = /* erratum 0116 workaround part 2 (no AUTOSTART) */ | (1 << DMA_ENABLE); -static inline void spin_stop_dma (struct net2280_dma_regs *dma) +static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma) { handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50); } -static inline void stop_dma (struct net2280_dma_regs *dma) +static inline void stop_dma (struct net2280_dma_regs __iomem *dma) { writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl); spin_stop_dma (dma); @@ -750,7 +749,7 @@ static inline void stop_dma (struct net2280_dma_regs *dma) static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) { - struct net2280_dma_regs *dma = ep->dma; + struct net2280_dma_regs __iomem *dma = ep->dma; writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION), &dma->dmacount); @@ -771,7 +770,7 @@ static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) static void start_dma (struct net2280_ep *ep, struct net2280_request *req) { u32 tmp; - struct net2280_dma_regs *dma = ep->dma; + struct net2280_dma_regs __iomem *dma = ep->dma; /* FIXME can't use DMA for ZLPs */ @@ -1419,10 +1418,34 @@ static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) return 0; } +static int net2280_pullup(struct usb_gadget *_gadget, int is_on) +{ + struct net2280 *dev; + u32 tmp; + unsigned long flags; + + if (!_gadget) + return -ENODEV; + dev = container_of (_gadget, struct net2280, gadget); + + spin_lock_irqsave (&dev->lock, flags); + tmp = readl (&dev->usb->usbctl); + dev->softconnect = (is_on != 0); + if (is_on) + tmp |= (1 << USB_DETECT_ENABLE); + else + tmp &= ~(1 << USB_DETECT_ENABLE); + writel (tmp, &dev->usb->usbctl); + spin_unlock_irqrestore (&dev->lock, flags); + + return 0; +} + static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, .wakeup = net2280_wakeup, .set_selfpowered = net2280_set_selfpowered, + .pullup = net2280_pullup, }; /*-------------------------------------------------------------------------*/ @@ -1807,8 +1830,6 @@ static void usb_reset (struct net2280 *dev) { u32 tmp; - /* force immediate bus disconnect, and synch through pci */ - writel (0, &dev->usb->usbctl); dev->gadget.speed = USB_SPEED_UNKNOWN; (void) readl (&dev->usb->usbctl); @@ -1902,10 +1923,8 @@ static void ep0_start (struct net2280 *dev) , &dev->usb->stdrsp); writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | (1 << SELF_POWERED_USB_DEVICE) - /* erratum 0102 workaround */ - | ((dev->chiprev == 0100) ? 0 : 1) << SUSPEND_IMMEDIATELY | (1 << REMOTE_WAKEUP_SUPPORT) - | (1 << USB_DETECT_ENABLE) + | (dev->softconnect << USB_DETECT_ENABLE) | (1 << SELF_POWERED_STATUS) , &dev->usb->usbctl); @@ -1957,6 +1976,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) dev->ep [i].irqs = 0; /* hook up the driver ... */ + dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; @@ -2028,6 +2048,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) stop_activity (dev, driver); spin_unlock_irqrestore (&dev->lock, flags); + net2280_pullup (&dev->gadget, 0); + driver->unbind (&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2492,15 +2514,23 @@ next_endpoints: static void handle_stat1_irqs (struct net2280 *dev, u32 stat) { struct net2280_ep *ep; - u32 tmp, num, scratch; + u32 tmp, num, mask, scratch; /* after disconnect there's nothing else to do! */ tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); + mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED); + + /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. + * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and + * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT + * only indicates a change in the reset state). + */ if (stat & tmp) { writel (tmp, &dev->regs->irqstat1); - if (((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) != 0 - || (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0 - ) && dev->gadget.speed != USB_SPEED_UNKNOWN) { + if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && + ((readl (&dev->usb->usbstat) & mask) == 0)) + || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0) + ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { DEBUG (dev, "disconnect %s\n", dev->driver->driver.name); stop_activity (dev, dev->driver); @@ -2525,8 +2555,6 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend (&dev->gadget); - /* we use SUSPEND_IMMEDIATELY */ - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); } else { if (dev->driver->resume) dev->driver->resume (&dev->gadget); @@ -2553,7 +2581,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) stat &= ~DMA_INTERRUPTS; scratch >>= 9; for (num = 0; scratch; num++) { - struct net2280_dma_regs *dma; + struct net2280_dma_regs __iomem *dma; tmp = 1 << num; if ((tmp & scratch) == 0) @@ -2722,7 +2750,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) { struct net2280 *dev; unsigned long resource, len; - void *base = NULL; + void __iomem *base = NULL; int retval, i; char buf [8], *bufp; @@ -2780,14 +2808,15 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) retval = -EFAULT; goto done; } - dev->regs = (struct net2280_regs *) base; - dev->usb = (struct net2280_usb_regs *) (base + 0x0080); - dev->pci = (struct net2280_pci_regs *) (base + 0x0100); - dev->dma = (struct net2280_dma_regs *) (base + 0x0180); - dev->dep = (struct net2280_dep_regs *) (base + 0x0200); - dev->epregs = (struct net2280_ep_regs *) (base + 0x0300); + dev->regs = (struct net2280_regs __iomem *) base; + dev->usb = (struct net2280_usb_regs __iomem *) (base + 0x0080); + dev->pci = (struct net2280_pci_regs __iomem *) (base + 0x0100); + dev->dma = (struct net2280_dma_regs __iomem *) (base + 0x0180); + dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); + dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); /* put into initial config, link up all endpoints */ + writel (0, &dev->usb->usbctl); usb_reset (dev); usb_reinit (dev); diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index ec9d6f7e7..8033c4eec 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -446,7 +446,7 @@ struct net2280_ep_regs { /* [11.9] */ */ static inline u32 -get_idx_reg (struct net2280_regs *regs, u32 index) +get_idx_reg (struct net2280_regs __iomem *regs, u32 index) { writel (index, ®s->idxaddr); /* NOTE: synchs device/cpu memory views */ @@ -454,7 +454,7 @@ get_idx_reg (struct net2280_regs *regs, u32 index) } static inline void -set_idx_reg (struct net2280_regs *regs, u32 index, u32 value) +set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value) { writel (index, ®s->idxaddr); writel (value, ®s->idxdata); @@ -507,8 +507,8 @@ struct net2280_dma { struct net2280_ep { struct usb_ep ep; - struct net2280_ep_regs *regs; - struct net2280_dma_regs *dma; + struct net2280_ep_regs __iomem *regs; + struct net2280_dma_regs __iomem *dma; struct net2280_dma *dummy; dma_addr_t td_dma; /* of dummy */ struct net2280 *dev; @@ -539,7 +539,7 @@ static inline void allow_status (struct net2280_ep *ep) /* count (<= 4) bytes in the next fifo write will be valid */ static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count) { - writeb (count, 2 + (u8 *) &ep->regs->ep_cfg); + writeb (count, 2 + (u8 __iomem *) &ep->regs->ep_cfg); } struct net2280_request { @@ -559,18 +559,19 @@ struct net2280 { struct usb_gadget_driver *driver; unsigned enabled : 1, protocol_stall : 1, + softconnect : 1, got_irq : 1, region : 1; u16 chiprev; /* pci state used to access those endpoints */ struct pci_dev *pdev; - struct net2280_regs *regs; - struct net2280_usb_regs *usb; - struct net2280_pci_regs *pci; - struct net2280_dma_regs *dma; - struct net2280_dep_regs *dep; - struct net2280_ep_regs *epregs; + struct net2280_regs __iomem *regs; + struct net2280_usb_regs __iomem *usb; + struct net2280_pci_regs __iomem *pci; + struct net2280_dma_regs __iomem *dma; + struct net2280_dep_regs __iomem *dep; + struct net2280_ep_regs __iomem *epregs; struct pci_pool *requests; // statistics... diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c new file mode 100644 index 000000000..e40089d79 --- /dev/null +++ b/drivers/usb/gadget/omap_udc.c @@ -0,0 +1,2695 @@ +/* + * omap_udc.c -- for OMAP 1610 udc, with OTG support + * + * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2004 David Brownell + * + * 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 + */ + +#undef DEBUG +#undef VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "omap_udc.h" + +#undef USB_TRACE + +/* OUT-dma seems to be behaving */ +#define USE_DMA + +/* ISO too */ +#define USE_ISO + + +#define DRIVER_DESC "OMAP UDC driver" +#define DRIVER_VERSION "24 August 2004" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + + +/* + * The OMAP UDC needs _very_ early endpoint setup: before enabling the + * D+ pullup to allow enumeration. That's too early for the gadget + * framework to use from usb_endpoint_enable(), which happens after + * enumeration as part of activating an interface. (But if we add an + * optional new "UDC not yet running" state to the gadget driver model, + * even just during driver binding, the endpoint autoconfig logic is the + * natural spot to manufacture new endpoints.) + * + * So instead of using endpoint enable calls to control the hardware setup, + * this driver defines a "fifo mode" parameter. It's used during driver + * initialization to choose among a set of pre-defined endpoint configs. + * See omap_udc_setup() for available modes, or to add others. That code + * lives in an init section, so use this driver as a module if you need + * to change the fifo mode after the kernel boots. + * + * Gadget drivers normally ignore endpoints they don't care about, and + * won't include them in configuration descriptors. That means only + * misbehaving hosts would even notice they exist. + */ +#ifdef USE_ISO +static unsigned fifo_mode = 3; +#else +static unsigned fifo_mode = 0; +#endif + +/* "modprobe omap_udc fifo_mode=42", or else as a kernel + * boot parameter "omap_udc:fifo_mode=42" + */ +module_param (fifo_mode, uint, 0); +MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)"); + + +#ifdef USE_DMA +static unsigned use_dma = 1; + +/* "modprobe omap_udc use_dma=y", or else as a kernel + * boot parameter "omap_udc:use_dma=y" + */ +module_param (use_dma, bool, 0); +MODULE_PARM_DESC (use_dma, "enable/disable DMA"); +#else /* !USE_DMA */ + +/* save a bit of code */ +#define use_dma 0 +#endif /* !USE_DMA */ + + +static const char driver_name [] = "omap_udc"; +static const char driver_desc [] = DRIVER_DESC; + +/*-------------------------------------------------------------------------*/ + +/* there's a notion of "current endpoint" for modifying endpoint + * state, and PIO access to its FIFO. + */ + +static void use_ep(struct omap_ep *ep, u16 select) +{ + u16 num = ep->bEndpointAddress & 0x0f; + + if (ep->bEndpointAddress & USB_DIR_IN) + num |= UDC_EP_DIR; + UDC_EP_NUM_REG = num | select; + /* when select, MUST deselect later !! */ +} + +static inline void deselect_ep(void) +{ + UDC_EP_NUM_REG &= ~UDC_EP_SEL; + /* 6 wait states before TX will happen */ +} + +static void dma_channel_claim(struct omap_ep *ep, unsigned preferred); + +/*-------------------------------------------------------------------------*/ + +static int omap_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + struct omap_udc *udc; + unsigned long flags; + u16 maxp; + + /* catch various bogus parameters */ + if (!_ep || !desc || ep->desc + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep->maxpacket < le16_to_cpu + (desc->wMaxPacketSize)) { + DBG("%s, bad ep or descriptor\n", __FUNCTION__); + return -EINVAL; + } + maxp = le16_to_cpu (desc->wMaxPacketSize); + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && maxp != ep->maxpacket) + || desc->wMaxPacketSize > ep->maxpacket + || !desc->wMaxPacketSize) { + DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); + return -ERANGE; + } + +#ifdef USE_ISO + if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC + && desc->bInterval != 1)) { + /* hardware wants period = 1; USB allows 2^(Interval-1) */ + DBG("%s, unsupported ISO period %dms\n", _ep->name, + 1 << (desc->bInterval - 1)); + return -EDOM; + } +#else + if (desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + DBG("%s, ISO nyet\n", _ep->name); + return -EDOM; + } +#endif + + /* xfer types must match, except that interrupt ~= bulk */ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DBG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); + return -EINVAL; + } + + udc = ep->udc; + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { + DBG("%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&udc->lock, flags); + + ep->desc = desc; + ep->irqs = 0; + ep->stopped = 0; + ep->ep.maxpacket = maxp; + + /* set endpoint to initial state */ + ep->dma_channel = 0; + ep->has_dma = 0; + ep->lch = -1; + use_ep(ep, UDC_EP_SEL); + UDC_CTRL_REG = UDC_RESET_EP; + ep->ackwait = 0; + deselect_ep(); + + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) + list_add(&ep->iso, &udc->iso); + + /* maybe assign a DMA channel to this endpoint */ + if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && !(ep->bEndpointAddress & USB_DIR_IN)) + /* FIXME ISO can dma, but prefers first channel. + * IN can dma, but lacks debugging. + */ + dma_channel_claim(ep, 0); + + /* PIO OUT may RX packets */ + if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC + && !ep->has_dma + && !(ep->bEndpointAddress & USB_DIR_IN)) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + + spin_unlock_irqrestore(&udc->lock, flags); + VDBG("%s enabled\n", _ep->name); + return 0; +} + +static void nuke(struct omap_ep *, int status); + +static int omap_ep_disable(struct usb_ep *_ep) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + unsigned long flags; + + if (!_ep || !ep->desc) { + DBG("%s, %s not enabled\n", __FUNCTION__, + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + ep->desc = 0; + nuke (ep, -ESHUTDOWN); + ep->ep.maxpacket = ep->maxpacket; + ep->has_dma = 0; + UDC_CTRL_REG = UDC_SET_HALT; + list_del_init(&ep->iso); + + spin_unlock_irqrestore(&ep->udc->lock, flags); + + VDBG("%s disabled\n", _ep->name); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +omap_alloc_request(struct usb_ep *ep, int gfp_flags) +{ + struct omap_req *req; + + req = kmalloc(sizeof *req, gfp_flags); + if (req) { + memset (req, 0, sizeof *req); + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD (&req->queue); + } + return &req->req; +} + +static void +omap_free_request(struct usb_ep *ep, struct usb_request *_req) +{ + struct omap_req *req = container_of(_req, struct omap_req, req); + + if (_req) + kfree (req); +} + +/*-------------------------------------------------------------------------*/ + +static void * +omap_alloc_buffer( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + int gfp_flags +) +{ + void *retval; + struct omap_ep *ep; + + ep = container_of(_ep, struct omap_ep, ep); + if (use_dma && ep->has_dma) { + static int warned; + if (!warned && bytes < PAGE_SIZE) { + dev_warn(ep->udc->gadget.dev.parent, + "using dma_alloc_coherent for " + "small allocations wastes memory\n"); + warned++; + } + return dma_alloc_coherent(ep->udc->gadget.dev.parent, + bytes, dma, gfp_flags); + } + + retval = kmalloc(bytes, gfp_flags); + if (retval) + *dma = virt_to_phys(retval); + return retval; +} + +static void omap_free_buffer( + struct usb_ep *_ep, + void *buf, + dma_addr_t dma, + unsigned bytes +) +{ + struct omap_ep *ep; + + ep = container_of(_ep, struct omap_ep, ep); + if (use_dma && _ep && ep->has_dma) + dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); + else + kfree (buf); +} + +/*-------------------------------------------------------------------------*/ + +static void +done(struct omap_ep *ep, struct omap_req *req, int status) +{ + unsigned stopped = ep->stopped; + + list_del_init(&req->queue); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + if (use_dma && ep->has_dma) { + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } else + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + } + +#ifndef USB_TRACE + if (status && status != -ESHUTDOWN) +#endif + VDBG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + spin_unlock(&ep->udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->udc->lock); + ep->stopped = stopped; +} + +/*-------------------------------------------------------------------------*/ + +#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) +#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL) + +#define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) +#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) + +static inline int +write_packet(u8 *buf, struct omap_req *req, unsigned max) +{ + unsigned len; + u16 *wp; + + len = min(req->req.length - req->req.actual, max); + req->req.actual += len; + + max = len; + if (likely((((int)buf) & 1) == 0)) { + wp = (u16 *)buf; + while (max >= 2) { + UDC_DATA_REG = *wp++; + max -= 2; + } + buf = (u8 *)wp; + } + while (max--) + *(volatile u8 *)&UDC_DATA_REG = *buf++; + return len; +} + +// FIXME change r/w fifo calling convention + + +// return: 0 = still running, 1 = completed, negative = errno +static int write_fifo(struct omap_ep *ep, struct omap_req *req) +{ + u8 *buf; + unsigned count; + int is_last; + u16 ep_stat; + + buf = req->req.buf + req->req.actual; + prefetch(buf); + + /* PIO-IN isn't double buffered except for iso */ + ep_stat = UDC_STAT_FLG_REG; + if (ep_stat & FIFO_UNWRITABLE) + return 0; + + count = ep->ep.maxpacket; + count = write_packet(buf, req, count); + UDC_CTRL_REG = UDC_SET_FIFO_EN; + ep->ackwait = 1; + + /* last packet is often short (sometimes a zlp) */ + if (count != ep->ep.maxpacket) + is_last = 1; + else if (req->req.length == req->req.actual + && !req->req.zero) + is_last = 1; + else + is_last = 0; + + /* NOTE: requests complete when all IN data is in a + * FIFO (or sometimes later, if a zlp was needed). + * Use usb_ep_fifo_status() where needed. + */ + if (is_last) + done(ep, req, 0); + return is_last; +} + +static inline int +read_packet(u8 *buf, struct omap_req *req, unsigned avail) +{ + unsigned len; + u16 *wp; + + len = min(req->req.length - req->req.actual, avail); + req->req.actual += len; + avail = len; + + if (likely((((int)buf) & 1) == 0)) { + wp = (u16 *)buf; + while (avail >= 2) { + *wp++ = UDC_DATA_REG; + avail -= 2; + } + buf = (u8 *)wp; + } + while (avail--) + *buf++ = *(volatile u8 *)&UDC_DATA_REG; + return len; +} + +// return: 0 = still running, 1 = queue empty, negative = errno +static int read_fifo(struct omap_ep *ep, struct omap_req *req) +{ + u8 *buf; + unsigned count, avail; + int is_last; + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + + for (;;) { + u16 ep_stat = UDC_STAT_FLG_REG; + + is_last = 0; + if (ep_stat & FIFO_UNREADABLE) + break; + + if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL)) + avail = ep->ep.maxpacket; + else + avail = UDC_RXFSTAT_REG; + count = read_packet(buf, req, avail); + + // FIXME double buffered PIO OUT wasn't behaving... + + /* partial packet reads may not be errors */ + if (count < ep->ep.maxpacket) { + is_last = 1; + /* overflowed this request? flush extra data */ + if (count != avail) { + req->req.status = -EOVERFLOW; + avail -= count; + while (avail--) + (void) *(volatile u8 *)&UDC_DATA_REG; + } + } else if (req->req.length == req->req.actual) + is_last = 1; + else + is_last = 0; + + if (!ep->bEndpointAddress) + break; + if (!ep->double_buf) { + UDC_CTRL_REG = UDC_SET_FIFO_EN; + if (!is_last) + break; + } + + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue) || !ep->double_buf) + break; + req = container_of(ep->queue.next, + struct omap_req, queue); + is_last = 0; + } + } + return is_last; +} + +/*-------------------------------------------------------------------------*/ + +/* Each USB transfer request using DMA maps to one or more DMA transfers. + * When DMA completion isn't request completion, the UDC continues with + * the next DMA transfer for that USB transfer. + */ + +static void next_in_dma(struct omap_ep *ep, struct omap_req *req) +{ + u16 txdma_ctrl; + unsigned length = req->req.length - req->req.actual; + + /* measure length in either bytes or packets */ + if (length <= (UDC_TXN_TSC + 1)) { + txdma_ctrl = UDC_TXN_EOT | length; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + length, 1, OMAP_DMA_SYNC_ELEMENT); + } else { + length = max(length / ep->maxpacket, + (unsigned) UDC_TXN_TSC + 1); + txdma_ctrl = length; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + ep->ep.maxpacket, length, + OMAP_DMA_SYNC_ELEMENT); + length *= ep->maxpacket; + } + + omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + + omap_start_dma(ep->lch); + UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel); + UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl; + req->dma_bytes = length; +} + +static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) +{ + if (status == 0) { + req->req.actual += req->dma_bytes; + + /* return if this request needs to send data or zlp */ + if (req->req.actual < req->req.length) + return; + if (req->req.zero + && req->dma_bytes != 0 + && (req->req.actual % ep->maxpacket) == 0) + return; + } else { + u32 last; + + // FIXME this surely isn't #bytes transferred + last = (omap_readw(OMAP_DMA_CSSA_U(ep->lch)) << 16) + | omap_readw(OMAP_DMA_CSSA_L(ep->lch)); + req->req.actual = last - req->req.dma; + } + + /* tx completion */ + omap_stop_dma(ep->lch); + UDC_DMA_IRQ_EN_REG &= ~UDC_TX_DONE_IE(ep->dma_channel); + done(ep, req, status); +} + +static void next_out_dma(struct omap_ep *ep, struct omap_req *req) +{ + unsigned packets; + + /* NOTE: we filtered out "short reads" before, so we know + * the buffer has only whole numbers of packets. + */ + + /* set up this DMA transfer, enable the fifo, start */ + packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; + packets = min(packets, (unsigned)UDC_RXN_TC + 1); + req->dma_bytes = packets * ep->ep.maxpacket; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + ep->ep.maxpacket, packets, + OMAP_DMA_SYNC_ELEMENT); + omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + + UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); + UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel); + UDC_EP_NUM_REG = (ep->bEndpointAddress & 0xf); + UDC_CTRL_REG = UDC_SET_FIFO_EN; + + omap_start_dma(ep->lch); +} + +static void +finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) +{ + u16 count; + + /* FIXME must be a better way to see how much dma + * happened, even when it never got going... + */ + count = omap_readw(OMAP_DMA_CDAC(ep->lch)); + count -= 0xffff & (req->req.dma + req->req.actual); + count += req->req.actual; + if (count <= req->req.length) + req->req.actual = count; + + if (count != req->dma_bytes || status) + omap_stop_dma(ep->lch); + + /* if this wasn't short, request may need another transfer */ + else if (req->req.actual < req->req.length) + return; + + /* rx completion */ + UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel); + done(ep, req, status); +} + +static void dma_irq(struct omap_udc *udc, u16 irq_src) +{ + u16 dman_stat = UDC_DMAN_STAT_REG; + struct omap_ep *ep; + struct omap_req *req; + + /* IN dma: tx to host */ + if (irq_src & UDC_TXN_DONE) { + ep = &udc->ep[16 + UDC_DMA_TX_SRC(dman_stat)]; + ep->irqs++; + /* can see TXN_DONE after dma abort */ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + finish_in_dma(ep, req, 0); + } + UDC_IRQ_SRC_REG = UDC_TXN_DONE; + + if (!list_empty (&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + next_in_dma(ep, req); + } + } + + /* OUT dma: rx from host */ + if (irq_src & UDC_RXN_EOT) { + ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; + ep->irqs++; + /* can see RXN_EOT after dma abort */ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + finish_out_dma(ep, req, 0); + } + UDC_IRQ_SRC_REG = UDC_RXN_EOT; + + if (!list_empty (&ep->queue)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + next_out_dma(ep, req); + } + } + + if (irq_src & UDC_RXN_CNT) { + ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; + DBG("%s, RX_CNT irq?\n", ep->ep.name); + UDC_IRQ_SRC_REG = UDC_RXN_CNT; + } +} + +static void dma_error(int lch, u16 ch_status, void *data) +{ + struct omap_ep *ep = data; + + /* if ch_status & OMAP_DMA_DROP_IRQ ... */ + /* if ch_status & OMAP_DMA_TOUT_IRQ ... */ + ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status); + + /* complete current transfer ... */ +} + +static void dma_channel_claim(struct omap_ep *ep, unsigned channel) +{ + u16 reg; + int status, restart, is_in; + + is_in = ep->bEndpointAddress & USB_DIR_IN; + if (is_in) + reg = UDC_TXDMA_CFG_REG; + else + reg = UDC_RXDMA_CFG_REG; + reg |= 1 << 12; /* "pulse" activated */ + + ep->dma_channel = 0; + ep->lch = -1; + if (channel == 0 || channel > 3) { + if ((reg & 0x0f00) == 0) + channel = 3; + else if ((reg & 0x00f0) == 0) + channel = 2; + else if ((reg & 0x000f) == 0) /* preferred for ISO */ + channel = 1; + else { + status = -EMLINK; + goto just_restart; + } + } + reg |= (0x0f & ep->bEndpointAddress) << (4 * (channel - 1)); + ep->dma_channel = channel; + + if (is_in) { + status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel, + ep->ep.name, dma_error, ep, &ep->lch); + if (status == 0) { + UDC_TXDMA_CFG_REG = reg; + omap_set_dma_dest_params(ep->lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + } + } else { + status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, + ep->ep.name, dma_error, ep, &ep->lch); + if (status == 0) { + UDC_RXDMA_CFG_REG = reg; + omap_set_dma_src_params(ep->lch, + OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + } + } + if (status) + ep->dma_channel = 0; + else { + ep->has_dma = 1; + omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); + + /* channel type P: hw synch (fifo) */ + omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch)); + } + +just_restart: + /* restart any queue, even if the claim failed */ + restart = !ep->stopped && !list_empty(&ep->queue); + + if (status) + DBG("%s no dma channel: %d%s\n", ep->ep.name, status, + restart ? " (restart)" : ""); + else + DBG("%s claimed %cxdma%d lch %d%s\n", ep->ep.name, + is_in ? 't' : 'r', + ep->dma_channel - 1, ep->lch, + restart ? " (restart)" : ""); + + if (restart) { + struct omap_req *req; + req = container_of(ep->queue.next, struct omap_req, queue); + if (ep->has_dma) + (is_in ? next_in_dma : next_out_dma)(ep, req); + else { + use_ep(ep, UDC_EP_SEL); + (is_in ? write_fifo : read_fifo)(ep, req); + deselect_ep(); + /* IN: 6 wait states before it'll tx */ + } + } +} + +static void dma_channel_release(struct omap_ep *ep) +{ + int shift = 4 * (ep->dma_channel - 1); + u16 mask = 0x0f << shift; + struct omap_req *req; + int active; + + /* abort any active usb transfer request */ + if (!list_empty(&ep->queue)) + req = container_of(ep->queue.next, struct omap_req, queue); + else + req = 0; + + active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; + + DBG("%s release %s %cxdma%d %p\n", ep->ep.name, + active ? "active" : "idle", + (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', + ep->dma_channel - 1, req); + + /* wait till current packet DMA finishes, and fifo empties */ + if (ep->bEndpointAddress & USB_DIR_IN) { + UDC_TXDMA_CFG_REG &= ~mask; + + if (req) { + if (active) + udelay(50); + finish_in_dma(ep, req, -ECONNRESET); + if (UDC_TXDMA_CFG_REG & mask) + WARN("%s, SPIN abort TX dma\n", ep->ep.name); + } + + /* host may empty the fifo (or not...) */ + while (UDC_TXDMA_CFG_REG & mask) + udelay(10); + + } else { + UDC_RXDMA_CFG_REG &= ~mask; + + /* dma empties the fifo */ + while (active && (UDC_RXDMA_CFG_REG & mask)) + udelay(10); + omap_stop_dma(ep->lch); + if (req) + finish_out_dma(ep, req, -ECONNRESET); + } + omap_free_dma(ep->lch); + ep->dma_channel = 0; + ep->lch = -1; + /* has_dma still set, till endpoint is fully quiesced */ +} + + +/*-------------------------------------------------------------------------*/ + +static int +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + struct omap_req *req = container_of(_req, struct omap_req, req); + struct omap_udc *udc; + unsigned long flags; + int is_iso = 0; + + /* catch various bogus parameters */ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { + DBG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + if (!_ep || (!ep->desc && ep->bEndpointAddress)) { + DBG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (req->req.length > ep->ep.maxpacket) + return -EMSGSIZE; + is_iso = 1; + } + + /* this isn't bogus, but OMAP DMA isn't the only hardware to + * have a hard time with partial packet reads... reject it. + */ + if (use_dma + && ep->has_dma + && ep->bEndpointAddress != 0 + && (ep->bEndpointAddress & USB_DIR_IN) == 0 + && (req->req.length % ep->ep.maxpacket) != 0) { + DBG("%s, no partial packet OUT reads\n", __FUNCTION__); + return -EMSGSIZE; + } + + udc = ep->udc; + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + if (use_dma && ep->has_dma) { + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + ep->udc->gadget.dev.parent, + req->req.buf, + req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + (ep->bEndpointAddress & USB_DIR_IN) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 0; + } + } + + VDBG("%s queue req %p, len %d buf %p\n", + ep->ep.name, _req, _req->length, _req->buf); + + spin_lock_irqsave(&udc->lock, flags); + + req->req.status = -EINPROGRESS; + req->req.actual = 0; + + /* maybe kickstart non-iso i/o queues */ + if (is_iso) + UDC_IRQ_EN_REG |= UDC_SOF_IE; + else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { + int is_in; + + if (ep->bEndpointAddress == 0) { + if (!udc->ep0_pending || !list_empty (&ep->queue)) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EL2HLT; + } + + /* empty DATA stage? */ + is_in = udc->ep0_in; + if (!req->req.length) { + + /* chip became CONFIGURED or ADDRESSED + * earlier; drivers may already have queued + * requests to non-control endpoints + */ + if (udc->ep0_set_config) { + u16 irq_en = UDC_IRQ_EN_REG; + + irq_en |= UDC_DS_CHG_IE | UDC_EP0_IE; + if (!udc->ep0_reset_config) + irq_en |= UDC_EPN_RX_IE + | UDC_EPN_TX_IE; + UDC_IRQ_EN_REG = irq_en; + } + + /* STATUS is reverse direction */ + UDC_EP_NUM_REG = is_in + ? UDC_EP_SEL + : (UDC_EP_SEL|UDC_EP_DIR); + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR; + + /* cleanup */ + udc->ep0_pending = 0; + done(ep, req, 0); + req = 0; + + /* non-empty DATA stage */ + } else if (is_in) { + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + } else { + if (udc->ep0_setup) + goto irq_wait; + UDC_EP_NUM_REG = UDC_EP_SEL; + } + } else { + is_in = ep->bEndpointAddress & USB_DIR_IN; + if (!ep->has_dma) + use_ep(ep, UDC_EP_SEL); + /* if ISO: SOF IRQs must be enabled/disabled! */ + } + + if (ep->has_dma) + (is_in ? next_in_dma : next_out_dma)(ep, req); + else if (req) { + if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) + req = 0; + deselect_ep(); + /* IN: 6 wait states before it'll tx */ + } + } + +irq_wait: + /* irq handler advances the queue */ + if (req != 0) + list_add_tail(&req->queue, &ep->queue); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + struct omap_req *req; + unsigned long flags; + + if (!_ep || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + } + + if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) { + int channel = ep->dma_channel; + + /* releasing the dma completion cancels the request, + * reclaiming the channel restarts the queue + */ + dma_channel_release(ep); + dma_channel_claim(ep, channel); + } else + done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->udc->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int omap_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); + unsigned long flags; + int status = -EOPNOTSUPP; + + spin_lock_irqsave(&ep->udc->lock, flags); + + /* just use protocol stalls for ep0; real halts are annoying */ + if (ep->bEndpointAddress == 0) { + if (!ep->udc->ep0_pending) + status = -EINVAL; + else if (value) { + if (ep->udc->ep0_set_config) { + WARN("error changing config?\n"); + UDC_SYSCON2_REG = UDC_CLR_CFG; + } + UDC_SYSCON2_REG = UDC_STALL_CMD; + ep->udc->ep0_pending = 0; + status = 0; + } else /* NOP */ + status = 0; + + /* otherwise, all active non-ISO endpoints can halt */ + } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) { + + /* IN endpoints must already be idle */ + if ((ep->bEndpointAddress & USB_DIR_IN) + && !list_empty(&ep->queue)) { + status = -EAGAIN; + goto done; + } + + if (value) { + int channel; + + if (use_dma && ep->dma_channel + && !list_empty(&ep->queue)) { + channel = ep->dma_channel; + dma_channel_release(ep); + } else + channel = 0; + + use_ep(ep, UDC_EP_SEL); + if (UDC_STAT_FLG_REG & UDC_NON_ISO_FIFO_EMPTY) { + UDC_CTRL_REG = UDC_SET_HALT; + status = 0; + } else + status = -EAGAIN; + deselect_ep(); + + if (channel) + dma_channel_claim(ep, channel); + } else { + use_ep(ep, 0); + UDC_CTRL_REG = UDC_RESET_EP; + ep->ackwait = 0; + if (!(ep->bEndpointAddress & USB_DIR_IN)) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + } + } +done: + VDBG("%s %s halt stat %d\n", ep->ep.name, + value ? "set" : "clear", status); + + spin_unlock_irqrestore(&ep->udc->lock, flags); + return status; +} + +static struct usb_ep_ops omap_ep_ops = { + .enable = omap_ep_enable, + .disable = omap_ep_disable, + + .alloc_request = omap_alloc_request, + .free_request = omap_free_request, + + .alloc_buffer = omap_alloc_buffer, + .free_buffer = omap_free_buffer, + + .queue = omap_ep_queue, + .dequeue = omap_ep_dequeue, + + .set_halt = omap_ep_set_halt, + // fifo_status ... report bytes in fifo + // fifo_flush ... flush fifo +}; + +/*-------------------------------------------------------------------------*/ + +static int omap_get_frame(struct usb_gadget *gadget) +{ + u16 sof = UDC_SOF_REG; + return (sof & UDC_TS_OK) ? (sof & UDC_TS) : -EL2NSYNC; +} + +static int omap_wakeup(struct usb_gadget *gadget) +{ + struct omap_udc *udc; + unsigned long flags; + int retval = -EHOSTUNREACH; + + udc = container_of(gadget, struct omap_udc, gadget); + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstat & UDC_SUS) { + /* NOTE: OTG spec erratum says that OTG devices may + * issue wakeups without host enable. + */ + if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) { + DBG("remote wakeup...\n"); + UDC_SYSCON2_REG = UDC_RMT_WKP; + retval = 0; + } + + /* NOTE: non-OTG systems may use SRP TOO... */ + } else if (!(udc->devstat & UDC_ATT)) { + if (udc->transceiver) + retval = otg_start_srp(udc->transceiver); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return retval; +} + +static int +omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct omap_udc *udc; + unsigned long flags; + u16 syscon1; + + udc = container_of(gadget, struct omap_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + syscon1 = UDC_SYSCON1_REG; + if (is_selfpowered) + syscon1 |= UDC_SELF_PWR; + else + syscon1 &= ~UDC_SELF_PWR; + UDC_SYSCON1_REG = syscon1; + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int can_pullup(struct omap_udc *udc) +{ + return udc->driver && udc->softconnect && udc->vbus_active; +} + +static void pullup_enable(struct omap_udc *udc) +{ + UDC_SYSCON1_REG |= UDC_PULLUP_EN; +#ifndef CONFIG_USB_OTG + OTG_CTRL_REG |= OTG_BSESSVLD; +#endif + UDC_IRQ_EN_REG = UDC_DS_CHG_IE; +} + +static void pullup_disable(struct omap_udc *udc) +{ +#ifndef CONFIG_USB_OTG + OTG_CTRL_REG &= ~OTG_BSESSVLD; +#endif + UDC_IRQ_EN_REG = UDC_DS_CHG_IE; + UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; +} + +/* + * Called by whatever detects VBUS sessions: external transceiver + * driver, or maybe GPIO0 VBUS IRQ. + */ +static int omap_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct omap_udc *udc; + unsigned long flags; + + udc = container_of(gadget, struct omap_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + VDBG("VBUS %s\n", is_active ? "on" : "off"); + udc->vbus_active = (is_active != 0); + if (can_pullup(udc)) + pullup_enable(udc); + else + pullup_disable(udc); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + struct omap_udc *udc; + + udc = container_of(gadget, struct omap_udc, gadget); + if (udc->transceiver) + return otg_set_power(udc->transceiver, mA); + return -EOPNOTSUPP; +} + +static int omap_pullup(struct usb_gadget *gadget, int is_on) +{ + struct omap_udc *udc; + unsigned long flags; + + udc = container_of(gadget, struct omap_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + udc->softconnect = (is_on != 0); + if (can_pullup(udc)) + pullup_enable(udc); + else + pullup_disable(udc); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static struct usb_gadget_ops omap_gadget_ops = { + .get_frame = omap_get_frame, + .wakeup = omap_wakeup, + .set_selfpowered = omap_set_selfpowered, + .vbus_session = omap_vbus_session, + .vbus_draw = omap_vbus_draw, + .pullup = omap_pullup, +}; + +/*-------------------------------------------------------------------------*/ + +/* dequeue ALL requests; caller holds udc->lock */ +static void nuke(struct omap_ep *ep, int status) +{ + struct omap_req *req; + + ep->stopped = 1; + + if (use_dma && ep->dma_channel) + dma_channel_release(ep); + + use_ep(ep, 0); + UDC_CTRL_REG = UDC_CLR_EP; + if (ep->bEndpointAddress && ep->bmAttributes != USB_ENDPOINT_XFER_ISOC) + UDC_CTRL_REG = UDC_SET_HALT; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct omap_req, queue); + done(ep, req, status); + } +} + +/* caller holds udc->lock */ +static void udc_quiesce(struct omap_udc *udc) +{ + struct omap_ep *ep; + + udc->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc->ep[0], -ESHUTDOWN); + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) + nuke(ep, -ESHUTDOWN); +} + +/*-------------------------------------------------------------------------*/ + +static void update_otg(struct omap_udc *udc) +{ + u16 devstat; + + if (!udc->gadget.is_otg) + return; + + if (OTG_CTRL_REG & OTG_ID) + devstat = UDC_DEVSTAT_REG; + else + devstat = 0; + + udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE); + udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT); + udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT); + + /* Enable HNP early, avoiding races on suspend irq path. + * ASSUMES OTG state machine B_BUS_REQ input is true. + */ + if (udc->gadget.b_hnp_enable) + OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ) + & ~OTG_PULLUP; +} + +static void ep0_irq(struct omap_udc *udc, u16 irq_src) +{ + struct omap_ep *ep0 = &udc->ep[0]; + struct omap_req *req = 0; + + ep0->irqs++; + + /* Clear any pending requests and then scrub any rx/tx state + * before starting to handle the SETUP request. + */ + if (irq_src & UDC_SETUP) + nuke(ep0, 0); + + /* IN/OUT packets mean we're in the DATA or STATUS stage. + * This driver uses only uses protocol stalls (ep0 never halts), + * and if we got this far the gadget driver already had a + * chance to stall. Tries to be forgiving of host oddities. + * + * NOTE: the last chance gadget drivers have to stall control + * requests is during their request completion callback. + */ + if (!list_empty(&ep0->queue)) + req = container_of(ep0->queue.next, struct omap_req, queue); + + /* IN == TX to host */ + if (irq_src & UDC_EP0_TX) { + int stat; + + UDC_IRQ_SRC_REG = UDC_EP0_TX; + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + stat = UDC_STAT_FLG_REG; + if (stat & UDC_ACK) { + if (udc->ep0_in) { + /* write next IN packet from response, + * or set up the status stage. + */ + if (req) + stat = write_fifo(ep0, req); + UDC_EP_NUM_REG = UDC_EP_DIR; + if (!req && udc->ep0_pending) { + UDC_EP_NUM_REG = UDC_EP_SEL; + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = 0; + udc->ep0_pending = 0; + } /* else: 6 wait states before it'll tx */ + } else { + /* ack status stage of OUT transfer */ + UDC_EP_NUM_REG = UDC_EP_DIR; + if (req) + done(ep0, req, 0); + } + req = 0; + } else if (stat & UDC_STALL) { + UDC_CTRL_REG = UDC_CLR_HALT; + UDC_EP_NUM_REG = UDC_EP_DIR; + } else { + UDC_EP_NUM_REG = UDC_EP_DIR; + } + } + + /* OUT == RX from host */ + if (irq_src & UDC_EP0_RX) { + int stat; + + UDC_IRQ_SRC_REG = UDC_EP0_RX; + UDC_EP_NUM_REG = UDC_EP_SEL; + stat = UDC_STAT_FLG_REG; + if (stat & UDC_ACK) { + if (!udc->ep0_in) { + stat = 0; + /* read next OUT packet of request, maybe + * reactiviting the fifo; stall on errors. + */ + if (!req || (stat = read_fifo(ep0, req)) < 0) { + UDC_SYSCON2_REG = UDC_STALL_CMD; + udc->ep0_pending = 0; + stat = 0; + } else if (stat == 0) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = 0; + + /* activate status stage */ + if (stat == 1) { + done(ep0, req, 0); + /* that may have STALLed ep0... */ + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = UDC_EP_DIR; + udc->ep0_pending = 0; + } + } else { + /* ack status stage of IN transfer */ + UDC_EP_NUM_REG = 0; + if (req) + done(ep0, req, 0); + } + } else if (stat & UDC_STALL) { + UDC_CTRL_REG = UDC_CLR_HALT; + UDC_EP_NUM_REG = 0; + } else { + UDC_EP_NUM_REG = 0; + } + } + + /* SETUP starts all control transfers */ + if (irq_src & UDC_SETUP) { + union u { + u16 word[4]; + struct usb_ctrlrequest r; + } u; + int status = -EINVAL; + struct omap_ep *ep; + + /* read the (latest) SETUP message */ + do { + UDC_EP_NUM_REG = UDC_SETUP_SEL; + /* two bytes at a time */ + u.word[0] = UDC_DATA_REG; + u.word[1] = UDC_DATA_REG; + u.word[2] = UDC_DATA_REG; + u.word[3] = UDC_DATA_REG; + UDC_EP_NUM_REG = 0; + } while (UDC_IRQ_SRC_REG & UDC_SETUP); + le16_to_cpus (&u.r.wValue); + le16_to_cpus (&u.r.wIndex); + le16_to_cpus (&u.r.wLength); + + /* Delegate almost all control requests to the gadget driver, + * except for a handful of ch9 status/feature requests that + * hardware doesn't autodecode _and_ the gadget API hides. + */ + udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; + udc->ep0_set_config = 0; + udc->ep0_pending = 1; + ep0->stopped = 0; + ep0->ackwait = 0; + switch (u.r.bRequest) { + case USB_REQ_SET_CONFIGURATION: + /* udc needs to know when ep != 0 is valid */ + if (u.r.bRequestType != USB_RECIP_DEVICE) + goto delegate; + if (u.r.wLength != 0) + goto do_stall; + udc->ep0_set_config = 1; + udc->ep0_reset_config = (u.r.wValue == 0); + VDBG("set config %d\n", u.r.wValue); + + /* update udc NOW since gadget driver may start + * queueing requests immediately; clear config + * later if it fails the request. + */ + if (udc->ep0_reset_config) + UDC_SYSCON2_REG = UDC_CLR_CFG; + else + UDC_SYSCON2_REG = UDC_DEV_CFG; + update_otg(udc); + goto delegate; + case USB_REQ_CLEAR_FEATURE: + /* clear endpoint halt */ + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wValue != USB_ENDPOINT_HALT + || u.r.wLength != 0) + goto do_stall; + ep = &udc->ep[u.r.wIndex & 0xf]; + if (ep != ep0) { + if (u.r.wIndex & USB_DIR_IN) + ep += 16; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC + || !ep->desc) + goto do_stall; + use_ep(ep, 0); + UDC_CTRL_REG = UDC_RESET_EP; + ep->ackwait = 0; + if (!(ep->bEndpointAddress & USB_DIR_IN)) + UDC_CTRL_REG = UDC_SET_FIFO_EN; + } + VDBG("%s halt cleared by host\n", ep->name); + goto ep0out_status_stage; + case USB_REQ_SET_FEATURE: + /* set endpoint halt */ + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wValue != USB_ENDPOINT_HALT + || u.r.wLength != 0) + goto do_stall; + ep = &udc->ep[u.r.wIndex & 0xf]; + if (u.r.wIndex & USB_DIR_IN) + ep += 16; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC + || ep == ep0 || !ep->desc) + goto do_stall; + if (use_dma && ep->has_dma) { + /* this has rude side-effects (aborts) and + * can't really work if DMA-IN is active + */ + DBG("%s host set_halt, NYET \n", ep->name); + goto do_stall; + } + use_ep(ep, 0); + /* can't halt if fifo isn't empty... */ + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_HALT; + VDBG("%s halted by host\n", ep->name); +ep0out_status_stage: + status = 0; + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + UDC_CTRL_REG = UDC_CLR_EP; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = UDC_EP_DIR; + udc->ep0_pending = 0; + break; + case USB_REQ_GET_STATUS: + /* return interface status. if we were pedantic, + * we'd detect non-existent interfaces, and stall. + */ + if (u.r.bRequestType + != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto delegate; + /* return two zero bytes */ + UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; + UDC_DATA_REG = 0; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + UDC_EP_NUM_REG = UDC_EP_DIR; + status = 0; + VDBG("GET_STATUS, interface %d\n", u.r.wIndex); + /* next, status stage */ + break; + default: +delegate: + /* activate the ep0out fifo right away */ + if (!udc->ep0_in && u.r.wLength) { + UDC_EP_NUM_REG = 0; + UDC_CTRL_REG = UDC_SET_FIFO_EN; + } + + /* gadget drivers see class/vendor specific requests, + * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, + * and more + */ + VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, u.r.wLength); + + /* The gadget driver may return an error here, + * causing an immediate protocol stall. + * + * Else it must issue a response, either queueing a + * response buffer for the DATA stage, or halting ep0 + * (causing a protocol stall, not a real halt). A + * zero length buffer means no DATA stage. + * + * It's fine to issue that response after the setup() + * call returns, and this IRQ was handled. + */ + udc->ep0_setup = 1; + spin_unlock(&udc->lock); + status = udc->driver->setup (&udc->gadget, &u.r); + spin_lock(&udc->lock); + udc->ep0_setup = 0; + } + + if (status < 0) { +do_stall: + VDBG("req %02x.%02x protocol STALL; stat %d\n", + u.r.bRequestType, u.r.bRequest, status); + if (udc->ep0_set_config) { + if (udc->ep0_reset_config) + WARN("error resetting config?\n"); + else + UDC_SYSCON2_REG = UDC_CLR_CFG; + } + UDC_SYSCON2_REG = UDC_STALL_CMD; + udc->ep0_pending = 0; + } + } +} + +/*-------------------------------------------------------------------------*/ + +#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT) + +static void devstate_irq(struct omap_udc *udc, u16 irq_src) +{ + u16 devstat, change; + + devstat = UDC_DEVSTAT_REG; + change = devstat ^ udc->devstat; + udc->devstat = devstat; + + if (change & (UDC_USB_RESET|UDC_ATT)) { + udc_quiesce(udc); + + if (change & UDC_ATT) { + /* driver for any external transceiver will + * have called omap_vbus_session() already + */ + if (devstat & UDC_ATT) { + udc->gadget.speed = USB_SPEED_FULL; + VDBG("connect\n"); + if (!udc->transceiver) + pullup_enable(udc); + // if (driver->connect) call it + } else if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + udc->gadget.speed = USB_SPEED_UNKNOWN; + if (!udc->transceiver) + pullup_disable(udc); + DBG("disconnect, gadget %s\n", + udc->driver->driver.name); + if (udc->driver->disconnect) { + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + } + change &= ~UDC_ATT; + } + + if (change & UDC_USB_RESET) { + if (devstat & UDC_USB_RESET) { + VDBG("RESET=1\n"); + } else { + udc->gadget.speed = USB_SPEED_FULL; + INFO("USB reset done, gadget %s\n", + udc->driver->driver.name); + /* ep0 traffic is legal from now on */ + UDC_IRQ_EN_REG = UDC_DS_CHG_IE | UDC_EP0_IE; + } + change &= ~UDC_USB_RESET; + } + } + if (change & UDC_SUS) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + // FIXME tell isp1301 to suspend/resume (?) + if (devstat & UDC_SUS) { + VDBG("suspend\n"); + update_otg(udc); + /* HNP could be under way already */ + if (udc->gadget.speed == USB_SPEED_FULL + && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } else { + VDBG("resume\n"); + if (udc->gadget.speed == USB_SPEED_FULL + && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + } + change &= ~UDC_SUS; + } + if (change & OTG_FLAGS) { + update_otg(udc); + change &= ~OTG_FLAGS; + } + + change &= ~(UDC_CFG|UDC_DEF|UDC_ADD); + if (change) + VDBG("devstat %03x, ignore change %03x\n", + devstat, change); + + UDC_IRQ_SRC_REG = UDC_DS_CHG; +} + +static irqreturn_t +omap_udc_irq(int irq, void *_udc, struct pt_regs *r) +{ + struct omap_udc *udc = _udc; + u16 irq_src; + irqreturn_t status = IRQ_NONE; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + irq_src = UDC_IRQ_SRC_REG; + + /* Device state change (usb ch9 stuff) */ + if (irq_src & UDC_DS_CHG) { + devstate_irq(_udc, irq_src); + status = IRQ_HANDLED; + irq_src &= ~UDC_DS_CHG; + } + + /* EP0 control transfers */ + if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) { + ep0_irq(_udc, irq_src); + status = IRQ_HANDLED; + irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX); + } + + /* DMA transfer completion */ + if (use_dma && (irq_src & (UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT))) { + dma_irq(_udc, irq_src); + status = IRQ_HANDLED; + irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT); + } + + irq_src &= ~(UDC_SOF|UDC_EPN_TX|UDC_EPN_RX); + if (irq_src) + DBG("udc_irq, unhandled %03x\n", irq_src); + spin_unlock_irqrestore(&udc->lock, flags); + + return status; +} + +static irqreturn_t +omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r) +{ + u16 epn_stat, irq_src; + irqreturn_t status = IRQ_NONE; + struct omap_ep *ep; + int epnum; + struct omap_udc *udc = _dev; + struct omap_req *req; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + epn_stat = UDC_EPN_STAT_REG; + irq_src = UDC_IRQ_SRC_REG; + + /* handle OUT first, to avoid some wasteful NAKs */ + if (irq_src & UDC_EPN_RX) { + epnum = (epn_stat >> 8) & 0x0f; + UDC_IRQ_SRC_REG = UDC_EPN_RX; + status = IRQ_HANDLED; + ep = &udc->ep[epnum]; + ep->irqs++; + + if (!list_empty(&ep->queue)) { + UDC_EP_NUM_REG = epnum | UDC_EP_SEL; + if ((UDC_STAT_FLG_REG & UDC_ACK)) { + int stat; + req = container_of(ep->queue.next, + struct omap_req, queue); + stat = read_fifo(ep, req); + // FIXME double buffered PIO OUT should work + } + UDC_EP_NUM_REG = epnum; + } + } + + /* then IN transfers */ + if (irq_src & UDC_EPN_TX) { + epnum = epn_stat & 0x0f; + UDC_IRQ_SRC_REG = UDC_EPN_TX; + status = IRQ_HANDLED; + ep = &udc->ep[16 + epnum]; + ep->irqs++; + ep->ackwait = 0; + + if (!list_empty(&ep->queue)) { + UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL; + if ((UDC_STAT_FLG_REG & UDC_ACK)) { + req = container_of(ep->queue.next, + struct omap_req, queue); + (void) write_fifo(ep, req); + } + UDC_EP_NUM_REG = epnum | UDC_EP_DIR; + /* 6 wait states before it'll tx */ + } + } + + spin_unlock_irqrestore(&udc->lock, flags); + return status; +} + +#ifdef USE_ISO +static irqreturn_t +omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r) +{ + struct omap_udc *udc = _dev; + struct omap_ep *ep; + int pending = 0; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + /* handle all non-DMA ISO transfers */ + list_for_each_entry (ep, &udc->iso, iso) { + u16 stat; + struct omap_req *req; + + if (ep->has_dma || list_empty(&ep->queue)) + continue; + req = list_entry(ep->queue.next, struct omap_req, queue); + + use_ep(ep, UDC_EP_SEL); + stat = UDC_STAT_FLG_REG; + + /* NOTE: like the other controller drivers, this isn't + * currently reporting lost or damaged frames. + */ + if (ep->bEndpointAddress & USB_DIR_IN) { + if (stat & UDC_MISS_IN) + /* done(ep, req, -EPROTO) */; + else + write_fifo(ep, req); + } else { + int status = 0; + + if (stat & UDC_NO_RXPACKET) + status = -EREMOTEIO; + else if (stat & UDC_ISO_ERR) + status = -EILSEQ; + else if (stat & UDC_DATA_FLUSH) + status = -ENOSR; + + if (status) + /* done(ep, req, status) */; + else + read_fifo(ep, req); + } + deselect_ep(); + /* 6 wait states before next EP */ + + ep->irqs++; + if (!list_empty(&ep->queue)) + pending = 1; + } + if (!pending) + UDC_IRQ_EN_REG &= ~UDC_SOF_IE; + UDC_IRQ_SRC_REG = UDC_SOF; + + spin_unlock_irqrestore(&udc->lock, flags); + return IRQ_HANDLED; +} +#endif + +/*-------------------------------------------------------------------------*/ + +static struct omap_udc *udc; + +int usb_gadget_register_driver (struct usb_gadget_driver *driver) +{ + int status = -ENODEV; + struct omap_ep *ep; + unsigned long flags; + + /* basic sanity tests */ + if (!udc) + return -ENODEV; + if (!driver + // FIXME if otg, check: driver->is_otg + || driver->speed < USB_SPEED_FULL + || !driver->bind + || !driver->unbind + || !driver->setup) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + /* reset state */ + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + ep->irqs = 0; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) + continue; + use_ep(ep, 0); + UDC_CTRL_REG = UDC_SET_HALT; + } + udc->ep0_pending = 0; + udc->ep[0].irqs = 0; + udc->softconnect = 1; + + /* hook up the driver */ + driver->driver.bus = 0; + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + status = driver->bind (&udc->gadget); + if (status) { + DBG("bind to %s --> %d\n", driver->driver.name, status); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto done; + } + DBG("bound to driver %s\n", driver->driver.name); + + UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK; + + /* connect to bus through transceiver */ + if (udc->transceiver) { + status = otg_set_peripheral(udc->transceiver, &udc->gadget); + if (status < 0) { + ERR("can't bind to transceiver\n"); + driver->unbind (&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto done; + } + } else { + if (can_pullup(udc)) + pullup_enable (udc); + else + pullup_disable (udc); + } + +done: + return status; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + unsigned long flags; + int status = -ENODEV; + + if (!udc) + return -ENODEV; + if (!driver || driver != udc->driver) + return -EINVAL; + + if (udc->transceiver) + (void) otg_set_peripheral(udc->transceiver, 0); + else + pullup_disable(udc); + + spin_lock_irqsave(&udc->lock, flags); + udc_quiesce(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + + + DBG("unregistered driver '%s'\n", driver->driver.name); + return status; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_OMAP_PROC + +#include + +static const char proc_filename[] = "driver/udc"; + +#define FOURBITS "%s%s%s%s" +#define EIGHTBITS FOURBITS FOURBITS + +static void proc_ep_show(struct seq_file *s, struct omap_ep *ep) +{ + u16 stat_flg; + struct omap_req *req; + char buf[20]; + + use_ep(ep, 0); + + if (use_dma && ep->has_dma) + snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ", + (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', + ep->dma_channel - 1, ep->lch); + else + buf[0] = 0; + + stat_flg = UDC_STAT_FLG_REG; + seq_printf(s, + "\n%s %sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n", + ep->name, buf, ep->irqs, stat_flg, + (stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "", + (stat_flg & UDC_MISS_IN) ? "miss_in " : "", + (stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "", + (stat_flg & UDC_ISO_ERR) ? "iso_err " : "", + (stat_flg & UDC_ISO_FIFO_EMPTY) ? "iso_fifo_empty " : "", + (stat_flg & UDC_ISO_FIFO_FULL) ? "iso_fifo_full " : "", + (stat_flg & UDC_EP_HALTED) ? "HALT " : "", + (stat_flg & UDC_STALL) ? "STALL " : "", + (stat_flg & UDC_NAK) ? "NAK " : "", + (stat_flg & UDC_ACK) ? "ACK " : "", + (stat_flg & UDC_FIFO_EN) ? "fifo_en " : "", + (stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "", + (stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : ""); + + if (list_empty (&ep->queue)) + seq_printf(s, "\t(queue empty)\n"); + else + list_for_each_entry (req, &ep->queue, queue) + seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); +} + +static char *trx_mode(unsigned m) +{ + switch (m) { + case 3: + case 0: return "6wire"; + case 1: return "4wire"; + case 2: return "3wire"; + default: return "unknown"; + } +} + +static int proc_udc_show(struct seq_file *s, void *_) +{ + u32 tmp; + struct omap_ep *ep; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + seq_printf(s, "%s, version: " DRIVER_VERSION +#ifdef USE_ISO + " (iso)" +#endif + "%s\n", + driver_desc, + use_dma ? " (dma)" : ""); + + tmp = UDC_REV_REG & 0xff; + seq_printf(s, + "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n" + "hmc %d, transceiver %08x %s\n", + tmp >> 4, tmp & 0xf, + OTG_REV_REG >> 4, OTG_REV_REG & 0xf, + fifo_mode, + udc->driver ? udc->driver->driver.name : "(none)", + HMC, USB_TRANSCEIVER_CTRL_REG, + udc->transceiver ? udc->transceiver->label : ""); + + /* OTG controller registers */ + tmp = OTG_SYSCON_1_REG; + seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," + FOURBITS "\n", tmp, + trx_mode(USB2_TRX_MODE(tmp)), + trx_mode(USB1_TRX_MODE(tmp)), + trx_mode(USB0_TRX_MODE(tmp)), + (tmp & OTG_IDLE_EN) ? " !otg" : "", + (tmp & HST_IDLE_EN) ? " !host" : "", + (tmp & DEV_IDLE_EN) ? " !dev" : "", + (tmp & OTG_RESET_DONE) ? " reset_done" : " reset_active"); + tmp = OTG_SYSCON_2_REG; + seq_printf(s, "otg_syscon2 %08x%s" EIGHTBITS + " b_ase_brst=%d hmc=%d\n", tmp, + (tmp & OTG_EN) ? " otg_en" : "", + (tmp & USBX_SYNCHRO) ? " synchro" : "", + // much more SRP stuff + (tmp & SRP_DATA) ? " srp_data" : "", + (tmp & SRP_VBUS) ? " srp_vbus" : "", + (tmp & OTG_PADEN) ? " otg_paden" : "", + (tmp & HMC_PADEN) ? " hmc_paden" : "", + (tmp & UHOST_EN) ? " uhost_en" : "", + (tmp & HMC_TLLSPEED) ? " tllspeed" : "", + (tmp & HMC_TLLATTACH) ? " tllattach" : "", + B_ASE_BRST(tmp), + OTG_HMC(tmp)); + tmp = OTG_CTRL_REG; + seq_printf(s, "otg_ctrl %06x" EIGHTBITS EIGHTBITS "%s\n", tmp, + (tmp & OTG_ASESSVLD) ? " asess" : "", + (tmp & OTG_BSESSEND) ? " bsess_end" : "", + (tmp & OTG_BSESSVLD) ? " bsess" : "", + (tmp & OTG_VBUSVLD) ? " vbus" : "", + (tmp & OTG_ID) ? " id" : "", + (tmp & OTG_DRIVER_SEL) ? " DEVICE" : " HOST", + (tmp & OTG_A_SETB_HNPEN) ? " a_setb_hnpen" : "", + (tmp & OTG_A_BUSREQ) ? " a_bus" : "", + (tmp & OTG_B_HNPEN) ? " b_hnpen" : "", + (tmp & OTG_B_BUSREQ) ? " b_bus" : "", + (tmp & OTG_BUSDROP) ? " busdrop" : "", + (tmp & OTG_PULLDOWN) ? " down" : "", + (tmp & OTG_PULLUP) ? " up" : "", + (tmp & OTG_DRV_VBUS) ? " drv" : "", + (tmp & OTG_PD_VBUS) ? " pd_vb" : "", + (tmp & OTG_PU_VBUS) ? " pu_vb" : "", + (tmp & OTG_PU_ID) ? " pu_id" : "" + ); + tmp = OTG_IRQ_EN_REG; + seq_printf(s, "otg_irq_en %04x" "\n", tmp); + tmp = OTG_IRQ_SRC_REG; + seq_printf(s, "otg_irq_src %04x" "\n", tmp); + tmp = OTG_OUTCTRL_REG; + seq_printf(s, "otg_outctrl %04x" "\n", tmp); + tmp = OTG_TEST_REG; + seq_printf(s, "otg_test %04x" "\n", tmp); + + tmp = UDC_SYSCON1_REG; + seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp, + (tmp & UDC_CFG_LOCK) ? " cfg_lock" : "", + (tmp & UDC_DATA_ENDIAN) ? " data_endian" : "", + (tmp & UDC_DMA_ENDIAN) ? " dma_endian" : "", + (tmp & UDC_NAK_EN) ? " nak" : "", + (tmp & UDC_AUTODECODE_DIS) ? " autodecode_dis" : "", + (tmp & UDC_SELF_PWR) ? " self_pwr" : "", + (tmp & UDC_SOFF_DIS) ? " soff_dis" : "", + (tmp & UDC_PULLUP_EN) ? " PULLUP" : ""); + // syscon2 is write-only + + /* UDC controller registers */ + if (!(tmp & UDC_PULLUP_EN)) { + seq_printf(s, "(suspended)\n"); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; + } + + tmp = UDC_DEVSTAT_REG; + seq_printf(s, "devstat %04x" EIGHTBITS "%s%s\n", tmp, + (tmp & UDC_B_HNP_ENABLE) ? " b_hnp" : "", + (tmp & UDC_A_HNP_SUPPORT) ? " a_hnp" : "", + (tmp & UDC_A_ALT_HNP_SUPPORT) ? " a_alt_hnp" : "", + (tmp & UDC_R_WK_OK) ? " r_wk_ok" : "", + (tmp & UDC_USB_RESET) ? " usb_reset" : "", + (tmp & UDC_SUS) ? " SUS" : "", + (tmp & UDC_CFG) ? " CFG" : "", + (tmp & UDC_ADD) ? " ADD" : "", + (tmp & UDC_DEF) ? " DEF" : "", + (tmp & UDC_ATT) ? " ATT" : ""); + seq_printf(s, "sof %04x\n", UDC_SOF_REG); + tmp = UDC_IRQ_EN_REG; + seq_printf(s, "irq_en %04x" FOURBITS "%s\n", tmp, + (tmp & UDC_SOF_IE) ? " sof" : "", + (tmp & UDC_EPN_RX_IE) ? " epn_rx" : "", + (tmp & UDC_EPN_TX_IE) ? " epn_tx" : "", + (tmp & UDC_DS_CHG_IE) ? " ds_chg" : "", + (tmp & UDC_EP0_IE) ? " ep0" : ""); + tmp = UDC_IRQ_SRC_REG; + seq_printf(s, "irq_src %04x" EIGHTBITS "%s%s\n", tmp, + (tmp & UDC_TXN_DONE) ? " txn_done" : "", + (tmp & UDC_RXN_CNT) ? " rxn_cnt" : "", + (tmp & UDC_RXN_EOT) ? " rxn_eot" : "", + (tmp & UDC_SOF) ? " sof" : "", + (tmp & UDC_EPN_RX) ? " epn_rx" : "", + (tmp & UDC_EPN_TX) ? " epn_tx" : "", + (tmp & UDC_DS_CHG) ? " ds_chg" : "", + (tmp & UDC_SETUP) ? " setup" : "", + (tmp & UDC_EP0_RX) ? " ep0out" : "", + (tmp & UDC_EP0_TX) ? " ep0in" : ""); + if (use_dma) { + unsigned i; + + tmp = UDC_DMA_IRQ_EN_REG; + seq_printf(s, "dma_irq_en %04x%s" EIGHTBITS "\n", tmp, + (tmp & UDC_TX_DONE_IE(3)) ? " tx2_done" : "", + (tmp & UDC_RX_CNT_IE(3)) ? " rx2_cnt" : "", + (tmp & UDC_RX_EOT_IE(3)) ? " rx2_eot" : "", + + (tmp & UDC_TX_DONE_IE(2)) ? " tx1_done" : "", + (tmp & UDC_RX_CNT_IE(2)) ? " rx1_cnt" : "", + (tmp & UDC_RX_EOT_IE(2)) ? " rx1_eot" : "", + + (tmp & UDC_TX_DONE_IE(1)) ? " tx0_done" : "", + (tmp & UDC_RX_CNT_IE(1)) ? " rx0_cnt" : "", + (tmp & UDC_RX_EOT_IE(1)) ? " rx0_eot" : ""); + + tmp = UDC_RXDMA_CFG_REG; + seq_printf(s, "rxdma_cfg %04x\n", tmp); + if (tmp) { + for (i = 0; i < 3; i++) { + if ((tmp & (0x0f << (i * 4))) == 0) + continue; + seq_printf(s, "rxdma[%d] %04x\n", i, + UDC_RXDMA_REG(i + 1)); + } + } + tmp = UDC_TXDMA_CFG_REG; + seq_printf(s, "txdma_cfg %04x\n", tmp); + if (tmp) { + for (i = 0; i < 3; i++) { + if (!(tmp & (0x0f << (i * 4)))) + continue; + seq_printf(s, "txdma[%d] %04x\n", i, + UDC_TXDMA_REG(i + 1)); + } + } + } + + tmp = UDC_DEVSTAT_REG; + if (tmp & UDC_ATT) { + proc_ep_show(s, &udc->ep[0]); + if (tmp & UDC_ADD) { + list_for_each_entry (ep, &udc->gadget.ep_list, + ep.ep_list) { + if (ep->desc) + proc_ep_show(s, ep); + } + } + } + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, 0); +} + +static struct file_operations proc_ops = { + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_proc_file(void) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry (proc_filename, 0, NULL); + if (pde) + pde->proc_fops = &proc_ops; +} + +static void remove_proc_file(void) +{ + remove_proc_entry(proc_filename, 0); +} + +#else + +static inline void create_proc_file(void) {} +static inline void remove_proc_file(void) {} + +#endif + +/*-------------------------------------------------------------------------*/ + +/* Before this controller can enumerate, we need to pick an endpoint + * configuration, or "fifo_mode" That involves allocating 2KB of packet + * buffer space among the endpoints we'll be operating. + */ +static unsigned __init +omap_ep_setup(char *name, u8 addr, u8 type, + unsigned buf, unsigned maxp, int dbuf) +{ + struct omap_ep *ep; + u16 epn_rxtx = 0; + + /* OUT endpoints first, then IN */ + ep = &udc->ep[addr & 0xf]; + if (addr & USB_DIR_IN) + ep += 16; + + /* in case of ep init table bugs */ + BUG_ON(ep->name[0]); + + /* chip setup ... bit values are same for IN, OUT */ + if (type == USB_ENDPOINT_XFER_ISOC) { + switch (maxp) { + case 8: epn_rxtx = 0 << 12; break; + case 16: epn_rxtx = 1 << 12; break; + case 32: epn_rxtx = 2 << 12; break; + case 64: epn_rxtx = 3 << 12; break; + case 128: epn_rxtx = 4 << 12; break; + case 256: epn_rxtx = 5 << 12; break; + case 512: epn_rxtx = 6 << 12; break; + default: BUG(); + } + epn_rxtx |= UDC_EPN_RX_ISO; + dbuf = 1; + } else { + /* pio-out could potentially double-buffer, + * as can (should!) DMA-IN + */ + if (!use_dma || (addr & USB_DIR_IN)) + dbuf = 0; + + switch (maxp) { + case 8: epn_rxtx = 0 << 12; break; + case 16: epn_rxtx = 1 << 12; break; + case 32: epn_rxtx = 2 << 12; break; + case 64: epn_rxtx = 3 << 12; break; + default: BUG(); + } + if (dbuf && addr) + epn_rxtx |= UDC_EPN_RX_DB; + } + if (addr) + epn_rxtx |= UDC_EPN_RX_VALID; + BUG_ON(buf & 0x07); + epn_rxtx |= buf >> 3; + + DBG("%s addr %02x rxtx %04x maxp %d%s buf %d\n", + name, addr, epn_rxtx, maxp, dbuf ? "x2" : "", buf); + + if (addr & USB_DIR_IN) + UDC_EP_TX_REG(addr & 0xf) = epn_rxtx; + else + UDC_EP_RX_REG(addr) = epn_rxtx; + + /* next endpoint's buffer starts after this one's */ + buf += maxp; + if (dbuf) + buf += maxp; + BUG_ON(buf > 2048); + + /* set up driver data structures */ + BUG_ON(strlen(name) >= sizeof ep->name); + strlcpy(ep->name, name, sizeof ep->name); + INIT_LIST_HEAD(&ep->queue); + INIT_LIST_HEAD(&ep->iso); + ep->bEndpointAddress = addr; + ep->bmAttributes = type; + ep->double_buf = dbuf; + ep->udc = udc; + + ep->ep.name = ep->name; + ep->ep.ops = &omap_ep_ops; + ep->ep.maxpacket = ep->maxpacket = maxp; + list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list); + + return buf; +} + +static void omap_udc_release(struct device *dev) +{ + complete(udc->done); + kfree (udc); + udc = 0; +} + +static int __init +omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) +{ + unsigned tmp, buf; + + /* abolish any previous hardware state */ + UDC_SYSCON1_REG = 0; + UDC_IRQ_EN_REG = 0; + UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK; + UDC_DMA_IRQ_EN_REG = 0; + UDC_RXDMA_CFG_REG = 0; + UDC_TXDMA_CFG_REG = 0; + + /* UDC_PULLUP_EN gates the chip clock */ + // OTG_SYSCON_1_REG |= DEV_IDLE_EN; + + udc = kmalloc (sizeof *udc, SLAB_KERNEL); + if (!udc) + return -ENOMEM; + + memset(udc, 0, sizeof *udc); + spin_lock_init (&udc->lock); + + udc->gadget.ops = &omap_gadget_ops; + udc->gadget.ep0 = &udc->ep[0].ep; + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->iso); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.name = driver_name; + + device_initialize(&udc->gadget.dev); + strcpy (udc->gadget.dev.bus_id, "gadget"); + udc->gadget.dev.release = omap_udc_release; + udc->gadget.dev.parent = &odev->dev; + if (use_dma) + udc->gadget.dev.dma_mask = odev->dev.dma_mask; + + udc->transceiver = xceiv; + + /* ep0 is special; put it right after the SETUP buffer */ + buf = omap_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, + 8 /* after SETUP */, 64 /* maxpacket */, 0); + list_del_init(&udc->ep[0].ep.ep_list); + + /* initially disable all non-ep0 endpoints */ + for (tmp = 1; tmp < 15; tmp++) { + UDC_EP_RX_REG(tmp) = 0; + UDC_EP_TX_REG(tmp) = 0; + } + +#define OMAP_BULK_EP(name,addr) \ + buf = omap_ep_setup(name "-bulk", addr, \ + USB_ENDPOINT_XFER_BULK, buf, 64, 1); +#define OMAP_INT_EP(name,addr, maxp) \ + buf = omap_ep_setup(name "-int", addr, \ + USB_ENDPOINT_XFER_INT, buf, maxp, 0); +#define OMAP_ISO_EP(name,addr, maxp) \ + buf = omap_ep_setup(name "-iso", addr, \ + USB_ENDPOINT_XFER_ISOC, buf, maxp, 1); + + switch (fifo_mode) { + case 0: + OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); + OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep3in", USB_DIR_IN | 3, 16); + break; + case 1: + OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); + OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_BULK_EP("ep3in", USB_DIR_IN | 3); + OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4); + + OMAP_BULK_EP("ep5in", USB_DIR_IN | 5); + OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); + OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6); + + OMAP_BULK_EP("ep7in", USB_DIR_IN | 7); + OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_BULK_EP("ep8in", USB_DIR_IN | 8); + OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8); + + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + OMAP_INT_EP("ep10out", USB_DIR_IN | 10, 16); + OMAP_INT_EP("ep11in", USB_DIR_IN | 9, 16); + OMAP_INT_EP("ep12out", USB_DIR_IN | 10, 16); + break; + +#ifdef USE_ISO + case 2: /* mixed iso/bulk */ + OMAP_ISO_EP("ep1in", USB_DIR_IN | 1, 256); + OMAP_ISO_EP("ep2out", USB_DIR_OUT | 2, 256); + OMAP_ISO_EP("ep3in", USB_DIR_IN | 3, 128); + OMAP_ISO_EP("ep4out", USB_DIR_OUT | 4, 128); + + OMAP_INT_EP("ep5in", USB_DIR_IN | 5, 16); + + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); + OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_INT_EP("ep8in", USB_DIR_IN | 8, 16); + break; + case 3: /* mixed bulk/iso */ + OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); + OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep3in", USB_DIR_IN | 3, 16); + + OMAP_BULK_EP("ep4in", USB_DIR_IN | 4); + OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_INT_EP("ep6in", USB_DIR_IN | 6, 16); + + OMAP_ISO_EP("ep7in", USB_DIR_IN | 7, 256); + OMAP_ISO_EP("ep8out", USB_DIR_OUT | 8, 256); + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + break; +#endif + + /* add more modes as needed */ + + default: + ERR("unsupported fifo_mode #%d\n", fifo_mode); + return -ENODEV; + } + UDC_SYSCON1_REG = UDC_CFG_LOCK|UDC_SELF_PWR; + INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf); + return 0; +} + +static int __init omap_udc_probe(struct device *dev) +{ + struct platform_device *odev = to_platform_device(dev); + int status = -ENODEV; + int hmc; + struct otg_transceiver *xceiv = 0; + const char *type = 0; + struct omap_usb_config *config = dev->platform_data; + + /* NOTE: "knows" the order of the resources! */ + if (!request_mem_region(odev->resource[0].start, + odev->resource[0].end - odev->resource[0].start + 1, + driver_name)) { + DBG("request_mem_region failed\n"); + return -EBUSY; + } + + INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n", + UDC_REV_REG >> 4, UDC_REV_REG & 0xf, + OTG_REV_REG >> 4, OTG_REV_REG & 0xf, + config->otg ? "Mini-AB" : "B/Mini-B"); + + /* use the mode given to us by board init code */ + hmc = HMC; + switch (hmc) { + case 3: + case 11: + case 19: + case 25: + xceiv = otg_get_transceiver(); + if (!xceiv) { + DBG("external transceiver not registered!\n"); + goto cleanup0; + } + type = xceiv->label; + break; + case 0: /* POWERUP DEFAULT == 0 */ + case 4: + case 12: + case 20: + type = "INTEGRATED"; + break; + case 21: /* internal loopback */ + type = "(loopback)"; + break; + case 14: /* transceiverless */ + type = "(none)"; + break; + + default: + ERR("unrecognized UDC HMC mode %d\n", hmc); + return -ENODEV; + } + INFO("hmc mode %d, transceiver %s\n", hmc, type); + + /* a "gadget" abstracts/virtualizes the controller */ + status = omap_udc_setup(odev, xceiv); + if (status) { + goto cleanup0; + } + xceiv = 0; + // "udc" is now valid + pullup_disable(udc); + udc->gadget.is_otg = (config->otg != 0); + + /* USB general purpose IRQ: ep0, state changes, dma, etc */ + status = request_irq(odev->resource[1].start, omap_udc_irq, + SA_SAMPLE_RANDOM, driver_name, udc); + if (status != 0) { + ERR( "can't get irq %ld, err %d\n", + odev->resource[1].start, status); + goto cleanup1; + } + + /* USB "non-iso" IRQ (PIO for all but ep0) */ + status = request_irq(odev->resource[2].start, omap_udc_pio_irq, + SA_SAMPLE_RANDOM, "omap_udc pio", udc); + if (status != 0) { + ERR( "can't get irq %ld, err %d\n", + odev->resource[2].start, status); + goto cleanup2; + } +#ifdef USE_ISO + status = request_irq(odev->resource[3].start, omap_udc_iso_irq, + SA_INTERRUPT, "omap_udc iso", udc); + if (status != 0) { + ERR("can't get irq %ld, err %d\n", + odev->resource[3].start, status); + goto cleanup3; + } +#endif + + create_proc_file(); + device_add(&udc->gadget.dev); + return 0; + +#ifdef USE_ISO +cleanup3: + free_irq(odev->resource[2].start, udc); +#endif + +cleanup2: + free_irq(odev->resource[1].start, udc); + +cleanup1: + kfree (udc); + udc = 0; + +cleanup0: + if (xceiv) + put_device(xceiv->dev); + release_mem_region(odev->resource[0].start, + odev->resource[0].end - odev->resource[0].start + 1); + return status; +} + +static int __exit omap_udc_remove(struct device *dev) +{ + struct platform_device *odev = to_platform_device(dev); + DECLARE_COMPLETION(done); + + if (!udc) + return -ENODEV; + + udc->done = &done; + + pullup_disable(udc); + if (udc->transceiver) { + put_device(udc->transceiver->dev); + udc->transceiver = 0; + } + UDC_SYSCON1_REG = 0; + + remove_proc_file(); + +#ifdef USE_ISO + free_irq(odev->resource[3].start, udc); +#endif + free_irq(odev->resource[2].start, udc); + free_irq(odev->resource[1].start, udc); + + release_mem_region(odev->resource[0].start, + odev->resource[0].end - odev->resource[0].start + 1); + + device_unregister(&udc->gadget.dev); + wait_for_completion(&done); + + return 0; +} + +/* suspend/resume/wakeup from sysfs (echo > power/state) */ + +static int omap_udc_suspend(struct device *dev, u32 state, u32 level) +{ + if (level != 0) + return 0; + + DBG("suspend, state %d\n", state); + omap_pullup(&udc->gadget, 0); + udc->gadget.dev.power.power_state = 3; + udc->gadget.dev.parent->power.power_state = 3; + return 0; +} + +static int omap_udc_resume(struct device *dev, u32 level) +{ + if (level != 0) + return 0; + + DBG("resume + wakeup/SRP\n"); + udc->gadget.dev.parent->power.power_state = 0; + udc->gadget.dev.power.power_state = 0; + omap_pullup(&udc->gadget, 1); + + /* maybe the host would enumerate us if we nudged it */ + msleep(100); + return omap_wakeup(&udc->gadget); +} + +/*-------------------------------------------------------------------------*/ + +static struct device_driver udc_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = omap_udc_probe, + .remove = __exit_p(omap_udc_remove), + .suspend = omap_udc_suspend, + .resume = omap_udc_resume, +}; + +static int __init udc_init(void) +{ + /* should work on many OMAP systems with at most minor changes, + * but the 1510 doesn't have an OTG controller. + */ + if (cpu_is_omap1510()) { + DBG("no OMAP1510 support yet\n"); + return -ENODEV; + } + INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc, + use_dma ? " (dma)" : ""); + return driver_register(&udc_driver); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h new file mode 100644 index 000000000..bd5420cd0 --- /dev/null +++ b/drivers/usb/gadget/omap_udc.h @@ -0,0 +1,199 @@ +/* + * omap_udc.h -- for omap 3.2 udc, with OTG support + * + * 2004 (C) Texas Instruments, Inc. + * 2004 (C) David Brownell + */ + +/* + * USB device/endpoint management registers + */ +#define UDC_REG(offset) __REG16(UDC_BASE + (offset)) + +#define UDC_REV_REG UDC_REG(0x0) /* Revision */ +#define UDC_EP_NUM_REG UDC_REG(0x4) /* Which endpoint */ +# define UDC_SETUP_SEL (1 << 6) +# define UDC_EP_SEL (1 << 5) +# define UDC_EP_DIR (1 << 4) + /* low 4 bits for endpoint number */ +#define UDC_DATA_REG UDC_REG(0x08) /* Endpoint FIFO */ +#define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */ +# define UDC_CLR_HALT (1 << 7) +# define UDC_SET_HALT (1 << 6) +# define UDC_SET_FIFO_EN (1 << 2) +# define UDC_CLR_EP (1 << 1) +# define UDC_RESET_EP (1 << 0) +#define UDC_STAT_FLG_REG UDC_REG(0x10) /* Endpoint status */ +# define UDC_NO_RXPACKET (1 << 15) +# define UDC_MISS_IN (1 << 14) +# define UDC_DATA_FLUSH (1 << 13) +# define UDC_ISO_ERR (1 << 12) +# define UDC_ISO_FIFO_EMPTY (1 << 9) +# define UDC_ISO_FIFO_FULL (1 << 8) +# define UDC_EP_HALTED (1 << 6) +# define UDC_STALL (1 << 5) +# define UDC_NAK (1 << 4) +# define UDC_ACK (1 << 3) +# define UDC_FIFO_EN (1 << 2) +# define UDC_NON_ISO_FIFO_EMPTY (1 << 1) +# define UDC_NON_ISO_FIFO_FULL (1 << 0) +#define UDC_RXFSTAT_REG UDC_REG(0x14) /* OUT bytecount */ +#define UDC_SYSCON1_REG UDC_REG(0x18) /* System config 1 */ +# define UDC_CFG_LOCK (1 << 8) +# define UDC_DATA_ENDIAN (1 << 7) +# define UDC_DMA_ENDIAN (1 << 6) +# define UDC_NAK_EN (1 << 4) +# define UDC_AUTODECODE_DIS (1 << 3) +# define UDC_SELF_PWR (1 << 2) +# define UDC_SOFF_DIS (1 << 1) +# define UDC_PULLUP_EN (1 << 0) +#define UDC_SYSCON2_REG UDC_REG(0x1C) /* System config 2 */ +# define UDC_RMT_WKP (1 << 6) +# define UDC_STALL_CMD (1 << 5) +# define UDC_DEV_CFG (1 << 3) +# define UDC_CLR_CFG (1 << 2) +#define UDC_DEVSTAT_REG UDC_REG(0x20) /* Device status */ +# define UDC_B_HNP_ENABLE (1 << 9) +# define UDC_A_HNP_SUPPORT (1 << 8) +# define UDC_A_ALT_HNP_SUPPORT (1 << 7) +# define UDC_R_WK_OK (1 << 6) +# define UDC_USB_RESET (1 << 5) +# define UDC_SUS (1 << 4) +# define UDC_CFG (1 << 3) +# define UDC_ADD (1 << 2) +# define UDC_DEF (1 << 1) +# define UDC_ATT (1 << 0) +#define UDC_SOF_REG UDC_REG(0x24) /* Start of frame */ +# define UDC_FT_LOCK (1 << 12) +# define UDC_TS_OK (1 << 11) +# define UDC_TS 0x03ff +#define UDC_IRQ_EN_REG UDC_REG(0x28) /* Interrupt enable */ +# define UDC_SOF_IE (1 << 7) +# define UDC_EPN_RX_IE (1 << 5) +# define UDC_EPN_TX_IE (1 << 4) +# define UDC_DS_CHG_IE (1 << 3) +# define UDC_EP0_IE (1 << 0) +#define UDC_DMA_IRQ_EN_REG UDC_REG(0x2C) /* DMA irq enable */ + /* rx/tx dma channels numbered 1-3 not 0-2 */ +# define UDC_TX_DONE_IE(n) (1 << (4 * (n) - 2)) +# define UDC_RX_CNT_IE(n) (1 << (4 * (n) - 3)) +# define UDC_RX_EOT_IE(n) (1 << (4 * (n) - 4)) +#define UDC_IRQ_SRC_REG UDC_REG(0x30) /* Interrupt source */ +# define UDC_TXN_DONE (1 << 10) +# define UDC_RXN_CNT (1 << 9) +# define UDC_RXN_EOT (1 << 8) +# define UDC_SOF (1 << 7) +# define UDC_EPN_RX (1 << 5) +# define UDC_EPN_TX (1 << 4) +# define UDC_DS_CHG (1 << 3) +# define UDC_SETUP (1 << 2) +# define UDC_EP0_RX (1 << 1) +# define UDC_EP0_TX (1 << 0) +# define UDC_IRQ_SRC_MASK 0x7bf +#define UDC_EPN_STAT_REG UDC_REG(0x34) /* EP irq status */ +#define UDC_DMAN_STAT_REG UDC_REG(0x38) /* DMA irq status */ +# define UDC_DMA_RX_SB (1 << 12) +# define UDC_DMA_RX_SRC(x) (((x)>>8) & 0xf) +# define UDC_DMA_TX_SRC(x) (((x)>>0) & 0xf) + + +/* DMA configuration registers: up to three channels in each direction. */ +#define UDC_RXDMA_CFG_REG UDC_REG(0x40) /* 3 eps for RX DMA */ +#define UDC_TXDMA_CFG_REG UDC_REG(0x44) /* 3 eps for TX DMA */ +#define UDC_DATA_DMA_REG UDC_REG(0x48) /* rx/tx fifo addr */ + +/* rx/tx dma control, numbering channels 1-3 not 0-2 */ +#define UDC_TXDMA_REG(chan) UDC_REG(0x50 - 4 + 4 * (chan)) +# define UDC_TXN_EOT (1 << 15) /* bytes vs packets */ +# define UDC_TXN_START (1 << 14) /* start transfer */ +# define UDC_TXN_TSC 0x03ff /* units in xfer */ +#define UDC_RXDMA_REG(chan) UDC_REG(0x60 - 4 + 4 * (chan)) +# define UDC_RXN_STOP (1 << 15) /* enable EOT irq */ +# define UDC_RXN_TC 0x00ff /* packets in xfer */ + + +/* + * Endpoint configuration registers (used before CFG_LOCK is set) + * UDC_EP_TX_REG(0) is unused + */ +#define UDC_EP_RX_REG(endpoint) UDC_REG(0x80 + (endpoint)*4) +# define UDC_EPN_RX_VALID (1 << 15) +# define UDC_EPN_RX_DB (1 << 14) + /* buffer size in bits 13, 12 */ +# define UDC_EPN_RX_ISO (1 << 11) + /* buffer pointer in low 11 bits */ +#define UDC_EP_TX_REG(endpoint) UDC_REG(0xc0 + (endpoint)*4) + /* same bitfields as in RX_REG */ + +/*-------------------------------------------------------------------------*/ + +struct omap_req { + struct usb_request req; + struct list_head queue; + unsigned dma_bytes; + unsigned mapped:1; +}; + +struct omap_ep { + struct usb_ep ep; + struct list_head queue; + unsigned long irqs; + struct list_head iso; + const struct usb_endpoint_descriptor *desc; + char name[14]; + u16 maxpacket; + u8 bEndpointAddress; + u8 bmAttributes; + unsigned double_buf:1; + unsigned stopped:1; + unsigned ackwait:1; + unsigned has_dma:1; + u8 dma_channel; + int lch; + struct omap_udc *udc; +}; + +struct omap_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + spinlock_t lock; + struct omap_ep ep[32]; + u16 devstat; + struct otg_transceiver *transceiver; + struct list_head iso; + unsigned softconnect:1; + unsigned vbus_active:1; + unsigned ep0_pending:1; + unsigned ep0_in:1; + unsigned ep0_set_config:1; + unsigned ep0_reset_config:1; + unsigned ep0_setup:1; + unsigned hmc:6; + + struct completion *done; +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +# define VDBG DBG +#else +# define VDBG(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) +#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) + +/*-------------------------------------------------------------------------*/ + +// #define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f) +#define HMC_1610 (OTG_SYSCON_2_REG & 0x3f) +#define HMC HMC_1610 + diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 63e538a57..c1139b51d 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -116,7 +117,7 @@ static const char ep0name [] = "ep0"; #ifdef USE_DMA static int use_dma = 1; -MODULE_PARM (use_dma, "i"); +module_param(use_dma, bool, 0); MODULE_PARM_DESC (use_dma, "true to use dma"); static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r); @@ -146,7 +147,7 @@ static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req); * ... so mode = 3 (or 7, 15, etc) does it for both */ static ushort fifo_mode = 0; -MODULE_PARM (fifo_mode, "h"); +module_param(fifo_mode, ushort, 0); MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode"); #endif @@ -1508,7 +1509,7 @@ static void udc_enable (struct pxa2xx_udc *dev) /* caller must be able to sleep in order to cope * with startup transients. */ - schedule_timeout(HZ/10); + msleep(100); /* enable suspend/resume and reset irqs */ udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ebfc22b2a..1e18e92a6 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -48,6 +48,8 @@ #include #include +#include "gadget_chips.h" + /* Wait Cond */ @@ -123,8 +125,8 @@ do { \ /* Defines */ -#define GS_VERSION_STR "v0.1" -#define GS_VERSION_NUM 0x0001 +#define GS_VERSION_STR "v1.0" +#define GS_VERSION_NUM 0x0100 #define GS_LONG_NAME "Gadget Serial" #define GS_SHORT_NAME "g_serial" @@ -173,164 +175,6 @@ static int debug = G_SERIAL_DEBUG; #endif /* G_SERIAL_DEBUG */ -/* USB Controllers */ - -/* - * NetChip 2280, PCI based. - * - * This has half a dozen configurable endpoints, four with dedicated - * DMA channels to manage their FIFOs. It supports high speed. - * Those endpoints can be arranged in any desired configuration. - */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define EP0_MAXPACKET 64 -static const char EP_OUT_NAME[] = "ep-a"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME[] = "ep-b"; -#define EP_IN_NUM 2 -#define HIGHSPEED -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode); - -static inline void hw_optimize(struct usb_gadget *gadget) -{ - /* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets - * for highspeed bulk) because we're not using ep-c/ep-d. - */ - net2280_set_fifo_mode (gadget, 1); -} -#endif - - -/* - * Dummy_hcd, software-based loopback controller. - * - * This imitates the abilities of the NetChip 2280, so we will use - * the same configuration. - */ -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -#define CHIP "dummy" -#define EP0_MAXPACKET 64 -static const char EP_OUT_NAME[] = "ep-a"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME[] = "ep-b"; -#define EP_IN_NUM 2 -#define HIGHSPEED -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - - -/* - * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. - * - * This has fifteen fixed-function full speed endpoints, and it - * can support all USB transfer types. - * - * These supports three or four configurations, with fixed numbers. - * The hardware interprets SET_INTERFACE, net effect is that you - * can't use altsettings or reset the interfaces independently. - * So stick to a single interface. - */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx" -#define EP0_MAXPACKET 16 -static const char EP_OUT_NAME[] = "ep2out-bulk"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME[] = "ep1in-bulk"; -#define EP_IN_NUM 1 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define CHIP "omap" -#define EP0_MAXPACKET 64 -static const char EP_OUT_NAME [] = "ep2out-bulk"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME [] = "ep1in-bulk"; -#define EP_IN_NUM 1 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* supports remote wakeup, but this driver doesn't */ - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - - -/* - * SA-1100 UDC: widely used in first gen Linux-capable PDAs. - * - * This has only two fixed function endpoints, which can only - * be used for bulk (or interrupt) transfers. (Plus control.) - * - * Since it can't flush its TX fifos without disabling the UDC, - * the current configuration or altsettings can't change except - * in special situations. So this is a case of "choose it right - * during enumeration" ... - */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#define EP0_MAXPACKET 8 -static const char EP_OUT_NAME[] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2in-bulk"; -#define EP_IN_NUM 2 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - - -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0116 -#define EP0_MAXPACKET 8 -static const char EP_OUT_NAME [] = "ep1-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2-bulk"; -#define EP_IN_NUM 2 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -/* - * USB Controller Defaults - */ -#ifndef EP0_MAXPACKET -#error Configure some USB peripheral controller for g_serial! -#endif - -#ifndef SELFPOWER -/* default: say we rely on bus power */ -#define SELFPOWER 0 -/* else value must be USB_CONFIG_ATT_SELFPOWER */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif /* Thanks to NetChip Technologies for donating this product ID. * @@ -449,11 +293,17 @@ static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, static unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count); +/* external functions */ +extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode); + /* Globals */ static struct gs_dev *gs_device; +static const char *EP_IN_NAME; +static const char *EP_OUT_NAME; + static struct semaphore gs_open_close_sem[GS_NUM_PORTS]; static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE; @@ -483,7 +333,7 @@ static struct tty_driver *gs_tty_driver; /* gadget driver struct */ static struct usb_gadget_driver gs_gadget_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, @@ -510,8 +360,9 @@ static struct usb_gadget_driver gs_gadget_driver = { #define GS_CONFIG_STR_ID 4 /* static strings, in iso 8859/1 */ +static char manufacturer[40]; static struct usb_string gs_strings[] = { - { GS_MANUFACTURER_STR_ID, UTS_SYSNAME " " UTS_RELEASE " with " CHIP }, + { GS_MANUFACTURER_STR_ID, manufacturer }, { GS_PRODUCT_STR_ID, GS_LONG_NAME }, { GS_SERIAL_STR_ID, "0" }, { GS_CONFIG_STR_ID, "Bulk" }, @@ -523,15 +374,13 @@ static struct usb_gadget_strings gs_string_table = { .strings = gs_strings, }; -static const struct usb_device_descriptor gs_device_desc = { +static struct usb_device_descriptor gs_device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bMaxPacketSize0 = EP0_MAXPACKET, .idVendor = __constant_cpu_to_le16(GS_VENDOR_ID), .idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(GS_VERSION_NUM), .iManufacturer = GS_MANUFACTURER_STR_ID, .iProduct = GS_PRODUCT_STR_ID, .iSerialNumber = GS_SERIAL_STR_ID, @@ -545,8 +394,8 @@ static const struct usb_config_descriptor gs_config_desc = { .bNumInterfaces = GS_NUM_INTERFACES, .bConfigurationValue = GS_BULK_CONFIG_ID, .iConfiguration = GS_CONFIG_STR_ID, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, }; static const struct usb_interface_descriptor gs_interface_desc = { @@ -557,46 +406,41 @@ static const struct usb_interface_descriptor gs_interface_desc = { .iInterface = GS_CONFIG_STR_ID, }; -static const struct usb_endpoint_descriptor gs_fullspeed_in_desc = { +static struct usb_endpoint_descriptor gs_fullspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), }; -static const struct usb_endpoint_descriptor gs_fullspeed_out_desc = { +static struct usb_endpoint_descriptor gs_fullspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM | USB_DIR_OUT, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), }; -static const struct usb_endpoint_descriptor gs_highspeed_in_desc = { +static struct usb_endpoint_descriptor gs_highspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static const struct usb_endpoint_descriptor gs_highspeed_out_desc = { +static struct usb_endpoint_descriptor gs_highspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -#ifdef HIGHSPEED -static const struct usb_qualifier_descriptor gs_qualifier_desc = { +#ifdef CONFIG_USB_GADGET_DUALSPEED +static struct usb_qualifier_descriptor gs_qualifier_desc = { .bLength = sizeof(struct usb_qualifier_descriptor), .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, /* assumes ep0 uses the same value for both speeds ... */ - .bMaxPacketSize0 = EP0_MAXPACKET, .bNumConfigurations = GS_NUM_CONFIGS, }; #endif @@ -608,17 +452,17 @@ MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); #if G_SERIAL_DEBUG -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on, larger values for more messages"); #endif -MODULE_PARM(read_q_size, "i"); +module_param(read_q_size, int, 0); MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32"); -MODULE_PARM(write_q_size, "i"); +module_param(write_q_size, int, 0); MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32"); -MODULE_PARM(write_buf_size, "i"); +module_param(write_buf_size, int, 0); MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192"); module_init(gs_module_init); @@ -1416,18 +1260,81 @@ requeue: static int gs_bind(struct usb_gadget *gadget) { int ret; + struct usb_ep *ep; struct gs_dev *dev; + usb_ep_autoconfig_reset(gadget); + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); + if (!ep) + goto autoconf_fail; + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + /* device specific bcdDevice value in device descriptor */ + if (gadget_is_net2280(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0001); + } else if (gadget_is_pxa(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0002); + } else if (gadget_is_sh(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0003); + } else if (gadget_is_sa1100(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0004); + } else if (gadget_is_goku(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0005); + } else if (gadget_is_mq11xx(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0006); + } else if (gadget_is_omap(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0007); + } else if (gadget_is_lh7a40x(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0008); + } else { + printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", + gadget->name); + /* unrecognized, but safe unless bulk is REALLY quirky */ + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); + } + + gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + + usb_gadget_set_selfpowered(gadget); + gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; - set_gadget_data(gadget, dev); + snprintf (manufacturer, sizeof(manufacturer), + UTS_SYSNAME " " UTS_RELEASE " with %s", gadget->name); memset(dev, 0, sizeof(struct gs_dev)); dev->dev_gadget = gadget; spin_lock_init(&dev->dev_lock); INIT_LIST_HEAD(&dev->dev_req_list); + set_gadget_data(gadget, dev); if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) { printk(KERN_ERR "gs_bind: cannot allocate ports\n"); @@ -1450,6 +1357,10 @@ static int gs_bind(struct usb_gadget *gadget) GS_LONG_NAME, GS_VERSION_STR); return 0; + +autoconf_fail: + printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name); + return -ENODEV; } /* @@ -1505,15 +1416,17 @@ static int gs_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctr memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; ret = min(ctrl->wLength, (u16)sizeof(struct usb_qualifier_descriptor)); memcpy(req->buf, &gs_qualifier_desc, ret); break; case USB_DT_OTHER_SPEED_CONFIG: -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: ret = gs_build_config_desc(req->buf, gadget->speed, ctrl->wValue >> 8, ctrl->wValue & 0xff); @@ -1677,7 +1590,9 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (config != GS_BULK_CONFIG_ID) return -EINVAL; - hw_optimize(gadget); + /* device specific optimizations */ + if (gadget_is_net2280(gadget)) + net2280_set_fifo_mode(gadget, 1); gadget_for_each_ep(ep, gadget) { diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 4fa5e1c8f..a415a33ed 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -399,7 +399,7 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { static char manufacturer [40]; static char serial [40]; -/* static strings, in iso 8859/1 */ +/* static strings, in UTF-8 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, @@ -960,7 +960,8 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_STRING: /* wIndex == language code. * this driver only handles one language, you can - * add others even if they don't use iso8859/1 + * add string tables for other languages, using + * any UTF-8 characters */ value = usb_gadget_get_string (&stringtab, ctrl->wValue & 0xff, req->buf); @@ -1185,6 +1186,8 @@ autoconf_fail: device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); } else if (gadget_is_omap (gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else if (gadget_is_lh7a40x(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); } else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. @@ -1236,6 +1239,12 @@ autoconf_fail: loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } + if (gadget->is_otg) { + otg_descriptor.bmAttributes |= USB_OTG_HNP, + source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + usb_gadget_set_selfpowered (gadget); init_timer (&dev->resume); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 946898ac4..c6e6362d0 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -52,6 +52,7 @@ config USB_EHCI_ROOT_HUB_TT config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB + select ISP1301_OMAP if MACH_OMAP_H2 ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index ad32ba159..bb8bf4c98 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -119,16 +119,16 @@ static void __attribute__((__unused__)) dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) { ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, - cpu_to_le32p (&qtd->hw_next), - cpu_to_le32p (&qtd->hw_alt_next), - cpu_to_le32p (&qtd->hw_token), - cpu_to_le32p (&qtd->hw_buf [0])); + le32_to_cpup (&qtd->hw_next), + le32_to_cpup (&qtd->hw_alt_next), + le32_to_cpup (&qtd->hw_token), + le32_to_cpup (&qtd->hw_buf [0])); if (qtd->hw_buf [1]) ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n", - cpu_to_le32p (&qtd->hw_buf [1]), - cpu_to_le32p (&qtd->hw_buf [2]), - cpu_to_le32p (&qtd->hw_buf [3]), - cpu_to_le32p (&qtd->hw_buf [4])); + le32_to_cpup (&qtd->hw_buf [1]), + le32_to_cpup (&qtd->hw_buf [2]), + le32_to_cpup (&qtd->hw_buf [3]), + le32_to_cpup (&qtd->hw_buf [4])); } static void __attribute__((__unused__)) @@ -331,14 +331,14 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } default: tmp = '?'; break; \ }; tmp; }) -static inline char token_mark (u32 token) +static inline char token_mark (__le32 token) { - token = le32_to_cpu (token); - if (token & QTD_STS_ACTIVE) + __u32 v = le32_to_cpu (token); + if (v & QTD_STS_ACTIVE) return '*'; - if (token & QTD_STS_HALT) + if (v & QTD_STS_HALT) return '-'; - if (!IS_SHORT_READ (token)) + if (!IS_SHORT_READ (v)) return ' '; /* tries to advance through hw_alt_next */ return '/'; @@ -371,25 +371,25 @@ static void qh_lines ( mark = '.'; /* use hw_qtd_next */ /* else alt_next points to some other qtd */ } - scratch = cpu_to_le32p (&qh->hw_info1); - hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0; + scratch = le32_to_cpup (&qh->hw_info1); + hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0; temp = scnprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", qh, scratch & 0x007f, speed_char (scratch), (scratch >> 8) & 0x000f, - scratch, cpu_to_le32p (&qh->hw_info2), - cpu_to_le32p (&qh->hw_token), mark, + scratch, le32_to_cpup (&qh->hw_info2), + le32_to_cpup (&qh->hw_token), mark, (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) ? "data1" : "data0", - (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); + (le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f); size -= temp; next += temp; /* hc may be modifying the list as we read it ... */ list_for_each (entry, &qh->qtd_list) { td = list_entry (entry, struct ehci_qtd, qtd_list); - scratch = cpu_to_le32p (&td->hw_token); + scratch = le32_to_cpup (&td->hw_token); mark = ' '; if (hw_curr == td->qtd_dma) mark = '*'; @@ -488,7 +488,8 @@ show_periodic (struct class_device *class_dev, char *buf) union ehci_shadow p, *seen; unsigned temp, size, seen_count; char *next; - unsigned i, tag; + unsigned i; + __le32 tag; if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) return 0; @@ -541,7 +542,7 @@ show_periodic (struct class_device *class_dev, char *buf) } /* show more info the first time around */ if (temp == seen_count && p.ptr) { - u32 scratch = cpu_to_le32p ( + u32 scratch = le32_to_cpup ( &p.qh->hw_info1); struct ehci_qtd *qtd; char *type = ""; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d3bb7b508..e25adf501 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -155,7 +155,7 @@ MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -289,7 +289,7 @@ static void ehci_watchdog (unsigned long param) static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { if (cap & (1 << 16)) { - int msec = 500; + int msec = 5000; struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller); /* request handoff to OS */ @@ -305,7 +305,10 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); - return 1; + // some BIOS versions seem buggy... + // return 1; + ehci_warn (ehci, "continuing after BIOS bug...\n"); + return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } @@ -337,8 +340,8 @@ static int ehci_hc_reset (struct usb_hcd *hcd) spin_lock_init (&ehci->lock); - ehci->caps = (struct ehci_caps *) hcd->regs; - ehci->regs = (struct ehci_regs *) (hcd->regs + + ehci->caps = hcd->regs; + ehci->regs = (hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase))); dbg_hcs_params (ehci, "reset"); dbg_hcc_params (ehci, "reset"); @@ -692,9 +695,18 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) timer_action_done (ehci, TIMER_IO_WATCHDOG); if (ehci->reclaim_ready) end_unlink_async (ehci, regs); + + /* another CPU may drop ehci->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (ehci->scanning) + return; + ehci->scanning = 1; scan_async (ehci, regs); if (ehci->next_uframe != -1) scan_periodic (ehci, regs); + ehci->scanning = 0; /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 452c73ede..4ff7f868b 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 */ @@ -455,7 +455,7 @@ static int ehci_hub_control ( #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); // we "know" this alignment is good, caller used kmalloc()... - *((u32 *) buf) = cpu_to_le32 (status); + *((__le32 *) buf) = cpu_to_le32 (status); break; case SetHubFeature: switch (wValue) { diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 31f311d53..beee4d996 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); } /*-------------------------------------------------------------------------*/ @@ -235,9 +235,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) } /* Hardware periodic table */ - ehci->periodic = (u32 *) + ehci->periodic = (__le32 *) dma_alloc_coherent (ehci->hcd.self.controller, - ehci->periodic_size * sizeof (u32), + ehci->periodic_size * sizeof(__le32), &ehci->periodic_dma, 0); if (ehci->periodic == 0) { goto fail; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index be39e7aba..b80a2f70d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -153,17 +153,9 @@ static void qtd_copy_status ( usb_pipein (urb->pipe) ? "in" : "out", token, urb->status); - /* stall indicates some recovery action is needed */ - if (urb->status == -EPIPE) { - int pipe = urb->pipe; - - if (!usb_pipecontrol (pipe)) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (pipe), - usb_pipeout (pipe)); - /* if async CSPLIT failed, try cleaning out the TT buffer */ - } else if (urb->dev->tt && !usb_pipeint (urb->pipe) + if (urb->status != -EPIPE + && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_ARC(ehci) @@ -729,7 +721,7 @@ done: static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - u32 dma = QH_NEXT (qh->qh_dma); + __le32 dma = QH_NEXT (qh->qh_dma); struct ehci_qh *head; /* (re)start the async schedule? */ @@ -764,7 +756,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -#define QH_ADDR_MASK __constant_le32_to_cpu(0x7f) +#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f) /* * For control/bulk/interrupt, return QH with these TDs appended. @@ -848,7 +840,7 @@ static struct ehci_qh *qh_append_tds ( if (likely (qtd != 0)) { struct ehci_qtd *dummy; dma_addr_t dma; - u32 token; + __le32 token; /* to avoid racing the HC, use the dummy td instead of * the first td of our list (becomes new dummy). both diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 10df2665e..0000c4608 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -44,7 +44,7 @@ static int ehci_get_frame (struct usb_hcd *hcd); * @tag: hardware tag for type of this record */ static union ehci_shadow * -periodic_next_shadow (union ehci_shadow *periodic, int tag) +periodic_next_shadow (union ehci_shadow *periodic, __le32 tag) { switch (tag) { case Q_TYPE_QH: @@ -64,7 +64,7 @@ periodic_next_shadow (union ehci_shadow *periodic, int tag) static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) { union ehci_shadow *prev_p = &ehci->pshadow [frame]; - u32 *hw_p = &ehci->periodic [frame]; + __le32 *hw_p = &ehci->periodic [frame]; union ehci_shadow here = *prev_p; union ehci_shadow *next_p; @@ -98,7 +98,7 @@ static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) static unsigned short periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { - u32 *hw_p = &ehci->periodic [frame]; + __le32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned usecs = 0; @@ -196,7 +196,7 @@ static int tt_no_collision ( */ for (; frame < ehci->periodic_size; frame += period) { union ehci_shadow here; - u32 type; + __le32 type; here = ehci->pshadow [frame]; type = Q_NEXT_TYPE (ehci->periodic [frame]); @@ -403,7 +403,7 @@ static int check_intr_schedule ( unsigned frame, unsigned uframe, const struct ehci_qh *qh, - u32 *c_maskp + __le32 *c_maskp ) { int retval = -ENOSPC; @@ -412,7 +412,7 @@ static int check_intr_schedule ( goto done; if (!qh->c_usecs) { retval = 0; - *c_maskp = cpu_to_le32 (0); + *c_maskp = 0; goto done; } @@ -447,7 +447,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) { int status; unsigned uframe; - u32 c_mask; + __le32 c_mask; unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ qh->hw_next = EHCI_LIST_END; @@ -1008,8 +1008,7 @@ sitd_slot_ok ( uframe += period_uframes; } while (uframe < mod); - stream->splits = stream->raw_mask << (uframe & 7); - cpu_to_le32s (&stream->splits); + stream->splits = cpu_to_le32(stream->raw_mask << (uframe & 7)); return 1; } @@ -1812,7 +1811,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) for (;;) { union ehci_shadow q, *q_p; - u32 type, *hw_p; + __le32 type, *hw_p; unsigned uframes; /* don't scan past the live uframe */ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index ed4d00291..0e8541133 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -52,12 +52,13 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - int reclaim_ready : 1; + unsigned reclaim_ready : 1; + unsigned scanning : 1; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 /* some HCs can do less */ unsigned periodic_size; - u32 *periodic; /* hw periodic table */ + __le32 *periodic; /* hw periodic table */ dma_addr_t periodic_dma; unsigned i_thresh; /* uframes HC might cache */ @@ -70,9 +71,9 @@ struct ehci_hcd { /* one per controller */ /* glue to PCI and HCD framework */ struct usb_hcd hcd; - struct ehci_caps *caps; - struct ehci_regs *regs; - u32 hcs_params; /* cached register copy */ + struct ehci_caps __iomem *caps; + struct ehci_regs __iomem *regs; + __u32 hcs_params; /* cached register copy */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -272,9 +273,9 @@ struct ehci_regs { */ struct ehci_qtd { /* first part defined by EHCI spec */ - u32 hw_next; /* see EHCI 3.5.1 */ - u32 hw_alt_next; /* see EHCI 3.5.2 */ - u32 hw_token; /* see EHCI 3.5.3 */ + __le32 hw_next; /* see EHCI 3.5.1 */ + __le32 hw_alt_next; /* see EHCI 3.5.2 */ + __le32 hw_token; /* see EHCI 3.5.3 */ #define QTD_TOGGLE (1 << 31) /* data toggle */ #define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) #define QTD_IOC (1 << 15) /* interrupt on complete */ @@ -288,8 +289,8 @@ struct ehci_qtd { #define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ #define QTD_STS_STS (1 << 1) /* split transaction state */ #define QTD_STS_PING (1 << 0) /* issue PING? */ - u32 hw_buf [5]; /* see EHCI 3.5.4 */ - u32 hw_buf_hi [5]; /* Appendix B */ + __le32 hw_buf [5]; /* see EHCI 3.5.4 */ + __le32 hw_buf_hi [5]; /* Appendix B */ /* the rest is HCD-private */ dma_addr_t qtd_dma; /* qtd address */ @@ -349,18 +350,18 @@ union ehci_shadow { struct ehci_qh { /* first part defined by EHCI spec */ - u32 hw_next; /* see EHCI 3.6.1 */ - u32 hw_info1; /* see EHCI 3.6.2 */ + __le32 hw_next; /* see EHCI 3.6.1 */ + __le32 hw_info1; /* see EHCI 3.6.2 */ #define QH_HEAD 0x00008000 - u32 hw_info2; /* see EHCI 3.6.2 */ - u32 hw_current; /* qtd list - see EHCI 3.6.4 */ + __le32 hw_info2; /* see EHCI 3.6.2 */ + __le32 hw_current; /* qtd list - see EHCI 3.6.4 */ /* qtd overlay (hardware parts of a struct ehci_qtd) */ - u32 hw_qtd_next; - u32 hw_alt_next; - u32 hw_token; - u32 hw_buf [5]; - u32 hw_buf_hi [5]; + __le32 hw_qtd_next; + __le32 hw_alt_next; + __le32 hw_token; + __le32 hw_buf [5]; + __le32 hw_buf_hi [5]; /* the rest is HCD-private */ dma_addr_t qh_dma; /* address of qh */ @@ -396,7 +397,7 @@ struct ehci_qh { struct ehci_iso_packet { /* These will be copied to iTD when scheduling */ u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ - u32 transaction; /* itd->hw_transaction[i] |= */ + __le32 transaction; /* itd->hw_transaction[i] |= */ u8 cross; /* buf crosses pages */ /* for full speed OUT splits */ u16 buf1; @@ -418,8 +419,8 @@ struct ehci_iso_sched { */ struct ehci_iso_stream { /* first two fields match QH, but info1 == 0 */ - u32 hw_next; - u32 hw_info1; + __le32 hw_next; + __le32 hw_info1; u32 refcount; u8 bEndpointAddress; @@ -433,7 +434,7 @@ struct ehci_iso_stream { unsigned long start; /* jiffies */ unsigned long rescheduled; int next_uframe; - u32 splits; + __le32 splits; /* the rest is derived from the endpoint descriptor, * trusting urb->interval == f(epdesc->bInterval) and @@ -446,12 +447,12 @@ struct ehci_iso_stream { unsigned bandwidth; /* This is used to initialize iTD's hw_bufp fields */ - u32 buf0; - u32 buf1; - u32 buf2; + __le32 buf0; + __le32 buf1; + __le32 buf2; /* this is used to initialize sITD's tt info */ - u32 address; + __le32 address; }; /*-------------------------------------------------------------------------*/ @@ -464,8 +465,8 @@ struct ehci_iso_stream { */ struct ehci_itd { /* first part defined by EHCI spec */ - u32 hw_next; /* see EHCI 3.3.1 */ - u32 hw_transaction [8]; /* see EHCI 3.3.2 */ + __le32 hw_next; /* see EHCI 3.3.1 */ + __le32 hw_transaction [8]; /* see EHCI 3.3.2 */ #define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ #define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */ #define EHCI_ISOC_BABBLE (1<<29) /* babble detected */ @@ -475,8 +476,8 @@ struct ehci_itd { #define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE) - u32 hw_bufp [7]; /* see EHCI 3.3.3 */ - u32 hw_bufp_hi [7]; /* Appendix B */ + __le32 hw_bufp [7]; /* see EHCI 3.3.3 */ + __le32 hw_bufp_hi [7]; /* Appendix B */ /* the rest is HCD-private */ dma_addr_t itd_dma; /* for this itd */ @@ -503,11 +504,11 @@ struct ehci_itd { */ struct ehci_sitd { /* first part defined by EHCI spec */ - u32 hw_next; + __le32 hw_next; /* uses bit field macros above - see EHCI 0.95 Table 3-8 */ - u32 hw_fullspeed_ep; /* EHCI table 3-9 */ - u32 hw_uframe; /* EHCI table 3-10 */ - u32 hw_results; /* EHCI table 3-11 */ + __le32 hw_fullspeed_ep; /* EHCI table 3-9 */ + __le32 hw_uframe; /* EHCI table 3-10 */ + __le32 hw_results; /* EHCI table 3-11 */ #define SITD_IOC (1 << 31) /* interrupt on completion */ #define SITD_PAGE (1 << 30) /* buffer 0/1 */ #define SITD_LENGTH(x) (0x3ff & ((x)>>16)) @@ -521,9 +522,9 @@ struct ehci_sitd { #define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE) - u32 hw_buf [2]; /* EHCI table 3-12 */ - u32 hw_backpointer; /* EHCI table 3-13 */ - u32 hw_buf_hi [2]; /* Appendix B */ + __le32 hw_buf [2]; /* EHCI table 3-12 */ + __le32 hw_backpointer; /* EHCI table 3-13 */ + __le32 hw_buf_hi [2]; /* Appendix B */ /* the rest is HCD-private */ dma_addr_t sitd_dma; @@ -548,8 +549,8 @@ struct ehci_sitd { * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. */ struct ehci_fstn { - u32 hw_next; /* any periodic q entry */ - u32 hw_prev; /* qh or EHCI_LIST_END */ + __le32 hw_next; /* any periodic q entry */ + __le32 hw_prev; /* qh or EHCI_LIST_END */ /* the rest is HCD-private */ dma_addr_t fstn_dma; diff --git a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c index 8a464917e..ade67124a 100644 --- a/drivers/usb/host/hc_simple.c +++ b/drivers/usb/host/hc_simple.c @@ -146,11 +146,6 @@ static int hci_submit_urb (struct urb * urb, int mem_flags) if (!urb->dev || !urb->dev->bus || urb->hcpriv) return -EINVAL; - if (usb_endpoint_halted - (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) { - printk ("hci_submit_urb: endpoint_halted\n"); - return -EPIPE; - } hci = (hci_t *) urb->dev->bus->hcpriv; /* a request to the virtual root hub */ diff --git a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c index 5bda71207..b57f1fe82 100644 --- a/drivers/usb/host/hc_sl811.c +++ b/drivers/usb/host/hc_sl811.c @@ -106,14 +106,14 @@ int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len, static int sofWaitCnt = 0; -MODULE_PARM (urb_debug, "i"); +module_param(urb_debug, int, 0); MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)"); -MODULE_PARM (base_addr, "i"); +module_param(base_addr, int, 0); MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000"); -MODULE_PARM (data_reg_addr, "i"); +module_param(data_reg_addr, int, 0); MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000"); -MODULE_PARM (irq, "i"); +module_param(irq, int, 0); MODULE_PARM_DESC (irq, "IRQ 34 (default)"); static int hc_reset (hci_t * hci); diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 54daaacdc..947bf4a5e 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -131,7 +131,7 @@ static char *hcfs2string (int state) static void ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) { - struct ohci_regs *regs = controller->regs; + struct ohci_regs __iomem *regs = controller->regs; u32 temp; temp = ohci_readl (®s->revision) & 0xff; @@ -336,7 +336,7 @@ static void __attribute__((unused)) ohci_dump_ed (const struct ohci_hcd *ohci, const char *label, const struct ed *ed, int verbose) { - u32 tmp = ed->hwINFO; + __le32 tmp = ed->hwINFO; char *type = ""; ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n", @@ -359,7 +359,7 @@ ohci_dump_ed (const struct ohci_hcd *ohci, const char *label, type, 0x007f & le32_to_cpu (tmp)); ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s\n", - tmp = le32_to_cpup (&ed->hwHeadP), + le32_to_cpup (&ed->hwHeadP), (ed->hwHeadP & ED_C) ? data1 : data0, (ed->hwHeadP & ED_H) ? " HALT" : "", le32_to_cpup (&ed->hwTailP), @@ -415,8 +415,8 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) /* dump a snapshot of the bulk or control schedule */ while (ed) { - u32 info = ed->hwINFO; - u32 scratch = cpu_to_le32p (&ed->hwINFO); + __le32 info = ed->hwINFO; + u32 scratch = le32_to_cpup (&ed->hwINFO); struct list_head *entry; struct td *td; @@ -439,7 +439,7 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) u32 cbp, be; td = list_entry (entry, struct td, td_list); - scratch = cpu_to_le32p (&td->hwINFO); + scratch = le32_to_cpup (&td->hwINFO); cbp = le32_to_cpup (&td->hwCBP); be = le32_to_cpup (&td->hwBE); temp = scnprintf (buf, size, @@ -541,8 +541,8 @@ show_periodic (struct class_device *class_dev, char *buf) /* show more info the first time around */ if (temp == seen_count) { - u32 info = ed->hwINFO; - u32 scratch = cpu_to_le32p (&ed->hwINFO); + __le32 info = ed->hwINFO; + u32 scratch = le32_to_cpup (&ed->hwINFO); struct list_head *entry; unsigned qlen = 0; @@ -599,7 +599,7 @@ show_registers (struct class_device *class_dev, char *buf) struct usb_bus *bus; struct usb_hcd *hcd; struct ohci_hcd *ohci; - struct ohci_regs *regs; + struct ohci_regs __iomem *regs; unsigned long flags; unsigned temp, size; char *next; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d13e98e35..0609e12ef 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -97,6 +97,7 @@ #include #include /* for in_interrupt () */ #include +#include #include "../core/hcd.h" #include #include /* needed by ohci-mem.c when no PCI */ @@ -593,7 +594,7 @@ static int hc_start (struct ohci_hcd *ohci) static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ohci_regs *regs = ohci->regs; + struct ohci_regs __iomem *regs = ohci->regs; int ints; /* we can eliminate a (slow) ohci_readl() @@ -693,7 +694,7 @@ static void ohci_stop (struct usb_hcd *hcd) /* must not be called from interrupt context */ -#ifdef CONFIG_PM +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) static void mark_children_gone (struct usb_device *dev) { diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index f6263bf9b..424971c4b 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -435,6 +435,89 @@ ohci_hub_descriptor ( /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_OTG + +static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + u32 status; + + if (!port) + return -EINVAL; + port--; + + /* start port reset before HNP protocol times out */ + status = ohci_readl(&ohci->regs->roothub.portstatus [port]); + if (!(status & RH_PS_CCS)) + return -ENODEV; + + /* khubd will finish the reset later */ + writel(RH_PS_PRS, &ohci->regs->roothub.portstatus [port]); + return 0; +} + +static void start_hnp(struct ohci_hcd *ohci); + +#else + +#define ohci_start_port_reset NULL + +#endif + +/*-------------------------------------------------------------------------*/ + + +/* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling, + * not necessarily continuous ... to guard against resume signaling. + * The short timeout is safe for non-root hubs, and is backward-compatible + * with earlier Linux hosts. + */ +#ifdef CONFIG_USB_SUSPEND +#define PORT_RESET_MSEC 50 +#else +#define PORT_RESET_MSEC 10 +#endif + +/* this timer value might be vendor-specific ... */ +#define PORT_RESET_HW_MSEC 10 + +/* wrap-aware logic stolen from */ +#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) + +/* called from some task, normally khubd */ +static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) +{ + u32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; + u32 temp; + u16 now = readl(&ohci->regs->fmnumber); + u16 reset_done = now + PORT_RESET_MSEC; + + /* build a "continuous enough" reset signal, with up to + * 3msec gap between pulses. scheduler HZ==100 must work; + * this might need to be deadline-scheduled. + */ + do { + /* spin until any current reset finishes */ + for (;;) { + temp = ohci_readl (portstat); + if (!(temp & RH_PS_PRS)) + break; + udelay (500); + } + + if (!(temp & RH_PS_CCS)) + break; + if (temp & RH_PS_PRSC) + writel (RH_PS_PRSC, portstat); + + /* start the next reset, sleep till it's probably done */ + writel (RH_PS_PRS, portstat); + msleep(PORT_RESET_HW_MSEC); + now = readl(&ohci->regs->fmnumber); + } while (tick_before(now, reset_done)); + /* caller synchronizes using PRSC */ +} + static int ohci_hub_control ( struct usb_hcd *hcd, u16 typeReq, @@ -503,14 +586,14 @@ static int ohci_hub_control ( break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - *(u32 *) buf = cpu_to_le32 (temp); + *(__le32 *) buf = cpu_to_le32 (temp); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - *(u32 *) buf = cpu_to_le32 (temp); + *(__le32 *) buf = cpu_to_le32 (temp); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ @@ -533,6 +616,12 @@ static int ohci_hub_control ( wIndex--; switch (wValue) { case USB_PORT_FEAT_SUSPEND: +#ifdef CONFIG_USB_OTG + if (ohci->hcd.self.otg_port == (wIndex + 1) + && ohci->hcd.self.b_hnp_enable) + start_hnp(ohci); + else +#endif writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [wIndex]); break; @@ -541,10 +630,7 @@ static int ohci_hub_control ( &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_RESET: - temp = ohci_readl (&ohci->regs->roothub.portstatus [wIndex]); - if (temp & RH_PS_CCS) - writel (RH_PS_PRS, - &ohci->regs->roothub.portstatus [wIndex]); + root_port_reset (ohci, wIndex); break; default: goto error; diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 1e5fc5d93..d133ff22a 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -2,27 +2,30 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2000-2004 David Brownell * (C) Copyright 2002 Hewlett-Packard Company * * OMAP Bus Glue * * Written by Christopher Hoover - * Based on fragments of previous driver by Rusell King et al. + * Based on fragments of previous driver by Russell King et al. * * Modified for OMAP from ohci-sa1111.c by Tony Lindgren * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc. * * This file is licenced under the GPL. */ - + #include #include +#include -#include #include #include #include +#include +#include +#include #include "ohci-omap.h" @@ -33,123 +36,54 @@ extern int usb_disabled(void); extern int ocpi_enable(void); -/* - * Use the first port only by default. Override with hmc_mode option. - * - * NOTE: Many OMAP-1510 Innovators supposedly have bad wiring for the USB ports - * 1 & 2, so only port 0 will work. To use the OHCI on the first port, use - * the Innovator USB client cable with a client-to-client connector and modify - * either the cable or the hub to feed 5V VBUS back to Innovator. VBUS should - * be the red lead in the cable. - * - * To mount USB hard disk as root, see the patch for do_mounts.c that tries - * remounting the root, and use root=0801 if your root is on sda1. Does not - * work with devfs. - */ -static int default_hmc_mode = 16; -static int hmc_mode = 1234; - -/* - * Set the USB host pin multiplexing and the selected HMC mode - */ -static int omap_usb_set_hmc_mode(int hmc_mode) -{ - unsigned int val; - - switch (hmc_mode) { - case 0: - /* 0: function, 1: disabled, 2: disabled */ - omap_cfg_reg(W4_USB_PUEN); - omap_cfg_reg(R18_1510_USB_GPIO0); - break; - case 4: - /* 0: function 1: host 2: host */ - omap_cfg_reg(usb1_speed); - omap_cfg_reg(usb1_susp); - omap_cfg_reg(usb1_seo); - omap_cfg_reg(usb1_txen); - omap_cfg_reg(usb1_txd); - omap_cfg_reg(usb1_vp); - omap_cfg_reg(usb1_vm); - omap_cfg_reg(usb1_rcv); - omap_cfg_reg(usb2_susp); - omap_cfg_reg(usb2_seo); - omap_cfg_reg(usb2_txen); - omap_cfg_reg(usb2_txd); - omap_cfg_reg(usb2_vp); - omap_cfg_reg(usb2_vm); - omap_cfg_reg(usb2_rcv); - break; - case 16: - /* 0: host, 1: disabled, 2: disabled */ - omap_cfg_reg(W9_USB0_TXEN); - omap_cfg_reg(AA9_USB0_VP); - omap_cfg_reg(Y5_USB0_RCV); - omap_cfg_reg(R9_USB0_VM); - omap_cfg_reg(V6_USB0_TXD); - omap_cfg_reg(W5_USB0_SE0); - break; - default: - printk("Unknown USB host configuration: %i\n", hmc_mode); - return -ENODEV; - } - - /* Write the selected HMC mode */ - val = readl(MOD_CONF_CTRL_0) & ~HMC_CLEAR; - val |= (hmc_mode << 1); - writel(val, MOD_CONF_CTRL_0); - - return 0; -} - /* * OHCI clock initialization for OMAP-1510 and 1610 */ static int omap_ohci_clock_power(int on) { if (on) { - if (cpu_is_omap_1510()) { + if (cpu_is_omap1510()) { /* Use DPLL, not APLL */ - writel(readl(ULPD_APLL_CTRL_REG) & ~APLL_NDPLL_SWITCH, - ULPD_APLL_CTRL_REG); + omap_writel(omap_readl(ULPD_APLL_CTRL) & ~APLL_NDPLL_SWITCH, + ULPD_APLL_CTRL); /* Enable DPLL */ - writel(readl(ULPD_DPLL_CTRL_REG) | DPLL_PLL_ENABLE, - ULPD_DPLL_CTRL_REG); + omap_writel(omap_readl(ULPD_DPLL_CTRL) | DPLL_PLL_ENABLE, + ULPD_DPLL_CTRL); /* Software request for USB 48MHz clock */ - writel(readl(ULPD_SOFT_REQ_REG) | SOFT_REQ_REG_REQ, - ULPD_SOFT_REQ_REG); + omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_REQ_REG_REQ, + ULPD_SOFT_REQ); - while (!(readl(ULPD_DPLL_CTRL_REG) & DPLL_LOCK)); + while (!(omap_readl(ULPD_DPLL_CTRL) & DPLL_LOCK)); } - if (cpu_is_omap_1610()) { + if (cpu_is_omap16xx()) { /* Enable OHCI */ - writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_OTG_REQ, - ULPD_SOFT_REQ_REG); + omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_OTG_REQ, + ULPD_SOFT_REQ); /* USB host clock request if not using OTG */ - writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_REQ, - ULPD_SOFT_REQ_REG); + omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_REQ, + ULPD_SOFT_REQ); - writel(readl(ULPD_STATUS_REQ_REG) | USB_HOST_DPLL_REQ, - ULPD_STATUS_REQ_REG); + omap_writel(omap_readl(ULPD_STATUS_REQ) | USB_HOST_DPLL_REQ, + ULPD_STATUS_REQ); } /* Enable 48MHz clock to USB */ - writel(readl(ULPD_CLOCK_CTRL_REG) | USB_MCLK_EN, - ULPD_CLOCK_CTRL_REG); + omap_writel(omap_readl(ULPD_CLOCK_CTRL) | USB_MCLK_EN, + ULPD_CLOCK_CTRL); - writel(readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), + omap_writel(omap_readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), ARM_IDLECT2); - writel(readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, + omap_writel(omap_readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, MOD_CONF_CTRL_0); } else { /* Disable 48MHz clock to USB */ - writel(readl(ULPD_CLOCK_CTRL_REG) & ~USB_MCLK_EN, - ULPD_CLOCK_CTRL_REG); + omap_writel(omap_readl(ULPD_CLOCK_CTRL) & ~USB_MCLK_EN, + ULPD_CLOCK_CTRL); /* FIXME: The DPLL stays on for now */ } @@ -163,13 +97,19 @@ static int omap_ohci_clock_power(int on) static int omap_ohci_transceiver_power(int on) { if (on) { - if (omap_is_innovator()) - writel(readl(OMAP1510_FPGA_HOST_CTRL) | 0x20, - OMAP1510_FPGA_HOST_CTRL); + if (machine_is_omap_innovator() && cpu_is_omap1510()) + fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) | 0x20, + INNOVATOR_FPGA_CAM_USB_CONTROL); + else if (machine_is_omap_osk()) { + /* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */ + } } else { - if (omap_is_innovator()) - writel(readl(OMAP1510_FPGA_HOST_CTRL) & ~0x20, - OMAP1510_FPGA_HOST_CTRL); + if (machine_is_omap_innovator() && cpu_is_omap1510()) + fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~0x20, + INNOVATOR_FPGA_CAM_USB_CONTROL); + else if (machine_is_omap_osk()) { + /* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */ + } } return 0; @@ -181,10 +121,10 @@ static int omap_ohci_transceiver_power(int on) static int omap_1510_local_bus_power(int on) { if (on) { - writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); + omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); udelay(200); } else { - writel(0, OMAP1510_LB_MMU_CTL); + omap_writel(0, OMAP1510_LB_MMU_CTL); } return 0; @@ -193,8 +133,8 @@ static int omap_1510_local_bus_power(int on) /* * OMAP-1510 specific Local Bus initialization * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. - * See also arch/mach-omap/memory.h for __virt_to_bus() and - * __bus_to_virt() which need to match with the physical + * See also arch/mach-omap/memory.h for __virt_to_dma() and + * __dma_to_virt() which need to match with the physical * Local Bus address below. */ static int omap_1510_local_bus_init(void) @@ -202,125 +142,115 @@ static int omap_1510_local_bus_init(void) unsigned int tlb; unsigned long lbaddr, physaddr; - writel((readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, + omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, OMAP1510_LB_CLOCK_DIV); /* Configure the Local Bus MMU table */ for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) { lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; physaddr = tlb * 0x00100000 + PHYS_OFFSET; - writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); - writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, + omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); + omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, OMAP1510_LB_MMU_CAM_L); - writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); - writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); - writel(tlb << 4, OMAP1510_LB_MMU_LCK); - writel(0x1, OMAP1510_LB_MMU_LD_TLB); + omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); + omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); + omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK); + omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB); } /* Enable the walking table */ - writel(readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); + omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); udelay(200); return 0; } -/* - * OMAP-1610 specific hardware initialization - * - * Intended to configure OMAP-1610 USB host and OTG ports depending on - * the HMC mode selected. - * - * FIXME: Currently only supports alternate ping group 2 mode, should - * be easy to modify for other configurations once there is some - * hardware to test with. - */ -static int omap_1610_usb_init(int mode) -{ - u_int val = 0; - - /* Configure the OMAP transceiver settings */ - val |= (1 << 8); /* CONF_USB2_UNI TRM p 15-205*/ - val |= (4 << 4); /* TRM p 5-59, p 15-157 (1224) */ +#ifdef CONFIG_USB_OTG - //val |= (1 << 3); /* Isolate integrated transceiver from port 0 */ - val |= (1 << 2); /* Disable pulldown on integrated transceiver DM */ - val |= (1 << 1); /* Disable pulldown on integraded transceiver DP */ +static void start_hnp(struct ohci_hcd *ohci) +{ + const unsigned port = ohci->hcd.self.otg_port - 1; + unsigned long flags; - writel(val, USB_TRANSCEIVER_CTRL); + otg_start_hnp(ohci->transceiver); - /* Set the USB0_TRX_MODE */ - val = 0; - val &= ~OTG_IDLE_EN; - val &= ~DEV_IDLE_EN; - val &= ~(7 << 16); /* Clear USB0_TRX_MODE */ - val |= (3 << 16); /* 0 or 3, 6-wire DAT/SE0, TRM p 15-159 */ - writel(val, OTG_SYSCON_1); + local_irq_save(flags); + ohci->transceiver->state = OTG_STATE_A_SUSPEND; + writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]); + OTG_CTRL_REG &= ~OTG_A_BUSREQ; + local_irq_restore(flags); +} - /* - * Control via OTG, see TRM p 15-163 - */ - val = 0; - //val |= 1; /* REVISIT: Enable OTG = 1 */ +#endif - /* Control via OTG */ - val &= ~HMC_PADEN; - val &= ~OTG_PADEN; - val |= UHOST_EN; +/*-------------------------------------------------------------------------*/ - val &= ~0x3f; /* Clear HMC mode */ - val |= mode; /* Set HMC mode */ - val &= ~(7 << 16); /* Clear ASE0_BRST */ - val |= (4 << 16); /* Must be 4 */ - val |= USBX_SYNCHRO; /* Must be set */ - val |= SRP_VBUS; - writel(val, OTG_SYSCON_2); +static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) +{ + struct omap_usb_config *config = pdev->dev.platform_data; + int need_transceiver = (config->otg != 0); - /* Enable OTG idle */ - //writel(readl(OTG_SYSCON_1) | OTG_IDLE_EN, OTG_SYSCON_1); + dev_dbg(&pdev->dev, "starting USB Controller\n"); - return 0; -} + if (config->otg) { + ohci->hcd.self.otg_port = config->otg; + /* default/minimum OTG power budget: 8 mA */ + ohci->power_budget = 8; + } -/*-------------------------------------------------------------------------*/ + /* boards can use OTG transceivers in non-OTG modes */ + need_transceiver = need_transceiver + || machine_is_omap_h2(); -static void omap_start_hc(struct omap_dev *dev) -{ - printk(KERN_DEBUG __FILE__ - ": starting OMAP OHCI USB Controller\n"); + if (cpu_is_omap16xx()) + ocpi_enable(); - /* - * Set the HMC mode for the USB ports - */ -#if 0 - /* See note about the Innovator wiring above */ - if (omap_is_innovator()) - hmc_mode = 4; /* 0: function 1: host 2: host */ +#ifdef CONFIG_ARCH_OMAP_OTG + if (need_transceiver) { + ohci->transceiver = otg_get_transceiver(); + if (ohci->transceiver) { + int status = otg_set_host(ohci->transceiver, + &ohci->hcd.self); + dev_dbg(&pdev->dev, "init %s transceiver, status %d\n", + ohci->transceiver->label, status); + if (status) { + if (ohci->transceiver) + put_device(ohci->transceiver->dev); + return status; + } + } else { + dev_err(&pdev->dev, "can't find transceiver\n"); + return -ENODEV; + } + } #endif - if (cpu_is_omap_1610()) - ocpi_enable(); - - omap_usb_set_hmc_mode(hmc_mode); + if (machine_is_omap_osk()) { + omap_request_gpio(9); + omap_set_gpio_direction(9, 1); + omap_set_gpio_dataout(9, 1); + } omap_ohci_clock_power(1); + omap_ohci_transceiver_power(1); - if (cpu_is_omap_1510()) { + if (cpu_is_omap1510()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } - if (cpu_is_omap_1610()) - omap_1610_usb_init(hmc_mode); + /* board init will have already handled HMC and mux setup. + * any external transceiver should already be initialized + * too, so all configured ports use the right signaling now. + */ - //omap_enable_device(dev); + return 0; } -static void omap_stop_hc(struct omap_dev *dev) +static void omap_stop_hc(struct platform_device *pdev) { - printk(KERN_DEBUG __FILE__ - ": stopping OMAP OHCI USB Controller\n"); + dev_dbg(&pdev->dev, "stopping USB Controller\n"); /* * FIXME: Put the USB host controller into reset. @@ -336,16 +266,7 @@ static void omap_stop_hc(struct omap_dev *dev) /*-------------------------------------------------------------------------*/ -static irqreturn_t usb_hcd_omap_hcim_irq (int irq, void *__hcd, struct pt_regs * r) -{ - struct usb_hcd *hcd = __hcd; - - return usb_hcd_irq(irq, hcd, r); -} - -/*-------------------------------------------------------------------------*/ - -void usb_hcd_omap_remove (struct usb_hcd *, struct omap_dev *); +void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ @@ -358,59 +279,71 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct omap_dev *); * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). */ int usb_hcd_omap_probe (const struct hc_driver *driver, - struct usb_hcd **hcd_out, - struct omap_dev *dev) + struct platform_device *pdev) { int retval; struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; - if (!request_mem_region(dev->res.start, - dev->res.end - dev->res.start + 1, hcd_name)) { - dbg("request_mem_region failed"); - return -EBUSY; + if (pdev->num_resources != 2) { + printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", + pdev->num_resources); + return -ENODEV; } - omap_start_hc(dev); + if (pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_IRQ) { + printk(KERN_ERR "hcd probe: invalid resource type\n"); + return -ENODEV; + } + + if (!request_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + return -EBUSY; + } hcd = driver->hcd_alloc (); if (hcd == NULL){ - dbg ("hcd_alloc failed"); + dev_dbg(&pdev->dev, "hcd_alloc failed\n"); retval = -ENOMEM; goto err1; } + dev_set_drvdata(&pdev->dev, hcd); + ohci = hcd_to_ohci(hcd); hcd->driver = (struct hc_driver *) driver; hcd->description = driver->description; - hcd->irq = dev->irq[0]; - hcd->regs = dev->mapbase; - hcd->self.controller = &dev->dev; + hcd->irq = pdev->resource[1].start; + hcd->regs = (void *)pdev->resource[0].start; + hcd->self.controller = &pdev->dev; + + retval = omap_start_hc(ohci, pdev); + if (retval < 0) + goto err2; retval = hcd_buffer_create (hcd); if (retval != 0) { - dbg ("pool alloc fail"); + dev_dbg(&pdev->dev, "pool alloc fail\n"); goto err1; } - retval = request_irq (hcd->irq, - usb_hcd_omap_hcim_irq, + retval = request_irq (hcd->irq, usb_hcd_irq, SA_INTERRUPT, hcd->description, hcd); if (retval != 0) { - dbg("request_irq failed"); + dev_dbg(&pdev->dev, "request_irq failed\n"); retval = -EBUSY; goto err2; } - info ("%s (OMAP) at 0x%p, irq %d\n", - hcd->description, hcd->regs, hcd->irq); + dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); usb_bus_init (&hcd->self); hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = (void *) hcd; - hcd->self.bus_name = "omap"; + hcd->self.bus_name = pdev->dev.bus_id; hcd->product_desc = "OMAP OHCI"; INIT_LIST_HEAD (&hcd->dev_list); @@ -418,11 +351,10 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, if ((retval = driver->start (hcd)) < 0) { - usb_hcd_omap_remove(hcd, dev); + usb_hcd_omap_remove(hcd, pdev); return retval; } - *hcd_out = hcd; return 0; err2: @@ -430,10 +362,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, if (hcd) driver->hcd_free(hcd); err1: - omap_stop_hc(dev); + omap_stop_hc(pdev); - release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + dev_set_drvdata(&pdev->dev, 0); return retval; } @@ -451,24 +385,27 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, * context, normally "rmmod", "apmd", or something similar. * */ -void usb_hcd_omap_remove (struct usb_hcd *hcd, struct omap_dev *dev) +void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) { void *base; - info ("remove: %s, state %x", hcd->self.bus_name, hcd->state); + dev_info(&pdev->dev, "remove: state %x\n", hcd->state); if (in_interrupt ()) BUG (); hcd->state = USB_STATE_QUIESCING; - dbg ("%s: roothub graceful disconnect", hcd->self.bus_name); + dev_dbg(&pdev->dev, "roothub graceful disconnect\n"); usb_disconnect (&hcd->self.root_hub); hcd->driver->stop (hcd); hcd_buffer_destroy (hcd); hcd->state = USB_STATE_HALT; + if (machine_is_omap_osk()) + omap_free_gpio(9); + free_irq (hcd->irq, hcd); usb_deregister_bus (&hcd->self); @@ -476,9 +413,10 @@ void usb_hcd_omap_remove (struct usb_hcd *hcd, struct omap_dev *dev) base = hcd->regs; hcd->driver->hcd_free (hcd); - omap_stop_hc(dev); + omap_stop_hc(pdev); - release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); } /*-------------------------------------------------------------------------*/ @@ -486,11 +424,13 @@ void usb_hcd_omap_remove (struct usb_hcd *hcd, struct omap_dev *dev) static int __devinit ohci_omap_start (struct usb_hcd *hcd) { + struct omap_usb_config *config; struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - ohci->hcca = dma_alloc_consistent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma); + config = hcd->self.controller->platform_data; + ohci->hcca = dma_alloc_coherent (hcd->self.controller, + sizeof *ohci->hcca, &ohci->hcca_dma, 0); if (!ohci->hcca) return -ENOMEM; @@ -500,6 +440,10 @@ ohci_omap_start (struct usb_hcd *hcd) return ret; } ohci->regs = hcd->regs; + + if (config->otg || config->rwc) + writel(OHCI_CTRL_RWC, &ohci->regs->control); + if (hc_reset (ohci) < 0) { ohci_stop (hcd); return -ENODEV; @@ -510,6 +454,9 @@ ohci_omap_start (struct usb_hcd *hcd) ohci_stop (hcd); return -EBUSY; } + if (ohci->power_budget) + hub_set_power_budget(ohci->hcd.self.root_hub, + ohci->power_budget); create_debug_files (ohci); #ifdef DEBUG @@ -533,10 +480,6 @@ static const struct hc_driver ohci_omap_hc_driver = { * basic lifecycle operations */ .start = ohci_omap_start, -#ifdef CONFIG_PM - /* suspend: ohci_omap_suspend, -- tbd */ - /* resume: ohci_omap_resume, -- tbd */ -#endif .stop = ohci_stop, /* @@ -566,104 +509,130 @@ static const struct hc_driver ohci_omap_hc_driver = { .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ -static int ohci_hcd_omap_drv_probe(struct omap_dev *dev) +static int ohci_hcd_omap_drv_probe(struct device *dev) { - struct usb_hcd *hcd = NULL; - int ret; + return usb_hcd_omap_probe(&ohci_omap_hc_driver, + to_platform_device(dev)); +} - if (usb_disabled()) - return -ENODEV; +static int ohci_hcd_omap_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + usb_hcd_omap_remove(hcd, pdev); + if (ohci->transceiver) { + (void) otg_set_host(ohci->transceiver, 0); + put_device(ohci->transceiver->dev); + } + dev_set_drvdata(dev, NULL); + + return 0; +} + +/*-------------------------------------------------------------------------*/ - ret = usb_hcd_omap_probe(&ohci_omap_hc_driver, &hcd, dev); +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) - if (ret == 0) - omap_set_drvdata(dev, hcd); +/* states match PCI usage, always suspending the root hub except that + * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset). + */ - return ret; +static int ohci_omap_suspend(struct device *dev, u32 state, u32 level) +{ + struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); + int status = -EINVAL; + + if (state <= dev->power.power_state) + return 0; + + dev_dbg(dev, "suspend to %d\n", state); + down(&ohci->hcd.self.root_hub->serialize); + status = ohci_hub_suspend(&ohci->hcd); + if (status == 0) { + if (state >= 4) { + /* power off + reset */ + OTG_SYSCON_2_REG &= ~UHOST_EN; + ohci->hcd.self.root_hub->state = USB_STATE_SUSPENDED; + state = 4; + } + ohci->hcd.state = HCD_STATE_SUSPENDED; + dev->power.power_state = state; + } + up(&ohci->hcd.self.root_hub->serialize); + return status; } -static int ohci_hcd_omap_drv_remove(struct omap_dev *dev) +static int ohci_omap_resume(struct device *dev, u32 level) { - struct usb_hcd *hcd = omap_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); + int status = 0; - usb_hcd_omap_remove(hcd, dev); + switch (dev->power.power_state) { + case 0: + break; + case 4: + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + OTG_SYSCON_2_REG |= UHOST_EN; + /* FALLTHROUGH */ + default: + dev_dbg(dev, "resume from %d\n", dev->power.power_state); +#ifdef CONFIG_USB_SUSPEND + /* get extra cleanup even if remote wakeup isn't in use */ + status = usb_resume_device(ohci->hcd.self.root_hub); +#else + down(&ohci->hcd.self.root_hub->serialize); + status = ohci_hub_resume(&ohci->hcd); + up(&ohci->hcd.self.root_hub->serialize); +#endif + if (status == 0) + dev->power.power_state = 0; + break; + } + return status; +} - omap_set_drvdata(dev, NULL); +#endif - return 0; -} +/*-------------------------------------------------------------------------*/ /* * Driver definition to register with the OMAP bus */ -static struct omap_driver ohci_hcd_omap_driver = { - .drv = { - .name = OMAP_OHCI_NAME, - }, - .devid = OMAP_OCP_DEVID_USB, - .busid = OMAP_BUS_OCP, - .clocks = 0, +static struct device_driver ohci_hcd_omap_driver = { + .name = "ohci", + .bus = &platform_bus_type, .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, -}; - -/* Any dma_mask must be set for OHCI to work */ -static u64 omap_dmamask = 0xffffffffUL; - -/* - * Device definition to match the driver above - */ -static struct omap_dev ohci_hcd_omap_device = { - .name = OMAP_OHCI_NAME, - .devid = OMAP_OCP_DEVID_USB, - .busid = OMAP_BUS_OCP, - .mapbase = (void *)OMAP_OHCI_BASE, - .dma_mask = &omap_dmamask, /* Needed only for OHCI */ - .res = { - .start = OMAP_OHCI_BASE, - .end = OMAP_OHCI_BASE + OMAP_OHCI_SIZE, - }, - .irq = { - INT_USB_HHC_1, - }, +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) + .suspend = ohci_omap_suspend, + .resume = ohci_omap_resume, +#endif }; static int __init ohci_hcd_omap_init (void) { - int ret; - - dbg (DRIVER_INFO " (OMAP)"); - dbg ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - if (hmc_mode < 0 || hmc_mode > 25) - hmc_mode = default_hmc_mode; - - /* Register the driver with OMAP bus */ - ret = omap_driver_register(&ohci_hcd_omap_driver); - if (ret != 0) + printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name); + if (usb_disabled()) return -ENODEV; - /* Register the device with OMAP bus */ - ret = omap_device_register(&ohci_hcd_omap_device); - if (ret != 0) { - omap_driver_unregister(&ohci_hcd_omap_driver); - return -ENODEV; - } + pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, + sizeof (struct ed), sizeof (struct td)); - return ret; + return driver_register(&ohci_hcd_omap_driver); } -MODULE_PARM(hmc_mode, "hmc_mode"); - static void __exit ohci_hcd_omap_cleanup (void) { - omap_device_unregister(&ohci_hcd_omap_device); - omap_driver_unregister(&ohci_hcd_omap_driver); + driver_unregister(&ohci_hcd_omap_driver); } module_init (ohci_hcd_omap_init); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index dc8bc13bf..73d9aee65 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -242,6 +242,7 @@ static const struct hc_driver ohci_pci_hc_driver = { .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ @@ -276,7 +277,7 @@ static int __init ohci_hcd_pci_init (void) if (usb_disabled()) return -ENODEV; - printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name, + pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); return pci_module_init (&ohci_pci_driver); } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 74c829f92..1afd40fec 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -136,7 +136,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) for (i = ed->branch; i < NUM_INTS; i += ed->interval) { struct ed **prev = &ohci->periodic [i]; - u32 *prev_p = &ohci->hcca->int_table [i]; + __le32 *prev_p = &ohci->hcca->int_table [i]; struct ed *here = *prev; /* sorting each branch by period (slow before fast) @@ -156,7 +156,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) ed->hwNextED = *prev_p; wmb (); *prev = ed; - *prev_p = cpu_to_le32p (&ed->dma); + *prev_p = cpu_to_le32(ed->dma); wmb(); } ohci->load [i] += ed->load; @@ -257,7 +257,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) for (i = ed->branch; i < NUM_INTS; i += ed->interval) { struct ed *temp; struct ed **prev = &ohci->periodic [i]; - u32 *prev_p = &ohci->hcca->int_table [i]; + __le32 *prev_p = &ohci->hcca->int_table [i]; while (*prev && (temp = *prev) != ed) { prev_p = &temp->hwNextED; @@ -427,20 +427,21 @@ static struct ed *ed_get ( */ if (ed->state == ED_IDLE) { u32 info; + __le32 hw_info; info = usb_pipedevice (pipe); info |= (ep >> 1) << 7; info |= usb_maxpacket (udev, pipe, is_out) << 16; - info = cpu_to_le32 (info); + hw_info = cpu_to_le32 (info); if (udev->speed == USB_SPEED_LOW) - info |= ED_LOWSPEED; + hw_info |= ED_LOWSPEED; /* only control transfers store pids in tds */ if (type != PIPE_CONTROL) { - info |= is_out ? ED_OUT : ED_IN; + hw_info |= is_out ? ED_OUT : ED_IN; if (type != PIPE_BULK) { /* periodic transfers... */ if (type == PIPE_ISOCHRONOUS) - info |= ED_ISO; + hw_info |= ED_ISO; else if (interval > 32) /* iso can be bigger */ interval = 32; ed->interval = interval; @@ -451,7 +452,7 @@ static struct ed *ed_get ( / 1000; } } - ed->hwINFO = info; + ed->hwINFO = hw_info; } done: @@ -751,12 +752,6 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = TD_CC_GET (tdINFO); - /* control endpoints only have soft stalls */ - if (type != PIPE_CONTROL && cc == TD_CC_STALL) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)); - /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) @@ -795,7 +790,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) struct urb *urb = td->urb; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; - u32 toggle = ed->hwHeadP & ED_C; + __le32 toggle = ed->hwHeadP & ED_C; /* clear ed halt; this is the td that caused it, but keep it inactive * until its urb->complete() has a chance to clean up. @@ -810,7 +805,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) */ while (tmp != &ed->td_list) { struct td *next; - u32 info; + __le32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -906,9 +901,6 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -/* wrap-aware logic stolen from */ -#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) - /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) @@ -919,7 +911,7 @@ rescan_all: for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) { struct list_head *entry, *tmp; int completed, modified; - u32 *prev; + __le32 *prev; /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs @@ -937,7 +929,7 @@ skip_ed: td = list_entry (ed->td_list.next, struct td, td_list); - head = cpu_to_le32 (ed->hwHeadP) & TD_MASK; + head = le32_to_cpu (ed->hwHeadP) & TD_MASK; /* INTR_WDH may need to clean up first */ if (td->td_dma != head) @@ -968,7 +960,7 @@ rescan_this: struct td *td; struct urb *urb; urb_priv_t *urb_priv; - u32 savebits; + __le32 savebits; td = list_entry (entry, struct td, td_list); urb = td->urb; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 5f0384417..19436cdd7 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -16,7 +16,7 @@ */ struct ed { /* first fields are hardware-specified, le32 */ - __u32 hwINFO; /* endpoint config bitmap */ + __le32 hwINFO; /* endpoint config bitmap */ /* info bits defined by hcd */ #define ED_DEQUEUE __constant_cpu_to_le32(1 << 27) /* info bits defined by the hardware */ @@ -25,11 +25,11 @@ struct ed { #define ED_LOWSPEED __constant_cpu_to_le32(1 << 13) #define ED_OUT __constant_cpu_to_le32(0x01 << 11) #define ED_IN __constant_cpu_to_le32(0x02 << 11) - __u32 hwTailP; /* tail of TD list */ - __u32 hwHeadP; /* head of TD list (hc r/w) */ + __le32 hwTailP; /* tail of TD list */ + __le32 hwHeadP; /* head of TD list (hc r/w) */ #define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ #define ED_H __constant_cpu_to_le32(0x01) /* halted */ - __u32 hwNextED; /* next ED in list */ + __le32 hwNextED; /* next ED in list */ /* rest are purely for the driver's use */ dma_addr_t dma; /* addr of ED */ @@ -71,7 +71,7 @@ struct ed { */ struct td { /* first fields are hardware-specified, le32 */ - __u32 hwINFO; /* transfer info bitmask */ + __le32 hwINFO; /* transfer info bitmask */ /* hwINFO bits for both general and iso tds: */ #define TD_CC 0xf0000000 /* condition code */ @@ -100,13 +100,13 @@ struct td { /* (no hwINFO #defines yet for iso tds) */ - __u32 hwCBP; /* Current Buffer Pointer (or 0) */ - __u32 hwNextTD; /* Next TD Pointer */ - __u32 hwBE; /* Memory Buffer End Pointer */ + __le32 hwCBP; /* Current Buffer Pointer (or 0) */ + __le32 hwNextTD; /* Next TD Pointer */ + __le32 hwBE; /* Memory Buffer End Pointer */ /* PSW is only for ISO */ #define MAXPSW 1 /* hardware allows 8 */ - __u16 hwPSW [MAXPSW]; + __le16 hwPSW [MAXPSW]; /* rest are purely for the driver's use */ __u8 index; @@ -171,16 +171,16 @@ static const int cc_to_error [16] = { */ struct ohci_hcca { #define NUM_INTS 32 - __u32 int_table [NUM_INTS]; /* periodic schedule */ + __le32 int_table [NUM_INTS]; /* periodic schedule */ /* * OHCI defines u16 frame_no, followed by u16 zero pad. * Since some processors can't do 16 bit bus accesses, * portable access must be a 32 bit byteswapped access. */ - u32 frame_no; /* current frame number */ + __le32 frame_no; /* current frame number */ #define OHCI_FRAME_NO(hccap) ((u16)le32_to_cpup(&(hccap)->frame_no)) - __u32 done_head; /* info returned for an interrupt */ + __le32 done_head; /* info returned for an interrupt */ u8 reserved_for_hc [116]; u8 what [4]; /* spec only identifies 252 bytes :) */ } __attribute__ ((aligned(256))); @@ -343,7 +343,7 @@ struct ohci_hcd { /* * I/O memory used to communicate with the HC (dma-consistent) */ - struct ohci_regs *regs; + struct ohci_regs __iomem *regs; /* * main memory used to communicate with the HC (dma-consistent). @@ -359,6 +359,13 @@ struct ohci_hcd { struct ed *ed_controltail; /* last in ctrl list */ struct ed *periodic [NUM_INTS]; /* shadow int_table */ + /* + * OTG controllers and transceivers need software interaction; + * other external transceivers should be software-transparent + */ + struct otg_transceiver *transceiver; + unsigned power_budget; + /* * memory management for queue data structures */ @@ -443,7 +450,7 @@ static inline unsigned int ohci_readl (void* regs) #else /* Standard version of ohci_readl uses standard, platform * specific implementation. */ -static inline unsigned int ohci_readl (void* regs) +static inline unsigned int ohci_readl (void __iomem * regs) { return readl (regs); } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index bf8ab3cd7..20a42f914 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -82,7 +82,7 @@ static int debug = 1; #else static int debug = 0; #endif -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level"); static char *errbuf; #define ERRBUF_LEN (32 * 1024) @@ -232,7 +232,7 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) /* * Inserts a td into qh list at the top. */ -static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth) +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth) { struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -376,7 +376,7 @@ static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; - u32 newlink; + __le32 newlink; unsigned int age; if (!qh) @@ -1120,10 +1120,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); - if (ret == -EPIPE) - /* endpoint has stalled - mark it halted */ - usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td))); err: /* @@ -1344,7 +1340,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) { - int ret = -EINVAL; + int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; struct urb *eurb; @@ -1352,7 +1348,8 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) spin_lock_irqsave(&uhci->schedule_lock, flags); - if (urb->status != -EINPROGRESS) /* URB already unlinked! */ + ret = urb->status; + if (ret != -EINPROGRESS) /* URB already unlinked! */ goto out; eurb = uhci_find_urb_ep(uhci, urb); @@ -1637,13 +1634,6 @@ static void stall_callback(unsigned long ptr) if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); - /* Check if the URB timed out */ - if (u->timeout && u->status == -EINPROGRESS && - time_after_eq(jiffies, up->inserttime + u->timeout)) { - u->status = -ETIMEDOUT; - list_move_tail(&up->urb_list, &list); - } - spin_unlock(&u->lock); } spin_unlock_irqrestore(&uhci->schedule_lock, flags); @@ -2258,7 +2248,8 @@ static int uhci_start(struct usb_hcd *hcd) irq = 7; /* Only place we don't use the frame list routines */ - uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle); + uhci->fl->frame[i] = UHCI_PTR_QH | + cpu_to_le32(uhci->skelqh[irq]->dma_handle); } /* diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index b4bf3b6ca..785c0c2cc 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -80,7 +80,7 @@ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ struct uhci_frame_list { - u32 frame[UHCI_NUMFRAMES]; + __le32 frame[UHCI_NUMFRAMES]; void *frame_cpu[UHCI_NUMFRAMES]; @@ -105,8 +105,8 @@ struct urb_priv; */ struct uhci_qh { /* Hardware fields */ - u32 link; /* Next queue */ - u32 element; /* Queue element pointer */ + __le32 link; /* Next queue */ + __le32 element; /* Queue element pointer */ /* Software fields */ dma_addr_t dma_handle; @@ -185,10 +185,10 @@ struct uhci_qh { */ struct uhci_td { /* Hardware fields */ - u32 link; - u32 status; - u32 token; - u32 buffer; + __le32 link; + __le32 status; + __le32 token; + __le32 buffer; /* Software fields */ dma_addr_t dma_handle; diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 2dde38163..22bbd7006 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -82,7 +82,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, */ case GetHubStatus: - *(__u32 *)buf = cpu_to_le32(0); + *(__le32 *)buf = cpu_to_le32(0); OK(4); /* hub power */ case GetPortStatus: if (!wIndex || wIndex > uhci->rh_numports) @@ -126,8 +126,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(uhci_dev(uhci), "port %d portsc %04x\n", wIndex, status); - *(__u16 *)buf = cpu_to_le16(wPortStatus); - *(__u16 *)(buf + 2) = cpu_to_le16(wPortChange); + *(__le16 *)buf = cpu_to_le16(wPortStatus); + *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); OK(4); case SetHubFeature: /* We don't implement these */ case ClearHubFeature: diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 230efaf7b..9d3aa3075 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -214,8 +214,8 @@ static struct usb_driver mts_usb_driver = { #ifdef MTS_DO_DEBUG static inline void mts_debug_dump(struct mts_desc* desc) { - MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n", - (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], + MTS_DEBUG("desc at 0x%x: toggle = %02x%02x\n", + (int)desc, (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] ); MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index b0261f8a6..44b8faee6 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -494,9 +494,9 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) } else { input_regs(inputdev, regs); - x = le16_to_cpu(get_unaligned((__u16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__u16 *) (data + 3))); - z = le16_to_cpu(get_unaligned((__u16 *) (data + 6))); + x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); + z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); p = (data[5] & 0x01) != 0 ? 1 : 0; dv = (data[5] & 0x02) != 0 ? 1 : 0; @@ -573,8 +573,8 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { input_regs(inputdev, regs); - x = le16_to_cpu(get_unaligned((__u16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__u16 *) (data + 3))); + x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); jitterable = data[5] & 0x1c; @@ -632,7 +632,7 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; macro = data[3]; - z = le16_to_cpu(get_unaligned((__u16 *) (data + 4))); + z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); if (dv != 0) { input_regs(inputdev, regs); @@ -729,7 +729,7 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) * hat switches (which just so happen to be the macroKeys.) */ else if (data[0] == 6) { - macro = le16_to_cpu(get_unaligned((__u16 *) (data + 1))); + macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); input_regs(inputdev, regs); if (macro > 0) { @@ -930,7 +930,7 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data) buf[0], buf[1], buf[2]); ret = -EIO; } else { - ret = le16_to_cpu(get_unaligned((__u16 *) (buf + 1))); + ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); } kfree(buf); return ret; @@ -2289,9 +2289,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(programmableDelay, "i"); +module_param(programmableDelay, int, 0); MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming"); -MODULE_PARM(jitterDelay, "i"); +module_param(jitterDelay, int, 0); MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay"); module_init(aiptek_init); diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index c1f1c1d20..61a42bdae 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/input/hid-core.c b/drivers/usb/input/hid-core.c index 79082d918..35baacd77 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -219,17 +219,13 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); return -1; } - usages = parser->local.usage_index; + + if (!(usages = max_t(int, parser->local.usage_index, parser->global.report_count))) + return 0; /* Ignore padding fields */ offset = report->size; report->size += parser->global.report_size * parser->global.report_count; - if (usages < parser->global.report_count) - usages = parser->global.report_count; - - if (usages == 0) - return 0; /* ignore padding fields */ - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) return 0; @@ -609,16 +605,16 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) case 2: if ((end - start) < 2) return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__u16*)start)); - start = (__u8 *)((__u16 *)start + 1); + item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); + start = (__u8 *)((__le16 *)start + 1); return start; case 3: item->size++; if ((end - start) < 4) return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__u32*)start)); - start = (__u8 *)((__u32 *)start + 1); + item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); + start = (__u8 *)((__le32 *)start + 1); return start; } @@ -760,15 +756,15 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1); + return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1 << n) - 1); } static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) { report += (offset >> 5) << 2; offset &= 31; - put_unaligned((get_unaligned((__u64*)report) + put_unaligned((get_unaligned((__le64*)report) & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) - | cpu_to_le64((__u64)value << offset), (__u64*)report); + | cpu_to_le64((__u64)value << offset), (__le64*)report); } /* @@ -923,20 +919,22 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) int status; switch (urb->status) { - case 0: /* success */ - hid_input_report(HID_INPUT_REPORT, urb, regs); - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dbg("nonzero status in input irq %d", urb->status); + case 0: /* success */ + hid_input_report(HID_INPUT_REPORT, urb, regs); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + return; + case -ETIMEDOUT: /* NAK */ + break; + default: /* error */ + warn("input irq status %d received", urb->status); } - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, SLAB_ATOMIC); if (status) - err ("can't resubmit intr, %s-%s/input%d, status %d", + err("can't resubmit intr, %s-%s/input%d, status %d", hid->dev->bus->bus_name, hid->dev->devpath, hid->ifnum, status); } @@ -1137,23 +1135,31 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) struct hid_device *hid = urb->context; unsigned long flags; - if (urb->status) - warn("output irq status %d received", urb->status); + switch (urb->status) { + case 0: /* success */ + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + break; + default: /* error */ + warn("output irq status %d received", urb->status); + } spin_lock_irqsave(&hid->outlock, flags); hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); if (hid->outhead != hid->outtail) { - hid_submit_out(hid); + if (hid_submit_out(hid)) { + clear_bit(HID_OUT_RUNNING, &hid->iofl);; + wake_up(&hid->wait); + } spin_unlock_irqrestore(&hid->outlock, flags); return; } clear_bit(HID_OUT_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); - wake_up(&hid->wait); } @@ -1166,26 +1172,34 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) struct hid_device *hid = urb->context; unsigned long flags; - if (urb->status) - warn("ctrl urb status %d received", urb->status); - spin_lock_irqsave(&hid->ctrllock, flags); - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + switch (urb->status) { + case 0: /* success */ + if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + case -EPIPE: /* report not available */ + break; + default: /* error */ + warn("ctrl urb status %d received", urb->status); + } hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->ctrlhead != hid->ctrltail) { - hid_submit_ctrl(hid); + if (hid_submit_ctrl(hid)) { + clear_bit(HID_CTRL_RUNNING, &hid->iofl); + wake_up(&hid->wait); + } spin_unlock_irqrestore(&hid->ctrllock, flags); return; } clear_bit(HID_CTRL_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); - wake_up(&hid->wait); } @@ -1211,7 +1225,8 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign hid->outhead = head; if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) - hid_submit_out(hid); + if (hid_submit_out(hid)) + clear_bit(HID_OUT_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->outlock, flags); return; @@ -1230,7 +1245,8 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign hid->ctrlhead = head; if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) - hid_submit_ctrl(hid); + if (hid_submit_ctrl(hid)) + clear_bit(HID_CTRL_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->ctrllock, flags); } @@ -1282,7 +1298,7 @@ int hid_open(struct hid_device *hid) void hid_close(struct hid_device *hid) { if (!--hid->open) - usb_unlink_urb(hid->urbin); + usb_kill_urb(hid->urbin); } /* @@ -1439,6 +1455,11 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 +#define USB_VENDOR_ID_CODEMERCS 0x07c0 +#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 + + static struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1453,20 +1474,20 @@ static struct hid_blacklist { { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, @@ -1619,11 +1640,17 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) struct usb_endpoint_descriptor *endpoint; int pipe; + int interval; endpoint = &interface->endpoint[n].desc; if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ continue; + /* handle potential highspeed HID correctly */ + interval = endpoint->bInterval; + if (dev->speed == USB_SPEED_HIGH) + interval = 1 << (interval - 1); + if (endpoint->bEndpointAddress & USB_DIR_IN) { int len; @@ -1636,9 +1663,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (len > HID_BUFFER_SIZE) len = HID_BUFFER_SIZE; usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, - hid_irq_in, hid, endpoint->bInterval); + hid_irq_in, hid, interval); hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } else { if (hid->urbout) continue; @@ -1646,9 +1673,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) goto fail; pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, - hid_irq_out, hid, 1); + hid_irq_out, hid, interval); hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + hid->urbout->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } } @@ -1698,8 +1725,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); + hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_ASYNC_UNLINK); return hid; @@ -1725,9 +1751,9 @@ static void hid_disconnect(struct usb_interface *intf) return; usb_set_intfdata(intf, NULL); - usb_unlink_urb(hid->urbin); - usb_unlink_urb(hid->urbout); - usb_unlink_urb(hid->urbctrl); + usb_kill_urb(hid->urbin); + usb_kill_urb(hid->urbout); + usb_kill_urb(hid->urbctrl); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); @@ -1835,8 +1861,8 @@ hiddev_init_fail: static void __exit hid_exit(void) { - hiddev_exit(); usb_deregister(&hid_driver); + hiddev_exit(); } module_init(hid_init); diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index ff319d9ad..44e466d19 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -223,16 +223,6 @@ static int hiddev_fasync(int fd, struct file *file, int on) return retval < 0 ? retval : 0; } -/* - * De-allocate a hiddev structure - */ -static struct usb_class_driver hiddev_class; -static void hiddev_cleanup(struct hiddev *hiddev) -{ - hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); - kfree(hiddev); -} /* * release file op @@ -253,7 +243,7 @@ static int hiddev_release(struct inode * inode, struct file * file) if (list->hiddev->exist) hid_close(list->hiddev->hid); else - hiddev_cleanup(list->hiddev); + kfree(list->hiddev); } kfree(list); @@ -636,16 +626,19 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd goto inval; field = report->field[uref->field_index]; - if (uref->usage_index >= field->maxusage) - goto inval; - if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi->num_values >= HID_MAX_USAGES || - uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi->num_values) >= field->maxusage) + if (cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref->usage_index >= field->maxusage) goto inval; + } else if (uref->usage_index >= field->report_count) + goto inval; + + else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && + (uref_multi->num_values >= HID_MAX_MULTI_USAGES || + uref->usage_index + uref_multi->num_values >= field->report_count || + uref->usage_index + uref_multi->num_values < uref->usage_index)) + goto inval; } - } switch (cmd) { case HIDIOCGUSAGE: @@ -795,17 +788,21 @@ int hiddev_connect(struct hid_device *hid) * This is where hid.c calls us to disconnect a hiddev device from the * corresponding hid device (usually because the usb device has disconnected) */ +static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; hiddev->exist = 0; + hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; + usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + if (hiddev->open) { hid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { - hiddev_cleanup(hiddev); + kfree(hiddev); } } diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index 43af4031f..39c0d38ae 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -26,10 +26,9 @@ MODULE_LICENSE(DRIVER_LICENSE); #define USB_VENDOR_ID_KBGEAR 0x084e -static int kb_pressure_click = 0x10; -MODULE_PARM (kb_pressure_click,"i"); -MODULE_PARM_DESC(kb_pressure_click, - "pressure threshold for clicks"); +static int kb_pressure_click = 0x10; +module_param(kb_pressure_click, int, 0); +MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); struct kbtab { signed char *data; @@ -67,8 +66,8 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - kbtab->x = le16_to_cpu(get_unaligned((u16 *) &data[1])); - kbtab->y = le16_to_cpu(get_unaligned((u16 *) &data[3])); + kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1])); + kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3])); kbtab->pressure = (data[5]); diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index c66001351..492a5cb12 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -285,8 +285,8 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); input_report_key(dev, BTN_TOOL_PEN, 1); - input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((u16 *) &data[1]))); - input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((u16 *) &data[3]))); + input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((__le16 *) &data[1]))); + input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((__le16 *) &data[3]))); input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127); input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); input_report_key(dev, BTN_STYLUS, (data[5] & 0x40)); @@ -329,8 +329,8 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) if (data[0] != 2) dbg("wacom_graphire_irq: received unknown report #%d", data[0]); - x = le16_to_cpu(*(u16 *) &data[2]); - y = le16_to_cpu(*(u16 *) &data[4]); + x = le16_to_cpu(*(__le16 *) &data[2]); + y = le16_to_cpu(*(__le16 *) &data[4]); input_regs(dev, regs); @@ -367,7 +367,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) input_report_abs(dev, ABS_Y, y); } - input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(u16 *) &data[6])); + input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); input_report_key(dev, BTN_STYLUS, data[1] & 0x02); input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); @@ -456,8 +456,8 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - input_report_abs(dev, ABS_X, be16_to_cpu(*(u16 *) &data[2])); - input_report_abs(dev, ABS_Y, be16_to_cpu(*(u16 *) &data[4])); + input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2])); + input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4])); input_report_abs(dev, ABS_DISTANCE, data[9]); if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig index 6dac4dc14..4ac7ac4f3 100644 --- a/drivers/usb/media/Kconfig +++ b/drivers/usb/media/Kconfig @@ -106,46 +106,6 @@ config USB_OV511 To compile this driver as a module, choose M here: the module will be called ov511. -config USB_PWC - tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV - ---help--- - Say Y or M here if you want to use one of these Philips & OEM - webcams: - * Philips PCA645, PCA646 - * Philips PCVC675, PCVC680, PCVC690 - * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 - * Askey VC010 - * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' - and 'Orbit'/'Sphere' - * Samsung MPC-C10, MPC-C30 - * Creative Webcam 5, Pro Ex - * SOTEC Afina Eye - * Visionite VCS-UC300, VCS-UM100 - - The PCA635, PCVC665 and PCVC720/20 are not supported by this driver - and never will be, but the 665 and 720/20 are supported by other - drivers. - - This driver has an optional plugin (called PWCX), which is - distributed as a binary module only. It contains code that allow you - to use higher resolutions and framerates but may not be distributed - as source. But even without this plugin you can these cams for most - applications. - - See for more information and - installation instructions. - - The built-in microphone is enabled by selecting USB Audio support. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Character Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called pwc. - config USB_SE401 tristate "USB SE401 Camera support" depends on USB && VIDEO_DEV @@ -163,11 +123,11 @@ config USB_SE401 module will be called se401. config USB_SN9C102 - tristate "USB SN9C10[12] PC Camera Controller support (EXPERIMENTAL)" - depends on USB && VIDEO_DEV && EXPERIMENTAL + tristate "USB SN9C10[12] PC Camera Controller support" + depends on USB && VIDEO_DEV ---help--- - Say Y here if you want support for cameras based on SN9C101 and - SN9C102 PC Camera Controllers. + Say Y here if you want support for cameras based on SONiX SN9C101 + or SN9C102 PC Camera Controllers. See for more informations. diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index 059764cd4..9f0a31eb6 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -2,15 +2,13 @@ # Makefile for USB Media drivers # -pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o -sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o sn9c102_pas202bcb.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o obj-$(CONFIG_USB_OV511) += ov511.o -obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_SN9C102) += sn9c102.o obj-$(CONFIG_USB_STV680) += stv680.o diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index 01f77cbc4..0e5425f32 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -61,7 +61,7 @@ static dabusb_t dabusb[NRDABUSB]; static int buffers = 256; -extern struct usb_driver dabusb_driver; +static struct usb_driver dabusb_driver; /*-------------------------------------------------------------------*/ @@ -868,7 +868,7 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM (buffers, "i"); +module_param(buffers, int, 0); MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); module_init (dabusb_init); diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c index f6b18a218..7503f5b96 100644 --- a/drivers/usb/media/dsbr100.c +++ b/drivers/usb/media/dsbr100.c @@ -107,7 +107,7 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file); static int usb_dsbr100_close(struct inode *inode, struct file *file); static int radio_nr = -1; -MODULE_PARM(radio_nr, "i"); +module_param(radio_nr, int, 0); /* Data for one (physical) device */ typedef struct { diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c index 2740aeb0f..277d65b38 100644 --- a/drivers/usb/media/ibmcam.c +++ b/drivers/usb/media/ibmcam.c @@ -124,38 +124,38 @@ static int init_model2_yb = -1; /* Settings for camera model 3 */ static int init_model3_input = 0; -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -MODULE_PARM(flags, "i"); +module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); -MODULE_PARM(framerate, "i"); +module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -MODULE_PARM(lighting, "i"); +module_param(lighting, int, 0); MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); -MODULE_PARM(sharpness, "i"); +module_param(sharpness, int, 0); MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); -MODULE_PARM(size, "i"); +module_param(size, int, 0); MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); -MODULE_PARM(init_brightness, "i"); +module_param(init_brightness, int, 0); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_contrast, "i"); +module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -MODULE_PARM(init_color, "i"); +module_param(init_color, int, 0); MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_hue, "i"); +module_param(init_hue, int, 0); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -MODULE_PARM(hue_correction, "i"); +module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); -MODULE_PARM(init_model2_rg2, "i"); +module_param(init_model2_rg2, int, 0); MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); -MODULE_PARM(init_model2_sat, "i"); +module_param(init_model2_sat, int, 0); MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)"); -MODULE_PARM(init_model2_yb, "i"); +module_param(init_model2_yb, int, 0); MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); /* 01.01.08 - Added for RCA video in support -LO */ -MODULE_PARM(init_model3_input, "i"); +module_param(init_model3_input, int, 0); MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); MODULE_AUTHOR ("Dmitri"); diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c index 5fc52c5d3..3376654ca 100644 --- a/drivers/usb/media/konicawc.c +++ b/drivers/usb/media/konicawc.c @@ -68,7 +68,7 @@ static const int debug = 0; /* Some default values for initial camera settings, can be set by modprobe */ -static enum frame_sizes size; +static int size; static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ static int brightness = MAX_BRIGHTNESS/2; static int contrast = MAX_CONTRAST/2; @@ -362,8 +362,8 @@ static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs) else if (!urb->status && !cam->last_data_urb->status) len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); - resubmit_urb(uvd, urb); resubmit_urb(uvd, cam->last_data_urb); + resubmit_urb(uvd, urb); cam->last_data_urb = NULL; uvd->stats.urb_length = len; uvd->stats.data_count += len; @@ -928,23 +928,23 @@ MODULE_DEVICE_TABLE(usb, id_table); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Simon Evans "); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_PARM(speed, "i"); +module_param(speed, int, 0); MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); -MODULE_PARM(size, "i"); +module_param(size, int, 0); MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); -MODULE_PARM(brightness, "i"); +module_param(brightness, int, 0); MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); -MODULE_PARM(contrast, "i"); +module_param(contrast, int, 0); MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); -MODULE_PARM(saturation, "i"); +module_param(saturation, int, 0); MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); -MODULE_PARM(sharpness, "i"); +module_param(sharpness, int, 0); MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); -MODULE_PARM(whitebal, "i"); +module_param(whitebal, int, 0); MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); #ifdef CONFIG_USB_DEBUG -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); #endif diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index 529a2de54..d040c8e30 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -119,78 +119,79 @@ static int remove_zeros; static int mirror; static int ov518_color; -MODULE_PARM(autobright, "i"); +module_param(autobright, int, 0); MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); -MODULE_PARM(autogain, "i"); +module_param(autogain, int, 0); MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); -MODULE_PARM(autoexp, "i"); +module_param(autoexp, int, 0); MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); -MODULE_PARM(snapshot, "i"); +module_param(snapshot, int, 0); MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); -MODULE_PARM(cams, "i"); +module_param(cams, int, 0); MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); -MODULE_PARM(compress, "i"); +module_param(compress, int, 0); MODULE_PARM_DESC(compress, "Turn on compression"); -MODULE_PARM(testpat, "i"); +module_param(testpat, int, 0); MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)"); -MODULE_PARM(dumppix, "i"); +module_param(dumppix, int, 0); MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); -MODULE_PARM(led, "i"); +module_param(led, int, 0); MODULE_PARM_DESC(led, "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); -MODULE_PARM(dump_bridge, "i"); +module_param(dump_bridge, int, 0); MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); -MODULE_PARM(dump_sensor, "i"); +module_param(dump_sensor, int, 0); MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); -MODULE_PARM(printph, "i"); +module_param(printph, int, 0); MODULE_PARM_DESC(printph, "Print frame start/end headers"); -MODULE_PARM(phy, "i"); +module_param(phy, int, 0); MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); -MODULE_PARM(phuv, "i"); +module_param(phuv, int, 0); MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); -MODULE_PARM(pvy, "i"); +module_param(pvy, int, 0); MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); -MODULE_PARM(pvuv, "i"); +module_param(pvuv, int, 0); MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); -MODULE_PARM(qhy, "i"); +module_param(qhy, int, 0); MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); -MODULE_PARM(qhuv, "i"); +module_param(qhuv, int, 0); MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); -MODULE_PARM(qvy, "i"); +module_param(qvy, int, 0); MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); -MODULE_PARM(qvuv, "i"); +module_param(qvuv, int, 0); MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); -MODULE_PARM(lightfreq, "i"); +module_param(lightfreq, int, 0); MODULE_PARM_DESC(lightfreq, "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); -MODULE_PARM(bandingfilter, "i"); +module_param(bandingfilter, int, 0); MODULE_PARM_DESC(bandingfilter, "Enable banding filter (to reduce effects of fluorescent lighting)"); -MODULE_PARM(clockdiv, "i"); +module_param(clockdiv, int, 0); MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); -MODULE_PARM(packetsize, "i"); +module_param(packetsize, int, 0); MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); -MODULE_PARM(framedrop, "i"); +module_param(framedrop, int, 0); MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); -MODULE_PARM(fastset, "i"); +module_param(fastset, int, 0); MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); -MODULE_PARM(force_palette, "i"); +module_param(force_palette, int, 0); MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); -MODULE_PARM(backlight, "i"); +module_param(backlight, int, 0); MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); -MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i"); +static int num_uv; +module_param_array(unit_video, int, num_uv, 0); MODULE_PARM_DESC(unit_video, "Force use of specific minor number(s). 0 is not allowed."); -MODULE_PARM(remove_zeros, "i"); +module_param(remove_zeros, int, 0); MODULE_PARM_DESC(remove_zeros, "Remove zero-padding from uncompressed incoming data"); -MODULE_PARM(mirror, "i"); +module_param(mirror, int, 0); MODULE_PARM_DESC(mirror, "Reverse image horizontally"); -MODULE_PARM(ov518_color, "i"); +module_param(ov518_color, int, 0); MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -472,7 +473,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) down(&ov->cbuf_lock); - *((u32 *)ov->cbuf) = __cpu_to_le32(val); + *((__le32 *)ov->cbuf) = __cpu_to_le32(val); rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), @@ -1169,7 +1170,7 @@ init_ov_sensor(struct usb_ov511 *ov) return -EIO; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && @@ -1182,7 +1183,7 @@ init_ov_sensor(struct usb_ov511 *ov) if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); /* Dummy read to sync I2C */ if (i2c_r(ov, 0x00) < 0) return -EIO; @@ -4947,7 +4948,7 @@ ov7xx0_configure(struct usb_ov511 *ov) return -1; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); i = 0; success = 0; diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c index 260bbd98b..c694caaac 100644 --- a/drivers/usb/media/se401.c +++ b/drivers/usb/media/se401.c @@ -53,9 +53,9 @@ MODULE_DEVICE_TABLE(usb, device_table); MODULE_AUTHOR("Jeroen Vreeken "); MODULE_DESCRIPTION("SE401 USB Camera Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(flickerless, "i"); +module_param(flickerless, int, 0); MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); -MODULE_PARM(video_nr, "i"); +module_param(video_nr, int, 0); static struct usb_driver se401_driver; diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h index fc9cb47e6..62ff21443 100644 --- a/drivers/usb/media/sn9c102.h +++ b/drivers/usb/media/sn9c102.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "sn9c102_sensor.h" @@ -39,6 +40,7 @@ #define SN9C102_DEBUG #define SN9C102_DEBUG_LEVEL 2 #define SN9C102_MAX_DEVICES 64 +#define SN9C102_PRESERVE_IMGSCALE 0 #define SN9C102_MAX_FRAMES 32 #define SN9C102_URBS 2 #define SN9C102_ISO_PACKETS 7 @@ -51,8 +53,8 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.01-beta" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) +#define SN9C102_MODULE_VERSION "1:1.08" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 8) SN9C102_ID_TABLE; SN9C102_SENSOR_TABLE; diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index bcd9fbd3b..9f775f740 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +84,7 @@ MODULE_PARM_DESC(debug, /*****************************************************************************/ -typedef char sn9c102_sof_header_t[7]; +typedef char sn9c102_sof_header_t[12]; typedef char sn9c102_eof_header_t[4]; static sn9c102_sof_header_t sn9c102_sof_header[] = { @@ -91,8 +92,6 @@ static sn9c102_sof_header_t sn9c102_sof_header[] = { {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, }; -/* Number of random bytes that complete the SOF above headers */ -#define SN9C102_SOFLEN 5 static sn9c102_eof_header_t sn9c102_eof_header[] = { {0x00, 0x00, 0x00, 0x00}, @@ -237,9 +236,6 @@ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) u8* buff = cam->control_buffer; int res; - if (index == 0x18) - value = (value & 0xcf) | (cam->reg[0x18] & 0x30); - *buff = value; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, @@ -443,14 +439,15 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) static void* sn9c102_find_sof_header(void* mem, size_t len) { - size_t soflen=sizeof(sn9c102_sof_header_t), SOFLEN=SN9C102_SOFLEN, i; + size_t soflen = sizeof(sn9c102_sof_header_t), i; u8 j, n = sizeof(sn9c102_sof_header) / soflen; - for (i = 0; (len >= soflen+SOFLEN) && (i <= len-soflen-SOFLEN); i++) + for (i = 0; (len >= soflen) && (i <= len - soflen); i++) for (j = 0; j < n; j++) - if (!memcmp(mem + i, sn9c102_sof_header[j], soflen)) + /* It's enough to compare 7 bytes */ + if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) /* Skips the header */ - return mem + i + soflen + SOFLEN; + return mem + i + soflen; return NULL; } @@ -517,10 +514,12 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) PDBGG("Isochrnous frame: length %u, #%u i", len, i) - /* NOTE: It is probably correct to assume that SOF and EOF + /* + NOTE: It is probably correct to assume that SOF and EOF headers do not occur between two consecutive packets, but who knows..Whatever is the truth, this assumption - doesn't introduce bugs. */ + doesn't introduce bugs. + */ redo: sof = sn9c102_find_sof_header(pos, len); @@ -764,9 +763,11 @@ static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) return (u8)val; } -/* NOTE 1: being inside one of the following methods implies that the v4l +/* + NOTE 1: being inside one of the following methods implies that the v4l device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long */ + NOTE 2: buffers are PAGE_SIZE long +*/ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) { @@ -1018,24 +1019,6 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t -sn9c102_store_redblue(struct class_device* cd, const char* buf, size_t len) -{ - ssize_t res = 0; - u8 value; - ssize_t count; - - value = sn9c102_strtou8(buf, len, &count); - if (!count) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, "0x10", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - - return res; -} - - static ssize_t sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) { @@ -1062,7 +1045,6 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(redblue, S_IWUGO, NULL, sn9c102_store_redblue); static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); @@ -1072,7 +1054,6 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam) video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_redblue); video_device_create_file(v4ldev, &class_device_attr_green); if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); @@ -1118,10 +1099,6 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) ae_endy = v_size / 2; int err = 0; - /* These are a sort of stroboscopic signal for some sensors */ - err += sn9c102_write_reg(cam, h_size, 0x1a); - err += sn9c102_write_reg(cam, v_size, 0x1b); - err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); err += sn9c102_write_reg(cam, h_size, 0x15); @@ -1134,8 +1111,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) return -EIO; PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " - "%u %u %u %u %u %u", h_start, v_start, h_size, v_size, ho_size, - vo_size) + "%u %u %u %u", h_start, v_start, h_size, v_size) return 0; } @@ -1229,7 +1205,10 @@ static int sn9c102_open(struct inode* inode, struct file* filp) struct sn9c102_device* cam; int err = 0; - /* This the only safe way to prevent race conditions with disconnect */ + /* + This is the only safe way to prevent race conditions with + disconnect + */ if (!down_read_trylock(&sn9c102_disconnect)) return -ERESTARTSYS; @@ -1727,6 +1706,12 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, return -EINVAL; } + /* Preserve R,G or B origin */ + rect->left = (s->_rect.left & 1L) ? + rect->left | 1L : rect->left & ~1L; + rect->top = (s->_rect.top & 1L) ? + rect->top | 1L : rect->top & ~1L; + if (rect->width < 16) rect->width = 16; if (rect->height < 16) @@ -1747,13 +1732,15 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, rect->width &= ~15L; rect->height &= ~15L; - { /* calculate the scaling factor */ + if (SN9C102_PRESERVE_IMGSCALE) { + /* Calculate the actual scaling factor */ u32 a, b; a = rect->width * rect->height; b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : - ((a / b) > 4 ? 4 : (a / b)))) : 1; - } + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; + } else + scale = 1; if (cam->stream == STREAM_ON) { cam->stream = STREAM_INTERRUPT; @@ -1879,12 +1866,12 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, memcpy(&rect, &(s->_rect), sizeof(rect)); - { /* calculate the scaling factor */ + { /* calculate the actual scaling factor */ u32 a, b; a = rect.width * rect.height; b = pix->width * pix->height; - scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : - ((a / b) > 4 ? 4 : (a / b)))) : 1; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; } rect.width = scale * pix->width; @@ -1895,13 +1882,21 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, if (rect.height < 16) rect.height = 16; if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left+bounds->width - rect.left; + rect.width = bounds->left + bounds->width - rect.left; if (rect.height > bounds->top + bounds->height - rect.top) rect.height = bounds->top + bounds->height - rect.top; rect.width &= ~15L; rect.height &= ~15L; + { /* adjust the scaling factor */ + u32 a, b; + a = rect.width * rect.height; + b = pix->width * pix->height; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; + } + pix->width = rect.width / scale; pix->height = rect.height / scale; @@ -2119,7 +2114,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, spin_lock_irqsave(&cam->queue_lock, lock_flags); f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); - list_del(&cam->outqueue); + list_del(cam->outqueue.next); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); f->state = F_UNUSED; diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c index 34bdfcf8e..a302a4845 100644 --- a/drivers/usb/media/sn9c102_pas106b.c +++ b/drivers/usb/media/sn9c102_pas106b.c @@ -40,13 +40,12 @@ static int pas106b_init(struct sn9c102_device* cam) err += sn9c102_i2c_write(cam, 0x02, 0x0c); err += sn9c102_i2c_write(cam, 0x03, 0x12); err += sn9c102_i2c_write(cam, 0x04, 0x05); - err += sn9c102_i2c_write(cam, 0x05, 0x22); - err += sn9c102_i2c_write(cam, 0x06, 0xac); - err += sn9c102_i2c_write(cam, 0x07, 0x00); + err += sn9c102_i2c_write(cam, 0x05, 0x5a); + err += sn9c102_i2c_write(cam, 0x06, 0x88); + err += sn9c102_i2c_write(cam, 0x07, 0x80); err += sn9c102_i2c_write(cam, 0x08, 0x01); - err += sn9c102_i2c_write(cam, 0x0a, 0x00); + err += sn9c102_i2c_write(cam, 0x0a, 0x01); err += sn9c102_i2c_write(cam, 0x0b, 0x00); - err += sn9c102_i2c_write(cam, 0x0d, 0x00); err += sn9c102_i2c_write(cam, 0x10, 0x06); err += sn9c102_i2c_write(cam, 0x11, 0x06); err += sn9c102_i2c_write(cam, 0x12, 0x00); @@ -64,11 +63,30 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam, { switch (ctrl->id) { case V4L2_CID_RED_BALANCE: - return (ctrl->value = sn9c102_i2c_read(cam, 0x0c))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; case V4L2_CID_BLUE_BALANCE: - return (ctrl->value = sn9c102_i2c_read(cam, 0x09))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; case V4L2_CID_BRIGHTNESS: - return (ctrl->value = sn9c102_i2c_read(cam, 0x0e))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_CONTRAST: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) + return -EIO; + ctrl->value &= 0x07; + return 0; default: return -EINVAL; } @@ -87,9 +105,15 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam, case V4L2_CID_BLUE_BALANCE: err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f); break; - case V4L2_CID_BRIGHTNESS: + case V4L2_CID_GAIN: err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f); break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x0d, 0x1f-(ctrl->value & 0x1f)); + break; + case V4L2_CID_CONTRAST: + err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03); + break; default: return -EINVAL; } @@ -130,7 +154,7 @@ static struct sn9c102_sensor pas106b = { .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x03, + .default_value = 0x04, .flags = 0, }, { @@ -140,7 +164,17 @@ static struct sn9c102_sensor pas106b = { .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x02, + .default_value = 0x06, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0d, .flags = 0, }, { @@ -150,7 +184,17 @@ static struct sn9c102_sensor pas106b = { .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x06, + .default_value = 0x1f, + .flags = 0, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0x00, + .maximum = 0x07, + .step = 0x01, + .default_value = 0x00, /* 0x00~0x03 have same effect */ .flags = 0, }, }, @@ -185,11 +229,13 @@ int sn9c102_probe_pas106b(struct sn9c102_device* cam) int r0 = 0, r1 = 0, err = 0; unsigned int pid = 0; - /* Minimal initialization to enable the I2C communication - NOTE: do NOT change the values! */ + /* + Minimal initialization to enable the I2C communication + NOTE: do NOT change the values! + */ err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ - err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 48 MHz */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ if (err) return -EIO; diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c new file mode 100644 index 000000000..26944eaf8 --- /dev/null +++ b/drivers/usb/media/sn9c102_pas202bcb.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera * + * Controllers * + * * + * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * + * * + * http://cadu.homelinux.com:8080/ * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor pas202bcb; + + +static int pas202bcb_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x20, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); + + err += sn9c102_i2c_write(cam, 0x02, 0x0c); + err += sn9c102_i2c_write(cam, 0x03, 0x40); + err += sn9c102_i2c_write(cam, 0x04, 0x07); + err += sn9c102_i2c_write(cam, 0x05, 0x25); + err += sn9c102_i2c_write(cam, 0x0d, 0x2c); + err += sn9c102_i2c_write(cam, 0x0e, 0x01); + err += sn9c102_i2c_write(cam, 0x0f, 0xa9); + err += sn9c102_i2c_write(cam, 0x08, 0x01); + err += sn9c102_i2c_write(cam, 0x0b, 0x01); + err += sn9c102_i2c_write(cam, 0x13, 0x63); + err += sn9c102_i2c_write(cam, 0x15, 0x70); + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + msleep(400); + + return err; +} + + +static int pas202bcb_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_BLUE_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_BRIGHTNESS: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + default: + return -EINVAL; + } +} + + +static int pas202bcb_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f)); + break; + default: + return -EINVAL; + } + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + return err; +} + + +static int pas202bcb_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &pas202bcb; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor pas202bcb = { + .name = "PAS202BCB", + .maintainer = "Carlos Eduardo Medaglia Dyonisio " + "", + .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .slave_read_id = 0x40, + .slave_write_id = 0x40, + .init = &pas202bcb_init, + .qctrl = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x05, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0c, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x0f, + .flags = 0, + }, + }, + .get_ctrl = &pas202bcb_get_ctrl, + .set_ctrl = &pas202bcb_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &pas202bcb_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + } +}; + + +int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) +{ + int r0 = 0, r1 = 0, err = 0; + unsigned int pid = 0; + + /* + * Minimal initialization to enable the I2C communication + * NOTE: do NOT change the values! + */ + err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ + err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ + if (err) + return -EIO; + + r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); + r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); + + if (r0 < 0 || r1 < 0) + return -EIO; + + pid = (r0 << 4) | ((r1 & 0xf0) >> 4); + if (pid != 0x017) + return -ENODEV; + + sn9c102_attach_sensor(cam, &pas202bcb); + + return 0; +} diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h index 54a3499b5..3e7e4a257 100644 --- a/drivers/usb/media/sn9c102_sensor.h +++ b/drivers/usb/media/sn9c102_sensor.h @@ -33,7 +33,8 @@ struct sn9c102_sensor; /*****************************************************************************/ -/* OVERVIEW. +/* + OVERVIEW. This is a small interface that allows you to add support for any CCD/CMOS image sensors connected to the SN9C10X bridges. The entire API is documented below. In the most general case, to support a sensor there are three steps @@ -48,26 +49,33 @@ struct sn9c102_sensor; "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do NOT need to touch the source code of the core module for the things to work properly, unless you find bugs or flaws in it. Finally, do not forget to - read the V4L2 API for completeness. */ + read the V4L2 API for completeness. +*/ /*****************************************************************************/ - -/* Probing functions: on success, you must attach the sensor to the camera + +/* + Probing functions: on success, you must attach the sensor to the camera by calling sn9c102_attach_sensor() provided below. To enable the I2C communication, you might need to perform a really basic initialization of the SN9C10X chip by using the write function declared ahead. - Functions must return 0 on success, the appropriate error otherwise. */ + Functions must return 0 on success, the appropriate error otherwise. +*/ extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); +extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); -/* Add the above entries to this table. Be sure to add the entry in the right +/* + Add the above entries to this table. Be sure to add the entry in the right place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom */ + the order of the list below, from top to bottom. +*/ #define SN9C102_SENSOR_TABLE \ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR vid/pid */\ + &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ @@ -81,28 +89,29 @@ sn9c102_attach_sensor(struct sn9c102_device* cam, /* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/ #define SN9C102_ID_TABLE \ static const struct usb_device_id sn9c102_id_table[] = { \ - { USB_DEVICE(0xc45, 0x6001), }, \ + { USB_DEVICE(0xc45, 0x6001), }, /* TAS5110C1B */ \ { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */ \ { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */ \ { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */ \ { USB_DEVICE(0xc45, 0x6024), }, \ - { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B Maybe also TAS5110C1B */\ - { USB_DEVICE(0xc45, 0x6028), }, /* Maybe PAS202B */ \ - { USB_DEVICE(0xc45, 0x6029), }, \ - { USB_DEVICE(0xc45, 0x602a), }, /* Maybe HV7131[D|E1] */ \ - { USB_DEVICE(0xc45, 0x602c), }, /* Maybe OV7620 */ \ - { USB_DEVICE(0xc45, 0x6030), }, /* Maybe MI03 */ \ - { USB_DEVICE(0xc45, 0x8001), }, \ + { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ + { USB_DEVICE(0xc45, 0x6028), }, /* PAS202BCB */ \ + { USB_DEVICE(0xc45, 0x6029), }, /* PAS106B */ \ + { USB_DEVICE(0xc45, 0x602a), }, /* HV7131[D|E1] */ \ + { USB_DEVICE(0xc45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0xc45, 0x6030), }, /* MI03 */ \ { } \ }; /*****************************************************************************/ -/* Read/write routines: they always return -1 on error, 0 or the read value +/* + Read/write routines: they always return -1 on error, 0 or the read value otherwise. NOTE that a real read operation is not supported by the SN9C10X chip for some of its registers. To work around this problem, a pseudo-read call is provided instead: it returns the last successfully written value - on the register (0 if it has never been written), the usual -1 on error. */ + on the register (0 if it has never been written), the usual -1 on error. +*/ /* The "try" I2C I/O versions are used when probing the sensor */ extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, @@ -110,10 +119,12 @@ extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); -/* This must be used if and only if the sensor doesn't implement the standard - I2C protocol, like the TASC sensors. There a number of good reasons why you - must use the single-byte versions of this function: do not abuse. It writes - n bytes, from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip) */ +/* + This must be used if and only if the sensor doesn't implement the standard + I2C protocol. There a number of good reasons why you must use the + single-byte versions of this function: do not abuse. It writes n bytes, + from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip). +*/ extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 n, u8 data0, u8 data1, u8 data2, u8 data3, @@ -127,12 +138,14 @@ extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); -/* NOTE: there are no debugging functions here. To uniform the output you must +/* + NOTE: there are no debugging functions here. To uniform the output you must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, already included here, the argument being the struct device 'dev' of the sensor structure. Do NOT use these macros before the sensor is attached or the kernel will crash! However you should not need to notify the user about - common errors or other messages, since this is done by the master module. */ + common errors or other messages, since this is done by the master module. +*/ /*****************************************************************************/ @@ -150,24 +163,31 @@ struct sn9c102_sensor { char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ - /* These sensor capabilities must be provided if the SN9C10X controller + /* + These sensor capabilities must be provided if the SN9C10X controller needs to communicate through the sensor serial interface by using - at least one of the i2c functions available */ + at least one of the i2c functions available. + */ enum sn9c102_i2c_frequency frequency; enum sn9c102_i2c_interface interface; - /* These identifiers must be provided if the image sensor implements + /* + These identifiers must be provided if the image sensor implements the standard I2C protocol. TASC sensors don't, although they have a serial interface: so this is a case where the "raw" I2C version - could be helpful. */ + could be helpful. + */ u8 slave_read_id, slave_write_id; /* reg. 0x09 */ - /* NOTE: Where not noted,most of the functions below are not mandatory. + /* + NOTE: Where not noted,most of the functions below are not mandatory. Set to null if you do not implement them. If implemented, - they must return 0 on success, the proper error otherwise. */ + they must return 0 on success, the proper error otherwise. + */ int (*init)(struct sn9c102_device* cam); - /* This function is called after the sensor has been attached. + /* + This function is called after the sensor has been attached. It should be used to initialize the sensor only, but may also configure part of the SN9C10X chip if necessary. You don't need to setup picture settings like brightness, contrast, etc.. here, if @@ -177,23 +197,29 @@ struct sn9c102_sensor { specified in the v4l2_queryctrl list of supported controls; Same suggestions apply for other settings, _if_ the corresponding methods are present; if not, the initialization must configure the - sensor according to the default configuration structures below. */ + sensor according to the default configuration structures below. + */ struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; - /* Optional list of default controls, defined as indicated in the - V4L2 API. Menu type controls are not handled by this interface. */ + /* + Optional list of default controls, defined as indicated in the + V4L2 API. Menu type controls are not handled by this interface. + */ int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); int (*set_ctrl)(struct sn9c102_device* cam, const struct v4l2_control* ctrl); - /* You must implement at least the set_ctrl method if you have defined + /* + You must implement at least the set_ctrl method if you have defined the list above. The returned value must follow the V4L2 specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER are not supported by this driver, so do not implement them. Also, - passed values are NOT checked to see if they are out of bounds. */ + passed values are NOT checked to see if they are out of bounds. + */ struct v4l2_cropcap cropcap; - /* Think the image sensor as a grid of R,G,B monochromatic pixels + /* + Think the image sensor as a grid of R,G,B monochromatic pixels disposed according to a particular Bayer pattern, which describes the complete array of pixels, from (0,0) to (xmax, ymax). We will use this coordinate system from now on. It is assumed the sensor @@ -221,11 +247,13 @@ struct sn9c102_sensor { NOTE: once you have defined the bounds of the active window (struct cropcap.bounds) you must not change them.anymore. Only 'bounds' and 'defrect' fields are mandatory, other fields - will be ignored. */ + will be ignored. + */ int (*set_crop)(struct sn9c102_device* cam, const struct v4l2_rect* rect); - /* To be called on VIDIOC_C_SETCROP. The core module always calls a + /* + To be called on VIDIOC_C_SETCROP. The core module always calls a default routine which configures the appropriate SN9C10X regs (also scaling), but you may need to override/adjust specific stuff. 'rect' contains width and height values that are multiple of 16: in @@ -237,10 +265,12 @@ struct sn9c102_sensor { frame after each HSYNC or VSYNC, so that the image starts with real RGB data (see regs 0x12,0x13) (having set H_SIZE and, V_SIZE you don't have to care about blank pixels or blank - lines at the end of each line or frame). */ + lines at the end of each line or frame). + */ struct v4l2_pix_format pix_format; - /* What you have to define here are: initial 'width' and 'height' of + /* + What you have to define here are: initial 'width' and 'height' of the target rectangle, the bayer 'pixelformat' and 'priv' which we'll be used to indicate the number of bits per pixel, 8 or 9. Nothing more. @@ -249,20 +279,27 @@ struct sn9c102_sensor { suggest 1/1. NOTE 2: as said above, you have to program the SN9C10X chip to get rid of any blank pixels, so that the output of the sensor - matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). */ + matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). + */ const struct device* dev; - /* This is the argument for dev_err(), dev_info() and dev_warn(). It + /* + This is the argument for dev_err(), dev_info() and dev_warn(). It is used for debugging purposes. You must not access the struct - before the sensor is attached. */ + before the sensor is attached. + */ const struct usb_device* usbdev; - /* Points to the usb_device struct after the sensor is attached. - Do not touch unless you know what you are doing. */ + /* + Points to the usb_device struct after the sensor is attached. + Do not touch unless you know what you are doing. + */ - /* Do NOT write to the data below, it's READ ONLY. It is used by the + /* + Do NOT write to the data below, it's READ ONLY. It is used by the core module to store successfully updated values of the above - settings, for rollbacks..etc..in case of errors during atomic I/O */ + settings, for rollbacks..etc..in case of errors during atomic I/O + */ struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; struct v4l2_rect _rect; }; diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c index d67470013..68e1b2e0c 100644 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ b/drivers/usb/media/sn9c102_tas5110c1b.c @@ -33,15 +33,33 @@ static int tas5110c1b_init(struct sn9c102_device* cam) err += sn9c102_write_reg(cam, 0x44, 0x01); err += sn9c102_write_reg(cam, 0x00, 0x10); err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x0a, 0x14); err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x06, 0x18); - err += sn9c102_write_reg(cam, 0xcb, 0x19); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + + err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0, + 0x80, 0, 0); return err; } +static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + return sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, + 0x02, 0x20, + 0xff - (ctrl->value & 0xff), + 0, 0); + default: + return -EINVAL; + } +} + + static int tas5110c1b_set_crop(struct sn9c102_device* cam, const struct v4l2_rect* rect) { @@ -53,6 +71,11 @@ static int tas5110c1b_set_crop(struct sn9c102_device* cam, err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); + /* Don't change ! */ + err += sn9c102_write_reg(cam, 0x14, 0x1a); + err += sn9c102_write_reg(cam, 0x0a, 0x1b); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + return err; } @@ -60,7 +83,22 @@ static int tas5110c1b_set_crop(struct sn9c102_device* cam, static struct sn9c102_sensor tas5110c1b = { .name = "TAS5110C1B", .maintainer = "Luca Risolia ", + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_3WIRES, .init = &tas5110c1b_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x48, + .flags = 0, + }, + }, + .set_ctrl = &tas5110c1b_set_ctrl, .cropcap = { .bounds = { .left = 0, @@ -90,8 +128,9 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) /* This sensor has no identifiers, so let's attach it anyway */ sn9c102_attach_sensor(cam, &tas5110c1b); - /* At the moment, only devices whose PID is 0x6005 have this sensor */ - if (tas5110c1b.usbdev->descriptor.idProduct != 0x6005) + /* At the moment, sensor detection is based on USB pid/vid */ + if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 && + tas5110c1b.usbdev->descriptor.idProduct != 0x6005) return -ENODEV; return 0; diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c index 5f1b0f9a6..0bab19435 100644 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ b/drivers/usb/media/sn9c102_tas5130d1b.c @@ -37,38 +37,45 @@ static int tas5130d1b_init(struct sn9c102_device* cam) err += sn9c102_write_reg(cam, 0x00, 0x14); err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x07, 0x18); - err += sn9c102_write_reg(cam, 0x33, 0x19); err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, 0x47, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, - 0xa9, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, - 0x49, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, - 0x6c, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, - 0x08, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x20, - 0x00, 0, 0); - - err += sn9c102_write_reg(cam, 0x63, 0x19); return err; } +static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + return sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, + 0x02, 0x20, + 0xff - (ctrl->value & 0xff), + 0, 0); + default: + return -EINVAL; + } +} + + static int tas5130d1b_set_crop(struct sn9c102_device* cam, const struct v4l2_rect* rect) { struct sn9c102_sensor* s = &tas5130d1b; - int err = 0; u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; + int err = 0; err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); + /* Do NOT change! */ + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0xf3, 0x19); + return err; } @@ -79,6 +86,19 @@ static struct sn9c102_sensor tas5130d1b = { .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, .init = &tas5130d1b_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .set_ctrl = &tas5130d1b_set_ctrl, .cropcap = { .bounds = { .left = 0, @@ -108,13 +128,9 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) /* This sensor has no identifiers, so let's attach it anyway */ sn9c102_attach_sensor(cam, &tas5130d1b); - /* At the moment, only devices whose PID is 0x6025 have this sensor */ + /* At the moment, sensor detection is based on USB pid/vid */ if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025) return -ENODEV; - dev_info(tas5130d1b.dev, "TAS5130D1B detected, but the support for it " - "is disabled at the moment - needs further " - "testing -\n"); - - return -ENODEV; + return 0; } diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index af460298a..cd73a45d0 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -93,11 +93,11 @@ static unsigned int debug = 0; MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); -MODULE_PARM (debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC (debug, "Debug enabled or not"); -MODULE_PARM (swapRGB_on, "i"); +module_param(swapRGB_on, int, 0); MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); -MODULE_PARM (video_nr, "i"); +module_param(video_nr, int, 0); /******************************************************************** * @@ -704,7 +704,6 @@ static int stv680_start_stream (struct usb_stv *stv680) usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), stv680->sbuf[i].data, stv680->rawbufsize, stv680_video_irq, stv680); - urb->timeout = PENCAM_TIMEOUT * 2; stv680->urb[i] = urb; err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); if (err) diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c index cbaf7d804..84f38839c 100644 --- a/drivers/usb/media/ultracam.c +++ b/drivers/usb/media/ultracam.c @@ -60,9 +60,9 @@ static int init_color = 128; static int init_hue = 128; static int hue_correction = 128; -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -MODULE_PARM(flags, "i"); +module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, " "1=B/W, " @@ -71,18 +71,18 @@ MODULE_PARM_DESC(flags, "4=test pattern, " "5=separate frames, " "6=clean frames"); -MODULE_PARM(framerate, "i"); +module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -MODULE_PARM(init_brightness, "i"); +module_param(init_brightness, int, 0); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_contrast, "i"); +module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -MODULE_PARM(init_color, "i"); +module_param(init_color, int, 0); MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_hue, "i"); +module_param(init_hue, int, 0); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -MODULE_PARM(hue_correction, "i"); +module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); /* diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c index d46b136c9..1107e398d 100644 --- a/drivers/usb/media/usbvideo.c +++ b/drivers/usb/media/usbvideo.c @@ -34,7 +34,7 @@ #endif static int video_nr = -1; -MODULE_PARM(video_nr, "i"); +module_param(video_nr, int, 0); /* * Local prototypes. diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 310c5a96c..c4bebdacd 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -269,7 +269,7 @@ typedef struct /* Forwards */ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs); static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp); -extern struct usb_driver auerswald_driver; +static struct usb_driver auerswald_driver; /*-------------------------------------------------------------------*/ @@ -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; + __le16 *pbuf; int ret; dbg ("probe: vendor id 0x%x, device id 0x%x", @@ -1976,8 +1977,7 @@ static int auerswald_probe (struct usb_interface *intf, dbg ("Version is %X", cp->version); /* allow some time to settle the device */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/3); + msleep(334); /* Try to get a suitable textual description of the device */ /* Device name:*/ @@ -2003,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 = (__le16 *) 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/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index cd7b548b9..06c4bfa2f 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -71,6 +71,8 @@ * - make device locking interruptible * 2004-04-30 - 0.95 Juergen Stuber * - check for valid udev on resubmitting and unlinking urbs + * 2004-08-03 - 0.96 Juergen Stuber + * - move reset into open to clean out spurious data */ #include @@ -98,12 +100,12 @@ /* Version Information */ -#define DRIVER_VERSION "v0.95" +#define DRIVER_VERSION "v0.96" #define DRIVER_AUTHOR "Juergen Stuber " #define DRIVER_DESC "LEGO USB Tower Driver" /* Module parameters */ -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); /* The defaults are chosen to work with the latest versions of leJOS and NQC. @@ -113,8 +115,8 @@ MODULE_PARM_DESC(debug, "Debug enabled or not"); * In this case read_buffer_size should exceed the maximal packet length * (417 for datalog uploads), and packet_timeout should be set. */ -static size_t read_buffer_size = 480; -MODULE_PARM(read_buffer_size, "i"); +static int read_buffer_size = 480; +module_param(read_buffer_size, int, 0); MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); /* Some legacy software likes to send packets in one piece. @@ -123,8 +125,8 @@ MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); * A problem with long writes is that the following read may time out * if the software is not prepared to wait long enough. */ -static size_t write_buffer_size = 480; -MODULE_PARM(write_buffer_size, "i"); +static int write_buffer_size = 480; +module_param(write_buffer_size, int, 0); MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); /* Some legacy software expects reads to contain whole LASM packets. @@ -138,7 +140,7 @@ MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); * Set it to 0 to disable. */ static int packet_timeout = 50; -MODULE_PARM(packet_timeout, "i"); +module_param(packet_timeout, int, 0); MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); /* Some legacy software expects blocking reads to time out. @@ -146,7 +148,7 @@ MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); * Set it to 0 to disable. */ static int read_timeout = 200; -MODULE_PARM(read_timeout, "i"); +module_param(read_timeout, int, 0); MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); /* As of kernel version 2.6.4 ehci-hcd uses an @@ -159,11 +161,11 @@ MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); * or set to 0 to use the standard interval from the endpoint descriptors. */ static int interrupt_in_interval = 2; -MODULE_PARM(interrupt_in_interval, "i"); +module_param(interrupt_in_interval, int, 0); MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms"); static int interrupt_out_interval = 8; -MODULE_PARM(interrupt_out_interval, "i"); +module_param(interrupt_out_interval, int, 0); MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms"); /* Define these values to match your device */ @@ -175,18 +177,18 @@ MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms"); #define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD struct tower_reset_reply { - __u16 size; /* little-endian */ + __le16 size; /* little-endian */ __u8 err_code; __u8 spare; } __attribute__ ((packed)); struct tower_get_version_reply { - __u16 size; /* little-endian */ + __le16 size; /* little-endian */ __u8 err_code; __u8 spare; __u8 major; __u8 minor; - __u16 build_no; /* little-endian */ + __le16 build_no; /* little-endian */ } __attribute__ ((packed)); @@ -341,6 +343,8 @@ static int tower_open (struct inode *inode, struct file *file) int subminor; int retval = 0; struct usb_interface *interface; + struct tower_reset_reply reset_reply; + int result; dbg(2, "%s: enter", __FUNCTION__); @@ -378,6 +382,22 @@ static int tower_open (struct inode *inode, struct file *file) } dev->open_count = 1; + /* reset the tower */ + result = usb_control_msg (dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &reset_reply, + sizeof(reset_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower reset control request failed"); + retval = result; + goto unlock_exit; + } + /* initialize in direction */ dev->read_buffer_length = 0; dev->read_packet_length = 0; @@ -694,7 +714,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t } /* write the data into interrupt_out_buffer from userspace */ - bytes_to_write = min(count, write_buffer_size); + bytes_to_write = min_t(int, count, write_buffer_size); dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __FUNCTION__, count, bytes_to_write); if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) { @@ -828,7 +848,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device struct lego_usb_tower *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor* endpoint; - struct tower_reset_reply reset_reply; struct tower_get_version_reply get_version_reply; int i; int retval = -ENOMEM; @@ -951,22 +970,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device /* let the user know what node this device is now attached to */ info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor); - /* reset the tower */ - result = usb_control_msg (udev, - usb_rcvctrlpipe(udev, 0), - LEGO_USB_TOWER_REQUEST_RESET, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - &reset_reply, - sizeof(reset_reply), - HZ); - if (result < 0) { - err("LEGO USB Tower reset control request failed"); - retval = result; - goto error; - } - /* get the firmware version and log it */ result = usb_control_msg (udev, usb_rcvctrlpipe(udev, 0), diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index b89b53401..8cca7e747 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -12,8 +12,6 @@ * controllers available at: http://www.phidgets.com/ * * Note that the driver takes input as: degrees.minutes - * -23 < degrees < 203 - * 0 < minutes < 59 * * CAUTION: Generally you should use 0 < degrees < 180 as anything else * is probably beyond the range of your servo and may damage it. @@ -21,6 +19,10 @@ * Jun 16, 2004: Sean Young * - cleanups * - was using memory after kfree() + * Aug 8, 2004: Sean Young + * - set the highest angle as high as the hardware allows, there are + * some odd servos out there + * */ #include @@ -87,6 +89,9 @@ change_position_v30(struct phidget_servo *servo, int servo_no, int degrees, int retval; unsigned char *buffer; + if (degrees < -23 || degrees > 362) + return -EINVAL; + buffer = kmalloc(6, GFP_KERNEL); if (!buffer) { dev_err(&servo->udev->dev, "%s - out of memory\n", @@ -157,6 +162,9 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees, int retval; unsigned char *buffer; + if (degrees < -23 || degrees > 278) + return -EINVAL; + buffer = kmalloc(2, GFP_KERNEL); if (!buffer) { dev_err(&servo->udev->dev, "%s - out of memory\n", @@ -212,10 +220,8 @@ static ssize_t set_servo##value (struct device *dev, \ return -EINVAL; \ } \ \ - if (degrees < -23 || degrees > (180 + 23) || \ - minutes < 0 || minutes > 59) { \ + if (minutes < 0 || minutes > 59) \ return -EINVAL; \ - } \ \ if (servo->type & SERVO_VERSION_30) \ retval = change_position_v30 (servo, value, degrees, \ diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c index cdf5919f8..0f9c57537 100644 --- a/drivers/usb/misc/tiglusb.c +++ b/drivers/usb/misc/tiglusb.c @@ -560,7 +560,7 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE (DRIVER_LICENSE); -MODULE_PARM (timeout, "i"); +module_param(timeout, int, 0); MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)"); /* --------------------------------------------------------------------- */ diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 8ee1b05ea..a03b8d44a 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1054,8 +1054,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size); if (!urb) return -ENOMEM; - if (async) - urb->transfer_flags |= URB_ASYNC_UNLINK; + urb->transfer_flags |= URB_ASYNC_UNLINK; urb->context = &completion; urb->complete = unlink1_callback; @@ -1074,17 +1073,20 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) * hcd states and code paths, even with little other system load. */ msleep (jiffies % (2 * INTERRUPT_RATE)); + if (async) { retry: - retval = usb_unlink_urb (urb); - if (retval == -EBUSY || retval == -EIDRM) { - /* we can't unlink urbs while they're completing. - * or if they've completed, and we haven't resubmitted. - * "normal" drivers would prevent resubmission, but - * since we're testing unlink paths, we can't. - */ - dev_dbg (&dev->intf->dev, "unlink retry\n"); - goto retry; - } + retval = usb_unlink_urb (urb); + if (retval == -EBUSY || retval == -EIDRM) { + /* we can't unlink urbs while they're completing. + * or if they've completed, and we haven't resubmitted. + * "normal" drivers would prevent resubmission, but + * since we're testing unlink paths, we can't. + */ + dev_dbg (&dev->intf->dev, "unlink retry\n"); + goto retry; + } + } else + usb_kill_urb (urb); if (!(retval == 0 || retval == -EINPROGRESS)) { dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval); return retval; @@ -1095,9 +1097,10 @@ retry: simple_free_urb (urb); if (async) - return (retval != -ECONNRESET) ? -ECONNRESET : 0; + return (retval == -ECONNRESET) ? 0 : retval - 1000; else - return (retval != -ENOENT) ? -ENOENT : 0; + return (retval == -ENOENT || retval == -EPERM) ? + 0 : retval - 2000; } static int unlink_simple (struct usbtest_dev *dev, int pipe, int len) diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index de9bf863e..455fe6e3b 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -242,7 +242,7 @@ static void catc_rx_done(struct urb *urb, struct pt_regs *regs) do { if(!catc->is_f5u011) { - pkt_len = le16_to_cpup((u16*)pkt_start); + pkt_len = le16_to_cpup((__le16*)pkt_start); if (pkt_len > urb->actual_length) { catc->stats.rx_length_errors++; catc->stats.rx_errors++; @@ -303,7 +303,7 @@ static void catc_irq_done(struct urb *urb, struct pt_regs *regs) else if (data[1] & 0x20) linksts = LinkBad; } else { - hasdata = (unsigned int)(be16_to_cpup((u16*)data) & 0x0fff); + hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff); if (data[0] == 0x90) linksts = LinkGood; else if (data[0] == 0xA0) diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 6eb637a80..40e921ade 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -203,7 +203,7 @@ struct kaweth_ethernet_configuration __u8 reserved2; eth_addr_t hw_addr; __u32 statistics_mask; - __u16 segment_size; + __le16 segment_size; __u16 max_multicast_filters; __u8 reserved3; } __attribute__ ((packed)); @@ -588,7 +588,7 @@ static void kaweth_usb_receive(struct urb *urb, struct pt_regs *regs) int count = urb->actual_length; int count2 = urb->transfer_buffer_length; - __u16 pkt_len = le16_to_cpup((u16 *)kaweth->rx_buf); + __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); struct sk_buff *skb; @@ -668,7 +668,7 @@ static int kaweth_open(struct net_device *net) INTBUFFERSIZE, int_callback, kaweth, - HZ/4); + 8); kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -763,7 +763,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb, struct pt_regs *regs) static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) { struct kaweth_device *kaweth = net->priv; - u16 *private_header; + __le16 *private_header; int res; @@ -794,7 +794,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) } } - private_header = (u16 *)__skb_push(skb, 2); + private_header = (__le16 *)__skb_push(skb, 2); *private_header = cpu_to_le16(skb->len-2); kaweth->tx_skb = skb; diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index f4f1071a3..c515916e3 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -78,8 +78,8 @@ static struct usb_device_id pegasus_ids[] = { MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(loopback, "i"); -MODULE_PARM(mii_mode, "i"); +module_param(loopback, bool, 0); +module_param(mii_mode, bool, 0); MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); @@ -286,7 +286,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) { int i; __u8 data[4] = { phy, 0, 0, indx }; - __u16 regdi; + __le16 regdi; set_register(pegasus, PhyCtrl, 0); set_registers(pegasus, PhyAddr, sizeof (data), data); @@ -347,7 +347,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) { int i; __u8 tmp; - __u16 retdatai; + __le16 retdatai; set_register(pegasus, EpromCtrl, 0); set_register(pegasus, EpromOffset, index); @@ -417,7 +417,7 @@ static inline void get_node_id(pegasus_t * pegasus, __u8 * id) for (i = 0; i < 3; i++) { read_eprom_word(pegasus, i, &w16); - ((__u16 *) id)[i] = cpu_to_le16p(&w16); + ((__le16 *) id)[i] = cpu_to_le16p(&w16); } } @@ -581,7 +581,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) if (!count) goto goon; - rx_status = le32_to_cpu(*(int *) (urb->transfer_buffer + count - 4)); + rx_status = le32_to_cpu(*(__le32 *) (urb->transfer_buffer + count - 4)); if (rx_status & 0x000e0000) { dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000); pegasus->stats.rx_errors++; @@ -594,7 +594,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) goto goon; } if (pegasus->chip == 0x8513) { - pkt_len = le32_to_cpu(*(int *)urb->transfer_buffer); + pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); pkt_len &= 0x0fff; pegasus->rx_skb->data += 2; } else { @@ -774,7 +774,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) netif_stop_queue(net); - ((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); + ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); memcpy(pegasus->tx_buff + 2, skb->data, skb->len); usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, usb_sndbulkpipe(pegasus->usb, 2), diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index d9d09e984..640aa5b68 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -160,7 +160,7 @@ struct rtl8150 { spinlock_t rx_pool_lock; struct usb_ctrlrequest dr; int intr_interval; - u16 rx_creg; + __le16 rx_creg; u8 *intr_buff; u8 phy; }; @@ -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; @@ -450,7 +450,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) goto goon; res = urb->actual_length; - rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4)); + rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4)); pkt_len = res - 4; skb_put(dev->rx_skb, pkt_len); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 2d68cb01e..cca6e72cf 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -166,7 +166,7 @@ #define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) // between wakeups -#define UNLINK_TIMEOUT_JIFFIES ((3 /*ms*/ * HZ)/1000) +#define UNLINK_TIMEOUT_MS 3 /*-------------------------------------------------------------------------*/ @@ -268,7 +268,7 @@ static const char driver_name [] = "usbnet"; /* use ethtool to change the level for any given device */ static int msg_level = 1; -MODULE_PARM (msg_level, "i"); +module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); @@ -937,8 +937,8 @@ struct ether_desc { u8 iMACAddress; u32 bmEthernetStatistics; - u16 wMaxSegmentSize; - u16 wNumberMCFilters; + __le16 wMaxSegmentSize; + __le16 wNumberMCFilters; u8 bNumberPowerFilters; } __attribute__ ((packed)); @@ -1074,7 +1074,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) info->u->bLength); goto bad_desc; } - dev->net->mtu = cpu_to_le16p ( + dev->net->mtu = le16_to_cpup ( &info->ether->wMaxSegmentSize) - ETH_HLEN; /* because of Zaurus, we may be ignoring the host @@ -2591,8 +2591,7 @@ static int usbnet_stop (struct net_device *net) while (skb_queue_len (&dev->rxq) && skb_queue_len (&dev->txq) && skb_queue_len (&dev->done)) { - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (UNLINK_TIMEOUT_JIFFIES); + msleep(UNLINK_TIMEOUT_MS); devdbg (dev, "waited for %d urb completions", temp); } dev->wait = NULL; diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 3ee5f493a..33613b008 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -44,7 +44,7 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v1.0" +#define DRIVER_VERSION "v1.01" #define DRIVER_AUTHOR "Matthias Bruestle" #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" @@ -111,6 +111,7 @@ struct cyberjack_private { static int cyberjack_startup (struct usb_serial *serial) { struct cyberjack_private *priv; + int i; dbg("%s", __FUNCTION__); @@ -128,6 +129,16 @@ static int cyberjack_startup (struct usb_serial *serial) init_waitqueue_head(&serial->port[0]->write_wait); + for (i = 0; i < serial->num_ports; ++i) { + int result; + serial->port[i]->interrupt_in_urb->dev = serial->dev; + result = usb_submit_urb(serial->port[i]->interrupt_in_urb, + GFP_KERNEL); + if (result) + err(" usb_submit_urb(read int) failed"); + dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); + } + return( 0 ); } @@ -138,6 +149,7 @@ static void cyberjack_shutdown (struct usb_serial *serial) dbg("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { + usb_unlink_urb (serial->port[i]->interrupt_in_urb); /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); @@ -168,17 +180,6 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp) priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); - /* shutdown any bulk reads that might be going on */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - err(" usb_submit_urb(read int) failed"); - dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); - return result; } @@ -190,11 +191,6 @@ static void cyberjack_close (struct usb_serial_port *port, struct file *filp) /* shutdown any bulk reads that might be going on */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - dbg("%s - usb_clear_halt", __FUNCTION__ ); - usb_clear_halt(port->serial->dev, port->write_urb->pipe); - usb_clear_halt(port->serial->dev, port->read_urb->pipe); - usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe); } } @@ -376,6 +372,10 @@ static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs) } tty = port->tty; + if (!tty) { + dbg("%s - ignoring since device not open\n", __FUNCTION__); + return; + } if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index f187b3165..3ac69f2c2 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -624,14 +624,7 @@ static void digi_wakeup_write( struct usb_serial_port *port ) wake_up_interruptible( &port->write_wait ); /* wake up line discipline */ - if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup ) - (tty->ldisc.write_wakeup)(tty); - - /* wake up other tty processes */ - wake_up_interruptible( &tty->write_wait ); - /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ - + tty_wakeup(tty); } @@ -1553,13 +1546,17 @@ static void digi_close( struct usb_serial_port *port, struct file *filp ) dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count ); + /* if disconnected, just clear flags */ + if (!usb_get_intfdata(port->serial->interface)) + goto exit; + /* do cleanup only after final close on this port */ spin_lock_irqsave( &priv->dp_port_lock, flags ); priv->dp_in_close = 1; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); /* tell line discipline to process only XON/XOFF */ - tty->closing = 1; + tty->closing = 1; /* wait for output to drain */ if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) { @@ -1569,8 +1566,7 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co /* flush driver and line discipline buffers */ if( tty->driver->flush_buffer ) tty->driver->flush_buffer( tty ); - if( tty->ldisc.flush_buffer ) - tty->ldisc.flush_buffer( tty ); + tty_ldisc_flush(tty); if (port->serial->dev) { /* wait for transmit idle */ @@ -1624,6 +1620,7 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co tty->closing = 0; +exit: spin_lock_irqsave( &priv->dp_port_lock, flags ); priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 972f3b91d..251a50fda 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -516,11 +516,7 @@ static void empeg_set_termios (struct usb_serial_port *port, struct termios *old */ port->tty->low_latency = 1; - /* Notify the tty driver that the termios have changed. */ - port->tty->ldisc.set_termios(port->tty, NULL); - return; - } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b35ab607a..9073ea84d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (21/Jul/2004) Ian Abbott + * Incorporated Steven Turner's code to add support for the FT2232C chip. + * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have + * fixed a couple of things. + * * (27/May/2004) Ian Abbott * Improved throttling code, mostly stolen from the WhiteHEAT driver. * @@ -259,7 +264,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.0" +#define DRIVER_VERSION "v1.4.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -489,11 +494,18 @@ static struct usb_device_id id_table_HE_TIRA1 [] = { }; +static struct usb_device_id id_table_FT2232C[] = { + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { } /* Terminating entry */ +}; + + static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, @@ -621,6 +633,8 @@ struct ftdi_private { __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ + __u16 interface; /* FT2232C port interface (0 for FT232/245) */ + int force_baud; /* if non-zero, force the baud rate to this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ }; @@ -637,6 +651,7 @@ struct ftdi_private { static int ftdi_SIO_startup (struct usb_serial *serial); static int ftdi_8U232AM_startup (struct usb_serial *serial); static int ftdi_FT232BM_startup (struct usb_serial *serial); +static int ftdi_FT2232C_startup (struct usb_serial *serial); static int ftdi_USB_UIRT_startup (struct usb_serial *serial); static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); @@ -739,6 +754,32 @@ static struct usb_serial_device_type ftdi_FT232BM_device = { .shutdown = ftdi_shutdown, }; +static struct usb_serial_device_type ftdi_FT2232C_device = { + .owner = THIS_MODULE, + .name = "FTDI FT2232C Compatible", + .id_table = id_table_FT2232C, + .num_interrupt_in = 0, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ftdi_open, + .close = ftdi_close, + .throttle = ftdi_throttle, + .unthrottle = ftdi_unthrottle, + .write = ftdi_write, + .write_room = ftdi_write_room, + .chars_in_buffer = ftdi_chars_in_buffer, + .read_bulk_callback = ftdi_read_bulk_callback, + .write_bulk_callback = ftdi_write_bulk_callback, + .tiocmget = ftdi_tiocmget, + .tiocmset = ftdi_tiocmset, + .ioctl = ftdi_ioctl, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .attach = ftdi_FT2232C_startup, + .shutdown = ftdi_shutdown, +}; + static struct usb_serial_device_type ftdi_USB_UIRT_device = { .owner = THIS_MODULE, .name = "USB-UIRT Infrared Tranceiver", @@ -866,7 +907,7 @@ static int set_rts(struct usb_serial_port *port, int high_or_low) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -896,7 +937,7 @@ static int set_dtr(struct usb_serial_port *port, int high_or_low) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -909,6 +950,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port); static int change_speed(struct usb_serial_port *port) { + struct ftdi_private *priv = usb_get_serial_port_data(port); char *buf; __u16 urb_value; __u16 urb_index; @@ -922,6 +964,9 @@ static int change_speed(struct usb_serial_port *port) urb_index_value = get_ftdi_divisor(port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); + if (priv->interface) { /* FT2232C */ + urb_index = (__u16)((urb_index << 8) | priv->interface); + } rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1015,7 +1060,12 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) } break; case FT232BM: /* FT232BM chip */ - chip_name = "FT232BM"; + case FT2232C: /* FT2232C chip */ + if (priv->chip_type == FT2232C) { + chip_name = "FT2232C"; + } else { + chip_name = "FT232BM"; + } if (baud <= 3000000) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { @@ -1231,6 +1281,35 @@ static int ftdi_FT232BM_startup (struct usb_serial *serial) return (0); } /* ftdi_FT232BM_startup */ +/* Startup for the FT2232C chip */ +/* Called from usbserial:serial_probe */ +static int ftdi_FT2232C_startup (struct usb_serial *serial) +{ /* ftdi_FT2232C_startup */ + struct ftdi_private *priv; + int err; + int inter; + + dbg("%s",__FUNCTION__); + err = ftdi_common_startup(serial); + if (err){ + return (err); + } + + priv = usb_get_serial_port_data(serial->port[0]); + priv->chip_type = FT2232C; + inter = serial->interface->altsetting->desc.bInterfaceNumber; + + if (inter) { + priv->interface = INTERFACE_B; + } + else { + priv->interface = INTERFACE_A; + } + priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ + + return (0); +} /* ftdi_FT2232C_startup */ + /* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ static int ftdi_USB_UIRT_startup (struct usb_serial *serial) @@ -1323,7 +1402,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, - 0, buf, 0, WDR_TIMEOUT); + priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would loose speed settings, etc. @@ -1373,6 +1452,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) static void ftdi_close (struct usb_serial_port *port, struct file *filp) { /* ftdi_close */ unsigned int c_cflag = port->tty->termios->c_cflag; + struct ftdi_private *priv = usb_get_serial_port_data(port); char buf[1]; dbg("%s", __FUNCTION__); @@ -1383,7 +1463,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, buf, 0, WDR_TIMEOUT) < 0) { + 0, priv->interface, buf, 0, + WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); } @@ -1796,7 +1877,7 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); } @@ -1875,7 +1956,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, 100) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); } @@ -1886,7 +1967,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); } @@ -1903,6 +1984,13 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ if (change_speed(port)) { err("%s urb failed to set baurdrate", __FUNCTION__); } + /* Ensure RTS and DTR are raised */ + else if (set_dtr(port, HIGH) < 0){ + err("%s Error from DTR HIGH urb", __FUNCTION__); + } + else if (set_rts(port, HIGH) < 0){ + err("%s Error from RTS HIGH urb", __FUNCTION__); + } } /* Set flow control */ @@ -1913,7 +2001,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0 , FTDI_SIO_RTS_CTS_HS, + 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); } @@ -1939,7 +2027,8 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - urb_value , FTDI_SIO_XON_XOFF_HS, + urb_value , (FTDI_SIO_XON_XOFF_HS + | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to xon/xoff flow control"); } @@ -1951,7 +2040,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); } @@ -1985,13 +2074,14 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) break; case FT8U232AM: case FT232BM: + case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2206,6 +2296,9 @@ static int __init ftdi_init (void) retval = usb_serial_register(&ftdi_FT232BM_device); if (retval) goto failed_FT232BM_register; + retval = usb_serial_register(&ftdi_FT2232C_device); + if (retval) + goto failed_FT2232C_register; retval = usb_serial_register(&ftdi_USB_UIRT_device); if (retval) goto failed_USB_UIRT_register; @@ -2223,6 +2316,8 @@ failed_usb_register: failed_HE_TIRA1_register: usb_serial_deregister(&ftdi_USB_UIRT_device); failed_USB_UIRT_register: + usb_serial_deregister(&ftdi_FT2232C_device); +failed_FT2232C_register: usb_serial_deregister(&ftdi_FT232BM_device); failed_FT232BM_register: usb_serial_deregister(&ftdi_8U232AM_device); @@ -2241,6 +2336,7 @@ static void __exit ftdi_exit (void) usb_deregister (&ftdi_driver); usb_serial_deregister (&ftdi_HE_TIRA1_device); usb_serial_deregister (&ftdi_USB_UIRT_device); + usb_serial_deregister (&ftdi_FT2232C_device); usb_serial_deregister (&ftdi_FT232BM_device); usb_serial_deregister (&ftdi_8U232AM_device); usb_serial_deregister (&ftdi_SIO_device); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 02554035e..232213b02 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -26,6 +26,7 @@ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ @@ -234,6 +235,21 @@ #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +/* Port interface code for FT2232C */ +#define INTERFACE_A 1 +#define INTERFACE_B 2 + + +/* + * BmRequestType: 1100 0000b + * bRequest: FTDI_E2_READ + * wValue: 0 + * wIndex: Address of word to read + * wLength: 2 + * Data: Will return a word of data from E2Address + * + */ + /* Port Identifier Table */ #define PIT_DEFAULT 0 /* SIOA */ #define PIT_SIOA 1 /* SIOA */ @@ -333,6 +349,7 @@ typedef enum { SIO = 1, FT8U232AM = 2, FT232BM = 3, + FT2232C = 4, } ftdi_chip_type_t; typedef enum { diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index e727628bd..1ef47613b 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -479,7 +479,7 @@ static void get_boot_desc (struct edgeport_serial *edge_serial); static void load_application_firmware (struct edgeport_serial *edge_serial); -static void unicode_to_ascii (char *string, short *unicode, int unicode_size); +static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size); @@ -504,7 +504,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial) __u32 BootNewVer; __u8 BootMajorVersion; __u8 BootMinorVersion; - __u16 BootBuildNumber; + __le16 BootBuildNumber; __u8 *BootImage; __u32 BootSize; struct edge_firmware_image_record *record; @@ -653,7 +653,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) memset (product_info, 0, sizeof(struct edgeport_product_info)); - product_info->ProductId = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_GENERATION_2); + product_info->ProductId = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_80251_NETCHIP); product_info->NumPorts = edge_serial->manuf_descriptor.NumPorts; product_info->ProdInfoVer = 0; @@ -669,7 +669,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate)); // check if this is 2nd generation hardware - if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) { + if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_80251_NETCHIP) { product_info->FirmwareMajorVersion = OperationalCodeImageVersion_GEN2.MajorVersion; product_info->FirmwareMinorVersion = OperationalCodeImageVersion_GEN2.MinorVersion; product_info->FirmwareBuildNumber = cpu_to_le16(OperationalCodeImageVersion_GEN2.BuildNumber); @@ -900,12 +900,7 @@ static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs) if (tty && edge_port->open) { /* let the tty driver wakeup if it has a special write_wakeup function */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - (tty->ldisc.write_wakeup)(tty); - } - - /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } // Release the Write URB @@ -1389,7 +1384,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge // to bother queueing a write. If it's too small, say a few bytes, // it's better to wait for more credits so we can do a larger // write. - if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) { + if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) { dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits ); return; } @@ -2747,7 +2742,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio * ASCII range, but it's only for debugging... * NOTE: expects the unicode in LE format ****************************************************************************/ -static void unicode_to_ascii (char *string, short *unicode, int unicode_size) +static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size) { int i; for (i = 0; i < unicode_size; ++i) { @@ -3007,9 +3002,6 @@ static void edge_shutdown (struct usb_serial *serial) static int __init edgeport_init(void) { int retval; - retval = usb_serial_register(&edgeport_1port_device); - if (retval) - goto failed_1port_device_register; retval = usb_serial_register(&edgeport_2port_device); if (retval) goto failed_2port_device_register; @@ -3031,8 +3023,6 @@ failed_8port_device_register: failed_4port_device_register: usb_serial_deregister(&edgeport_2port_device); failed_2port_device_register: - usb_serial_deregister(&edgeport_1port_device); -failed_1port_device_register: return retval; } @@ -3045,7 +3035,6 @@ failed_1port_device_register: static void __exit edgeport_exit (void) { usb_deregister (&io_driver); - usb_serial_deregister (&edgeport_1port_device); usb_serial_deregister (&edgeport_2port_device); usb_serial_deregister (&edgeport_4port_device); usb_serial_deregister (&edgeport_8port_device); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 386139d45..5112d7aac 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -107,11 +107,11 @@ struct edgeport_product_info { __u8 BootMajorVersion; /* Boot Firmware version: xx. */ __u8 BootMinorVersion; /* yy. */ - __u16 BootBuildNumber; /* zzzz (LE format) */ + __le16 BootBuildNumber; /* zzzz (LE format) */ __u8 FirmwareMajorVersion; /* Operational Firmware version:xx. */ __u8 FirmwareMinorVersion; /* yy. */ - __u16 FirmwareBuildNumber; /* zzzz (LE format) */ + __le16 FirmwareBuildNumber; /* zzzz (LE format) */ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ __u8 Unused1[1]; /* Available */ diff --git a/drivers/usb/serial/io_fw_down.h b/drivers/usb/serial/io_fw_down.h index 245740eb1..d01ec7b22 100644 --- a/drivers/usb/serial/io_fw_down.h +++ b/drivers/usb/serial/io_fw_down.h @@ -17,7 +17,7 @@ unsigned short Addr; unsigned short Len; unsigned char Data[0]; - } __attribute ((packed)); + } __attribute__ ((packed)); struct edge_firmware_version_info { unsigned char MajorVersion; @@ -36,11 +36,11 @@ static unsigned char IMAGE_ARRAY_NAME[] = { // Segment #1, Start Address 00ff0000, Length 6 0xff,0x00,0x00,0x00,0x06,0x00, - 0x02, 0x00, 0x80, 0x02, 0x49, 0x39, + 0x02, 0x00, 0x80, 0x02, 0x44, 0xb0, // Segment #2, Start Address 00ff000b, Length 3 0xff,0x00,0x0b,0x00,0x03,0x00, - 0x02, 0x44, 0x1a, + 0x02, 0x44, 0x72, // Segment #3, Start Address 00ff0013, Length 3 0xff,0x00,0x13,0x00,0x03,0x00, @@ -72,11 +72,11 @@ static unsigned char IMAGE_ARRAY_NAME[] = { // Segment #10, Start Address 00ff004b, Length 3 0xff,0x00,0x4b,0x00,0x03,0x00, - 0x02, 0x70, 0xd4, + 0x02, 0x6e, 0xc4, // Segment #11, Start Address 00ff0053, Length 3 0xff,0x00,0x53,0x00,0x03,0x00, - 0x02, 0x77, 0x9d, + 0x02, 0x75, 0x8d, // Segment #12, Start Address 00ff007b, Length 3 0xff,0x00,0x7b,0x00,0x03,0x00, @@ -86,657 +86,745 @@ static unsigned char IMAGE_ARRAY_NAME[] = { 0xff,0x00,0x80,0x00,0x07,0x00, 0x7e, 0x14, 0x00, 0x00, 0x02, 0x40, 0x51, -// Segment #14, Start Address 00ff4000, Length 15920 -0xff,0x00,0x00,0x40,0x30,0x3e, +// Segment #14, Start Address 00ff3000, Length 2178 +0xff,0x00,0x00,0x30,0x82,0x08, + 0x12, 0x37, 0x28, 0x12, 0x30, 0x3e, 0x12, 0x30, 0x54, 0x12, 0x30, 0xe5, 0x12, 0x31, 0x68, 0x12, + 0x35, 0x20, 0x12, 0x38, 0x58, 0x12, 0x31, 0x15, 0x12, 0x31, 0x40, 0x12, 0x30, 0xa0, 0x80, 0xe0, + 0xe5, 0x23, 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, 0x09, 0xb1, 0x01, 0xcf, 0xb4, 0x00, 0x02, 0x80, + 0x05, 0x14, 0x19, 0xb1, 0x01, 0xcf, 0xa5, 0x0b, 0xbe, 0x31, 0x2f, 0x78, 0xeb, 0x22, 0xc2, 0xaf, + 0x7e, 0xb3, 0x3f, 0xf1, 0xb4, 0x01, 0x0a, 0xc0, 0xf1, 0x75, 0xf1, 0x02, 0x12, 0x70, 0xef, 0xd0, + 0xf1, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, 0x60, 0x43, 0x7e, 0x07, 0x01, 0xe1, 0xbe, 0x04, + 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, + 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, 0x04, 0x0a, 0x32, 0x09, 0x53, 0x67, 0x8e, 0x5e, + 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, + 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, + 0xc2, 0xaf, 0x7e, 0x20, 0x00, 0x7e, 0x30, 0x01, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x32, 0x01, + 0x8f, 0xbe, 0x34, 0x00, 0x00, 0x68, 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, 0x21, 0xca, + 0x19, 0x49, 0x22, 0x30, 0xd5, 0x99, 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, + 0x78, 0xd6, 0xd2, 0xaf, 0x22, 0x46, 0x0f, 0x49, 0x67, 0x4c, 0xbf, 0x50, 0x17, 0x53, 0x6f, 0x56, + 0xc7, 0x5a, 0x1f, 0x5d, 0x77, 0xc2, 0xaf, 0xe5, 0x32, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, + 0x07, 0xca, 0xb8, 0x12, 0x31, 0x02, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, + 0xaf, 0x22, 0xca, 0x28, 0x12, 0x67, 0xab, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, 0xb2, 0x67, + 0x8e, 0xf4, 0x52, 0x32, 0x22, 0xc2, 0xaf, 0xe5, 0x34, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, + 0x07, 0xca, 0xb8, 0x12, 0x31, 0x32, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, + 0xaf, 0x22, 0xca, 0x28, 0x0a, 0x22, 0x09, 0x42, 0x00, 0x3e, 0x12, 0x69, 0xc2, 0xda, 0x28, 0x22, + 0xc2, 0xaf, 0xe5, 0x35, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, + 0x5d, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x7e, + 0x40, 0x00, 0x12, 0x6c, 0x5b, 0xda, 0x28, 0x22, 0xc2, 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, + 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, 0x85, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, + 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x31, 0x90, 0x89, 0x24, + 0x31, 0xa0, 0x32, 0x10, 0x32, 0x80, 0x32, 0xf0, 0x33, 0x60, 0x33, 0xd0, 0x34, 0x40, 0x34, 0xb0, + 0x7e, 0x27, 0x01, 0x8f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x49, 0x30, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0x9f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x9f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xcf, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xcf, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x18, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xcf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x91, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x4c, 0x88, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa1, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa1, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd0, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd0, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x19, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd0, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x93, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x4f, 0xe0, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa3, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa3, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd1, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd1, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1a, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd1, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x95, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x53, 0x38, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa5, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa5, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd2, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd2, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1b, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd2, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x97, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x56, 0x90, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa7, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa7, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd3, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd3, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1c, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd3, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x99, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x59, 0xe8, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xa9, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xa9, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd4, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd4, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1d, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd4, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x9b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x5d, 0x40, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xab, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xab, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd5, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd5, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1e, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd5, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x27, 0x01, 0x9d, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x60, 0x98, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0xad, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0xad, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xd6, 0x80, + 0x2e, 0x7e, 0x63, 0x01, 0xd6, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x62, 0xb6, 0x40, 0x18, 0x75, 0x31, 0xb3, 0x12, 0x7c, 0x15, 0xc2, 0x1f, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xd6, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0xc2, 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x35, + 0x3d, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, + 0x0a, 0x2b, 0x49, 0x22, 0x35, 0x48, 0x89, 0x24, 0x35, 0x58, 0x35, 0x92, 0x35, 0xcc, 0x36, 0x06, + 0x36, 0x40, 0x36, 0x7a, 0x36, 0xb4, 0x36, 0xee, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 0x14, + 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x49, 0x30, + 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, + 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x20, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, + 0xf1, 0x22, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, + 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4c, 0x88, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, + 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, + 0x21, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x82, 0x00, + 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, + 0x12, 0x12, 0x4f, 0xe0, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, + 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x22, 0xc0, 0xf1, 0x75, 0xf1, 0x01, + 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, + 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x53, 0x38, 0x7d, 0x21, + 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, + 0x12, 0x7c, 0x15, 0xc2, 0x23, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, + 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, + 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x56, 0x90, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, + 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x24, 0xc0, + 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x59, 0xe8, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, + 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x25, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, + 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, + 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5d, 0x40, 0x7d, 0x21, 0xda, 0x19, + 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, + 0x15, 0xc2, 0x26, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, + 0x87, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, + 0x19, 0x7d, 0x12, 0x12, 0x60, 0x98, 0x7d, 0x21, 0xda, 0x19, 0x5e, 0xb0, 0x01, 0x7e, 0xa0, 0x90, + 0x12, 0x62, 0x93, 0x40, 0x12, 0x75, 0x31, 0xb8, 0x12, 0x7c, 0x15, 0xc2, 0x27, 0xc0, 0xf1, 0x75, + 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0xc2, 0xaf, 0xe5, 0x33, 0x60, 0x14, 0x7e, 0x20, + 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x37, 0x45, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2f, + 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x37, 0x50, 0x89, 0x24, + 0x37, 0x60, 0x37, 0x7f, 0x37, 0x9e, 0x37, 0xbd, 0x37, 0xdc, 0x37, 0xfb, 0x38, 0x1a, 0x38, 0x39, + 0x7e, 0x24, 0x80, 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x48, 0x1b, 0xda, 0x19, 0x10, 0x04, 0x02, + 0x80, 0x0c, 0xd2, 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, + 0x24, 0x81, 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4b, 0x73, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, + 0x0c, 0xd2, 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, + 0x82, 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4e, 0xcb, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, + 0xd2, 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x83, + 0x00, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x52, 0x23, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, + 0x01, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x84, 0x00, + 0xca, 0x19, 0x7d, 0x12, 0x12, 0x55, 0x7b, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, + 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x85, 0x00, 0xca, + 0x19, 0x7d, 0x12, 0x12, 0x58, 0xd3, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, 0xc0, + 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x86, 0x00, 0xca, 0x19, + 0x7d, 0x12, 0x12, 0x5c, 0x2b, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, 0xc0, 0xf1, + 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x7e, 0x24, 0x87, 0x00, 0xca, 0x19, 0x7d, + 0x12, 0x12, 0x5f, 0x83, 0xda, 0x19, 0x10, 0x04, 0x02, 0x80, 0x0c, 0xd2, 0x01, 0xc0, 0xf1, 0x75, + 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0xc2, 0xaf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0xa9, + 0x32, 0xf2, 0x1a, 0x7e, 0x07, 0x01, 0xe1, 0xbe, 0x04, 0x00, 0x00, 0x78, 0x10, 0xe5, 0xf5, 0x33, + 0x82, 0xe7, 0x40, 0x09, 0x85, 0x31, 0x31, 0x12, 0x7c, 0x15, 0x75, 0xf6, 0x00, 0xd0, 0xf1, 0xd2, + 0xaf, 0x22, + +// Segment #15, Start Address 00ff4000, Length 15381 +0xff,0x00,0x00,0x40,0x15,0x3c, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x14, 0x7f, 0xf8, 0x7e, 0x24, 0x00, 0xfe, 0x7d, 0x31, 0x0b, 0x1a, - 0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x6a, 0x7e, 0xf8, 0x00, 0x59, 0xd2, - 0x04, 0xc2, 0x94, 0xd2, 0x95, 0x7e, 0xf4, 0x40, 0x2c, 0x02, 0x40, 0x7c, 0x12, 0x7f, 0x3f, 0xf5, - 0x2e, 0x7a, 0xa1, 0x2d, 0x7a, 0x11, 0x58, 0x12, 0x77, 0xda, 0x12, 0x40, 0xdc, 0x7e, 0xb3, 0x3f, - 0xf1, 0x60, 0x03, 0x12, 0x43, 0x68, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x7f, 0xd2, 0xaf, 0x02, 0x44, - 0x06, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x5f, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xa9, + 0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x6a, 0x7e, 0xf8, 0x00, 0x6f, 0xd2, + 0x04, 0xc2, 0x94, 0xd2, 0x95, 0x7e, 0xf4, 0x40, 0x2c, 0x02, 0x40, 0x7c, 0x12, 0x7d, 0x30, 0xf5, + 0x2f, 0x7a, 0xa1, 0x30, 0x7a, 0x11, 0x6e, 0x12, 0x75, 0xca, 0x12, 0x40, 0xdc, 0x7e, 0xb3, 0x3f, + 0xf1, 0x60, 0x03, 0x12, 0x43, 0xd4, 0x75, 0xf1, 0x00, 0x12, 0x76, 0x6f, 0xd2, 0xaf, 0x02, 0x30, + 0x00, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x5f, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xa9, 0x25, 0x87, 0x03, 0xa9, 0xd5, 0x87, 0xd2, 0x93, 0x89, 0x08, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x78, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xc2, 0x93, 0x89, 0x08, 0x7e, 0x08, 0x00, 0x20, - 0x7e, 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x8e, 0x02, 0x7e, 0x4b, 0x7e, 0x08, - 0x01, 0x59, 0x7e, 0x44, 0x28, 0x7c, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xa0, 0x02, 0x7e, 0x4b, - 0x7e, 0x08, 0x00, 0x59, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xb2, 0x02, - 0x7e, 0x4b, 0x75, 0x57, 0x20, 0x75, 0x56, 0x30, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x54, 0x58, 0x75, - 0x55, 0x08, 0x75, 0x51, 0x08, 0x75, 0x53, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, - 0x00, 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x42, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, + 0x7e, 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x8e, 0x02, 0x7c, 0x30, 0x7e, 0x08, + 0x01, 0x6f, 0x7e, 0x44, 0x28, 0x7c, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xa0, 0x02, 0x7c, 0x30, + 0x7e, 0x08, 0x00, 0x6f, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xb2, 0x02, + 0x7c, 0x30, 0x75, 0x6d, 0x20, 0x75, 0x6c, 0x30, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x6a, 0x58, 0x75, + 0x6b, 0x08, 0x75, 0x67, 0x08, 0x75, 0x69, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, + 0x00, 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x58, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, 0xb8, 0x7f, 0x75, 0xb3, 0x07, 0x75, 0xb2, 0x07, 0xd2, 0xa9, 0x22, 0xd2, 0x92, 0xe4, 0xd5, 0xe0, - 0xfd, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2e, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, - 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x72, 0x0b, 0x20, - 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 0xb0, + 0xfd, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2f, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, + 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x7e, 0x0b, 0x20, + 0xbe, 0x21, 0x2f, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x10, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x80, 0x19, 0xb0, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x02, 0x19, 0xa0, 0x00, 0x04, 0x19, 0xb0, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb0, 0x00, 0x0c, - 0x74, 0x07, 0x20, 0x68, 0x02, 0x74, 0x0f, 0x19, 0xb0, 0x00, 0x04, 0x30, 0x6b, 0x17, 0x74, 0xbf, - 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x28, 0x20, 0x68, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 0x74, - 0x03, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 0x00, - 0x10, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 0x00, - 0x10, 0x54, 0x08, 0x19, 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 0xb2, - 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x41, 0x99, 0x89, 0x24, 0x41, 0xa9, 0x41, 0xc6, 0x41, 0xe3, 0x42, - 0x00, 0x42, 0x1d, 0x42, 0x3a, 0x42, 0x57, 0x42, 0x74, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x08, 0x7e, - 0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x6d, 0x00, 0x7a, 0x07, 0x01, - 0x79, 0x7a, 0x07, 0x01, 0x89, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, - 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 0x07, - 0x01, 0x8b, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, - 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 0x22, - 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x0b, 0x7e, 0x04, 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, - 0x01, 0x6f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7f, 0x7a, 0x07, 0x01, 0x8f, 0x22, 0xc2, 0x14, 0xc2, - 0x1c, 0xc2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x6d, - 0x00, 0x7a, 0x07, 0x01, 0x81, 0x7a, 0x07, 0x01, 0x91, 0x22, 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 0x0d, - 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, 0x7a, 0x07, 0x01, 0x73, 0x6d, 0x00, 0x7a, 0x07, - 0x01, 0x83, 0x7a, 0x07, 0x01, 0x93, 0x22, 0xc2, 0x16, 0xc2, 0x1e, 0xc2, 0x0e, 0x7e, 0x04, 0x21, - 0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x85, 0x7a, - 0x07, 0x01, 0x95, 0x22, 0xc2, 0x17, 0xc2, 0x1f, 0xc2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, - 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x87, 0x7a, 0x07, 0x01, 0x97, - 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x42, 0x9c, 0x89, 0x24, 0x42, 0xac, 0x42, 0xc3, - 0x42, 0xda, 0x42, 0xf1, 0x43, 0x08, 0x43, 0x1f, 0x43, 0x36, 0x43, 0x4d, 0x30, 0x40, 0x07, 0x20, - 0x58, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, 0x50, 0x04, 0xc2, 0x28, 0x80, 0x02, - 0xd2, 0x28, 0x22, 0x30, 0x41, 0x07, 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 0x07, - 0x20, 0x51, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x42, 0x07, 0x20, 0x5a, 0x04, - 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, 0x07, 0x20, 0x52, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2a, - 0x22, 0x30, 0x43, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, 0x4b, 0x07, 0x20, 0x53, - 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x44, 0x07, 0x20, 0x5c, 0x04, 0xc2, 0x2c, - 0x80, 0x0c, 0x30, 0x4c, 0x07, 0x20, 0x54, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 0x30, - 0x45, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x55, 0x04, 0xc2, - 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x46, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 0x0c, - 0x30, 0x4e, 0x07, 0x20, 0x56, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, 0x47, 0x07, - 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x57, 0x04, 0xc2, 0x2f, 0x80, - 0x02, 0xd2, 0x2f, 0x22, 0x43, 0xcc, 0x43, 0x79, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 0x0a, - 0x5b, 0x49, 0x55, 0x43, 0x64, 0x99, 0x54, 0xd3, 0x22, 0xa9, 0xc5, 0x87, 0x12, 0x43, 0xd7, 0x7e, - 0x04, 0x05, 0xcd, 0x7a, 0x07, 0x01, 0xc1, 0x7a, 0x07, 0x01, 0xc3, 0x7e, 0x04, 0x01, 0xcd, 0x7a, - 0x07, 0x01, 0xc7, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x04, 0x76, 0xbd, 0x7a, 0x05, 0x4b, 0x75, 0xf1, - 0x01, 0x75, 0xe1, 0x1f, 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x75, 0xf1, 0x02, 0x75, 0xe1, 0x03, - 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x43, 0xa2, 0x1c, 0x12, 0x40, 0xeb, 0x7e, 0x20, 0x00, 0x12, - 0x41, 0x8e, 0x0b, 0x20, 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0xa9, 0xd5, 0x87, 0x12, - 0x43, 0xd7, 0xd2, 0x92, 0xc2, 0xa8, 0x22, 0x75, 0xa3, 0x00, 0x53, 0xa2, 0x03, 0x75, 0xc1, 0x00, - 0x53, 0xc0, 0x03, 0x7e, 0x00, 0x05, 0x7a, 0x01, 0xf1, 0x43, 0xf4, 0x80, 0x43, 0xe4, 0x80, 0xe5, - 0xf2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xf2, 0xe5, 0xe2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xe2, 0x75, - 0xe1, 0x10, 0xa5, 0xd8, 0xe1, 0x22, 0x12, 0x44, 0x76, 0x12, 0x44, 0x8c, 0x12, 0x45, 0x27, 0x12, - 0x45, 0x57, 0x12, 0x49, 0x0f, 0x12, 0x44, 0xd8, 0x80, 0xec, 0xca, 0x09, 0x12, 0x44, 0x58, 0x10, - 0x01, 0x12, 0xd5, 0x51, 0x1e, 0x63, 0x53, 0x01, 0x7e, 0x00, 0x54, 0x2e, 0x01, 0x53, 0xa5, 0xe6, - 0xf5, 0x51, 0x80, 0x12, 0x20, 0x02, 0x1e, 0x75, 0x53, 0x00, 0x85, 0x54, 0x51, 0xd2, 0x02, 0x74, - 0x00, 0x80, 0x0d, 0x30, 0x02, 0x0f, 0xc2, 0x02, 0x7e, 0x00, 0x56, 0x2e, 0x01, 0x53, 0xa5, 0xe6, - 0x53, 0x90, 0xcf, 0x42, 0x90, 0xda, 0x09, 0x32, 0xe5, 0x23, 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, - 0x09, 0xb1, 0x01, 0xb9, 0xb4, 0x00, 0x02, 0x80, 0x05, 0x14, 0x19, 0xb1, 0x01, 0xb9, 0xa5, 0x0a, - 0xbe, 0x21, 0x2e, 0x78, 0xeb, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 0x3f, 0xf1, 0xb4, 0x01, 0x0a, 0xc0, - 0xf1, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xff, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, - 0x60, 0x43, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, - 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, - 0x04, 0x0a, 0x32, 0x09, 0x53, 0x6a, 0x93, 0x5e, 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, - 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, - 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x26, 0x60, 0x36, 0x7e, 0x20, - 0x00, 0x7e, 0x30, 0x01, 0xe5, 0x26, 0xa5, 0x5b, 0x68, 0x21, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, - 0x32, 0x01, 0x79, 0xbe, 0x34, 0x00, 0x00, 0x68, 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, - 0x21, 0xca, 0x19, 0x49, 0x22, 0x45, 0x17, 0x99, 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, - 0x21, 0x2e, 0x78, 0xd0, 0xd2, 0xaf, 0x22, 0x4a, 0x98, 0x4d, 0xcd, 0x51, 0x02, 0x54, 0x37, 0x57, - 0x6c, 0x5a, 0xa1, 0x5d, 0xd6, 0x61, 0x0b, 0xc2, 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, - 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x44, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, - 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x12, 0x6a, 0xac, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, - 0xb2, 0x6a, 0x93, 0xf4, 0x52, 0x24, 0x22, 0xc2, 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, 0x00, - 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x74, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, - 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x45, 0x7f, 0x89, 0x24, 0x45, - 0x8f, 0x45, 0xff, 0x46, 0x6f, 0x46, 0xdf, 0x47, 0x4f, 0x47, 0xbf, 0x48, 0x2f, 0x48, 0x9f, 0x7e, - 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4d, - 0x96, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x89, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x89, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xb9, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xb9, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x18, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xb9, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x50, - 0xcb, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x8b, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8b, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xba, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xba, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x19, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xba, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x54, - 0x00, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x8d, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8d, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbb, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbb, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1a, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbb, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x57, - 0x35, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x8f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbc, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbc, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1b, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbc, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x81, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5a, - 0x6a, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x91, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x91, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbd, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbd, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1c, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbd, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5d, - 0x9f, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x93, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x93, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbe, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbe, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1d, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbe, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x60, - 0xd4, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x95, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x95, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbf, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xbf, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1e, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xbf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, - 0x27, 0x01, 0x87, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x64, - 0x09, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, - 0x97, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x97, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xc0, 0x80, 0x2e, - 0x7e, 0x63, 0x01, 0xc0, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, - 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1f, 0x6c, 0x00, - 0x7a, 0x03, 0x01, 0xc0, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0xc2, - 0xaf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0xa9, 0x32, 0xf2, 0x1a, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, - 0x00, 0x00, 0x78, 0x10, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 0x40, 0x09, 0x85, 0x31, 0x2f, 0x12, 0x7e, - 0x30, 0x75, 0xf6, 0x00, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, - 0xf0, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xd2, 0x01, 0x75, 0x2f, 0x89, 0x12, 0x7e, 0x30, 0x7e, - 0x14, 0x80, 0x00, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xd8, 0x20, 0x70, 0x5a, - 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xf0, 0x20, 0x71, 0x4b, 0xa5, - 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x08, 0xa5, 0x0a, 0x09, 0xb1, 0x00, - 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x20, 0x20, 0x72, 0x30, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, - 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x38, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, - 0x4a, 0x50, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x68, 0xa5, 0x0a, - 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x80, 0x30, 0x04, 0x0c, 0xc2, 0x04, 0xc0, - 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, - 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x75, 0x2f, 0x80, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x81, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x66, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x82, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x83, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x66, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x84, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x85, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x67, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x86, 0x12, 0x7e, 0x30, 0x54, 0x3e, - 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, - 0x75, 0x2f, 0x87, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, - 0x67, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x10, 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, - 0x08, 0x22, 0x75, 0x2f, 0xa0, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, - 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, - 0x03, 0x12, 0x4d, 0x96, 0x30, 0x30, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x08, 0x22, 0x30, 0xe6, 0x02, - 0xd2, 0x60, 0x7e, 0x37, 0x01, 0x79, 0x7e, 0x27, 0x01, 0x99, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, - 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, - 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, - 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x60, 0xc4, 0x22, 0xc2, - 0x60, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, - 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x99, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x99, 0x7e, 0x37, 0x01, - 0x79, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, - 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, - 0x59, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x0d, 0xcd, - 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x09, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, - 0x59, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4b, 0x0b, 0x22, 0xd2, 0x08, 0x7e, - 0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x75, 0x2f, 0x94, 0x12, 0x7e, - 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, - 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, - 0x7e, 0x27, 0x01, 0xa9, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, - 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, - 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, - 0x00, 0x00, 0x2e, 0x27, 0x01, 0xa9, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, - 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, - 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0x80, 0x7f, 0x7a, 0x51, - 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x00, 0x00, 0x2e, 0x67, - 0x01, 0xa9, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, - 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, - 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, - 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, - 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, - 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, - 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, - 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, - 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, - 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, - 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, - 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, - 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4c, 0x6f, 0x75, - 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, - 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0xda, - 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4c, 0x6f, 0xda, 0xb8, 0x02, - 0x4d, 0x96, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, - 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, - 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, - 0x50, 0x80, 0x02, 0xc2, 0x50, 0x12, 0x42, 0xac, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, - 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, - 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, - 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, - 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4c, 0xc3, 0x75, - 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x09, 0x01, - 0x22, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x75, 0x2f, 0xa1, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x81, - 0x00, 0x80, 0x06, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, - 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x50, 0xcb, 0x30, 0x31, 0x06, 0x20, 0xe6, 0x4f, 0xd2, - 0x09, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x61, 0x7e, 0x37, 0x01, 0x7b, 0x7e, 0x27, 0x01, 0x9b, 0x9d, - 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 0x37, 0x01, 0x7b, 0x7e, - 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, - 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, - 0x10, 0x61, 0xc4, 0x22, 0xc2, 0x61, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, - 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9b, 0x28, 0x04, 0x7e, 0x27, - 0x01, 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, - 0x7a, 0x37, 0x01, 0x7b, 0x7e, 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, - 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, - 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0x9e, 0x44, 0x11, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x0d, 0xcd, 0x7d, 0x24, - 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5b, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4e, - 0x40, 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, - 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, - 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xab, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, - 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, - 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, - 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, 0x01, 0xab, 0x1b, 0x38, 0x20, 0x0b, 0x35, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, - 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, - 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, - 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, - 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xab, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, - 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, - 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, - 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, - 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, - 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, - 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, - 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, - 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, - 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, - 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, - 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, - 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, - 0xe7, 0x02, 0x4f, 0xa4, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, - 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, - 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, - 0x4f, 0xa4, 0xda, 0xb8, 0x02, 0x50, 0xcb, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, - 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, - 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, - 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x12, 0x42, 0xc3, 0x02, 0x65, 0x9c, - 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, - 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, - 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, - 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, - 0x22, 0x02, 0x4f, 0xf8, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, - 0x30, 0x22, 0x10, 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x75, 0x2f, 0xa2, 0x12, - 0x7e, 0x30, 0x7e, 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, - 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x54, 0x00, 0x30, 0x32, - 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0a, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x62, 0x7e, 0x37, 0x01, 0x7d, - 0x7e, 0x27, 0x01, 0x9d, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, - 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xcc, - 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, - 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x62, 0xc4, 0x22, 0xc2, 0x62, 0x2d, 0x23, 0x68, 0x78, 0x6d, - 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, - 0x9d, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x9d, 0x32, 0x7d, 0x02, 0x2e, - 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, - 0x42, 0xbe, 0x44, 0x15, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, - 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x15, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, - 0x34, 0x11, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5d, 0x12, 0x68, 0x34, 0xbe, 0x25, - 0x20, 0x78, 0x03, 0x02, 0x51, 0x75, 0x22, 0xd2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, - 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, - 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, - 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xad, 0x2e, 0x24, - 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, - 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, - 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xad, - 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, - 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, - 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, - 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, - 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x02, 0x00, 0x2e, 0x67, 0x01, 0xad, 0x9e, 0x24, 0x00, 0x02, - 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, - 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, - 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, - 0x23, 0x23, 0x44, 0x02, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, - 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, - 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, - 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, - 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, - 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, - 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, - 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, - 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, - 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x52, 0xd9, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, - 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, - 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, - 0x68, 0x07, 0xca, 0xb8, 0x12, 0x52, 0xd9, 0xda, 0xb8, 0x02, 0x54, 0x00, 0x09, 0xb1, 0x00, 0x18, - 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, - 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, - 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x12, - 0x42, 0xda, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, - 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, - 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, - 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, - 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x53, 0x2d, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, - 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, - 0x22, 0x75, 0x2f, 0xa3, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, + 0x74, 0x07, 0xa9, 0x20, 0x30, 0x0b, 0xa9, 0x35, 0x30, 0x05, 0xbe, 0x20, 0x01, 0x28, 0x02, 0x74, + 0x0f, 0x19, 0xb0, 0x00, 0x04, 0xa9, 0x33, 0x30, 0x18, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x74, + 0x28, 0xa9, 0x20, 0x30, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 0x74, 0x03, 0x19, 0xb0, 0x00, + 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 0x00, 0x10, 0x22, 0x7e, 0x04, + 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 0x00, 0x10, 0x54, 0x08, 0x19, + 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, + 0x22, 0x41, 0xa5, 0x89, 0x24, 0x41, 0xb5, 0x41, 0xd4, 0x41, 0xf3, 0x42, 0x12, 0x42, 0x31, 0x42, + 0x50, 0x42, 0x6f, 0x42, 0x8e, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x20, 0xc2, 0x08, 0x7e, 0x04, 0x09, + 0xe3, 0x7a, 0x07, 0x01, 0x6f, 0x7a, 0x07, 0x01, 0x7f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x8f, 0x7a, + 0x07, 0x01, 0x9f, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x21, 0xc2, 0x09, 0x7e, 0x04, 0x0d, 0xe3, + 0x7a, 0x07, 0x01, 0x71, 0x7a, 0x07, 0x01, 0x81, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x91, 0x7a, 0x07, + 0x01, 0xa1, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x22, 0xc2, 0x0a, 0x7e, 0x04, 0x11, 0xe3, 0x7a, + 0x07, 0x01, 0x73, 0x7a, 0x07, 0x01, 0x83, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x93, 0x7a, 0x07, 0x01, + 0xa3, 0x22, 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x23, 0xc2, 0x0b, 0x7e, 0x04, 0x15, 0xe3, 0x7a, 0x07, + 0x01, 0x75, 0x7a, 0x07, 0x01, 0x85, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x95, 0x7a, 0x07, 0x01, 0xa5, + 0x22, 0xc2, 0x14, 0xc2, 0x1c, 0xc2, 0x24, 0xc2, 0x0c, 0x7e, 0x04, 0x19, 0xe3, 0x7a, 0x07, 0x01, + 0x77, 0x7a, 0x07, 0x01, 0x87, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x97, 0x7a, 0x07, 0x01, 0xa7, 0x22, + 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 0x25, 0xc2, 0x0d, 0x7e, 0x04, 0x1d, 0xe3, 0x7a, 0x07, 0x01, 0x79, + 0x7a, 0x07, 0x01, 0x89, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x99, 0x7a, 0x07, 0x01, 0xa9, 0x22, 0xc2, + 0x16, 0xc2, 0x1e, 0xc2, 0x26, 0xc2, 0x0e, 0x7e, 0x04, 0x21, 0xe3, 0x7a, 0x07, 0x01, 0x7b, 0x7a, + 0x07, 0x01, 0x8b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x9b, 0x7a, 0x07, 0x01, 0xab, 0x22, 0xc2, 0x17, + 0xc2, 0x1f, 0xc2, 0x27, 0xc2, 0x0f, 0x7e, 0x04, 0x25, 0xe3, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, + 0x01, 0x8d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x9d, 0x7a, 0x07, 0x01, 0xad, 0x22, 0x7c, 0xb2, 0x23, + 0x0a, 0x2b, 0x49, 0x22, 0x42, 0xb8, 0x89, 0x24, 0x42, 0xc8, 0x42, 0xe9, 0x43, 0x0a, 0x43, 0x2b, + 0x43, 0x4c, 0x43, 0x6d, 0x43, 0x8e, 0x43, 0xaf, 0x30, 0x50, 0x07, 0x20, 0x68, 0x04, 0xc2, 0x28, + 0x80, 0x16, 0x30, 0x40, 0x07, 0x20, 0x60, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, + 0x58, 0x04, 0xc2, 0x28, 0x80, 0x02, 0xd2, 0x28, 0x22, 0x30, 0x51, 0x07, 0x20, 0x69, 0x04, 0xc2, + 0x29, 0x80, 0x16, 0x30, 0x41, 0x07, 0x20, 0x61, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 0x07, + 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x52, 0x07, 0x20, 0x6a, 0x04, + 0xc2, 0x2a, 0x80, 0x16, 0x30, 0x42, 0x07, 0x20, 0x62, 0x04, 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, + 0x07, 0x20, 0x5a, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2a, 0x22, 0x30, 0x53, 0x07, 0x20, 0x6b, + 0x04, 0xc2, 0x2b, 0x80, 0x16, 0x30, 0x43, 0x07, 0x20, 0x63, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, + 0x4b, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x54, 0x07, 0x20, + 0x6c, 0x04, 0xc2, 0x2c, 0x80, 0x16, 0x30, 0x44, 0x07, 0x20, 0x64, 0x04, 0xc2, 0x2c, 0x80, 0x0c, + 0x30, 0x4c, 0x07, 0x20, 0x5c, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 0x30, 0x55, 0x07, + 0x20, 0x6d, 0x04, 0xc2, 0x2d, 0x80, 0x16, 0x30, 0x45, 0x07, 0x20, 0x65, 0x04, 0xc2, 0x2d, 0x80, + 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x56, + 0x07, 0x20, 0x6e, 0x04, 0xc2, 0x2e, 0x80, 0x16, 0x30, 0x46, 0x07, 0x20, 0x66, 0x04, 0xc2, 0x2e, + 0x80, 0x0c, 0x30, 0x4e, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, + 0x57, 0x07, 0x20, 0x6f, 0x04, 0xc2, 0x2f, 0x80, 0x16, 0x30, 0x47, 0x07, 0x20, 0x67, 0x04, 0xc2, + 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x02, 0xd2, 0x2f, 0x22, + 0x44, 0x38, 0x43, 0xe5, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 0x0a, 0x5b, 0x49, 0x55, 0x43, + 0xd0, 0x99, 0x54, 0xd3, 0x22, 0xa9, 0xc5, 0x87, 0x12, 0x44, 0x43, 0x7e, 0x04, 0x05, 0xe3, 0x7a, + 0x07, 0x01, 0xd7, 0x7a, 0x07, 0x01, 0xd9, 0x7e, 0x04, 0x01, 0xe3, 0x7a, 0x07, 0x01, 0xdd, 0x7a, + 0x07, 0x01, 0xdf, 0x7e, 0x04, 0x74, 0xad, 0x7a, 0x05, 0x61, 0x75, 0xf1, 0x01, 0x75, 0xe1, 0x1f, + 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x75, 0xf1, 0x02, 0x75, 0xe1, 0x03, 0x75, 0xe4, 0x04, 0x75, + 0xf4, 0x04, 0x43, 0xa2, 0x1c, 0x12, 0x40, 0xeb, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x9a, 0x0b, 0x20, + 0xbe, 0x21, 0x2f, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0xa9, 0xd5, 0x87, 0x12, 0x44, 0x43, 0xd2, 0x92, + 0xc2, 0xa8, 0x22, 0x75, 0xa3, 0x00, 0x53, 0xa2, 0x03, 0x75, 0xc1, 0x00, 0x53, 0xc0, 0x03, 0x7e, + 0x00, 0x05, 0x7a, 0x01, 0xf1, 0x43, 0xf4, 0x80, 0x43, 0xe4, 0x80, 0xe5, 0xf2, 0x54, 0x7f, 0x44, + 0x08, 0xf5, 0xf2, 0xe5, 0xe2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xe2, 0x75, 0xe1, 0x10, 0xa5, 0xd8, + 0xe1, 0x22, 0xca, 0x09, 0x12, 0x30, 0x20, 0x10, 0x01, 0x12, 0xd5, 0x67, 0x1e, 0x63, 0x69, 0x01, + 0x7e, 0x00, 0x6a, 0x2e, 0x01, 0x69, 0xa5, 0xe6, 0xf5, 0x67, 0x80, 0x12, 0x20, 0x02, 0x1e, 0x75, + 0x69, 0x00, 0x85, 0x6a, 0x67, 0xd2, 0x02, 0x74, 0x00, 0x80, 0x0d, 0x30, 0x02, 0x0f, 0xc2, 0x02, + 0x7e, 0x00, 0x6c, 0x2e, 0x01, 0x69, 0xa5, 0xe6, 0x53, 0x90, 0xcf, 0x42, 0x90, 0xda, 0x09, 0x32, + 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, 0xf0, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xd2, 0x01, + 0x75, 0x31, 0x89, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x80, 0x00, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, + 0x03, 0x02, 0x45, 0x4f, 0x20, 0x78, 0x5a, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, + 0x02, 0x45, 0x67, 0x20, 0x79, 0x4b, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, + 0x45, 0x7f, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, 0x97, 0x20, 0x7a, + 0x30, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, 0xaf, 0xa5, 0x0a, 0x09, + 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, 0xc7, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, + 0xe0, 0x03, 0x02, 0x45, 0xdf, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x45, + 0xf7, 0x30, 0x04, 0x0c, 0xc2, 0x04, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, + 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x75, + 0x31, 0x80, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, + 0x2b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x81, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0x6b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, + 0x31, 0x82, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, + 0xab, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x83, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0xeb, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, + 0x31, 0x84, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, + 0x2b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x85, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, 0x6b, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, + 0x31, 0x86, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, + 0xab, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x75, 0x31, 0x87, 0x12, 0x7c, 0x15, 0x54, 0x3e, 0x0a, + 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x64, 0xeb, 0xca, 0x06, 0xc6, 0x44, 0x89, 0x54, 0x10, + 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x75, 0x31, 0xa0, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x49, 0x30, 0x20, 0xe6, 0x03, 0xd2, 0x08, + 0x22, 0x30, 0x30, 0x49, 0xd2, 0x70, 0x7e, 0x37, 0x01, 0x8f, 0x7e, 0x27, 0x01, 0xaf, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x48, 0x7a, 0x05, 0x48, 0x7a, 0x37, 0x01, 0x8f, 0x7e, 0x37, + 0x01, 0x6f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x6f, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x70, 0xc4, 0x22, 0xc2, 0x70, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x8f, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xaf, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xaf, 0x7e, 0x37, 0x01, 0x8f, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x48, 0x7a, 0x05, 0x48, 0x7a, + 0x37, 0x01, 0x8f, 0x7e, 0x37, 0x01, 0x6f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x6f, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x0d, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x09, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x6f, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x46, 0x7f, + 0x22, 0xd2, 0x08, 0x7e, 0x04, 0x09, 0xe3, 0x7a, 0x07, 0x01, 0x6f, 0x7a, 0x07, 0x01, 0x7f, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xbf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x00, 0x00, 0x2e, 0x27, 0x01, 0xbf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x00, 0x00, 0x2e, 0x67, 0x01, 0xbf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x47, 0xe3, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x10, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x47, + 0xe3, 0xda, 0xb8, 0x02, 0x49, 0x30, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x68, 0x80, 0x02, 0xc2, 0x68, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x60, 0x80, 0x02, + 0xc2, 0x60, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0x12, + 0x42, 0xc8, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x48, 0x35, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x09, 0x01, 0x22, 0x20, 0x29, 0x03, 0xd2, 0x09, + 0x22, 0x75, 0x31, 0xa1, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x81, 0x00, 0x80, 0x06, 0x20, 0x29, 0x03, + 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x4c, 0x88, 0x20, 0xe6, 0x03, 0xd2, 0x09, 0x22, 0x30, 0x31, 0x49, 0xd2, 0x71, 0x7e, 0x37, + 0x01, 0x91, 0x7e, 0x27, 0x01, 0xb1, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x4a, 0x7a, + 0x05, 0x4a, 0x7a, 0x37, 0x01, 0x91, 0x7e, 0x37, 0x01, 0x71, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x11, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x71, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x71, 0xc4, 0x22, 0xc2, 0x71, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x91, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xb1, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xb1, 0x7e, 0x37, 0x01, 0x91, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x4a, 0x7a, 0x05, 0x4a, 0x7a, 0x37, 0x01, 0x91, 0x7e, 0x37, 0x01, 0x71, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x71, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x11, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x0d, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x71, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x49, 0xd7, 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x0d, 0xe3, 0x7a, + 0x07, 0x01, 0x71, 0x7a, 0x07, 0x01, 0x81, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc1, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, + 0x01, 0xc1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xc1, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4b, 0x3b, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4b, 0x3b, 0xda, 0xb8, 0x02, 0x4c, 0x88, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x69, 0x80, 0x02, 0xc2, 0x69, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x61, 0x80, 0x02, 0xc2, 0x61, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0x12, 0x42, 0xe9, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4b, + 0x8d, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, + 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x75, 0x31, 0xa2, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x4f, 0xe0, 0x20, 0xe6, 0x03, 0xd2, 0x0a, + 0x22, 0x30, 0x32, 0x49, 0xd2, 0x72, 0x7e, 0x37, 0x01, 0x93, 0x7e, 0x27, 0x01, 0xb3, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x4c, 0x7a, 0x05, 0x4c, 0x7a, 0x37, 0x01, 0x93, 0x7e, 0x37, + 0x01, 0x73, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x73, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x72, 0xc4, 0x22, 0xc2, 0x72, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x93, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xb3, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xb3, 0x7e, 0x37, 0x01, 0x93, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x4c, 0x7a, 0x05, 0x4c, 0x7a, + 0x37, 0x01, 0x93, 0x7e, 0x37, 0x01, 0x73, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x73, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x15, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x11, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x73, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4d, 0x2f, + 0x22, 0xd2, 0x0a, 0x7e, 0x04, 0x11, 0xe3, 0x7a, 0x07, 0x01, 0x73, 0x7a, 0x07, 0x01, 0x83, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc3, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xc3, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x02, 0x00, 0x2e, 0x67, 0x01, 0xc3, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x02, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x4e, 0x93, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4e, + 0x93, 0xda, 0xb8, 0x02, 0x4f, 0xe0, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x6a, 0x80, 0x02, 0xc2, 0x6a, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x62, 0x80, 0x02, + 0xc2, 0x62, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0x12, + 0x43, 0x0a, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4e, 0xe5, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, + 0x22, 0x75, 0x31, 0xa3, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, 0xd2, 0x0b, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, - 0x12, 0x57, 0x35, 0x30, 0x33, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0b, 0x22, 0x30, 0xe6, 0x02, 0xd2, - 0x63, 0x7e, 0x37, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x9f, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, - 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 0x5f, 0x7d, 0x43, 0x2d, - 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5f, 0x75, 0x2f, 0x94, 0x12, 0x7e, - 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x63, 0xc4, 0x22, 0xc2, 0x63, - 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, - 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9f, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9f, 0x7e, 0x37, 0x01, 0x7f, - 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, - 0x01, 0x5f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5f, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x19, 0xcd, 0x9d, - 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x15, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5f, - 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x54, 0xaa, 0x22, 0xd2, 0x0b, 0x7e, 0x04, - 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 0x01, 0x6f, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, - 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, - 0x27, 0x01, 0xaf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, - 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, - 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x03, - 0x00, 0x2e, 0x27, 0x01, 0xaf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, - 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, - 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, - 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, - 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, - 0xaf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, - 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, - 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, - 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, - 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, - 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, - 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, - 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, - 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, - 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, - 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, - 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, - 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x56, 0x0e, 0x75, 0x2f, - 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, - 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, - 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x56, 0x0e, 0xda, 0xb8, 0x02, 0x57, - 0x35, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, - 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, - 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, - 0x80, 0x02, 0xc2, 0x53, 0x12, 0x42, 0xf1, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, - 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, - 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, - 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, - 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x56, 0x62, 0x75, 0x2f, - 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0c, 0x01, 0x22, - 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x2f, 0xa4, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x84, 0x00, - 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, - 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5a, 0x6a, 0x30, 0x34, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0c, - 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x64, 0x7e, 0x37, 0x01, 0x81, 0x7e, 0x27, 0x01, 0xa1, 0x9d, 0x32, - 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, - 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x61, - 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, - 0x64, 0xc4, 0x22, 0xc2, 0x64, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, - 0x81, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa1, 0x28, 0x04, 0x7e, 0x27, 0x01, - 0xa1, 0x7e, 0x37, 0x01, 0x81, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, - 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, - 0x13, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, - 0x9e, 0x44, 0x1d, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x19, 0xcd, 0x7d, 0x24, 0x2d, - 0x43, 0x7a, 0x47, 0x01, 0x61, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x57, 0xdf, - 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, - 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, - 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb1, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, - 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, - 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, - 0x01, 0xc9, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 0xb1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, - 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, - 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x12, 0x53, 0x38, 0x20, 0xe6, 0x03, 0xd2, 0x0b, 0x22, 0x30, 0x33, 0x49, 0xd2, 0x73, 0x7e, 0x37, + 0x01, 0x95, 0x7e, 0x27, 0x01, 0xb5, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x4e, 0x7a, + 0x05, 0x4e, 0x7a, 0x37, 0x01, 0x95, 0x7e, 0x37, 0x01, 0x75, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x19, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x75, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x73, 0xc4, 0x22, 0xc2, 0x73, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x95, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xb5, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xb5, 0x7e, 0x37, 0x01, 0x95, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x4e, 0x7a, 0x05, 0x4e, 0x7a, 0x37, 0x01, 0x95, 0x7e, 0x37, 0x01, 0x75, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x19, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x75, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x19, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x15, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x75, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x50, 0x87, 0x22, 0xd2, 0x0b, 0x7e, 0x04, 0x15, 0xe3, 0x7a, + 0x07, 0x01, 0x75, 0x7a, 0x07, 0x01, 0x85, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc5, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x03, 0x00, 0x2e, 0x27, + 0x01, 0xc5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, 0xc5, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x51, 0xeb, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x51, 0xeb, 0xda, 0xb8, 0x02, 0x53, 0x38, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6b, 0x80, 0x02, 0xc2, 0x6b, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x63, 0x80, 0x02, 0xc2, 0x63, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0x12, 0x43, 0x2b, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x52, + 0x3d, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, + 0x0c, 0x01, 0x22, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x31, 0xa4, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x84, 0x00, 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x56, 0x90, 0x20, 0xe6, 0x03, 0xd2, 0x0c, + 0x22, 0x30, 0x34, 0x49, 0xd2, 0x74, 0x7e, 0x37, 0x01, 0x97, 0x7e, 0x27, 0x01, 0xb7, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x50, 0x7a, 0x05, 0x50, 0x7a, 0x37, 0x01, 0x97, 0x7e, 0x37, + 0x01, 0x77, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x77, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x74, 0xc4, 0x22, 0xc2, 0x74, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x97, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xb7, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xb7, 0x7e, 0x37, 0x01, 0x97, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x50, 0x7a, 0x05, 0x50, 0x7a, + 0x37, 0x01, 0x97, 0x7e, 0x37, 0x01, 0x77, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x77, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x1d, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x19, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x77, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x53, 0xdf, + 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x19, 0xe3, 0x7a, 0x07, 0x01, 0x77, 0x7a, 0x07, 0x01, 0x87, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 0xc7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x14, 0x22, - 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, - 0x04, 0x00, 0x2e, 0x67, 0x01, 0xb1, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, - 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, - 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x04, 0x00, 0x2e, 0x67, 0x01, 0xc7, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x04, 0x7a, 0x69, - 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, - 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, - 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, - 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, - 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, - 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, - 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, - 0x02, 0x59, 0x43, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0x02, 0x55, 0x43, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, - 0xd2, 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x59, - 0x43, 0xda, 0xb8, 0x02, 0x5a, 0x6a, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, - 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, - 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, - 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x12, 0x43, 0x08, 0x02, 0x65, 0x9c, 0x75, - 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, - 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, - 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, - 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, - 0x02, 0x59, 0x97, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, - 0x22, 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x75, 0x2f, 0xa5, 0x12, 0x7e, - 0x30, 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, - 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5d, 0x9f, 0x30, 0x35, 0x06, - 0x20, 0xe6, 0x4f, 0xd2, 0x0d, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x65, 0x7e, 0x37, 0x01, 0x83, 0x7e, - 0x27, 0x01, 0xa3, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 0x7a, 0x05, 0x3c, 0x7a, - 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x21, 0xcc, 0x38, - 0x68, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, - 0x30, 0x12, 0x68, 0x34, 0x10, 0x65, 0xc4, 0x22, 0xc2, 0x65, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, - 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa3, - 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa3, 0x7e, 0x37, 0x01, 0x83, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, - 0x3c, 0x7a, 0x05, 0x3c, 0x7a, 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, - 0xbe, 0x44, 0x21, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, - 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x21, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, - 0x1d, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x63, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, - 0x78, 0x03, 0x02, 0x5b, 0x14, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, - 0x7a, 0x07, 0x01, 0x73, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, - 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, - 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb3, 0x2e, 0x24, 0x00, - 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, - 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, - 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, 0x01, 0xb3, 0x1b, - 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, - 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, - 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, - 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, - 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 0x01, 0xb3, 0x9e, 0x24, 0x00, 0x02, 0x40, - 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, - 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, - 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, - 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, - 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, - 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, - 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, - 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, - 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, - 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, - 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, - 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, - 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5c, 0x78, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, + 0xd2, 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x55, + 0x43, 0xda, 0xb8, 0x02, 0x56, 0x90, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x6c, 0x80, 0x02, 0xc2, 0x6c, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x64, 0x80, 0x02, + 0xc2, 0x64, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0x12, + 0x43, 0x4c, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x55, 0x95, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, + 0x22, 0x75, 0x31, 0xa5, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, + 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x59, 0xe8, 0x20, 0xe6, 0x03, 0xd2, 0x0d, 0x22, 0x30, 0x35, 0x49, 0xd2, 0x75, 0x7e, 0x37, + 0x01, 0x99, 0x7e, 0x27, 0x01, 0xb9, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x52, 0x7a, + 0x05, 0x52, 0x7a, 0x37, 0x01, 0x99, 0x7e, 0x37, 0x01, 0x79, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x21, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x79, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x75, 0xc4, 0x22, 0xc2, 0x75, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x99, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xb9, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xb9, 0x7e, 0x37, 0x01, 0x99, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x52, 0x7a, 0x05, 0x52, 0x7a, 0x37, 0x01, 0x99, 0x7e, 0x37, 0x01, 0x79, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x21, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x79, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x21, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x1d, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x79, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x57, 0x37, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x1d, 0xe3, 0x7a, + 0x07, 0x01, 0x79, 0x7a, 0x07, 0x01, 0x89, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xc9, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, + 0x01, 0xc9, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, - 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, - 0x07, 0xca, 0xb8, 0x12, 0x5c, 0x78, 0xda, 0xb8, 0x02, 0x5d, 0x9f, 0x09, 0xb1, 0x00, 0x18, 0x7e, - 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, - 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, - 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 0x02, 0xc2, 0x55, 0x12, 0x43, - 0x1f, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, - 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, - 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, - 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, - 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5c, 0xcc, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, - 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0e, 0x01, 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, - 0x75, 0x2f, 0xa6, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x86, 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, - 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, - 0x60, 0xd4, 0x30, 0x36, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0e, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x66, - 0x7e, 0x37, 0x01, 0x85, 0x7e, 0x27, 0x01, 0xa5, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, - 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, - 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x65, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x66, 0xc4, 0x22, 0xc2, 0x66, 0x2d, - 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x68, - 0x6a, 0xbe, 0x27, 0x01, 0xa5, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa5, 0x7e, 0x37, 0x01, 0x85, 0x9d, - 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, - 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x65, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, - 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x25, 0xcd, 0x9d, 0x24, - 0x12, 0x68, 0x34, 0x7e, 0x34, 0x21, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x65, 0x12, - 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5e, 0x49, 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x21, - 0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, - 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, - 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, - 0x01, 0xb5, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, - 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, - 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x06, 0x00, - 0x2e, 0x27, 0x01, 0xb5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, - 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, - 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, - 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, - 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x06, 0x00, 0x2e, 0x67, 0x01, 0xb5, - 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, - 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, - 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, - 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, - 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, - 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, - 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, - 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, - 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, - 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, - 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, - 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, - 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5f, 0xad, 0x75, 0x2f, 0x99, - 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, - 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, - 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5f, 0xad, 0xda, 0xb8, 0x02, 0x60, 0xd4, - 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, - 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, - 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, - 0x02, 0xc2, 0x56, 0x12, 0x43, 0x36, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, - 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, - 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, - 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, - 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x60, 0x01, 0x75, 0x2f, 0x95, - 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, - 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x75, 0x2f, 0xa7, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x87, 0x00, 0x80, - 0x06, 0x20, 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, - 0xda, 0xb8, 0x68, 0x03, 0x12, 0x64, 0x09, 0x30, 0x37, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0f, 0x22, - 0x30, 0xe6, 0x02, 0xd2, 0x67, 0x7e, 0x37, 0x01, 0x87, 0x7e, 0x27, 0x01, 0xa7, 0x9d, 0x32, 0x40, - 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 0x87, 0x7e, 0x37, 0x01, - 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x67, 0x75, - 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x67, - 0xc4, 0x22, 0xc2, 0x67, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x87, - 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa7, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa7, - 0x7e, 0x37, 0x01, 0x87, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, - 0x01, 0x87, 0x7e, 0x37, 0x01, 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x13, - 0x7a, 0x47, 0x01, 0x67, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, - 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, - 0x44, 0x29, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x25, 0xcd, 0x7d, 0x24, 0x2d, 0x43, - 0x7a, 0x47, 0x01, 0x67, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x61, 0x7e, 0x22, - 0xd2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x75, 0x2f, - 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, - 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, - 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, - 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, - 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, - 0xc9, 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, 0x01, 0xb7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, - 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, - 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, - 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, - 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x07, - 0x00, 0x2e, 0x67, 0x01, 0xb7, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, - 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, - 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, - 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, - 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, - 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, - 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, - 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, - 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, - 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, - 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, - 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, - 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, - 0x62, 0xe2, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, - 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, - 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x62, 0xe2, - 0xda, 0xb8, 0x02, 0x64, 0x09, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, - 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, - 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, - 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x12, 0x43, 0x4d, 0x02, 0x65, 0x9c, 0x75, 0x2f, - 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, - 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, - 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, - 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, - 0x63, 0x36, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, - 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, - 0x20, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, - 0xd2, 0x50, 0x80, 0x02, 0xc2, 0x50, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, - 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, - 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x02, - 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, - 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, - 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, - 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, - 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, - 0x53, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, - 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, - 0x50, 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, - 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, - 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, - 0x02, 0xc2, 0x55, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, - 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, - 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 0x02, 0xc2, 0x56, 0x02, 0x65, 0x88, 0x7c, - 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, - 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, - 0x57, 0x80, 0x02, 0xc2, 0x57, 0x02, 0x65, 0x88, 0x54, 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, - 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0x22, 0xca, 0x19, 0x5e, 0x20, - 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, - 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, 0x64, 0x00, 0x02, 0x02, 0x65, 0xe7, 0xca, - 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, - 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, - 0x7e, 0x64, 0x00, 0x03, 0x02, 0x65, 0xe7, 0xd2, 0x04, 0x7e, 0x27, 0x01, 0xcb, 0x2d, 0x26, 0xbe, - 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7e, 0x79, 0xa0, - 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, - 0x01, 0xcb, 0x7e, 0x25, 0x30, 0x2d, 0x26, 0x7a, 0x25, 0x30, 0x7a, 0x07, 0x01, 0xc9, 0xda, 0x19, - 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0x9a, 0x12, 0x7e, 0x30, 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, - 0x01, 0xcd, 0x80, 0xd7, 0x4d, 0x42, 0x4a, 0xae, 0x4b, 0xa8, 0x4d, 0x7b, 0x49, 0x4f, 0x49, 0x4f, - 0x4c, 0xa7, 0x49, 0x4f, 0x4d, 0xbf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x4d, 0xc6, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x50, 0x77, 0x4d, 0xe3, 0x4e, 0xdd, 0x50, 0xb0, 0x49, 0x4f, 0x49, 0x4f, - 0x4f, 0xdc, 0x49, 0x4f, 0x50, 0xf4, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x50, 0xfb, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x53, 0xac, 0x51, 0x18, 0x52, 0x12, 0x53, 0xe5, 0x49, 0x4f, 0x49, 0x4f, - 0x53, 0x11, 0x49, 0x4f, 0x54, 0x29, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x54, 0x30, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x56, 0xe1, 0x54, 0x4d, 0x55, 0x47, 0x57, 0x1a, 0x49, 0x4f, 0x49, 0x4f, - 0x56, 0x46, 0x49, 0x4f, 0x57, 0x5e, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x57, 0x65, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x16, 0x57, 0x82, 0x58, 0x7c, 0x5a, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x59, 0x7b, 0x49, 0x4f, 0x5a, 0x93, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x9a, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5d, 0x4b, 0x5a, 0xb7, 0x5b, 0xb1, 0x5d, 0x84, 0x49, 0x4f, 0x49, 0x4f, - 0x5c, 0xb0, 0x49, 0x4f, 0x5d, 0xc8, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x5d, 0xcf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x60, 0x80, 0x5d, 0xec, 0x5e, 0xe6, 0x60, 0xb9, 0x49, 0x4f, 0x49, 0x4f, - 0x5f, 0xe5, 0x49, 0x4f, 0x60, 0xfd, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x61, 0x04, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x63, 0xb5, 0x61, 0x21, 0x62, 0x1b, 0x63, 0xee, 0x49, 0x4f, 0x49, 0x4f, - 0x63, 0x1a, 0x49, 0x4f, 0x64, 0x32, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x64, 0x39, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, - 0x49, 0x4f, 0x49, 0x4f, 0xca, 0x29, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x10, 0x9c, 0xb5, - 0xa4, 0x2e, 0x54, 0x68, 0x51, 0x89, 0x54, 0x7e, 0x39, 0x00, 0x7a, 0x19, 0x00, 0x0b, 0x34, 0x80, - 0xe9, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, - 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, - 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, - 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 0x01, 0xc9, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x58, 0x9b, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x58, 0x9b, 0xda, 0xb8, 0x02, 0x59, 0xe8, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6d, 0x80, 0x02, 0xc2, 0x6d, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x65, 0x80, 0x02, 0xc2, 0x65, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0x12, 0x43, 0x6d, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x58, + 0xed, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, + 0x0e, 0x01, 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x75, 0x31, 0xa6, 0x12, 0x7c, 0x15, 0x7e, + 0x14, 0x86, 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5d, 0x40, 0x20, 0xe6, 0x03, 0xd2, 0x0e, + 0x22, 0x30, 0x36, 0x49, 0xd2, 0x76, 0x7e, 0x37, 0x01, 0x9b, 0x7e, 0x27, 0x01, 0xbb, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x54, 0x7a, 0x05, 0x54, 0x7a, 0x37, 0x01, 0x9b, 0x7e, 0x37, + 0x01, 0x7b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x7b, + 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, + 0x76, 0xc4, 0x22, 0xc2, 0x76, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x9b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xbb, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xbb, 0x7e, 0x37, 0x01, 0x9b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x54, 0x7a, 0x05, 0x54, 0x7a, + 0x37, 0x01, 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xe2, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x7b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, + 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x25, 0xe3, 0x9d, 0x24, 0x12, 0x65, 0x2b, 0x7e, 0x34, 0x21, 0xe3, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x7b, 0x12, 0x65, 0x2b, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5a, 0x8f, + 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x21, 0xe3, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 0x07, 0x01, 0x8b, 0x75, + 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, + 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xcb, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, + 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xdf, 0x7e, 0x24, 0x06, 0x00, 0x2e, 0x27, 0x01, 0xcb, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, + 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, + 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, + 0x06, 0x00, 0x2e, 0x67, 0x01, 0xcb, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, + 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, + 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, + 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x5b, 0xf3, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5b, + 0xf3, 0xda, 0xb8, 0x02, 0x5d, 0x40, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, + 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, + 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, + 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, + 0x6e, 0x80, 0x02, 0xc2, 0x6e, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x66, 0x80, 0x02, + 0xc2, 0x66, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0x12, + 0x43, 0x8e, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5c, 0x45, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, + 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, 0x2f, 0x03, 0xd2, 0x0f, + 0x22, 0x75, 0x31, 0xa7, 0x12, 0x7c, 0x15, 0x7e, 0x14, 0x87, 0x00, 0x80, 0x06, 0x20, 0x2f, 0x03, + 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x60, 0x98, 0x20, 0xe6, 0x03, 0xd2, 0x0f, 0x22, 0x30, 0x37, 0x49, 0xd2, 0x77, 0x7e, 0x37, + 0x01, 0x9d, 0x7e, 0x27, 0x01, 0xbd, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x56, 0x7a, + 0x05, 0x56, 0x7a, 0x37, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x29, 0xe2, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x7d, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x7a, 0x51, + 0x31, 0x12, 0x7c, 0x15, 0x12, 0x65, 0x2b, 0x10, 0x77, 0xc4, 0x22, 0xc2, 0x77, 0x2d, 0x23, 0x68, + 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x9d, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, + 0x27, 0x01, 0xbd, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xbd, 0x7e, 0x37, 0x01, 0x9d, 0x9d, 0x32, 0x7d, + 0x02, 0x2e, 0x05, 0x56, 0x7a, 0x05, 0x56, 0x7a, 0x37, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xe2, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x7d, 0x75, 0x31, 0x94, + 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x02, 0x65, 0x2b, 0x75, 0x31, 0x94, 0x12, + 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x29, 0xe3, 0x9d, 0x24, 0x12, 0x65, + 0x2b, 0x7e, 0x34, 0x25, 0xe3, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x7d, 0x12, 0x65, 0x2b, + 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5d, 0xe7, 0x22, 0xd2, 0x0f, 0x7e, 0x04, 0x25, 0xe3, 0x7a, + 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 0x75, 0x31, 0x94, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x00, + 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x92, 0x12, 0x7c, 0x15, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x27, 0x01, 0xcd, + 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, + 0x46, 0x7a, 0x05, 0x46, 0x7a, 0x37, 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdf, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xdf, 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, + 0x01, 0xcd, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0xbe, 0x50, 0x38, + 0x78, 0x03, 0x02, 0x66, 0x16, 0x02, 0x65, 0xfb, 0x75, 0x31, 0x99, 0x12, 0x7c, 0x15, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, 0x7d, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, + 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x24, 0x7e, 0x64, 0x07, 0x00, 0x2e, 0x67, 0x01, 0xcd, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x65, 0xfb, 0x7e, 0x34, 0x01, 0xe3, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdf, 0x02, 0x65, 0xfb, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x01, 0xe3, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x31, + 0x93, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xbd, 0x04, 0x68, 0x29, 0x7a, 0x07, + 0x01, 0xdf, 0x7e, 0x47, 0x01, 0xe1, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xe1, 0x2e, 0x35, 0x46, 0x7a, + 0x35, 0x46, 0x22, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0x2c, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd1, 0xd2, 0x04, 0x7e, + 0x07, 0x01, 0xe1, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xdf, 0x7e, + 0x44, 0x05, 0xe3, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xce, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5f, 0x4b, 0x75, 0x31, 0x99, 0x12, 0x7c, + 0x15, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5f, 0x4b, 0xda, 0xb8, 0x02, 0x60, 0x98, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, 0x7c, 0x15, + 0xa5, 0xfc, 0x5e, 0xb0, 0xf0, 0xa5, 0xfd, 0x09, 0xb1, 0x00, 0x18, 0x4c, 0x4b, 0x5e, 0xb0, 0xf0, + 0xbc, 0xb5, 0x78, 0xf1, 0x5e, 0x40, 0x0f, 0x4c, 0x54, 0x7c, 0xb5, 0x5e, 0x50, 0x0b, 0x68, 0x2a, + 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6f, 0x80, 0x02, 0xc2, 0x6f, 0xa5, 0xfd, 0x5e, + 0x50, 0x20, 0x68, 0x04, 0xd2, 0x67, 0x80, 0x02, 0xc2, 0x67, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, + 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0x12, 0x43, 0xaf, 0x02, 0x62, 0x93, 0x75, 0x31, 0x91, + 0x12, 0x7c, 0x15, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x20, 0xe0, 0x08, + 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x62, 0x93, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, + 0x12, 0x62, 0x93, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, + 0x61, 0x00, 0x00, 0x12, 0x62, 0xb6, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5f, + 0x9d, 0x75, 0x31, 0x95, 0x12, 0x7c, 0x15, 0x22, 0x75, 0x31, 0x96, 0x12, 0x7c, 0x15, 0x22, 0x7c, + 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, + 0x68, 0x04, 0xd2, 0x68, 0x80, 0x02, 0xc2, 0x68, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, + 0x60, 0x80, 0x02, 0xc2, 0x60, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, + 0xc2, 0x58, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, + 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x69, 0x80, 0x02, 0xc2, 0x69, 0xa5, 0xfd, + 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x61, 0x80, 0x02, 0xc2, 0x61, 0xa5, 0xfd, 0x5e, 0x50, 0x80, + 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, + 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6a, + 0x80, 0x02, 0xc2, 0x6a, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x62, 0x80, 0x02, 0xc2, + 0x62, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0x02, 0x62, + 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, + 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6b, 0x80, 0x02, 0xc2, 0x6b, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, + 0x04, 0xd2, 0x63, 0x80, 0x02, 0xc2, 0x63, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5b, + 0x80, 0x02, 0xc2, 0x5b, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, + 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6c, 0x80, 0x02, 0xc2, 0x6c, + 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x64, 0x80, 0x02, 0xc2, 0x64, 0xa5, 0xfd, 0x5e, + 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, + 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, + 0xd2, 0x6d, 0x80, 0x02, 0xc2, 0x6d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x65, 0x80, + 0x02, 0xc2, 0x65, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, + 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, + 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6e, 0x80, 0x02, 0xc2, 0x6e, 0xa5, 0xfd, 0x5e, 0x50, + 0x20, 0x68, 0x04, 0xd2, 0x66, 0x80, 0x02, 0xc2, 0x66, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, + 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0x02, 0x62, 0x7f, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, + 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x10, 0x68, 0x04, 0xd2, 0x6f, 0x80, 0x02, + 0xc2, 0x6f, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x67, 0x80, 0x02, 0xc2, 0x67, 0xa5, + 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0x02, 0x62, 0x7f, 0x54, + 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, 0x75, 0x31, 0x90, 0x12, 0x7c, 0x15, 0xf5, 0x31, 0x12, + 0x7c, 0x15, 0x22, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xe3, 0xca, 0x79, + 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, + 0x64, 0x00, 0x02, 0x02, 0x62, 0xde, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, + 0xe3, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, + 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, 0x7e, 0x64, 0x00, 0x03, 0x02, 0x62, 0xde, 0xd2, 0x04, + 0x7e, 0x27, 0x01, 0xe1, 0x2d, 0x26, 0xbe, 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xdf, + 0x7e, 0x44, 0x05, 0xe3, 0x7e, 0x79, 0xa0, 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, + 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, 0x01, 0xe1, 0x7e, 0x25, 0x46, 0x2d, 0x26, 0x7a, 0x25, + 0x46, 0x7a, 0x07, 0x01, 0xdf, 0xda, 0x19, 0xc2, 0xd7, 0x22, 0x75, 0x31, 0x9a, 0x12, 0x7c, 0x15, + 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, 0x01, 0xe3, 0x80, 0xd7, 0x48, 0xb6, 0x46, 0x25, 0x47, + 0x1c, 0x49, 0x15, 0x44, 0xc6, 0x44, 0xc6, 0x48, 0x1b, 0x44, 0xc6, 0x49, 0x59, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x49, 0x60, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x4c, 0x0e, 0x49, 0x7d, 0x4a, + 0x74, 0x4c, 0x6d, 0x44, 0xc6, 0x44, 0xc6, 0x4b, 0x73, 0x44, 0xc6, 0x4c, 0xb1, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x4c, 0xb8, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x4f, 0x66, 0x4c, 0xd5, 0x4d, + 0xcc, 0x4f, 0xc5, 0x44, 0xc6, 0x44, 0xc6, 0x4e, 0xcb, 0x44, 0xc6, 0x50, 0x09, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x50, 0x10, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x52, 0xbe, 0x50, 0x2d, 0x51, + 0x24, 0x53, 0x1d, 0x44, 0xc6, 0x44, 0xc6, 0x52, 0x23, 0x44, 0xc6, 0x53, 0x61, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x53, 0x68, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x56, 0x16, 0x53, 0x85, 0x54, + 0x7c, 0x56, 0x75, 0x44, 0xc6, 0x44, 0xc6, 0x55, 0x7b, 0x44, 0xc6, 0x56, 0xb9, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x56, 0xc0, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x59, 0x6e, 0x56, 0xdd, 0x57, + 0xd4, 0x59, 0xcd, 0x44, 0xc6, 0x44, 0xc6, 0x58, 0xd3, 0x44, 0xc6, 0x5a, 0x11, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x5a, 0x18, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x5c, 0xc6, 0x5a, 0x35, 0x5b, + 0x2c, 0x5d, 0x25, 0x44, 0xc6, 0x44, 0xc6, 0x5c, 0x2b, 0x44, 0xc6, 0x5d, 0x69, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x5d, 0x70, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x60, 0x1e, 0x5d, 0x8d, 0x5e, + 0x84, 0x60, 0x7d, 0x44, 0xc6, 0x44, 0xc6, 0x5f, 0x83, 0x44, 0xc6, 0x60, 0xc1, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x60, 0xc8, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, + 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0x44, 0xc6, 0xca, 0x29, 0x1e, 0x50, 0x40, + 0x0d, 0x7e, 0x54, 0x0b, 0x10, 0x9c, 0xb5, 0xa4, 0x2e, 0x54, 0x65, 0x48, 0x89, 0x54, 0x7e, 0x39, + 0x00, 0x7a, 0x19, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, @@ -744,12 +832,12 @@ static unsigned char IMAGE_ARRAY_NAME[] = { 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, - 0x35, 0xda, 0x29, 0x22, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x1c, 0x9c, 0xb5, 0xa4, 0x2e, - 0x54, 0x69, 0x1f, 0x89, 0x54, 0x7e, 0x19, 0x00, 0x7a, 0x39, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x7e, - 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, - 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, - 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, - 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, + 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, + 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, + 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, + 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0xda, 0x29, 0x22, 0x1e, 0x50, 0x40, 0x0d, 0x7e, + 0x54, 0x0b, 0x1c, 0x9c, 0xb5, 0xa4, 0x2e, 0x54, 0x66, 0x16, 0x89, 0x54, 0x7e, 0x19, 0x00, 0x7a, + 0x39, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, @@ -765,157 +853,176 @@ static unsigned char IMAGE_ARRAY_NAME[] = { 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, - 0x00, 0x0b, 0x35, 0x22, 0x6a, 0x9b, 0x6c, 0x4f, 0x6c, 0x67, 0x6c, 0x82, 0x6d, 0x1d, 0x6d, 0xb5, - 0x6d, 0xd0, 0x6e, 0x62, 0x6d, 0xeb, 0x6e, 0x2c, 0x7c, 0xb3, 0xbe, 0xb0, 0x09, 0x28, 0x14, 0x75, - 0x2f, 0x09, 0x12, 0x7e, 0x30, 0x75, 0x57, 0x10, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x43, 0xe1, 0xc0, - 0xd0, 0xf1, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x6a, 0x54, 0x0b, 0x58, - 0x50, 0x89, 0x54, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x2f, 0xb0, 0x12, 0x7e, - 0x30, 0x0a, 0x22, 0x09, 0xb2, 0x6a, 0x93, 0x42, 0x24, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, - 0x3b, 0x49, 0x33, 0x6a, 0xb7, 0x89, 0x34, 0x6a, 0xc7, 0x6a, 0xf5, 0x6b, 0x23, 0x6b, 0x51, 0x6b, - 0x7f, 0x6b, 0xad, 0x6b, 0xdb, 0x6c, 0x09, 0x12, 0x41, 0xa9, 0xd2, 0x28, 0xd2, 0x08, 0xc2, 0x40, - 0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x7e, 0x04, 0x00, 0x20, - 0x7a, 0x07, 0x01, 0x99, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xa9, 0x12, 0x41, 0x16, 0x12, - 0x64, 0x40, 0x02, 0x6c, 0x37, 0x12, 0x41, 0xc6, 0xd2, 0x29, 0xd2, 0x09, 0xc2, 0x41, 0xc2, 0x49, - 0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xba, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, - 0x01, 0x9b, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xab, 0x12, 0x41, 0x16, 0x12, 0x64, 0x69, - 0x02, 0x6c, 0x37, 0x12, 0x41, 0xe3, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, 0xc2, 0x4a, 0xc2, 0x3a, - 0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9d, - 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xad, 0x12, 0x41, 0x16, 0x12, 0x64, 0x92, 0x02, 0x6c, - 0x37, 0x12, 0x42, 0x00, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, 0xc2, 0x3b, 0xc2, 0x33, - 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9f, 0x7e, 0x04, - 0x00, 0x38, 0x7a, 0x07, 0x01, 0xaf, 0x12, 0x41, 0x16, 0x12, 0x64, 0xbb, 0x02, 0x6c, 0x37, 0x12, - 0x42, 0x1d, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, 0xc2, 0x34, 0x6d, 0x00, - 0x7a, 0x03, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa1, 0x7e, 0x04, 0x00, 0x38, - 0x7a, 0x07, 0x01, 0xb1, 0x12, 0x41, 0x16, 0x12, 0x64, 0xe4, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x3a, - 0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, 0x6d, 0x00, 0x7a, 0x03, - 0x01, 0xbe, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, - 0x01, 0xb3, 0x12, 0x41, 0x16, 0x12, 0x65, 0x0d, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x57, 0xd2, 0x2e, - 0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbf, - 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb5, - 0x12, 0x41, 0x16, 0x12, 0x65, 0x36, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x74, 0xd2, 0x2f, 0xd2, 0x0f, - 0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x7e, 0x04, - 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa7, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb7, 0x12, 0x41, - 0x16, 0x12, 0x65, 0x5f, 0x02, 0x6c, 0x37, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, 0x0f, 0x12, 0x65, 0xbf, - 0x40, 0x0c, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xc2, 0xd7, 0x22, 0x75, - 0x2f, 0xb1, 0x12, 0x7e, 0x30, 0x0a, 0x52, 0x23, 0x6d, 0x00, 0x59, 0x05, 0x00, 0x32, 0x12, 0x41, - 0x72, 0x12, 0x41, 0x8e, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb2, 0x12, 0x7e, 0x30, 0x0a, 0x22, 0x09, - 0xb2, 0x6a, 0x93, 0x42, 0x23, 0x7e, 0xb0, 0x9c, 0x19, 0xb2, 0x01, 0xb9, 0x12, 0x45, 0x74, 0xd0, - 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, - 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, - 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, - 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, - 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 0xb8, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, - 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0x3e, 0x20, - 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x20, 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, - 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 0x59, 0x46, 0x01, 0xa9, 0x09, 0xb0, 0x00, 0x10, 0x44, - 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x11, 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, - 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 0x46, 0x01, 0xa9, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, - 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, - 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x04, 0x44, 0x80, 0x80, 0x02, 0x54, 0x7f, - 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x02, 0x80, 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, - 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, - 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xda, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x10, 0xa5, - 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x04, 0xa5, - 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x29, 0x42, 0x26, - 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x15, 0xa5, 0xee, 0x52, 0x29, 0x7c, 0x74, - 0x5e, 0x70, 0x02, 0x78, 0x0a, 0x52, 0x26, 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0x99, 0x12, - 0x42, 0x91, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, - 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, - 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, - 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb5, 0x12, 0x7e, - 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, - 0x0c, 0xe5, 0x58, 0xb4, 0x07, 0x23, 0x09, 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, - 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, - 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb6, 0x12, - 0x7e, 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe5, 0x58, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, - 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, - 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, - 0xa8, 0x22, 0x75, 0x2f, 0xb4, 0x12, 0x7e, 0x30, 0x7a, 0x21, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, - 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0xb0, 0x01, 0x7e, 0xa0, 0xc8, 0x7c, 0x64, 0x12, 0x65, 0xbf, 0xc0, - 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xd0, 0xa8, 0x22, 0x6e, 0x9c, 0x6e, 0xe3, - 0x6f, 0x2a, 0x6f, 0x71, 0x6f, 0xb8, 0x6f, 0xff, 0x70, 0x46, 0x70, 0x8d, 0x75, 0x2f, 0x55, 0x12, - 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, - 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x69, 0x7e, 0x27, 0x01, 0x79, 0x2d, 0x23, 0x7e, 0x09, - 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x0d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, - 0x78, 0xec, 0x7a, 0x17, 0x01, 0x69, 0x7a, 0x27, 0x01, 0x79, 0x02, 0x4a, 0x98, 0x7e, 0x14, 0x09, - 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x01, 0x12, 0x7e, 0x30, 0x7a, - 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6b, 0x7e, - 0x27, 0x01, 0x7b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, - 0x14, 0x11, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6b, 0x7a, 0x27, 0x01, - 0x7b, 0x02, 0x4d, 0xcd, 0x7e, 0x14, 0x0d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, - 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, - 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6d, 0x7e, 0x27, 0x01, 0x7d, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, - 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x15, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, - 0x7a, 0x17, 0x01, 0x6d, 0x7a, 0x27, 0x01, 0x7d, 0x02, 0x51, 0x02, 0x7e, 0x14, 0x11, 0xcd, 0x80, - 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x03, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, - 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6f, 0x7e, 0x27, 0x01, - 0x7f, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x19, - 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6f, 0x7a, 0x27, 0x01, 0x7f, 0x02, - 0x54, 0x37, 0x7e, 0x14, 0x15, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, - 0x04, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, - 0x7e, 0x17, 0x01, 0x71, 0x7e, 0x27, 0x01, 0x81, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, - 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, - 0x01, 0x71, 0x7a, 0x27, 0x01, 0x81, 0x02, 0x57, 0x6c, 0x7e, 0x14, 0x19, 0xcd, 0x80, 0xeb, 0x75, - 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x05, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, - 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x73, 0x7e, 0x27, 0x01, 0x83, 0x2d, - 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x21, 0xcc, 0x38, - 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x73, 0x7a, 0x27, 0x01, 0x83, 0x02, 0x5a, 0xa1, - 0x7e, 0x14, 0x1d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x06, 0x12, - 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, - 0x01, 0x75, 0x7e, 0x27, 0x01, 0x85, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, - 0x0b, 0x14, 0xbe, 0x14, 0x25, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x75, - 0x7a, 0x27, 0x01, 0x85, 0x02, 0x5d, 0xd6, 0x7e, 0x14, 0x21, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, - 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, - 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x77, 0x7e, 0x27, 0x01, 0x87, 0x2d, 0x23, 0x7e, - 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x29, 0xcc, 0x38, 0x0f, 0x1b, - 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x77, 0x7a, 0x27, 0x01, 0x87, 0x02, 0x61, 0x0b, 0x7e, 0x14, - 0x25, 0xcd, 0x80, 0xeb, 0xca, 0xb8, 0xc0, 0xf1, 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0xe5, 0xc0, - 0x54, 0x03, 0x68, 0x05, 0x12, 0x77, 0xdd, 0x80, 0xf5, 0x30, 0xc2, 0x08, 0x75, 0xf1, 0x01, 0x12, - 0x71, 0xe9, 0x80, 0x14, 0x30, 0xc3, 0x08, 0x75, 0xf1, 0x01, 0x12, 0x71, 0x0d, 0x80, 0x09, 0x30, - 0xc4, 0x06, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xf9, 0xd0, 0xf1, 0xda, 0xb8, 0x32, 0x75, 0x2f, 0x10, - 0x12, 0x7e, 0x30, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x5c, 0xe5, - 0xe5, 0x54, 0xc0, 0x68, 0x4f, 0xe5, 0xe6, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xc5, 0x2d, 0x35, 0xbe, - 0x34, 0x04, 0x00, 0x38, 0x4a, 0x7a, 0x37, 0x01, 0xc5, 0x7e, 0x37, 0x01, 0xc3, 0x7d, 0x43, 0x2d, - 0x45, 0xbe, 0x44, 0x09, 0xcc, 0x38, 0x40, 0x7a, 0x47, 0x01, 0xc3, 0x75, 0x2f, 0x11, 0x12, 0x7e, - 0x30, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x73, 0xc8, 0xa9, 0x21, 0xe5, 0x1f, 0xa9, 0xd4, + 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, + 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, + 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, + 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x22, 0x67, 0x96, 0x69, 0x63, 0x69, + 0x7b, 0x6a, 0x49, 0x6a, 0xe4, 0x6b, 0x8e, 0x6b, 0xa9, 0x6c, 0x3b, 0x6b, 0xc4, 0x6c, 0x05, 0x69, + 0x96, 0x69, 0xaa, 0x7c, 0xb3, 0xbe, 0xb0, 0x0b, 0x28, 0x14, 0x75, 0x31, 0x09, 0x12, 0x7c, 0x15, + 0x75, 0x6d, 0x10, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x22, 0xc0, 0xa8, + 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x67, 0x4b, 0x0b, 0x58, 0x50, 0x89, 0x54, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x31, 0xb0, 0x12, 0x7c, 0x15, 0x0a, 0x32, 0x09, 0xb3, + 0x67, 0x8e, 0x42, 0x32, 0x19, 0x43, 0x00, 0x36, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x3b, + 0x49, 0x33, 0x67, 0xcb, 0x0a, 0x22, 0x09, 0x32, 0x00, 0x36, 0x09, 0xb2, 0x67, 0x8e, 0xa5, 0xbb, + 0x00, 0x05, 0xf4, 0x52, 0x33, 0x80, 0x02, 0x42, 0x33, 0x89, 0x34, 0x67, 0xdb, 0x68, 0x09, 0x68, + 0x37, 0x68, 0x65, 0x68, 0x93, 0x68, 0xc1, 0x68, 0xef, 0x69, 0x1d, 0x12, 0x41, 0xb5, 0xd2, 0x28, + 0xd2, 0x08, 0xc2, 0x40, 0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xcf, + 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xaf, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xbf, + 0x12, 0x41, 0x16, 0x12, 0x60, 0xcf, 0x02, 0x69, 0x4b, 0x12, 0x41, 0xd4, 0xd2, 0x29, 0xd2, 0x09, + 0xc2, 0x41, 0xc2, 0x49, 0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd0, 0x7e, 0x04, + 0x00, 0x20, 0x7a, 0x07, 0x01, 0xb1, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc1, 0x12, 0x41, + 0x16, 0x12, 0x61, 0x05, 0x02, 0x69, 0x4b, 0x12, 0x41, 0xf3, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, + 0xc2, 0x4a, 0xc2, 0x3a, 0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd1, 0x7e, 0x04, 0x00, 0x20, + 0x7a, 0x07, 0x01, 0xb3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc3, 0x12, 0x41, 0x16, 0x12, + 0x61, 0x3b, 0x02, 0x69, 0x4b, 0x12, 0x42, 0x12, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, + 0xc2, 0x3b, 0xc2, 0x33, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd2, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, + 0x01, 0xb5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc5, 0x12, 0x41, 0x16, 0x12, 0x61, 0x71, + 0x02, 0x69, 0x4b, 0x12, 0x42, 0x31, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, + 0xc2, 0x34, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd3, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xb7, + 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc7, 0x12, 0x41, 0x16, 0x12, 0x61, 0xa7, 0x02, 0x69, + 0x4b, 0x12, 0x42, 0x50, 0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, + 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xd4, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xb9, 0x7e, 0x04, + 0x00, 0x38, 0x7a, 0x07, 0x01, 0xc9, 0x12, 0x41, 0x16, 0x12, 0x61, 0xdd, 0x02, 0x69, 0x4b, 0x12, + 0x42, 0x6f, 0xd2, 0x2e, 0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, + 0x7a, 0x03, 0x01, 0xd5, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x38, + 0x7a, 0x07, 0x01, 0xcb, 0x12, 0x41, 0x16, 0x12, 0x62, 0x13, 0x02, 0x69, 0x4b, 0x12, 0x42, 0x8e, + 0xd2, 0x2f, 0xd2, 0x0f, 0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, + 0x01, 0xd6, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, + 0x01, 0xcd, 0x12, 0x41, 0x16, 0x12, 0x62, 0x49, 0x02, 0x69, 0x4b, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, + 0x0f, 0x12, 0x62, 0xb6, 0x40, 0x0c, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, + 0xc2, 0xd7, 0x22, 0x75, 0x31, 0xb1, 0x12, 0x7c, 0x15, 0x0a, 0x52, 0x23, 0x6d, 0x00, 0x59, 0x05, + 0x00, 0x48, 0x12, 0x41, 0x7e, 0x12, 0x41, 0x9a, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb2, 0x12, 0x7c, + 0x15, 0x0a, 0x22, 0x09, 0xb2, 0x67, 0x8e, 0x42, 0x23, 0x7e, 0xb0, 0x9c, 0x19, 0xb2, 0x01, 0xcf, + 0x12, 0x31, 0x85, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb7, 0x12, 0x7c, 0x15, 0x0a, 0x22, 0x09, 0xb2, + 0x67, 0x8e, 0x42, 0x24, 0x12, 0x35, 0x3d, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb9, 0x12, 0x7c, 0x15, + 0x0a, 0x32, 0x09, 0xb3, 0x67, 0x8e, 0x42, 0x34, 0x19, 0x43, 0x00, 0x3e, 0x12, 0x69, 0xc2, 0xd0, + 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x0b, 0x7c, 0xb4, 0x20, 0xe0, 0x04, 0x6d, 0x33, 0x80, 0x04, + 0x49, 0x30, 0x01, 0x8f, 0x7e, 0xa0, 0xd8, 0xa5, 0xef, 0xca, 0x0b, 0xca, 0x29, 0x12, 0x62, 0xb6, + 0xda, 0x29, 0xda, 0x0b, 0x40, 0x62, 0x75, 0x31, 0xba, 0x12, 0x7c, 0x15, 0x7c, 0xb4, 0x30, 0xe0, + 0x1e, 0x6d, 0x33, 0x59, 0x30, 0x01, 0x8f, 0x7e, 0x34, 0x09, 0xe3, 0x0a, 0x82, 0x7e, 0x94, 0x04, + 0x00, 0xad, 0x89, 0x2d, 0x39, 0x59, 0x30, 0x01, 0x6f, 0x59, 0x30, 0x01, 0x7f, 0x7c, 0xb4, 0x30, + 0xe1, 0x10, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0xb0, 0x00, 0x08, 0x44, 0x04, 0x19, 0xb0, + 0x00, 0x08, 0x0a, 0x02, 0x09, 0xb0, 0x67, 0x8e, 0x42, 0x21, 0xf4, 0x52, 0x34, 0x7c, 0xb2, 0x23, + 0x0a, 0x0b, 0xca, 0x19, 0x49, 0x00, 0x30, 0xd5, 0x99, 0x04, 0xda, 0x19, 0xc0, 0xf1, 0x75, 0xf1, + 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0xc2, 0xd7, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, + 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, + 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 0x00, 0x10, + 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 0x5e, 0x70, + 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 0xb8, 0x74, + 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, + 0x62, 0x09, 0xb6, 0x67, 0x8e, 0x3e, 0x20, 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x20, + 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 0x59, 0x46, + 0x01, 0xbf, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x11, + 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 0x46, 0x01, + 0xbf, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x0a, 0x62, 0x09, 0xb6, + 0x67, 0x8e, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xa5, 0xee, 0x52, + 0x26, 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0xaf, 0xda, 0x28, 0x09, 0x30, 0x00, 0x0c, 0x74, + 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x0c, + 0x44, 0x80, 0xca, 0xb8, 0xa5, 0xed, 0x42, 0x2a, 0xda, 0xb8, 0x80, 0x0a, 0x54, 0x7f, 0xca, 0xb8, + 0xa5, 0xee, 0x52, 0x2a, 0xda, 0xb8, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x02, 0x80, + 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x02, + 0x68, 0x10, 0xa5, 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0xaf, + 0x80, 0x04, 0xa5, 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, + 0x29, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0xaf, 0x80, 0x0b, 0xa5, 0xee, 0x52, + 0x29, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x78, 0x00, 0x12, 0x42, 0xad, 0xd0, 0xa8, 0x22, 0x7e, 0x04, + 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, + 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, + 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, + 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb5, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, + 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, 0x0c, 0xe5, 0x6e, 0xb4, 0x07, 0x23, 0x09, + 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, + 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, + 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb6, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x80, 0x00, 0x4c, + 0x02, 0xe5, 0x6e, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, + 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, + 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x31, 0xb4, 0x12, 0x7c, + 0x15, 0x7a, 0x21, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x41, 0x31, 0x12, 0x7c, 0x15, 0x0a, 0x32, 0x09, + 0xb3, 0x67, 0x8e, 0x42, 0x35, 0x12, 0x6c, 0x5b, 0xd0, 0xa8, 0x22, 0x7e, 0xb0, 0x01, 0x7e, 0xa0, + 0xc8, 0x7c, 0x64, 0x12, 0x62, 0xb6, 0x40, 0x13, 0x0a, 0x32, 0x09, 0xb3, 0x67, 0x8e, 0xf4, 0x52, + 0x35, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x6f, 0xd9, 0xd0, 0xf1, 0x22, 0x6c, 0x8c, 0x6c, 0xd3, + 0x6d, 0x1a, 0x6d, 0x61, 0x6d, 0xa8, 0x6d, 0xef, 0x6e, 0x36, 0x6e, 0x7d, 0x75, 0x31, 0x55, 0x12, + 0x7c, 0x15, 0x75, 0x31, 0x00, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, + 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x8f, 0x2d, 0x23, 0x7e, 0x09, + 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x0d, 0xe2, 0x38, 0x0f, 0x1b, 0x34, + 0x78, 0xec, 0x7a, 0x17, 0x01, 0x7f, 0x7a, 0x27, 0x01, 0x8f, 0x02, 0x46, 0x0f, 0x7e, 0x14, 0x09, + 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x01, 0x12, 0x7c, 0x15, 0x7a, + 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x81, 0x7e, + 0x27, 0x01, 0x91, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, + 0x14, 0x11, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x81, 0x7a, 0x27, 0x01, + 0x91, 0x02, 0x49, 0x67, 0x7e, 0x14, 0x0d, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, + 0x75, 0x31, 0x02, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, + 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x83, 0x7e, 0x27, 0x01, 0x93, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, + 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x15, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, + 0x7a, 0x17, 0x01, 0x83, 0x7a, 0x27, 0x01, 0x93, 0x02, 0x4c, 0xbf, 0x7e, 0x14, 0x11, 0xe3, 0x80, + 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x03, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, + 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x85, 0x7e, 0x27, 0x01, + 0x95, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x19, + 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x85, 0x7a, 0x27, 0x01, 0x95, 0x02, + 0x50, 0x17, 0x7e, 0x14, 0x15, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, + 0x04, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, + 0x7e, 0x17, 0x01, 0x87, 0x7e, 0x27, 0x01, 0x97, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, + 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1d, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, + 0x01, 0x87, 0x7a, 0x27, 0x01, 0x97, 0x02, 0x53, 0x6f, 0x7e, 0x14, 0x19, 0xe3, 0x80, 0xeb, 0x75, + 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x05, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, + 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x89, 0x7e, 0x27, 0x01, 0x99, 0x2d, + 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x21, 0xe2, 0x38, + 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x89, 0x7a, 0x27, 0x01, 0x99, 0x02, 0x56, 0xc7, + 0x7e, 0x14, 0x1d, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, 0x12, 0x7c, 0x15, 0x75, 0x31, 0x06, 0x12, + 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, + 0x01, 0x8b, 0x7e, 0x27, 0x01, 0x9b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, + 0x0b, 0x14, 0xbe, 0x14, 0x25, 0xe2, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x8b, + 0x7a, 0x27, 0x01, 0x9b, 0x02, 0x5a, 0x1f, 0x7e, 0x14, 0x21, 0xe3, 0x80, 0xeb, 0x75, 0x31, 0x55, + 0x12, 0x7c, 0x15, 0x75, 0x31, 0x07, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, 0x15, 0x7a, + 0x71, 0x31, 0x12, 0x7c, 0x15, 0x7e, 0x17, 0x01, 0x8d, 0x7e, 0x27, 0x01, 0x9d, 0x2d, 0x23, 0x7e, + 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x29, 0xe2, 0x38, 0x0f, 0x1b, + 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x8d, 0x7a, 0x27, 0x01, 0x9d, 0x02, 0x5d, 0x77, 0x7e, 0x14, + 0x25, 0xe3, 0x80, 0xeb, 0xca, 0xb8, 0xc0, 0xf1, 0x75, 0x31, 0x02, 0x12, 0x7c, 0x15, 0xe5, 0xc0, + 0x54, 0x03, 0x68, 0x05, 0x12, 0x75, 0xcd, 0x80, 0xf5, 0x30, 0xc2, 0x08, 0x75, 0xf1, 0x01, 0x12, + 0x6f, 0xd9, 0x80, 0x14, 0x30, 0xc3, 0x08, 0x75, 0xf1, 0x01, 0x12, 0x6e, 0xfd, 0x80, 0x09, 0x30, + 0xc4, 0x06, 0x75, 0xf1, 0x02, 0x12, 0x70, 0xe9, 0xd0, 0xf1, 0xda, 0xb8, 0x32, 0x75, 0x31, 0x10, + 0x12, 0x7c, 0x15, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x5c, 0xe5, + 0xe5, 0x54, 0xc0, 0x68, 0x4f, 0xe5, 0xe6, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xdb, 0x2d, 0x35, 0xbe, + 0x34, 0x04, 0x00, 0x38, 0x4a, 0x7a, 0x37, 0x01, 0xdb, 0x7e, 0x37, 0x01, 0xd9, 0x7d, 0x43, 0x2d, + 0x45, 0xbe, 0x44, 0x09, 0xe2, 0x38, 0x40, 0x7a, 0x47, 0x01, 0xd9, 0x75, 0x31, 0x11, 0x12, 0x7c, + 0x15, 0x7a, 0xb1, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x71, 0xb8, 0xa9, 0x21, 0xe5, 0x1f, 0xa9, 0xd4, 0xe4, 0xa9, 0x24, 0xe4, 0xfc, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x3b, 0xe5, 0xe5, 0x54, 0xc0, 0x78, - 0xb4, 0x12, 0x76, 0x6a, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x80, 0x29, 0x80, 0x58, 0x75, - 0x2f, 0x16, 0x12, 0x7e, 0x30, 0x80, 0xed, 0x75, 0x2f, 0x12, 0x12, 0x7e, 0x30, 0x7a, 0xb1, 0x2f, - 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x09, 0xcd, 0x9d, 0x54, 0x12, 0x73, 0xc8, 0x7e, 0x34, 0x05, 0xcd, - 0x7d, 0x54, 0x2d, 0x43, 0x80, 0xa1, 0xe5, 0xe5, 0x54, 0x03, 0x78, 0x12, 0x75, 0x2f, 0x13, 0x12, - 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xe9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe9, 0x80, 0xa7, 0x75, 0x2f, - 0x14, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xed, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xed, 0xa9, 0xd7, - 0xe4, 0xa9, 0x27, 0xe4, 0xfc, 0x80, 0x9d, 0x75, 0x2f, 0x15, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, - 0xf1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf1, 0x80, 0xe5, 0x75, 0x2f, 0x18, 0x12, 0x7e, 0x30, 0xca, + 0xb4, 0x12, 0x74, 0x5a, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x80, 0x29, 0x80, 0x58, 0x75, + 0x31, 0x16, 0x12, 0x7c, 0x15, 0x80, 0xed, 0x75, 0x31, 0x12, 0x12, 0x7c, 0x15, 0x7a, 0xb1, 0x31, + 0x12, 0x7c, 0x15, 0x9e, 0x44, 0x09, 0xe3, 0x9d, 0x54, 0x12, 0x71, 0xb8, 0x7e, 0x34, 0x05, 0xe3, + 0x7d, 0x54, 0x2d, 0x43, 0x80, 0xa1, 0xe5, 0xe5, 0x54, 0x03, 0x78, 0x12, 0x75, 0x31, 0x13, 0x12, + 0x7c, 0x15, 0x7e, 0x0f, 0x29, 0xff, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xff, 0x80, 0xa7, 0x75, 0x31, + 0x14, 0x12, 0x7c, 0x15, 0x7e, 0x0f, 0x2a, 0x03, 0x0b, 0x0c, 0x7a, 0x0f, 0x2a, 0x03, 0xa9, 0xd7, + 0xe4, 0xa9, 0x27, 0xe4, 0xfc, 0x80, 0x9d, 0x75, 0x31, 0x15, 0x12, 0x7c, 0x15, 0x7e, 0x0f, 0x2a, + 0x07, 0x0b, 0x0c, 0x7a, 0x0f, 0x2a, 0x07, 0x80, 0xe5, 0x75, 0x31, 0x18, 0x12, 0x7c, 0x15, 0xca, 0x09, 0xca, 0x39, 0xca, 0x2b, 0xc2, 0xc2, 0xa9, 0x21, 0xf2, 0x52, 0xe5, 0xf5, 0x33, 0x82, 0xe7, - 0x40, 0x44, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x54, 0x00, 0x40, 0x9d, 0x35, 0x40, 0x43, 0x7a, 0x37, - 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc7, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x52, - 0x7a, 0x47, 0x01, 0xc7, 0x7d, 0x45, 0x12, 0x75, 0x26, 0xa9, 0x20, 0xf5, 0x22, 0x75, 0x2f, 0x19, - 0x12, 0x7e, 0x30, 0x7a, 0x91, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x81, 0xf7, 0x7a, 0x91, 0xf6, 0xe5, + 0x40, 0x44, 0x7e, 0x37, 0x01, 0xe1, 0x7e, 0x54, 0x00, 0x40, 0x9d, 0x35, 0x40, 0x43, 0x7a, 0x37, + 0x01, 0xe1, 0x7e, 0x37, 0x01, 0xdd, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x05, 0xe2, 0x38, 0x52, + 0x7a, 0x47, 0x01, 0xdd, 0x7d, 0x45, 0x12, 0x73, 0x16, 0xa9, 0x20, 0xf5, 0x22, 0x75, 0x31, 0x19, + 0x12, 0x7c, 0x15, 0x7a, 0x91, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x81, 0xf7, 0x7a, 0x91, 0xf6, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 0x50, 0xbc, 0xda, 0x2b, 0xda, 0x39, 0xda, 0x09, 0x22, 0x80, 0x41, 0x80, - 0x64, 0x2d, 0x53, 0x6d, 0x33, 0x70, 0xb7, 0x7e, 0x04, 0x01, 0xcd, 0x7a, 0x07, 0x01, 0xc9, 0x7a, - 0x07, 0x01, 0xc7, 0xa9, 0x32, 0xf2, 0xdf, 0x85, 0x30, 0x2f, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x00, - 0x80, 0xd4, 0xca, 0x59, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x54, 0x12, 0x75, 0x26, 0x7e, 0x34, 0x01, - 0xcd, 0x7d, 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc7, 0x12, 0x75, 0x26, 0xda, 0x49, 0x80, 0x99, - 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x0f, 0x29, 0xd9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xd9, - 0x80, 0x9d, 0x7e, 0x0f, 0x29, 0xe1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe1, 0xa9, 0xd7, 0xf4, 0xa9, - 0x27, 0xf4, 0xfc, 0x80, 0x8a, 0x7e, 0x0f, 0x29, 0xdd, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xdd, 0x80, - 0xeb, 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x2f, 0x29, 0xf9, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, - 0xf9, 0x80, 0x34, 0x7e, 0x2f, 0x2a, 0x01, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x01, 0xa9, 0xd7, 0xf4, - 0xa9, 0x27, 0xf4, 0xfc, 0x80, 0x21, 0x7e, 0x2f, 0x29, 0xfd, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, 0xfd, - 0x80, 0xeb, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x2f, 0x28, 0x12, 0x7e, 0x30, 0xca, + 0x64, 0x2d, 0x53, 0x6d, 0x33, 0x70, 0xb7, 0x7e, 0x04, 0x01, 0xe3, 0x7a, 0x07, 0x01, 0xdf, 0x7a, + 0x07, 0x01, 0xdd, 0xa9, 0x32, 0xf2, 0xdf, 0x85, 0x30, 0x31, 0x12, 0x7c, 0x15, 0x75, 0xf6, 0x00, + 0x80, 0xd4, 0xca, 0x59, 0x9e, 0x44, 0x05, 0xe3, 0x9d, 0x54, 0x12, 0x73, 0x16, 0x7e, 0x34, 0x01, + 0xe3, 0x7d, 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xdd, 0x12, 0x73, 0x16, 0xda, 0x49, 0x80, 0x99, + 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x0f, 0x29, 0xef, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xef, + 0x80, 0x9d, 0x7e, 0x0f, 0x29, 0xf7, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf7, 0xa9, 0xd7, 0xf4, 0xa9, + 0x27, 0xf4, 0xfc, 0x80, 0x8a, 0x7e, 0x0f, 0x29, 0xf3, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf3, 0x80, + 0xeb, 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x2f, 0x2a, 0x0f, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, + 0x0f, 0x80, 0x34, 0x7e, 0x2f, 0x2a, 0x17, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x17, 0xa9, 0xd7, 0xf4, + 0xa9, 0x27, 0xf4, 0xfc, 0x80, 0x21, 0x7e, 0x2f, 0x2a, 0x13, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x13, + 0x80, 0xeb, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x31, 0x28, 0x12, 0x7c, 0x15, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xc2, 0xc4, 0xa9, 0x21, 0xf2, 0xb6, 0xe5, 0xf5, 0x33, 0x72, 0xe7, - 0x40, 0xe0, 0x7e, 0x0d, 0x30, 0x7e, 0x1d, 0x34, 0x7e, 0x2d, 0x38, 0x7e, 0x3d, 0x3c, 0x7e, 0x85, - 0x40, 0x7d, 0x90, 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, + 0x40, 0xe0, 0x7e, 0x0d, 0x46, 0x7e, 0x1d, 0x4a, 0x7e, 0x2d, 0x4e, 0x7e, 0x3d, 0x52, 0x7e, 0x85, + 0x56, 0x7d, 0x90, 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, 0x97, 0x4d, 0x98, 0x68, 0x72, 0x7a, 0x11, 0xf3, 0x7a, 0x01, 0xf3, 0x7a, 0x31, 0xf3, 0x7a, 0x21, 0xf3, 0x7a, 0x51, 0xf3, 0x7a, 0x41, 0xf3, 0x7a, 0x71, 0xf3, 0x7a, 0x61, 0xf3, 0x7a, 0x91, 0xf3, - 0x7a, 0x81, 0xf3, 0x30, 0x73, 0x1a, 0x7a, 0xb1, 0xf3, 0x7a, 0xa1, 0xf3, 0x7a, 0xd1, 0xf3, 0x7a, + 0x7a, 0x81, 0xf3, 0x30, 0x7b, 0x1a, 0x7a, 0xb1, 0xf3, 0x7a, 0xa1, 0xf3, 0x7a, 0xd1, 0xf3, 0x7a, 0xc1, 0xf3, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, 0x7d, 0x78, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, - 0xa9, 0x30, 0xf5, 0x03, 0x02, 0x72, 0xe6, 0x75, 0x2f, 0x29, 0x12, 0x7e, 0x30, 0x20, 0x73, 0x0b, - 0x75, 0x2f, 0x0a, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x0a, 0x80, 0x09, 0x75, 0x2f, 0x12, 0x12, 0x7e, - 0x30, 0x75, 0xf6, 0x12, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x30, 0x7a, 0x0d, 0x34, 0x7a, 0x0d, - 0x38, 0x7a, 0x0d, 0x3c, 0x7a, 0x05, 0x40, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x1e, 0xb0, - 0x40, 0x0c, 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x75, 0x0b, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0xa1, + 0xa9, 0x30, 0xf5, 0x03, 0x02, 0x70, 0xd6, 0x75, 0x31, 0x29, 0x12, 0x7c, 0x15, 0x20, 0x7b, 0x0b, + 0x75, 0x31, 0x0a, 0x12, 0x7c, 0x15, 0x75, 0xf6, 0x0a, 0x80, 0x09, 0x75, 0x31, 0x12, 0x12, 0x7c, + 0x15, 0x75, 0xf6, 0x12, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x46, 0x7a, 0x0d, 0x4a, 0x7a, 0x0d, + 0x4e, 0x7a, 0x0d, 0x52, 0x7a, 0x05, 0x56, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x1e, 0xb0, + 0x40, 0x0c, 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x72, 0xfb, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0xa1, 0xe3, 0x7a, 0x39, 0xa0, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, @@ -937,7 +1044,7 @@ static unsigned char IMAGE_ARRAY_NAME[] = { 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x22, 0x1e, 0xb0, 0x40, 0x0c, - 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x76, 0x69, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0x39, 0xa0, 0x7a, + 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x74, 0x59, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0x39, 0xa0, 0x7a, 0xa1, 0xf3, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, @@ -958,144 +1065,144 @@ static unsigned char IMAGE_ARRAY_NAME[] = { 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, - 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x22, 0xc2, 0xaf, 0x7e, 0x37, 0x01, 0xc5, - 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xc1, 0x7e, 0x54, 0x09, 0xcd, 0x9d, 0x50, 0xbd, 0x35, - 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x4b, 0x99, 0x64, 0xda, 0x39, 0x7e, 0x07, 0x01, - 0xc5, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xc5, 0x2e, 0x37, 0x01, 0xc1, 0x7a, 0x37, 0x01, 0xc1, 0xbe, - 0x34, 0x09, 0xcc, 0x28, 0xc7, 0x7e, 0x34, 0x05, 0xcd, 0x7a, 0x37, 0x01, 0xc1, 0x80, 0xbd, 0xd2, - 0xaf, 0x22, 0x75, 0x2f, 0x53, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, 0x80, 0x11, 0x75, 0x2f, 0x51, - 0x12, 0x7e, 0x30, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 0x7c, 0xb2, - 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x6e, 0x8c, 0x7c, 0xb2, 0x54, 0x78, - 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x4d, 0x7a, 0x25, - 0x4f, 0x7e, 0x64, 0x77, 0x47, 0x7a, 0x65, 0x4b, 0x89, 0x24, 0x02, 0x77, 0x55, 0x7e, 0x64, 0x76, - 0xbd, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 0x19, 0xca, - 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x4d, 0x7e, 0x64, - 0x77, 0x33, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x76, 0xb2, 0x7a, - 0x65, 0x4b, 0x22, 0x75, 0x2f, 0x52, 0x12, 0x7e, 0x30, 0x7e, 0x21, 0x4d, 0x7e, 0x09, 0x30, 0x0b, - 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x2f, 0x54, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, - 0x7e, 0x25, 0x4f, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x77, 0xd1, 0x30, 0xe6, - 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 0x6a, 0x68, - 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x77, 0xd9, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 0x39, 0xda, - 0x09, 0x7e, 0x64, 0x76, 0xbd, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x4d, 0xf5, 0x4f, - 0x7e, 0x64, 0x77, 0x96, 0x80, 0x99, 0x7e, 0x15, 0x4d, 0xe5, 0x4f, 0x80, 0xc4, 0xc0, 0xd0, 0xc0, - 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0xa9, 0x20, 0xdf, 0x12, 0xa9, 0x21, 0xdf, 0x1b, 0x75, 0x2f, 0x01, - 0x12, 0x7e, 0x30, 0x53, 0xdf, 0xf7, 0x12, 0x40, 0xdc, 0x80, 0x0d, 0x75, 0x2f, 0xfe, 0x12, 0x7e, - 0x30, 0x7e, 0x14, 0x00, 0x53, 0x02, 0x40, 0x51, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, - 0x32, 0x03, 0xa5, 0xcb, 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x02, 0x78, 0x52, 0xca, 0x0b, 0xca, + 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x22, 0xc2, 0xaf, 0x7e, 0x37, 0x01, 0xdb, + 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xd7, 0x7e, 0x54, 0x09, 0xe3, 0x9d, 0x50, 0xbd, 0x35, + 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x61, 0x99, 0x64, 0xda, 0x39, 0x7e, 0x07, 0x01, + 0xdb, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xdb, 0x2e, 0x37, 0x01, 0xd7, 0x7a, 0x37, 0x01, 0xd7, 0xbe, + 0x34, 0x09, 0xe2, 0x28, 0xc7, 0x7e, 0x34, 0x05, 0xe3, 0x7a, 0x37, 0x01, 0xd7, 0x80, 0xbd, 0xd2, + 0xaf, 0x22, 0x75, 0x31, 0x53, 0x12, 0x7c, 0x15, 0x7e, 0x15, 0x63, 0x80, 0x11, 0x75, 0x31, 0x51, + 0x12, 0x7c, 0x15, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 0x7c, 0xb2, + 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x6c, 0x7c, 0x7c, 0xb2, 0x54, 0x78, + 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x63, 0x7a, 0x25, + 0x65, 0x7e, 0x64, 0x75, 0x37, 0x7a, 0x65, 0x61, 0x89, 0x24, 0x02, 0x75, 0x45, 0x7e, 0x64, 0x74, + 0xad, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 0x19, 0xca, + 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x63, 0x7e, 0x64, + 0x75, 0x23, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x74, 0xa2, 0x7a, + 0x65, 0x61, 0x22, 0x75, 0x31, 0x52, 0x12, 0x7c, 0x15, 0x7e, 0x21, 0x63, 0x7e, 0x09, 0x30, 0x0b, + 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x31, 0x54, 0x12, 0x7c, 0x15, 0x7e, 0x15, 0x63, + 0x7e, 0x25, 0x65, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x75, 0xc1, 0x30, 0xe6, + 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 0x67, 0x63, + 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x75, 0xc9, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 0x39, 0xda, + 0x09, 0x7e, 0x64, 0x74, 0xad, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x63, 0xf5, 0x65, + 0x7e, 0x64, 0x75, 0x86, 0x80, 0x99, 0x7e, 0x15, 0x63, 0xe5, 0x65, 0x80, 0xc4, 0xc0, 0xd0, 0xc0, + 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0xa9, 0x20, 0xdf, 0x12, 0xa9, 0x21, 0xdf, 0x1b, 0x75, 0x31, 0x01, + 0x12, 0x7c, 0x15, 0x53, 0xdf, 0xf7, 0x12, 0x40, 0xdc, 0x80, 0x0d, 0x75, 0x31, 0xfe, 0x12, 0x7c, + 0x15, 0x7e, 0x14, 0x00, 0x53, 0x02, 0x40, 0x51, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, + 0x32, 0x03, 0xa5, 0xcb, 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x02, 0x76, 0x42, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0xc0, - 0xf1, 0x7e, 0xb3, 0x2a, 0x1d, 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, - 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x78, - 0xcd, 0x80, 0x14, 0x30, 0xc1, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x78, 0xcd, 0x80, 0x09, 0x30, 0xc0, - 0x06, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, + 0xf1, 0x7e, 0xb3, 0x2a, 0x33, 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, + 0x75, 0xf1, 0x00, 0x12, 0x76, 0x2c, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x76, + 0xbd, 0x80, 0x14, 0x30, 0xc1, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x76, 0xbd, 0x80, 0x09, 0x30, 0xc0, + 0x06, 0x75, 0xf1, 0x00, 0x12, 0x76, 0x2c, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0xc2, 0xc0, 0x7e, 0xb3, - 0x2a, 0x1d, 0xb4, 0x02, 0x07, 0x12, 0x78, 0x5e, 0x02, 0x78, 0x52, 0x22, 0xb4, 0x01, 0xfc, 0x02, - 0x78, 0x98, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2a, 0x1d, 0x7a, 0x03, 0x2a, 0x1e, 0x22, 0x7e, 0xb3, - 0x2a, 0x15, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, - 0x05, 0x0c, 0x75, 0x2f, 0x71, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xf5, 0x8f, 0x22, 0x75, - 0xf6, 0x00, 0x22, 0xbe, 0x57, 0x2a, 0x1b, 0x28, 0x04, 0x7e, 0x57, 0x2a, 0x1b, 0x7a, 0x0f, 0x2a, - 0x20, 0x7a, 0x57, 0x2a, 0x24, 0x02, 0x78, 0x98, 0x7e, 0xef, 0x2a, 0x20, 0x7e, 0xf7, 0x2a, 0x24, - 0x7e, 0x07, 0x2a, 0x24, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, - 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x2a, 0x20, 0x7a, - 0xf7, 0x2a, 0x24, 0x75, 0x2f, 0x06, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, - 0x2f, 0x03, 0x12, 0x7e, 0x30, 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, - 0xd7, 0xf4, 0xa9, 0x27, 0xf4, 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x79, 0x44, 0x7e, - 0xb3, 0x2a, 0x1e, 0xb4, 0x02, 0x0f, 0xa9, 0xd4, 0xe4, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x2a, 0x1e, - 0x7a, 0xb3, 0x2a, 0x1d, 0x22, 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, 0x7c, 0x32, 0x7e, 0x13, 0x2a, - 0x1f, 0x2c, 0x21, 0x7a, 0x23, 0x2a, 0x1f, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x2a, 0x26, 0xe5, 0xe3, - 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, 0x75, 0x2f, 0x70, 0x12, 0x7e, - 0x30, 0x7e, 0xb3, 0x2a, 0x1f, 0x7e, 0xa3, 0x2a, 0x1c, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x79, 0xdb, - 0x22, 0x02, 0x7d, 0x44, 0xe5, 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, 0xe2, 0x7e, 0x01, 0xe3, 0x7e, - 0x11, 0xe3, 0x7e, 0x31, 0xe3, 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, 0x7e, 0x41, 0xe3, 0x7e, 0x71, - 0xe3, 0x7e, 0x61, 0xe3, 0x7a, 0x0f, 0x2a, 0x15, 0x7a, 0x1f, 0x2a, 0x19, 0x75, 0x2f, 0x04, 0x12, - 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x21, - 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x31, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, 0x2f, 0x12, 0x7e, 0x30, - 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, - 0x7e, 0x30, 0xa9, 0xd4, 0xe4, 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, 0x12, 0x79, 0xaf, 0x22, 0x6d, - 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2a, 0x24, 0x7a, 0x03, 0x2a, 0x1f, 0x7e, 0xb3, 0x2a, - 0x15, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x2a, 0x1e, 0x7a, 0x33, 0x2a, 0x1d, 0xbe, 0x07, 0x2a, 0x1b, - 0x68, 0x09, 0x22, 0x7a, 0x33, 0x2a, 0x1e, 0x7a, 0x23, 0x2a, 0x1d, 0x7e, 0xb3, 0x2a, 0x15, 0x54, - 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, - 0x30, 0xe4, 0x03, 0x02, 0x7d, 0x44, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, - 0x90, 0x7a, 0x07, 0x75, 0x84, 0xff, 0x73, 0x02, 0x7b, 0x5b, 0x02, 0x7a, 0x4f, 0x02, 0x7b, 0xf8, - 0x02, 0x7c, 0x13, 0x02, 0x7a, 0xf4, 0x02, 0x7a, 0xb5, 0x02, 0x7c, 0x2c, 0x02, 0x7c, 0x2c, 0x02, - 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, - 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x35, 0x02, 0x7c, 0xe9, 0x02, 0x7c, 0x32, - 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x7e, - 0xb3, 0x2a, 0x16, 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, 0x56, 0x7c, 0x0b, 0x7e, 0x13, - 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x72, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, - 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x4e, 0x40, 0x35, 0x02, 0x78, 0x83, - 0xb4, 0x08, 0x10, 0x75, 0x2f, 0x74, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf1, 0xf5, 0xf3, 0x75, - 0xf6, 0x01, 0x22, 0xb4, 0x00, 0x1c, 0x75, 0x2f, 0x75, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf2, - 0x30, 0xe0, 0x05, 0x75, 0xf3, 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, 0x75, 0xf3, 0x00, 0x75, 0xf6, - 0x02, 0x22, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x00, 0x35, 0x75, 0x2f, 0x76, 0x12, - 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, - 0x09, 0xe5, 0xe1, 0x30, 0xe7, 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, 0xe1, 0x30, 0xe6, 0x04, 0x74, - 0x01, 0x80, 0x02, 0x74, 0x00, 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, - 0x22, 0x02, 0x7d, 0x44, 0xc0, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x42, 0xf1, 0x7e, 0xb3, - 0x2a, 0x18, 0xb4, 0x00, 0x45, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x01, 0x24, 0x75, 0x2f, 0x77, 0x12, - 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x78, 0x05, 0x53, 0xe1, 0x3f, 0x80, 0x37, 0x7e, - 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, 0x53, 0xe1, 0xbf, 0x80, 0x26, - 0xb4, 0x03, 0x17, 0x75, 0x2f, 0x78, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, - 0x43, 0xe1, 0x80, 0x80, 0x11, 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x75, - 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x22, 0xd0, 0xf1, 0x02, 0x78, 0x7f, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, - 0x09, 0x23, 0x75, 0x2f, 0x79, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xbe, 0xb3, 0x3f, 0xf1, - 0x68, 0x11, 0xca, 0xb8, 0xc0, 0xf1, 0x12, 0x43, 0x68, 0xd0, 0xf1, 0xda, 0xb8, 0x50, 0x76, 0x7a, - 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x2f, 0x7a, 0x12, 0x7e, 0x30, 0x80, 0x62, - 0xb4, 0x03, 0x19, 0x75, 0x2f, 0x7b, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x55, - 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 0x75, - 0x2f, 0x7c, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 0xf2, - 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, - 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x73, 0x12, 0x7e, - 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x7a, - 0x40, 0x03, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0b, 0xf6, 0x75, - 0x2f, 0x7d, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0x7e, 0xa3, 0x2a, 0x1a, 0x4c, 0xab, 0x78, - 0xe4, 0x80, 0xdf, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0a, 0xdb, 0x75, 0x2f, 0x7e, 0x12, 0x7e, 0x30, - 0x7e, 0xb3, 0x2a, 0x18, 0x70, 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0x02, 0x7d, 0x44, 0x02, - 0x7d, 0x44, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x04, 0x20, 0x75, 0x2f, 0xc3, 0x12, - 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x18, 0x2a, 0x26, 0x7a, 0x1c, - 0x00, 0x00, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0x02, 0x7c, 0xe3, 0xb4, 0x06, 0x3a, 0x75, - 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, - 0xd7, 0x2a, 0x17, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0x75, - 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7e, - 0x75, 0xd0, 0x87, 0xd0, 0xa8, 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, - 0x87, 0x12, 0x78, 0x7f, 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, - 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, 0x7e, 0x57, 0x2a, 0x17, 0x4d, - 0x55, 0x68, 0x05, 0xa9, 0xd2, 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, 0x80, 0x16, 0xb4, 0x07, 0x16, - 0xc2, 0xaf, 0x7e, 0x07, 0x2a, 0x19, 0x7e, 0x17, 0x2a, 0x17, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, - 0xca, 0x28, 0x32, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x03, 0x15, - 0x75, 0x2f, 0xc2, 0x12, 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x57, - 0x2a, 0x1b, 0x02, 0x78, 0x83, 0xb4, 0x05, 0x39, 0x75, 0x2f, 0xc0, 0x12, 0x7e, 0x30, 0xc0, 0xa8, - 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, - 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2a, 0x17, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0xd0, 0x87, - 0xd0, 0xa8, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x2a, 0x1b, 0x02, 0x78, - 0x83, 0x02, 0x7d, 0x44, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x43, 0xe1, 0xc0, 0x22, 0xc0, 0xa8, - 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x19, 0x7e, 0x08, 0x2a, 0x26, - 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x7e, 0x3c, 0xda, 0x59, 0xda, 0x0b, 0xd0, - 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, - 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x2b, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, - 0x7f, 0x61, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0xbd, 0x74, - 0x78, 0x11, 0x75, 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x12, 0x7e, 0x75, 0x40, 0x06, 0xd0, 0x87, 0xd0, - 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, - 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0xc2, - 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, 0x34, 0x7f, 0xcc, 0x7e, 0x1b, - 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, - 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, - 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, - 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, - 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, + 0x2a, 0x33, 0xb4, 0x02, 0x07, 0x12, 0x76, 0x4e, 0x02, 0x76, 0x42, 0x22, 0xb4, 0x01, 0xfc, 0x02, + 0x76, 0x88, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2a, 0x33, 0x7a, 0x03, 0x2a, 0x34, 0x22, 0x7e, 0xb3, + 0x2a, 0x2b, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, + 0x05, 0x0c, 0x75, 0x31, 0x71, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0xf5, 0x8f, 0x22, 0x75, + 0xf6, 0x00, 0x22, 0xbe, 0x57, 0x2a, 0x31, 0x28, 0x04, 0x7e, 0x57, 0x2a, 0x31, 0x7a, 0x0f, 0x2a, + 0x36, 0x7a, 0x57, 0x2a, 0x3a, 0x02, 0x76, 0x88, 0x7e, 0xef, 0x2a, 0x36, 0x7e, 0xf7, 0x2a, 0x3a, + 0x7e, 0x07, 0x2a, 0x3a, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, + 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x2a, 0x36, 0x7a, + 0xf7, 0x2a, 0x3a, 0x75, 0x31, 0x06, 0x12, 0x7c, 0x15, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, + 0x31, 0x03, 0x12, 0x7c, 0x15, 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, + 0xd7, 0xf4, 0xa9, 0x27, 0xf4, 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x77, 0x29, 0x7e, + 0xb3, 0x2a, 0x34, 0xb4, 0x02, 0x04, 0xa9, 0xd4, 0xe4, 0x22, 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, + 0x7c, 0x32, 0x7e, 0x13, 0x2a, 0x35, 0x2c, 0x21, 0x7a, 0x23, 0x2a, 0x35, 0x7e, 0x00, 0x00, 0x2e, + 0x04, 0x2a, 0x3c, 0xe5, 0xe3, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, + 0x75, 0x31, 0x70, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x35, 0x7e, 0xa3, 0x2a, 0x32, 0xbc, 0xab, + 0x78, 0x03, 0x12, 0x77, 0xc0, 0x22, 0x02, 0x7b, 0x29, 0xe5, 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, + 0xe2, 0x7e, 0x01, 0xe3, 0x7e, 0x11, 0xe3, 0x7e, 0x31, 0xe3, 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, + 0x7e, 0x41, 0xe3, 0x7e, 0x71, 0xe3, 0x7e, 0x61, 0xe3, 0x7a, 0x0f, 0x2a, 0x2b, 0x7a, 0x1f, 0x2a, + 0x2f, 0x75, 0x31, 0x04, 0x12, 0x7c, 0x15, 0x7a, 0x01, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x11, 0x31, + 0x12, 0x7c, 0x15, 0x7a, 0x21, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x31, 0x31, 0x12, 0x7c, 0x15, 0x7a, + 0x41, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x51, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x61, 0x31, 0x12, 0x7c, + 0x15, 0x7a, 0x71, 0x31, 0x12, 0x7c, 0x15, 0xa9, 0xd4, 0xe4, 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, + 0x12, 0x77, 0x94, 0x22, 0x6d, 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2a, 0x3a, 0x7a, 0x03, + 0x2a, 0x35, 0x7e, 0xb3, 0x2a, 0x2b, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x2a, 0x34, 0x7a, 0x33, 0x2a, + 0x33, 0xbe, 0x07, 0x2a, 0x31, 0x68, 0x09, 0x22, 0x7a, 0x33, 0x2a, 0x34, 0x7a, 0x23, 0x2a, 0x33, + 0x7e, 0xb3, 0x2a, 0x2b, 0x54, 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, + 0xd2, 0xe4, 0x30, 0xe5, 0x06, 0x30, 0xe4, 0x03, 0x02, 0x7b, 0x29, 0x54, 0x3e, 0xf5, 0xf0, 0x03, + 0x54, 0x1f, 0xc3, 0x25, 0xf0, 0x90, 0x77, 0xec, 0x75, 0x84, 0xff, 0x73, 0x02, 0x79, 0x40, 0x02, + 0x78, 0x34, 0x02, 0x79, 0xdd, 0x02, 0x79, 0xf8, 0x02, 0x78, 0xd9, 0x02, 0x78, 0x9a, 0x02, 0x7a, + 0x11, 0x02, 0x7a, 0x11, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, + 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x14, 0x02, 0x7a, 0x1a, 0x02, + 0x7a, 0xce, 0x02, 0x7a, 0x17, 0x02, 0x7a, 0x17, 0x02, 0x7a, 0x17, 0x02, 0x7a, 0x17, 0x02, 0x7a, + 0x17, 0x02, 0x7a, 0x17, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x2a, 0x2d, 0x60, + 0x56, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x2e, 0x7e, 0x17, 0x2a, 0x2f, 0x75, 0x31, 0x72, 0x12, 0x7c, + 0x15, 0x7a, 0x01, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x11, 0x31, 0x12, 0x7c, 0x15, 0x12, 0x7b, 0x33, + 0x40, 0x35, 0x02, 0x76, 0x73, 0xb4, 0x08, 0x10, 0x75, 0x31, 0x74, 0x12, 0x7c, 0x15, 0x7e, 0xb3, + 0x3f, 0xf1, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0xb4, 0x00, 0x1c, 0x75, 0x31, 0x75, 0x12, 0x7c, + 0x15, 0x7e, 0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x05, 0x75, 0xf3, 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, + 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x7b, 0x29, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x00, + 0x35, 0x75, 0x31, 0x76, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x30, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, + 0xb3, 0x2a, 0x30, 0x20, 0xe7, 0x09, 0xe5, 0xe1, 0x30, 0xe7, 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, + 0xe1, 0x30, 0xe6, 0x04, 0x74, 0x01, 0x80, 0x02, 0x74, 0x00, 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, + 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x7b, 0x29, 0xc0, 0xf1, 0x7e, 0xb3, 0x2a, 0x30, 0x54, + 0x0f, 0x42, 0xf1, 0x7e, 0xb3, 0x2a, 0x2e, 0xb4, 0x00, 0x45, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x01, + 0x24, 0x75, 0x31, 0x77, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x30, 0x54, 0x0f, 0x78, 0x05, 0x53, + 0xe1, 0x3f, 0x80, 0x37, 0x7e, 0xb3, 0x2a, 0x30, 0x20, 0xe7, 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, + 0x53, 0xe1, 0xbf, 0x80, 0x26, 0xb4, 0x03, 0x17, 0x75, 0x31, 0x78, 0x12, 0x7c, 0x15, 0x7e, 0xb3, + 0x2a, 0x30, 0x20, 0xe7, 0x05, 0x43, 0xe1, 0x80, 0x80, 0x11, 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, + 0xe1, 0xc0, 0xd0, 0xf1, 0x75, 0x31, 0x07, 0x12, 0x7c, 0x15, 0x22, 0xd0, 0xf1, 0x02, 0x76, 0x6f, + 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x09, 0x23, 0x75, 0x31, 0x79, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, + 0x2e, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x11, 0xca, 0xb8, 0xc0, 0xf1, 0x12, 0x43, 0xd4, 0xd0, 0xf1, + 0xda, 0xb8, 0x50, 0x76, 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x31, 0x7a, + 0x12, 0x7c, 0x15, 0x80, 0x62, 0xb4, 0x03, 0x19, 0x75, 0x31, 0x7b, 0x12, 0x7c, 0x15, 0x7e, 0xb3, + 0x2a, 0x2e, 0xb4, 0x01, 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, + 0x46, 0xb4, 0x01, 0x19, 0x75, 0x31, 0x7c, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0xb4, 0x01, + 0x39, 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, + 0x7e, 0xb3, 0x2a, 0x2d, 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x2e, 0x7e, 0x17, 0x2a, 0x2f, + 0x75, 0x31, 0x73, 0x12, 0x7c, 0x15, 0x7a, 0x01, 0x31, 0x12, 0x7c, 0x15, 0x7a, 0x11, 0x31, 0x12, + 0x7c, 0x15, 0x12, 0x7b, 0x5f, 0x40, 0x03, 0x02, 0x76, 0x6f, 0x02, 0x7b, 0x29, 0x7e, 0xb3, 0x2a, + 0x2c, 0xb4, 0x0b, 0xf6, 0x75, 0x31, 0x7d, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0x7e, 0xa3, + 0x2a, 0x30, 0x4c, 0xab, 0x78, 0xe4, 0x80, 0xdf, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x0a, 0xdb, 0x75, + 0x31, 0x7e, 0x12, 0x7c, 0x15, 0x7e, 0xb3, 0x2a, 0x2e, 0x70, 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, + 0x22, 0x02, 0x7b, 0x29, 0x02, 0x7b, 0x29, 0x02, 0x7b, 0x29, 0x7e, 0xb3, 0x2a, 0x2c, 0xb4, 0x04, + 0x20, 0x75, 0x31, 0xc3, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x2d, 0x7e, + 0x18, 0x2a, 0x3c, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 0x2a, 0x31, 0x12, 0x7c, 0x21, 0x02, 0x7a, + 0xc8, 0xb4, 0x06, 0x3a, 0x75, 0x31, 0xc1, 0x12, 0x7c, 0x15, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, + 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x2a, 0x2d, 0x7e, 0x78, 0x2a, 0x3c, 0x7a, 0x7c, 0x00, 0x00, + 0x7e, 0x77, 0x2a, 0x31, 0x75, 0x31, 0xc1, 0x12, 0x7c, 0x15, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, + 0xa9, 0xd5, 0x87, 0x12, 0x7c, 0x5a, 0xd0, 0x87, 0xd0, 0xa8, 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, + 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x76, 0x6f, 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, + 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, + 0x7e, 0x57, 0x2a, 0x2d, 0x4d, 0x55, 0x68, 0x05, 0xa9, 0xd2, 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, + 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x2a, 0x2f, 0x7e, 0x17, 0x2a, 0x2d, 0xc0, + 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x76, 0x6f, 0x02, 0x7b, 0x29, 0x7e, 0xb3, + 0x2a, 0x2c, 0xb4, 0x03, 0x15, 0x75, 0x31, 0xc2, 0x12, 0x7c, 0x15, 0x7e, 0x04, 0x00, 0x01, 0x7e, + 0x17, 0x2a, 0x2d, 0x7e, 0x57, 0x2a, 0x31, 0x02, 0x76, 0x73, 0xb4, 0x05, 0x39, 0x75, 0x31, 0xc0, + 0x12, 0x7c, 0x15, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x7e, 0x08, 0x2a, 0x3c, + 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2a, 0x2d, 0x7e, 0x47, 0x2a, 0x31, + 0x12, 0x7c, 0x21, 0xd0, 0x87, 0xd0, 0xa8, 0x7e, 0x08, 0x2a, 0x3c, 0x7a, 0x0c, 0x00, 0x00, 0x7e, + 0x57, 0x2a, 0x31, 0x02, 0x76, 0x73, 0x02, 0x7b, 0x29, 0x75, 0x31, 0x07, 0x12, 0x7c, 0x15, 0x43, + 0xe1, 0xc0, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7b, 0x9e, 0x40, + 0x19, 0x7e, 0x08, 0x2a, 0x3c, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x7c, 0x21, + 0xda, 0x59, 0xda, 0x0b, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, + 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7b, 0x9e, 0x40, 0x2b, 0x7e, 0x58, 0x00, + 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 0x2a, 0x3c, 0x7a, 0x7c, 0x00, 0x00, 0x7e, + 0x77, 0x2a, 0x31, 0xbd, 0x74, 0x78, 0x11, 0x75, 0x31, 0xc1, 0x12, 0x7c, 0x15, 0x12, 0x7c, 0x5a, + 0x40, 0x06, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, + 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, + 0x87, 0x7e, 0x34, 0x7f, 0xc2, 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, + 0x34, 0x7f, 0xcc, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, + 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, + 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, + 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, + 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, + 0xff, 0xc3, 0x22, 0xd3, 0x22, -// Segment #15, Start Address 00ff7fc6, Length 4 +// Segment #16, Start Address 00ff7fc6, Length 4 0xff,0x00,0xc6,0x7f,0x04,0x00, - 0x01, 0x0c, 0x03, 0x00, + 0x01, 0x10, 0x04, 0x00, -// Segment #16, Start Address 00ff7e30, Length 315 -0xff,0x00,0x30,0x7e,0x3b,0x01, - 0xca, 0x08, 0x7e, 0x01, 0x2f, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, +// Segment #17, Start Address 00ff7c15, Length 330 +0xff,0x00,0x15,0x7c,0x4a,0x01, + 0xca, 0x08, 0x7e, 0x01, 0x31, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, 0x0b, 0xc0, 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 0xfc, 0x7c, 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 0x44, 0x00, 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 0xfa, 0x7f, 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, - 0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x7e, 0x9f, + 0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x7c, 0x84, 0xda, 0x79, 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x43, 0x90, 0x30, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, @@ -1104,16 +1211,17 @@ static unsigned char IMAGE_ARRAY_NAME[] = { 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2c, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 0x16, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x03, 0x63, 0x90, 0x30, 0x4d, 0x77, 0x78, 0x93, 0xc2, - 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, - 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, - 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 0xfe, 0x0b, 0x1a, 0x00, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, - 0x51, 0x23, 0x7e, 0x18, 0x7f, 0x15, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, - 0x08, 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, + 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x42, 0x08, 0x06, 0x04, 0x02, 0x04, 0x00, + 0x02, 0x01, 0x04, 0x01, 0x02, 0x82, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x04, 0x02, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x02, 0x02, 0x08, 0x02, 0x04, 0x20, 0x04, 0x7e, 0x18, 0x7f, 0xbd, 0x7a, + 0x1c, 0x00, 0xfe, 0x0b, 0x1a, 0x00, 0x5e, 0x10, 0x1f, 0xbe, 0x10, 0x1a, 0x38, 0x1a, 0x0a, 0x51, + 0x23, 0x7e, 0x18, 0x7c, 0xfa, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, + 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, }; static struct edge_firmware_version_info IMAGE_VERSION_NAME = { - 1, 12, 3 }; // Major, Minor, Build + 1, 16, 4 }; // Major, Minor, Build #undef IMAGE_VERSION_NAME diff --git a/drivers/usb/serial/io_fw_down3.h b/drivers/usb/serial/io_fw_down3.h index 20eecb39d..93b56d68a 100644 --- a/drivers/usb/serial/io_fw_down3.h +++ b/drivers/usb/serial/io_fw_down3.h @@ -1,11 +1,11 @@ //************************************************************** //* Edgeport Binary Image (for TI based products) -//* Generated by TIBin2C v1.00 +//* Generated by TIBin2C v2.00 (watchport) //* Copyright (C) 2001 Inside Out Networks, All rights reserved. //************************************************************** -static int IMAGE_SIZE = 12166; +static int IMAGE_SIZE = 12749; struct EDGE_FIRMWARE_VERSION_INFO { @@ -16,7 +16,7 @@ struct EDGE_FIRMWARE_VERSION_INFO static struct EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = { - 4, 1, 0 // Major, Minor, Build + 4, 10, 0 // Major, Minor, Build }; @@ -27,20 +27,20 @@ static unsigned char IMAGE_ARRAY_NAME[] = // WORD Length; // BYTE CheckSum; // }; -0x83, 0x2f, -0x33, +0xca, 0x31, +0xa8, -0x02, 0x24, 0x84, 0x02, 0x1f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x45, -0x8c, 0x85, 0x46, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, -0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x44, -0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x44, 0x75, -0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x92, 0xe5, 0x81, -0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x1a, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, -0xfa, 0x74, 0x08, 0x25, 0x44, 0xf8, 0x05, 0x44, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x44, -0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x44, 0x00, 0x80, 0xef, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0x86, -0x81, 0xe5, 0x44, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, -0x78, 0x92, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, +0x02, 0x26, 0xfe, 0x02, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x3f, +0x8c, 0x85, 0x40, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, +0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x3e, +0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x3e, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x3e, 0x75, +0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x8c, 0xe5, 0x81, +0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x94, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, +0xfa, 0x74, 0x08, 0x25, 0x3e, 0xf8, 0x05, 0x3e, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x3e, +0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x3e, 0x00, 0x80, 0xef, 0xe5, 0x3e, 0x24, 0x10, 0xf8, 0x86, +0x81, 0xe5, 0x3e, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, +0x78, 0x8c, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x30, 0x01, 0x4d, 0x30, 0xb4, 0x48, 0x10, 0x00, 0x45, 0x90, 0xff, 0x08, 0xe0, 0x54, 0x20, 0xf8, 0x90, 0xff, 0x48, 0xe0, 0x54, 0x20, 0xf9, @@ -50,747 +50,783 @@ static unsigned char IMAGE_ARRAY_NAME[] = 0xa3, 0xe0, 0xcb, 0xf0, 0x6b, 0x60, 0x02, 0x7e, 0x04, 0x22, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0xff, 0x93, 0x74, 0x01, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03, -0x02, 0x11, 0x1a, 0x85, 0x47, 0x8d, 0x85, 0x48, 0x8b, 0x74, 0xae, 0xf5, 0x82, 0x74, 0xfa, 0xf5, +0x02, 0x11, 0x94, 0x85, 0x41, 0x8d, 0x85, 0x42, 0x8b, 0x74, 0xaf, 0xf5, 0x82, 0x74, 0xfa, 0xf5, 0x83, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c, 0x90, 0xff, 0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, -0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, -0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, +0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x27, +0x8d, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 0xa3, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c, -0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, -0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, -0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, -0x20, 0x02, 0x03, 0x30, 0x01, 0x7b, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, -0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, 0x7e, -0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x22, 0x12, 0x00, 0xc9, 0xee, 0x64, -0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, 0x02, -0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x22, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, 0x22, -0x7c, 0x0a, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, -0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, 0x80, -0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, 0xd2, -0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, 0x60, -0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x43, 0x60, -0x13, 0x14, 0xf5, 0x43, 0x70, 0x0e, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x10, 0x95, -0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, -0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x90, -0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb5, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, -0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, 0x01, -0x7f, 0x08, 0x8e, 0x34, 0x8f, 0x35, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff, -0xea, 0x90, 0xfa, 0xb9, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x18, 0x49, 0x78, 0x24, 0x7c, 0x00, 0x7d, -0x00, 0x12, 0x19, 0x6c, 0x7e, 0x00, 0x7f, 0x05, 0x12, 0x13, 0x8f, 0xe4, 0xf5, 0x53, 0xe5, 0x53, -0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x18, 0x2a, 0xe4, 0x12, 0x13, 0xfb, 0x05, 0x53, 0x04, 0x12, -0x18, 0x1b, 0x80, 0xea, 0x12, 0x18, 0x49, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, 0xc0, -0x70, 0x03, 0x02, 0x08, 0xb8, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, -0xfe, 0x54, 0x0f, 0xf5, 0x53, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, 0x90, -0xff, 0x01, 0xe0, 0x12, 0x15, 0x0f, 0x03, 0x55, 0x00, 0x04, 0x28, 0x01, 0x05, 0x2f, 0x03, 0x05, -0xf6, 0x05, 0x06, 0x38, 0x06, 0x07, 0x9a, 0x08, 0x07, 0xe2, 0x09, 0x08, 0x3e, 0x0a, 0x08, 0x7e, -0x0b, 0x00, 0x00, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, -0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x02, 0x45, 0x34, -0x60, 0x03, 0x02, 0x0e, 0xac, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, 0x02, -0x60, 0x03, 0x02, 0x0e, 0xac, 0xee, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0x2a, 0x74, 0x01, -0x12, 0x13, 0xfb, 0x78, 0x6d, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x18, 0x2a, 0x74, 0x02, 0x12, 0x13, -0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 0x60, -0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, -0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x60, -0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x53, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, -0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 0x80, 0x19, 0x15, 0x53, 0x30, -0x0a, 0x0b, 0x12, 0x18, 0xbd, 0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x80, 0x09, 0x12, 0x18, 0xcb, -0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0x60, 0x05, 0x74, 0x01, -0x12, 0x13, 0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, -0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, -0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, -0xac, 0x78, 0x6d, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, -0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb5, 0xe0, -0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, -0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 0xb9, 0xe0, 0x70, -0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x07, -0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, 0x54, -0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x53, 0x24, 0xfe, 0x60, 0x1b, -0x04, 0x70, 0x2e, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, -0x80, 0x1f, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 0x80, 0x16, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, -0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 0xce, 0x80, 0x07, 0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2a, -0xce, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, -0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, -0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, -0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, -0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, -0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x78, 0x6d, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, -0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, -0x30, 0xe0, 0x07, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0a, 0xe5, -0x53, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, -0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xff, -0x12, 0x2f, 0x3b, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, -0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x19, 0x7a, 0x02, 0x19, 0x3e, -0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, -0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x44, 0x08, -0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, -0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, -0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0xac, -0x90, 0xfa, 0xba, 0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x2c, 0x01, 0x80, 0x03, -0x53, 0x2c, 0xfe, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, -0xe5, 0x35, 0x45, 0x34, 0x70, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, -0xac, 0x90, 0xfa, 0xb9, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, -0x75, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xed, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, -0x49, 0x12, 0x19, 0x73, 0x7d, 0x03, 0x12, 0x0e, 0xf3, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, -0xb0, 0x90, 0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, -0x04, 0xae, 0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x18, 0x49, 0x90, 0xf9, 0x65, 0xe0, 0x30, -0xe4, 0x0d, 0x12, 0x19, 0x73, 0x7d, 0x14, 0x12, 0x0e, 0xf3, 0x60, 0x10, 0x02, 0x0e, 0xac, 0x12, -0x19, 0x73, 0x7d, 0x04, 0x12, 0x0f, 0x47, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 0xb0, 0x90, -0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 0x04, 0xae, -0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x19, 0x73, 0x7d, 0x05, 0x12, 0x0f, 0x47, 0x60, 0x03, -0x02, 0x0e, 0xac, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x12, 0x18, 0x90, 0x7d, 0x01, 0x12, 0x23, -0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xba, 0xe0, 0x90, -0xfa, 0xb1, 0xf0, 0xe4, 0xf5, 0x52, 0x90, 0xfa, 0xb1, 0xe0, 0xff, 0xe5, 0x52, 0xc3, 0x9f, 0x50, -0x24, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0xff, 0xfd, 0x90, 0xfa, 0xb3, 0xe4, 0x8d, 0xf0, 0x12, -0x14, 0x2f, 0x90, 0xfa, 0xb2, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0e, -0xac, 0x05, 0x52, 0x80, 0xd1, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0x24, 0xfe, 0xff, 0x90, 0xfa, -0xb2, 0xf0, 0xfd, 0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0x7a, 0xf9, 0x79, 0x6e, 0x7b, -0x01, 0x8b, 0x2d, 0x8a, 0x2e, 0x89, 0x2f, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x18, -0x90, 0x12, 0x23, 0xee, 0x8f, 0x52, 0x05, 0x52, 0x05, 0x52, 0x12, 0x18, 0x2a, 0xe5, 0x52, 0x12, -0x13, 0xfb, 0x12, 0x18, 0x2a, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x14, 0x0d, 0xaf, 0x52, 0x7e, -0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x50, 0x02, 0x80, 0x04, 0xae, 0x34, 0xaf, 0x35, -0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, -0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, -0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, -0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, -0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x00, 0x75, 0x2f, 0x29, 0x02, -0x0f, 0x2f, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, -0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 0x90, 0xfa, 0xba, -0xe0, 0x94, 0x01, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, -0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0e, -0xac, 0x90, 0xfa, 0xba, 0xe0, 0xf5, 0x29, 0xe5, 0x29, 0x70, 0x08, 0x43, 0x2c, 0x01, 0x53, 0x2c, -0xfd, 0x80, 0x06, 0x53, 0x2c, 0xfe, 0x43, 0x2c, 0x02, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, -0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, -0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, -0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, -0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x7f, 0x01, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, -0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, -0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, -0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, -0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xff, 0x01, 0x12, 0x19, 0x8a, 0xef, 0x12, -0x13, 0xfb, 0x90, 0xfa, 0xb5, 0x12, 0x19, 0x8a, 0x90, 0x00, 0x01, 0xef, 0x12, 0x14, 0x0d, 0x90, -0x00, 0x02, 0xe4, 0x12, 0x14, 0x0d, 0x74, 0x03, 0x12, 0x18, 0x1b, 0x90, 0xfa, 0xb9, 0xe0, 0xff, -0xa3, 0xe0, 0x85, 0x2f, 0x82, 0x85, 0x2e, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, -0xe0, 0x12, 0x15, 0x0f, 0x09, 0x3d, 0x02, 0x09, 0x5f, 0x04, 0x09, 0x81, 0x05, 0x09, 0xad, 0x06, -0x09, 0xcb, 0x07, 0x09, 0xe9, 0x08, 0x0a, 0x07, 0x09, 0x0a, 0x25, 0x0b, 0x0a, 0xda, 0x80, 0x0c, -0xfa, 0x81, 0x0d, 0x1c, 0x82, 0x0b, 0x21, 0x83, 0x0b, 0x6a, 0x84, 0x0b, 0x89, 0x85, 0x0b, 0xc5, -0x86, 0x0c, 0x07, 0x87, 0x0c, 0x95, 0x88, 0x0c, 0xd0, 0x89, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, -0x0d, 0xcf, 0xc0, 0x0e, 0x00, 0xc1, 0x0e, 0x11, 0xc2, 0x00, 0x00, 0x0e, 0x9b, 0xe5, 0x2c, 0x20, -0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, -0xfd, 0x7c, 0x00, 0x7f, 0x07, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 0xc0, 0xe5, -0x2c, 0x20, 0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, -0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, -0xc0, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x19, 0x99, 0x50, 0x06, 0xe5, 0x35, -0x45, 0x34, 0x70, 0x05, 0x7f, 0x02, 0x02, 0x2e, 0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 0xfe, 0x24, -0xfd, 0x50, 0x02, 0x80, 0x03, 0x02, 0x2f, 0x28, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, -0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, -0x00, 0x7f, 0x08, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, -0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, -0x09, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, -0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, -0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, -0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x10, 0x9c, -0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, -0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x10, 0x9c, 0x7f, 0x07, -0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x56, 0x12, 0x18, 0xd9, 0x70, 0x4a, 0x90, 0xff, 0x02, -0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 0x80, 0x12, 0xe5, 0x52, 0xb4, -0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x52, 0x12, -0x17, 0x8b, 0x12, 0x19, 0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x05, -0x12, 0x2f, 0x76, 0x80, 0x06, 0x85, 0x2a, 0x30, 0x85, 0x2b, 0x31, 0x75, 0x2d, 0x01, 0x75, 0x2e, -0xf9, 0x75, 0x2f, 0x71, 0x02, 0x29, 0x2d, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x12, 0x18, -0xd9, 0x60, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x19, 0x99, 0x40, 0x05, 0x7f, 0x03, 0x02, -0x2e, 0xa5, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, -0x80, 0x12, 0xe5, 0x52, 0xb4, 0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, -0xf0, 0x04, 0xf5, 0x52, 0x12, 0x17, 0x8b, 0x02, 0x2f, 0x28, 0x12, 0x19, 0xa3, 0x12, 0x27, 0x19, -0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x78, -0x6e, 0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, -0xe4, 0x12, 0x14, 0x0d, 0x90, 0xfa, 0xb6, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x82, 0xe6, 0xfc, -0x08, 0xe6, 0x8c, 0x83, 0x12, 0x18, 0xa3, 0xef, 0xf0, 0x12, 0x2f, 0x80, 0xe4, 0xff, 0x02, 0x2e, -0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, -0x70, 0x06, 0xa3, 0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, -0xba, 0xe0, 0x42, 0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 0x70, -0x06, 0xa3, 0xe0, 0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xba, -0xe0, 0x42, 0xb0, 0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x49, 0x90, 0xfa, 0xb5, -0xe0, 0xb4, 0x01, 0x0a, 0x12, 0x18, 0x2a, 0xe5, 0x90, 0x12, 0x13, 0xfb, 0x80, 0x08, 0x12, 0x18, -0x2a, 0xe5, 0xb0, 0x12, 0x13, 0xfb, 0x02, 0x0f, 0x2f, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x30, -0x12, 0x18, 0x53, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, -0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x19, 0xad, 0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb6, -0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x04, 0x12, 0x19, 0xb4, 0xf0, -0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x36, 0x12, 0x18, 0x53, 0x60, -0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, -0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, -0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, -0xdf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x46, 0x04, 0x60, 0x03, 0x02, -0x0c, 0x90, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x04, 0xf0, 0x90, -0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x6a, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x61, 0x90, -0xff, 0xa4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x53, 0x30, 0x95, 0x09, -0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x47, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, -0x80, 0x3e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x04, 0xf0, 0x90, -0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x2a, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x21, 0x90, -0xff, 0xb4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x13, 0x30, 0x93, 0x09, -0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfd, 0xf0, -0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, -0xe0, 0x60, 0x09, 0x90, 0xff, 0xa2, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa2, 0xe0, -0x54, 0xbf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb2, 0xe0, 0x44, -0x40, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, -0x12, 0x18, 0x49, 0x12, 0x18, 0x5b, 0x60, 0x0f, 0x04, 0x70, 0x16, 0x90, 0xff, 0xa4, 0xe0, 0x12, -0x18, 0x2a, 0x12, 0x13, 0xfb, 0x80, 0x0a, 0x90, 0xff, 0xb4, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, -0xfb, 0x75, 0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x12, -0x19, 0x46, 0x7f, 0x03, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0xff, -0x7e, 0x00, 0x12, 0x2d, 0xee, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, 0xe4, 0xf5, 0x54, 0xf5, -0x55, 0x90, 0xfa, 0xbb, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, 0xb3, 0xf0, 0xa3, 0x74, -0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, 0xb8, 0xf0, 0xd3, 0x94, -0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, -0xd6, 0xe5, 0x23, 0x45, 0x22, 0x70, 0x73, 0x12, 0x18, 0x62, 0x90, 0xfa, 0xbb, 0x12, 0x19, 0x65, -0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, 0xfa, 0xb8, 0x74, 0x40, -0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 0xd6, 0xe5, 0x23, -0x45, 0x22, 0x70, 0x46, 0x12, 0x18, 0x62, 0x80, 0xd1, 0x75, 0x52, 0x02, 0x90, 0xfa, 0xbb, 0xe4, -0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb3, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, 0xf0, 0x7b, 0x00, 0x7a, -0x00, 0x79, 0x52, 0x90, 0xfa, 0xbc, 0xe0, 0xf5, 0x50, 0x7d, 0x0f, 0x7c, 0x00, 0x12, 0x26, 0x25, -0x75, 0x22, 0x00, 0x8f, 0x23, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, 0x40, 0xf5, 0x41, -0x7d, 0x01, 0x12, 0x23, 0xee, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0xaf, 0x23, 0x02, 0x2e, 0xa5, 0x90, -0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x62, -0xf0, 0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0f, -0x90, 0xf9, 0x61, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x2e, 0xa5, -0x12, 0x19, 0xa3, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x2e, -0xa5, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, -0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, -0x12, 0x19, 0xad, 0x12, 0x0e, 0xfe, 0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, -0x44, 0x10, 0x12, 0x0e, 0xfe, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, -0x19, 0xad, 0xf0, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, -0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, -0x92, 0x80, 0x23, 0x12, 0x19, 0xb4, 0x12, 0x0f, 0x1e, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, -0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x1e, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, -0xd2, 0x92, 0x12, 0x19, 0xb4, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x07, -0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x2f, 0x76, 0x22, -0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, -0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0xab, -0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x22, 0xaa, 0x54, 0xa9, 0x55, 0x7b, 0xff, 0x90, 0xfa, 0xb3, 0xe0, -0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xb8, 0xe0, 0xf5, 0x50, 0x12, 0x26, 0x25, 0x75, 0x22, 0x00, -0x8f, 0x23, 0x22, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 0xef, 0x22, 0xf0, 0x7f, -0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x12, -0x23, 0xee, 0x8f, 0x52, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x22, 0xf0, 0x7f, -0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x75, -0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x02, 0x2f, 0x3b, -0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, -0xef, 0x22, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb0, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, -0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, -0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, 0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, -0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, 0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, -0x04, 0xc0, 0x05, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, -0x0f, 0xfe, 0x7f, 0x00, 0x7e, 0x00, 0xe5, 0x49, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x19, 0xe0, 0x54, -0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, -0x49, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, -0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, -0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, -0x12, 0x10, 0x95, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, -0x4a, 0x75, 0xa8, 0x88, 0xec, 0x70, 0x02, 0x7c, 0x3f, 0x8c, 0x43, 0x22, 0xe5, 0x44, 0x24, 0x08, -0xf8, 0x76, 0x00, 0x12, 0x10, 0xec, 0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, -0xc0, 0x06, 0x7c, 0xff, 0x12, 0x0f, 0xfe, 0xe5, 0x49, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x19, 0xe0, -0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x49, 0x80, 0x07, -0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, 0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, -0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, -0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, -0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, 0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, -0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, 0xee, 0x12, 0x10, 0x95, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, -0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, 0x43, 0x00, 0x85, 0x4a, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, -0xc0, 0x83, 0xc3, 0xe5, 0x49, 0x24, 0xe8, 0x50, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf4, 0xef, 0x60, -0x31, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x0f, -0xfe, 0xd0, 0x04, 0x43, 0x07, 0x80, 0xe5, 0x49, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x19, 0xf5, 0x82, -0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, 0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x49, 0x12, -0x10, 0x95, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x02, 0x11, 0x1a, 0xc0, 0x04, 0x7c, 0x20, -0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, 0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, -0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, 0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, -0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, 0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, -0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, 0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, -0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, 0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, -0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0xd2, 0xb0, 0xd2, -0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, -0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, -0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x48, 0x8e, -0x47, 0x22, 0xc3, 0xef, 0x94, 0xbc, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, -0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x46, 0x8e, 0x45, 0x22, 0xef, -0x70, 0x01, 0x22, 0xc0, 0x00, 0xe5, 0x44, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x44, 0x24, 0x08, -0xf8, 0xc6, 0x54, 0x7f, 0xf6, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x10, 0xec, 0x80, +0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x25, +0xb4, 0x02, 0x22, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x27, +0x8d, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, +0x80, 0x03, 0x02, 0x02, 0x62, 0x74, 0x15, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x20, 0x04, +0xf1, 0x20, 0x02, 0x03, 0x30, 0x01, 0xeb, 0x74, 0x18, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, +0x14, 0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, +0x7e, 0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x33, 0x12, 0x00, 0xc9, 0xee, +0x64, 0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, +0x02, 0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x33, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, +0x33, 0x7c, 0x0a, 0x74, 0x18, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, +0xa3, 0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, +0x80, 0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, +0xd2, 0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, +0x60, 0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x3d, +0x60, 0x13, 0x14, 0xf5, 0x3d, 0x70, 0x0e, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, +0x0f, 0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, +0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, +0x90, 0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, +0xec, 0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, +0x01, 0x7f, 0x08, 0x8e, 0x3b, 0x8f, 0x3c, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, +0xff, 0xea, 0x90, 0xfa, 0xba, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x1c, 0x30, 0xe4, 0xf5, 0x4d, 0xe5, +0x4d, 0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x1c, 0x11, 0xe4, 0x12, 0x1a, 0x38, 0x05, 0x4d, 0x04, +0x12, 0x1c, 0x02, 0x80, 0xea, 0x12, 0x1c, 0x30, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, +0xc0, 0x70, 0x03, 0x02, 0x08, 0xc5, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, +0xe0, 0xfe, 0x54, 0x0f, 0xf5, 0x4d, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, +0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b, 0x4c, 0x03, 0x56, 0x00, 0x04, 0x29, 0x01, 0x05, 0x3c, 0x03, +0x06, 0x03, 0x05, 0x06, 0x45, 0x06, 0x07, 0xa7, 0x08, 0x07, 0xef, 0x09, 0x08, 0x4b, 0x0a, 0x08, +0x8b, 0x0b, 0x00, 0x00, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x64, 0x02, 0x45, +0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, +0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xee, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0x11, 0x74, +0x01, 0x12, 0x1a, 0x38, 0x78, 0x67, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x1c, 0x11, 0x74, 0x02, 0x12, +0x1a, 0x38, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb6, 0xe0, +0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0f, +0x26, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb6, 0xe0, 0xff, +0x60, 0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0xb2, 0x40, 0x03, 0x02, 0x0f, +0x26, 0xe5, 0x4d, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x1c, 0x0e, 0x12, 0x1a, +0x38, 0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x1c, 0x0e, 0x12, 0x1a, 0x38, 0x80, 0x19, 0x15, 0x4d, +0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0x12, 0x1c, 0x0c, 0x12, 0x1a, 0x38, 0x80, 0x09, 0x12, 0x1c, +0xb3, 0x12, 0x1c, 0x0c, 0x12, 0x1a, 0x38, 0x12, 0x1c, 0x11, 0x12, 0x19, 0xf2, 0x60, 0x05, 0x74, +0x01, 0x12, 0x1a, 0x38, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, +0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x14, 0x60, 0x2d, +0x14, 0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x04, +0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, +0x0f, 0x26, 0x78, 0x67, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, +0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb6, +0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb6, 0xe0, 0xd3, +0x94, 0x01, 0x40, 0x03, 0x02, 0x0f, 0x26, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xfa, 0xba, 0xe0, +0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0xb2, 0x40, 0x03, 0x02, 0x0f, +0x26, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, +0x07, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x4d, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, +0x54, 0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x4d, 0x24, 0xfe, 0x60, +0x20, 0x24, 0xfb, 0x60, 0x34, 0x24, 0x06, 0x70, 0x35, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, +0xfd, 0x7f, 0x03, 0x12, 0x2d, 0xa8, 0x80, 0x26, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2d, 0xa8, 0x80, +0x1d, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2d, 0xa8, 0x80, 0x0e, +0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2d, 0xa8, 0x80, 0x05, 0x7f, 0x87, 0x12, 0x31, 0x32, 0x15, 0x4d, +0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, 0x09, 0x12, 0x1c, +0xb3, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, +0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, +0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, +0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, +0x60, 0x03, 0x02, 0x0f, 0x26, 0x78, 0x67, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, 0x02, 0x31, 0xb1, +0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, 0x07, +0xe5, 0x4d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x0a, 0xe5, 0x4d, 0xd3, 0x94, +0x01, 0x40, 0x03, 0x02, 0x0f, 0x26, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xfa, 0xba, 0xe0, 0x70, +0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x12, 0x31, 0x82, +0x40, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, +0xe5, 0x4d, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x1d, 0x64, 0x02, 0x1d, 0x2f, 0xe5, 0x35, 0x20, +0xe1, 0x03, 0x02, 0x0f, 0x26, 0x15, 0x4d, 0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0xf5, 0x83, 0xe0, +0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x1c, 0xb3, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0xe4, 0xff, +0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, +0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, +0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xbb, +0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x35, 0x01, 0x80, 0x03, 0x53, 0x35, 0xfe, +0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, +0x3b, 0x70, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xba, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, 0x75, 0x24, 0x02, +0x60, 0x03, 0x02, 0x0f, 0x26, 0xed, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0x30, 0x12, 0x1d, +0x5d, 0x7d, 0x03, 0x12, 0x0f, 0x6d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0x2a, 0x90, 0xfa, +0xb3, 0xe0, 0xfd, 0xa3, 0x12, 0x1c, 0x7b, 0x12, 0x0f, 0x89, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, +0xaf, 0x3c, 0x02, 0x0f, 0xba, 0x12, 0x1c, 0x30, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe4, 0x0d, 0x12, +0x1d, 0x5d, 0x7d, 0x14, 0x12, 0x0f, 0x6d, 0x60, 0x10, 0x02, 0x0f, 0x26, 0x12, 0x1d, 0x5d, 0x7d, +0x04, 0x12, 0x0f, 0xc1, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0x2a, 0x90, 0xfa, 0xb3, 0xe0, +0xfd, 0xa3, 0x12, 0x1c, 0x7b, 0x12, 0x0f, 0x89, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, +0x02, 0x0f, 0xba, 0x12, 0x1d, 0x5d, 0x7d, 0x05, 0x12, 0x0f, 0xc1, 0x60, 0x03, 0x02, 0x0f, 0x26, +0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x12, 0x1c, 0x78, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, +0xb4, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xbb, 0xe0, 0x90, 0xfa, 0xb2, 0xf0, +0xe4, 0xf5, 0x4c, 0x90, 0xfa, 0xb2, 0xe0, 0xff, 0xe5, 0x4c, 0xc3, 0x9f, 0x50, 0x24, 0x12, 0x1c, +0x72, 0x12, 0x0f, 0xcc, 0xff, 0xfd, 0x90, 0xfa, 0xb4, 0xe4, 0x8d, 0xf0, 0x12, 0x1a, 0x6c, 0x90, +0xfa, 0xb3, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0f, 0x26, 0x05, 0x4c, +0x80, 0xd1, 0x12, 0x1c, 0x72, 0x12, 0x0f, 0xcc, 0x24, 0xfe, 0xff, 0x90, 0xfa, 0xb3, 0xf0, 0xfd, +0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1a, 0x6c, 0x7a, 0xf9, 0x79, 0x6f, 0x7b, 0x01, 0x8b, 0x36, +0x8a, 0x37, 0x89, 0x38, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x1c, 0x78, 0x12, 0x25, +0xd7, 0x8f, 0x4c, 0x05, 0x4c, 0x05, 0x4c, 0x12, 0x1c, 0x11, 0xe5, 0x4c, 0x12, 0x1a, 0x38, 0x12, +0x1c, 0x11, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x1a, 0x4a, 0xaf, 0x4c, 0x7e, 0x00, 0xc3, 0xef, +0x95, 0x3c, 0xee, 0x95, 0x3b, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, 0x8e, 0x39, 0x8f, +0x3a, 0x02, 0x2c, 0x07, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, +0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, +0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, +0x12, 0x1c, 0xc9, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, +0x02, 0x0f, 0x26, 0x75, 0x36, 0x00, 0x75, 0x37, 0x00, 0x75, 0x38, 0x32, 0x02, 0x0f, 0xa9, 0xe5, +0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, +0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xd3, 0x90, 0xfa, 0xbb, 0xe0, 0x94, 0x01, +0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x60, 0x03, +0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xbb, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x70, 0x08, 0x43, 0x35, 0x01, 0x53, 0x35, 0xfd, 0x80, 0x06, +0x53, 0x35, 0xfe, 0x43, 0x35, 0x02, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe7, 0x03, +0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, +0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, +0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, +0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x7f, 0x01, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, +0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xd3, 0x90, 0xfa, 0xbb, +0xe0, 0x94, 0x00, 0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, +0xc9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, +0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xff, 0x01, 0x12, 0x1d, 0x74, 0xef, 0x12, 0x1a, 0x38, 0x90, +0xfa, 0xb6, 0x12, 0x1d, 0x74, 0x90, 0x00, 0x01, 0xef, 0x12, 0x1a, 0x4a, 0x90, 0x00, 0x02, 0xe4, +0x12, 0x1a, 0x4a, 0x74, 0x03, 0x12, 0x1c, 0x02, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0xa3, 0xe0, 0x85, +0x38, 0x82, 0x85, 0x37, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b, +0x4c, 0x09, 0x4a, 0x02, 0x09, 0x6c, 0x04, 0x09, 0x8e, 0x05, 0x09, 0xba, 0x06, 0x09, 0xd8, 0x07, +0x09, 0xf6, 0x08, 0x0a, 0x14, 0x09, 0x0a, 0x32, 0x0b, 0x0a, 0xe7, 0x80, 0x0d, 0x6f, 0x81, 0x0d, +0xa0, 0x82, 0x0b, 0x2e, 0x83, 0x0b, 0x77, 0x84, 0x0b, 0x96, 0x85, 0x0b, 0xdb, 0x86, 0x0c, 0x26, +0x87, 0x0c, 0xb7, 0x88, 0x0d, 0x42, 0x89, 0x0a, 0x50, 0x92, 0x0a, 0x50, 0x93, 0x0e, 0x53, 0xc0, +0x0e, 0x7f, 0xc1, 0x0e, 0x90, 0xc2, 0x00, 0x00, 0x0f, 0x15, 0xe5, 0x35, 0x20, 0xe7, 0x05, 0x7f, +0x05, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, +0x7f, 0x07, 0x02, 0x11, 0x16, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0x18, 0xe5, 0x35, 0x20, 0xe7, +0x05, 0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, +0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x11, 0x16, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0x18, 0xe5, 0x35, +0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1d, 0x92, 0x50, 0x06, 0xe5, 0x3c, 0x45, 0x3b, 0x70, +0x05, 0x7f, 0x02, 0x02, 0x30, 0xec, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfe, 0x24, 0xfd, 0x50, 0x02, +0x80, 0x03, 0x02, 0x31, 0x6f, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, +0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x08, +0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, +0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x09, 0x02, 0x11, +0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, +0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, 0x11, 0x16, 0x7f, +0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, +0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, +0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, +0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, +0xe5, 0x35, 0x30, 0xe7, 0x56, 0x12, 0x1c, 0xc9, 0x70, 0x4a, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x4c, +0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5, 0x4c, 0xb4, 0x83, 0x05, 0x75, +0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x4c, 0x12, 0x1b, 0x72, 0x12, +0x1d, 0x8b, 0x12, 0x25, 0x39, 0x12, 0x1c, 0xd9, 0x12, 0x1a, 0x0b, 0x60, 0x05, 0x12, 0x31, 0xbd, +0x80, 0x06, 0x85, 0x33, 0x39, 0x85, 0x34, 0x3a, 0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38, +0x72, 0x02, 0x2c, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, 0x18, 0x12, 0x1c, 0xc9, 0x60, 0x05, +0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x1d, 0x92, 0x40, 0x05, 0x7f, 0x03, 0x02, 0x30, 0xec, 0x90, +0xff, 0x02, 0xe0, 0xf5, 0x4c, 0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5, +0x4c, 0xb4, 0x83, 0x05, 0x75, 0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5, +0x4c, 0x12, 0x1b, 0x72, 0x02, 0x31, 0x6f, 0x12, 0x1d, 0x9c, 0x12, 0x2a, 0x06, 0x12, 0x1c, 0x83, +0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x78, 0x68, 0x12, 0x1b, +0x28, 0x90, 0x00, 0x02, 0x12, 0x1a, 0x0b, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, 0xe4, 0x12, 0x1a, +0x4a, 0x90, 0xfa, 0xb7, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x7c, 0xe6, 0xfc, 0x08, 0xe6, 0x8c, +0x83, 0x12, 0x1c, 0x8b, 0xef, 0xf0, 0x12, 0x31, 0xc7, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x90, 0xfa, +0xb6, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3, +0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, 0xbb, 0xe0, 0x42, +0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3, 0xe0, +0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xbb, 0xe0, 0x42, 0xb0, +0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0x30, 0x90, 0xfa, 0xb6, 0xe0, 0xb4, 0x01, +0x0a, 0x12, 0x1c, 0x11, 0xe5, 0x90, 0x12, 0x1a, 0x38, 0x80, 0x08, 0x12, 0x1c, 0x11, 0xe5, 0xb0, +0x12, 0x1a, 0x38, 0x02, 0x0f, 0xa9, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x24, 0x12, 0x12, 0x1c, 0x41, +0x20, 0xe1, 0x33, 0x12, 0x1c, 0xd0, 0xef, 0x24, 0xfc, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, +0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x1d, 0xa6, +0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, +0x80, 0x04, 0x12, 0x1d, 0xad, 0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x90, 0xfa, 0xb6, 0xe0, 0xff, +0x24, 0x12, 0x12, 0x1c, 0x41, 0x20, 0xe1, 0x39, 0x12, 0x1c, 0xd0, 0xef, 0x24, 0xfc, 0x60, 0x1b, +0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, +0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb7, 0xe0, 0x60, +0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf, +0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x12, 0x1c, 0xc1, 0x60, 0x4d, 0x04, 0x60, +0x03, 0x02, 0x0c, 0xb2, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x0f, 0x90, 0xff, 0xa4, 0x12, 0x1c, 0x3a, +0x30, 0xe1, 0x6f, 0x12, 0x1d, 0x7c, 0x02, 0x0c, 0xb2, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfb, 0x12, +0x1c, 0x3d, 0xfe, 0x30, 0xe1, 0x5c, 0x30, 0xe2, 0x11, 0x30, 0xb4, 0x05, 0x12, 0x1d, 0x7c, 0x80, +0x51, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x48, 0x30, 0x95, 0x05, 0x12, 0x1d, 0x7c, +0x80, 0x40, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x37, 0x90, 0xfa, 0xb7, 0xe0, 0x60, +0x12, 0x90, 0xff, 0xb4, 0x12, 0x1c, 0x3a, 0x30, 0xe1, 0x28, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, +0xf0, 0x80, 0x1f, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfb, 0x12, 0x1c, 0x3d, 0x30, 0xe1, 0x13, 0x30, +0x93, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, +0xfd, 0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfc, +0x60, 0x40, 0x04, 0x70, 0x78, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xa2, 0xe0, 0x44, +0x40, 0xf0, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x65, 0xd2, 0x03, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90, +0xff, 0xa3, 0xef, 0x54, 0x7f, 0xf0, 0x80, 0x55, 0x30, 0x03, 0x0e, 0x90, 0xff, 0xa3, 0xe0, 0x44, +0x80, 0xf0, 0xc2, 0x03, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, +0x80, 0x3b, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xb2, 0xe0, 0x44, 0x40, 0xf0, 0xa3, +0xe0, 0xff, 0x30, 0xe7, 0x28, 0xd2, 0x04, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90, 0xff, 0xb3, 0xef, +0x54, 0x7f, 0xf0, 0x80, 0x18, 0x30, 0x04, 0x0e, 0x90, 0xff, 0xb3, 0xe0, 0x44, 0x80, 0xf0, 0xc2, +0x04, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, +0x30, 0xec, 0x12, 0x1c, 0x30, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfc, 0x60, 0x0f, 0x04, 0x70, 0x16, +0x90, 0xff, 0xa6, 0xe0, 0x12, 0x1c, 0x11, 0x12, 0x1a, 0x38, 0x80, 0x0a, 0x90, 0xff, 0xb6, 0xe0, +0x12, 0x1c, 0x11, 0x12, 0x1a, 0x38, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, 0x2c, 0x07, 0xe4, +0xff, 0x12, 0x30, 0xec, 0x12, 0x1d, 0x37, 0x7f, 0x03, 0x12, 0x12, 0x19, 0x90, 0xf9, 0x15, 0xe0, +0x30, 0xe4, 0x08, 0x90, 0xff, 0x93, 0x74, 0x80, 0xf0, 0x80, 0x10, 0x90, 0xff, 0xfc, 0xe0, 0x54, +0x7f, 0xf0, 0x7f, 0xff, 0x7e, 0x00, 0x12, 0x30, 0x16, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, +0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x90, 0xfa, 0xbc, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, +0xb4, 0xf0, 0xa3, 0x74, 0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, +0xb9, 0xf0, 0xd3, 0x94, 0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbd, 0xe0, 0x90, 0xfa, +0xb9, 0xf0, 0x12, 0x0f, 0x50, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x73, 0x12, 0x1c, 0x4a, 0x90, 0xfa, +0xbc, 0x12, 0x1d, 0x56, 0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, +0xfa, 0xb9, 0x74, 0x40, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbd, 0xe0, 0x90, 0xfa, 0xb9, 0xf0, 0x12, +0x0f, 0x50, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x46, 0x12, 0x1c, 0x4a, 0x80, 0xd1, 0x75, 0x4c, 0x02, +0x90, 0xfa, 0xbc, 0xe4, 0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb4, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, +0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0x90, 0xfa, 0xbd, 0xe0, 0xf5, 0x4a, 0x7d, 0x0f, 0x7c, +0x00, 0x12, 0x28, 0x9f, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0xe4, +0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xaf, 0x31, +0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x64, 0xf0, +0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb7, 0xe0, 0x54, 0x0f, 0x90, +0xf9, 0x63, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, +0x1d, 0x9c, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x30, 0xec, +0x12, 0x1c, 0xd0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, +0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, 0x12, 0x1d, 0xa6, 0x12, 0x0f, 0x78, +0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x78, 0xff, +0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, 0x1d, 0xa6, 0xf0, 0x90, 0xfa, 0xb7, +0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, +0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, 0x92, 0x80, 0x23, 0x12, 0x1d, 0xad, +0x12, 0x0f, 0x98, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, +0x0f, 0x98, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, 0xd2, 0x92, 0x12, 0x1d, 0xad, 0xf0, +0xe4, 0xff, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, +0x18, 0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x31, 0xbd, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, +0x90, 0xfa, 0xb4, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, +0xfa, 0xb4, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22, +0xaa, 0x4e, 0xa9, 0x4f, 0x7b, 0xff, 0x90, 0xfa, 0xb4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, +0xb9, 0xe0, 0xf5, 0x4a, 0x12, 0x28, 0x9f, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x22, 0x12, 0x22, 0xa0, +0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22, 0xf0, 0x7f, 0x01, 0x12, 0x12, 0x19, 0x90, 0xff, +0xa6, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x54, 0xa0, 0x22, 0x12, 0x25, 0xd7, 0x8f, 0x4c, 0x7e, 0x00, +0xc3, 0xef, 0x95, 0x3c, 0xee, 0x95, 0x3b, 0x22, 0xf0, 0x7f, 0x01, 0x12, 0x12, 0x19, 0x90, 0xff, +0xb6, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x54, 0xa0, 0x22, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, +0x2c, 0x07, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x02, 0x31, 0x82, 0x8e, 0x39, 0x8f, 0x3a, 0x02, 0x2c, +0x07, 0x12, 0x22, 0xa0, 0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22, 0x7d, 0x01, 0x12, 0x25, +0xd7, 0x90, 0xfa, 0xb1, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, 0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, +0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, 0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, +0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, 0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, +0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x05, 0xe5, 0x3e, 0x24, +0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, 0x10, 0x78, 0x7f, 0x00, 0x7e, 0x00, +0xe5, 0x43, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, +0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3, +0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, +0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, +0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x12, 0x11, 0x0f, 0xd0, 0x05, 0xd0, +0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, 0x44, 0x75, 0xa8, 0x88, 0xec, 0x70, +0x02, 0x7c, 0x3f, 0x8c, 0x3d, 0x22, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, 0x66, +0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x06, 0x7c, 0xff, 0x12, 0x10, +0x78, 0xe5, 0x43, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, +0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, +0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, +0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, +0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, 0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, +0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, 0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, +0xee, 0x12, 0x11, 0x0f, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, +0x3d, 0x00, 0x85, 0x44, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc3, 0xe5, 0x43, 0x24, +0xe8, 0x50, 0x05, 0x12, 0x11, 0x66, 0x80, 0xf4, 0xef, 0x60, 0x31, 0x90, 0x30, 0x54, 0xe4, 0x93, +0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x10, 0x78, 0xd0, 0x04, 0x43, 0x07, 0x80, +0xe5, 0x43, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, +0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x43, 0x12, 0x11, 0x0f, 0xd0, 0x83, 0xd0, 0x82, +0xd0, 0xf0, 0x22, 0x02, 0x11, 0x94, 0xc0, 0x04, 0x7c, 0x20, 0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, +0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, 0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, +0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, 0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, +0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, 0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, +0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, +0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, +0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0xd2, 0xb0, 0xd2, 0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, +0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, +0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, 0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, +0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x42, 0x8e, 0x41, 0x22, 0xc3, 0xef, 0x94, 0xbc, +0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, +0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x40, 0x8e, 0x3f, 0x22, 0xef, 0x70, 0x01, 0x22, 0xc0, 0x00, 0xc0, +0xa8, 0xc2, 0xaf, 0xe5, 0x3e, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0xc6, +0x54, 0x7f, 0xf6, 0xd0, 0xa8, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x11, 0x66, 0x80, 0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08, 0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5, -0x12, 0x10, 0xec, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, -0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0xa0, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, +0x12, 0x11, 0x66, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, +0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0x9a, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78, -0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x0e, 0xf5, 0x82, -0xe5, 0xf0, 0x34, 0x2e, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, +0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x36, 0xf5, 0x82, +0xe5, 0xf0, 0x34, 0x30, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, 0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24, 0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04, -0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x44, 0x00, 0x75, 0x49, +0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x3e, 0x00, 0x75, 0x43, 0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76, 0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90, -0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, +0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x30, 0x54, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, 0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f, 0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75, -0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x91, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, -0xe5, 0x49, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x19, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, +0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x8b, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, +0xe5, 0x43, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, 0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6, 0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08, -0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x11, 0xc1, 0xad, 0x07, 0xaf, 0x02, -0x12, 0x11, 0xd8, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x10, 0xec, 0x80, 0xc1, 0xe7, -0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, -0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, -0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, -0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, -0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, -0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, -0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, -0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, -0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, -0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, -0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, -0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, -0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, -0xf0, 0xef, 0x60, 0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, -0x50, 0xb9, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, -0x23, 0x90, 0x13, 0x0f, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, -0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, -0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, -0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, -0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, -0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, -0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, -0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, -0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, -0x83, 0xe0, 0x38, 0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, -0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, -0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, -0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, -0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, -0xe9, 0x93, 0x22, 0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, -0x50, 0x06, 0xf7, 0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, -0x19, 0x22, 0xf8, 0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, -0xe8, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, -0xf0, 0x22, 0xbb, 0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, -0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, -0x08, 0xe6, 0xf9, 0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, -0xe0, 0xfa, 0xa3, 0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, -0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, -0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, -0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, -0xff, 0xf9, 0x74, 0x02, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, 0x00, -0x7a, 0x00, 0x79, 0x37, 0x75, 0x40, 0x00, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0xe5, 0x37, -0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x37, 0x64, 0x07, 0x60, 0x0b, 0xe5, 0x37, 0x64, 0x06, -0x60, 0x05, 0xe5, 0x37, 0xb4, 0x14, 0x1b, 0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0xe5, -0x37, 0xb4, 0x07, 0x08, 0x90, 0xf9, 0x65, 0x74, 0x02, 0xf0, 0x80, 0x06, 0x90, 0xf9, 0x65, 0x74, -0x01, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x17, 0x71, 0x90, 0xff, -0xf5, 0xe5, 0x37, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, -0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x12, 0x17, 0x71, 0xe5, 0x37, 0x30, 0xe7, -0x02, 0xd2, 0x02, 0xe4, 0xf5, 0x2c, 0xf5, 0x2a, 0xf5, 0x2b, 0xf5, 0x29, 0x12, 0x19, 0x92, 0x12, -0x18, 0x49, 0x12, 0x19, 0x6c, 0x90, 0xf9, 0x66, 0x12, 0x15, 0x06, 0x90, 0xf9, 0x6b, 0x12, 0x15, -0x06, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, 0x74, -0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0x12, -0x18, 0xbf, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x37, 0x12, 0x18, 0xcd, 0xf5, 0x83, 0xe4, 0xf0, 0x05, -0x37, 0xe5, 0x37, 0xb4, 0x07, 0xe7, 0x78, 0x80, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x2f, 0x06, -0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x2f, 0x13, 0xe4, 0x93, 0xff, 0x08, -0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x18, 0xaf, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, 0x08, -0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, 0x9f, -0x78, 0x81, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x18, 0x41, 0xce, 0xc3, 0x13, 0xce, 0x13, -0xd8, 0xf9, 0xff, 0xed, 0x12, 0x19, 0x07, 0xef, 0xf0, 0xed, 0x12, 0x19, 0x2d, 0xe4, 0xf5, 0x37, -0xe5, 0x37, 0x90, 0x2f, 0x00, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xe5, 0x37, 0x25, 0xe0, 0x24, -0x07, 0xf5, 0x82, 0xe4, 0x34, 0x2f, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, 0x53, -0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xaf, 0x12, 0x19, 0x15, 0x24, 0x47, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, 0x19, -0x07, 0xef, 0xf0, 0x12, 0x18, 0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, -0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x19, 0x2d, 0xe9, -0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, -0x02, 0x17, 0x46, 0x78, 0x7e, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xf9, 0x12, 0x19, 0x15, 0x24, -0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, -0x12, 0x19, 0x1a, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x18, -0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 0x24, 0x05, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5, 0x37, 0x64, 0x04, 0x60, 0x03, 0x02, 0x16, -0x70, 0x90, 0x2f, 0x05, 0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0x12, 0x18, 0xf7, 0xe4, 0xf0, 0x90, -0x2f, 0x04, 0x93, 0xff, 0xf6, 0x12, 0x18, 0xad, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, 0xf0, -0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, -0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, -0x2f, 0xe5, 0x52, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, -0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0x74, 0x11, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, -0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x06, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, -0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0xab, 0x2d, -0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, -0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, -0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x04, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, -0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x05, 0xe0, -0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, -0x35, 0x2e, 0xf5, 0x2e, 0x22, 0xf5, 0x83, 0xe0, 0x54, 0x08, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, -0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, 0x78, 0x81, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, -0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, 0x75, 0x2d, 0x01, 0x75, 0x2e, 0xf9, 0x75, -0x2f, 0x6e, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xfa, 0xb5, 0xe0, 0x24, -0xfc, 0x22, 0x90, 0xfa, 0xb8, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xbc, 0xe0, 0x9f, 0xf0, -0x90, 0xfa, 0xbb, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xb3, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, -0x25, 0x55, 0xf5, 0x55, 0xee, 0x35, 0x54, 0xf5, 0x54, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb0, -0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x22, 0x78, 0x82, 0xe6, 0xfe, 0x08, -0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, -0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x53, 0x75, -0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0xe5, 0x53, 0x75, 0xf0, 0x08, -0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, -0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x75, 0x2a, 0x00, 0x8f, 0x2b, 0x90, 0xf9, 0x6b, -0x12, 0x14, 0xfd, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, -0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, 0xe4, -0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, 0xa4, -0x22, 0x74, 0xae, 0x25, 0x36, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, -0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, 0xff, -0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, 0xfc, -0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x6d, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x65, -0xf0, 0x22, 0x12, 0x14, 0xdf, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xf9, -0x79, 0x6e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, -0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x66, 0x02, -0x14, 0xfd, 0x75, 0x30, 0x01, 0x75, 0x31, 0x09, 0x22, 0xd3, 0xe5, 0x35, 0x94, 0x08, 0xe5, 0x34, -0x94, 0x01, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x90, 0xfa, 0xb6, 0xf0, 0x22, 0x90, 0xff, 0xa4, -0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xef, 0x22, 0x8f, 0x38, 0x12, 0x27, 0x19, -0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xe0, 0xfd, -0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x12, 0x20, 0x7c, 0x24, -0x07, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x12, 0x20, 0xbe, 0x24, 0x09, 0x12, 0x20, 0x25, 0xef, 0xf0, -0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x20, 0x2f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, -0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, 0x82, 0xe0, 0x33, 0xd0, -0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xe0, 0xfc, 0xa3, 0xe0, -0xfd, 0xec, 0xff, 0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xef, 0xf0, 0xed, -0x12, 0x20, 0xbe, 0x24, 0x07, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, -0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x20, 0x69, 0xa3, 0xe0, -0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, -0x2f, 0x4d, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x12, 0x20, 0xae, 0x24, 0x06, 0x12, 0x20, 0x25, -0xe0, 0x60, 0x03, 0x43, 0x07, 0x04, 0x53, 0x07, 0xfc, 0x78, 0x86, 0x12, 0x20, 0x96, 0x24, 0x04, -0x12, 0x20, 0x25, 0xe0, 0x42, 0x07, 0x43, 0x07, 0x80, 0x12, 0x20, 0xa6, 0xf5, 0x82, 0x8a, 0x83, -0xa3, 0xa3, 0xef, 0xf0, 0x12, 0x20, 0xbe, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x8d, 0x82, -0x8c, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, -0x03, 0x43, 0x07, 0x20, 0xec, 0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, -0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 0x4c, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x42, -0x12, 0x20, 0xae, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 0x60, 0x31, 0x14, 0x60, 0x29, 0x14, -0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 0x38, 0xb4, 0x03, 0x0d, 0x30, 0x95, -0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, 0x43, 0x07, -0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, 0x07, 0xfd, -0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x20, 0x94, 0x24, 0x04, 0x12, 0x20, 0x25, 0xef, 0xf0, 0x8d, -0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, -0x4a, 0xee, 0x30, 0xe1, 0x43, 0x08, 0x12, 0x20, 0xb0, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, -0x60, 0x2c, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, -0x38, 0xb4, 0x03, 0x0d, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x1f, 0x43, 0x07, 0x80, 0x80, -0x1a, 0x30, 0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x12, 0x43, 0x07, 0x80, 0x80, 0x0d, 0x53, 0x07, -0x7f, 0x80, 0x08, 0x43, 0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x86, 0x12, 0x20, 0x65, -0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, -0xec, 0x30, 0xe3, 0x05, 0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, -0x43, 0x07, 0x10, 0x80, 0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, -0x03, 0x53, 0x07, 0xf7, 0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, -0xed, 0x30, 0xe6, 0x05, 0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, -0x43, 0x07, 0x02, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x78, 0x84, 0x12, 0x20, 0x65, 0xa3, 0xef, 0xf0, -0x12, 0x2f, 0x80, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x8e, 0xef, 0xf6, 0x12, 0x27, 0x19, -0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0xfd, 0x12, 0x20, 0x53, 0x90, -0x00, 0x0a, 0x12, 0x20, 0x78, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x14, -0x0d, 0x12, 0x20, 0x70, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x59, 0x12, 0x20, -0x7c, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xf5, 0x5a, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, -0xf5, 0x5b, 0xe5, 0x59, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x8e, 0xf6, 0xd3, 0x94, 0x00, -0x40, 0x06, 0xe5, 0x5a, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x8e, 0xe6, 0x12, 0x20, 0x52, 0x90, 0x00, -0x0c, 0xef, 0x12, 0x14, 0x0d, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, -0xff, 0x53, 0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x59, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, -0x5a, 0x20, 0xe5, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 0x20, 0xe7, 0x03, 0x43, -0x07, 0x02, 0xe5, 0x59, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x59, 0x30, 0xe2, 0x03, 0x43, -0x07, 0x20, 0xe5, 0x59, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x59, 0x30, 0xe1, 0x03, -0x43, 0x07, 0x80, 0xe5, 0x59, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x59, 0x30, 0xe6, 0x03, -0x43, 0x06, 0x08, 0xe5, 0x5a, 0x20, 0xe4, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, -0x20, 0xe7, 0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, -0x8f, 0xf0, 0x12, 0x14, 0xb2, 0xe5, 0x5b, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, -0x12, 0x20, 0x52, 0x90, 0x00, 0x08, 0xef, 0x12, 0x14, 0x0d, 0x80, 0x0a, 0x12, 0x20, 0x53, 0x90, -0x00, 0x08, 0xe4, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x03, 0x12, 0x20, 0x52, 0x90, 0x00, 0x07, -0xef, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x14, -0x0d, 0x90, 0x00, 0x07, 0x12, 0x13, 0xce, 0x70, 0x13, 0x12, 0x20, 0x53, 0xe9, 0x24, 0x09, 0xf9, -0xe4, 0x3a, 0xfa, 0x12, 0x13, 0xb5, 0xff, 0xc3, 0x13, 0x12, 0x13, 0xfb, 0x12, 0x20, 0x94, 0x24, -0x08, 0x12, 0x20, 0x25, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x20, -0x25, 0xe0, 0xfd, 0xee, 0xed, 0x12, 0x20, 0x52, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x14, -0xb2, 0x12, 0x2f, 0x80, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 0x90, 0xfa, -0xe2, 0xe0, 0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, -0xfa, 0xd6, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xff, 0x7e, 0x00, -0x90, 0xfa, 0xd2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, -0x12, 0x14, 0x5b, 0xff, 0x90, 0xfa, 0xd4, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, -0x01, 0x8e, 0x56, 0x8f, 0x57, 0x74, 0x0a, 0x25, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, -0x90, 0xfa, 0xd7, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd5, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, -0xff, 0x90, 0xfa, 0xd9, 0xf0, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0x90, 0xfa, 0xd2, 0xe0, 0x94, -0x00, 0x50, 0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 0x60, 0x03, 0xe0, 0xff, -0x22, 0x12, 0x2a, 0x80, 0x90, 0xfa, 0xd2, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, -0xfa, 0xd6, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, -0xfa, 0xd9, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, -0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, 0x2a, 0x80, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x58, -0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7f, 0x00, 0x22, 0xaa, 0x56, 0xa9, -0x57, 0x7b, 0x01, 0x90, 0xfa, 0xd4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xd9, 0xe0, 0xf5, -0x50, 0x12, 0x26, 0x25, 0x90, 0xfa, 0xd8, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, -0xfe, 0x60, 0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x1e, 0xed, 0x24, 0x06, 0x60, 0x03, 0x02, 0x1f, -0x35, 0x78, 0x77, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, -0x74, 0x33, 0x90, 0xfa, 0x90, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xae, 0x74, 0x01, 0xf0, -0x22, 0x78, 0x78, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, -0x74, 0x43, 0x90, 0xfa, 0x92, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, -0x22, 0x90, 0xfa, 0x9c, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x1f, 0x35, 0x90, 0xff, 0xa6, 0xe0, -0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, -0x90, 0xff, 0xa6, 0x12, 0x20, 0x83, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, -0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x57, 0x90, 0xfa, -0xca, 0xe0, 0xff, 0x74, 0x34, 0x90, 0xfa, 0x94, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa6, -0xe0, 0xa3, 0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, -0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x20, 0x83, 0x90, -0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, -0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, -0x96, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, -0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, -0x06, 0xc0, 0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc8, 0xf0, 0x90, 0xff, 0x92, 0xe4, -0xf0, 0xef, 0x12, 0x15, 0x0f, 0x1f, 0xed, 0x26, 0x1f, 0xed, 0x2e, 0x1f, 0x90, 0x30, 0x1f, 0x90, -0x32, 0x1f, 0x9e, 0x38, 0x1f, 0xb0, 0x3a, 0x1f, 0xe2, 0x3e, 0x1f, 0xcd, 0x44, 0x1f, 0xc2, 0x46, -0x1f, 0xd8, 0x50, 0x1f, 0xd8, 0x52, 0x1f, 0xd8, 0x54, 0x1f, 0xd8, 0x56, 0x00, 0x00, 0x1f, 0xf2, -0x90, 0xfa, 0xc8, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x10, 0x9c, 0x80, 0x62, 0x7c, 0x00, -0x7d, 0x01, 0x7f, 0x03, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, -0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x02, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, -0x80, 0x3e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x10, 0x9c, 0x80, 0x33, 0x7c, 0x00, 0x7d, -0x01, 0x7f, 0x06, 0x12, 0x10, 0x9c, 0x80, 0x28, 0x90, 0xfa, 0xc8, 0xe0, 0xff, 0x12, 0x1e, 0x4a, -0x80, 0x1e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x10, 0x9c, 0x80, 0x13, 0x12, 0x25, 0x13, -0x80, 0x0e, 0x90, 0xfa, 0xc8, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x29, 0xda, -0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, -0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x82, 0xe6, 0xfe, 0x08, -0xe6, 0x24, 0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x78, 0x82, 0xe6, -0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, -0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, 0xff, 0x7a, 0x2f, 0x79, 0x52, 0x7e, 0x00, 0x7f, 0x0a, 0x02, -0x13, 0x8f, 0xff, 0x90, 0xf9, 0x6b, 0x02, 0x14, 0xfd, 0x90, 0xf9, 0x66, 0x12, 0x14, 0xfd, 0x90, -0x00, 0x04, 0x02, 0x13, 0xce, 0xe6, 0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, -0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xed, 0x12, 0x14, 0x0d, 0x8f, 0x82, 0x8e, 0x83, -0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, -0xf0, 0x4e, 0xf0, 0x22, 0x78, 0x84, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, 0x83, 0x22, 0xa6, 0x07, -0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x22, 0x78, 0x84, 0xe6, 0xfa, 0x08, 0xe6, 0xfb, 0x22, 0x78, 0x86, -0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, -0x8a, 0x83, 0xe5, 0x82, 0x22, 0x8b, 0x38, 0x8a, 0x39, 0x89, 0x3a, 0x8d, 0x3b, 0x90, 0xfa, 0xce, -0xe4, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe0, -0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xcd, 0xe0, 0x65, -0x3b, 0x60, 0x46, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x21, -0x54, 0x90, 0xfa, 0xcd, 0xe0, 0xff, 0x90, 0xfa, 0xd0, 0xe4, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0x12, -0x21, 0x54, 0x90, 0xfa, 0xd0, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xce, 0xcf, 0xf0, 0xa3, 0xef, -0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xa3, 0x75, 0xf0, 0x00, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xce, 0xe4, -0x75, 0xf0, 0x04, 0x12, 0x14, 0x2f, 0x02, 0x20, 0xd6, 0x90, 0xfa, 0xcf, 0xe0, 0x24, 0x01, 0xff, -0x90, 0xfa, 0xce, 0xe0, 0x34, 0x00, 0xab, 0x38, 0xaa, 0x39, 0xa9, 0x3a, 0x8f, 0xf0, 0x12, 0x14, -0x93, 0x7f, 0x00, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe4, 0x75, 0xf0, -0x01, 0x12, 0x14, 0x2f, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x8f, 0x68, -0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xfb, -0xf0, 0x44, 0x02, 0xf0, 0x08, 0x12, 0x20, 0x65, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x20, 0x7c, -0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x82, 0xe6, 0xfe, 0x08, 0xe6, 0xff, -0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x68, 0x24, 0xfe, 0x44, 0x20, 0xfc, -0x4d, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, -0x82, 0x8e, 0x83, 0xa3, 0x74, 0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, -0x05, 0x12, 0x20, 0x25, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x95, 0x25, 0x68, 0xf5, 0x82, -0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, -0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, -0x25, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x68, 0xf8, 0x74, 0x04, 0x46, -0xf6, 0x7f, 0x00, 0x22, 0x8b, 0x62, 0x8a, 0x63, 0x89, 0x64, 0x12, 0x2a, 0x62, 0x90, 0xfa, 0xbf, -0x12, 0x15, 0x06, 0xaa, 0x63, 0xa9, 0x64, 0x90, 0xfa, 0xc2, 0x12, 0x15, 0x06, 0x90, 0xfa, 0xc3, -0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xc2, 0x12, 0x14, 0xfd, 0xe9, 0x24, 0x01, -0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc5, 0x12, 0x15, 0x06, 0xab, 0x62, 0xaa, 0x63, 0xa9, 0x64, -0x12, 0x2a, 0x6e, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x88, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, -0xff, 0x78, 0x88, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xbf, 0x12, 0x2a, 0x43, 0xff, 0x78, -0x89, 0xf6, 0x90, 0xfa, 0xc2, 0x12, 0x2a, 0x43, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x89, 0xf6, 0x12, -0x2a, 0x40, 0x5e, 0x4f, 0xff, 0x78, 0x89, 0xf6, 0x12, 0x2a, 0x49, 0x75, 0xf0, 0x02, 0x12, 0x14, -0x2f, 0x90, 0xfa, 0xc3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0xab, 0x62, 0xaa, 0x63, 0xa9, -0x64, 0x90, 0x00, 0x04, 0x12, 0x13, 0xce, 0x30, 0xe4, 0x03, 0x12, 0x2a, 0x58, 0x78, 0x88, 0x06, -0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x22, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x90, 0xfa, -0xbe, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbd, 0xf0, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x26, -0x14, 0x70, 0x70, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x22, 0x14, 0x80, -0x62, 0x12, 0x2a, 0x79, 0x12, 0x1d, 0x5e, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0x80, 0x55, 0x90, 0xfa, -0xbe, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, 0x12, -0x29, 0x85, 0x80, 0x3f, 0xe5, 0x5e, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5d, 0xfa, 0x7b, 0x01, 0xc0, -0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xfd, 0x90, -0x00, 0x08, 0x12, 0x14, 0x5b, 0xf5, 0x41, 0x85, 0xf0, 0x40, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, -0x12, 0x23, 0xee, 0x90, 0xfa, 0xbd, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, 0xbe, -0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbe, 0xe0, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x02, 0x12, 0x14, 0x0d, -0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0x89, 0x7f, 0x02, 0x12, 0x11, 0x9f, 0x78, 0x6d, -0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, 0xb1, 0xd2, 0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, -0x7a, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, -0x78, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, -0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, 0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, -0xe3, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, 0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, -0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7a, -0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x78, -0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x15, -0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe3, 0xe0, 0xf5, 0xa8, 0x02, 0x10, 0x0c, 0x8b, 0x3c, -0x8a, 0x3d, 0x89, 0x3e, 0x8d, 0x3f, 0xe5, 0x3f, 0x70, 0x03, 0xaf, 0x3f, 0x22, 0x12, 0x2a, 0xa8, -0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x40, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x2e, 0xd4, 0x50, 0xf2, -0x12, 0x24, 0x7b, 0x40, 0x0b, 0x7f, 0x00, 0x22, 0x12, 0x2a, 0xc7, 0x12, 0x24, 0x7b, 0x50, 0xf8, -0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, 0x3f, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, -0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, 0xf5, 0x42, 0xe5, 0x3f, 0x14, 0xff, 0xe5, 0x42, 0xc3, -0x9f, 0x50, 0x2a, 0x12, 0x2e, 0xbd, 0x40, 0x03, 0xaf, 0x42, 0x22, 0xc3, 0xe5, 0x3f, 0x95, 0x42, -0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2a, 0xba, 0x05, 0x42, -0x74, 0x01, 0x25, 0x3e, 0xf5, 0x3e, 0xe4, 0x35, 0x3d, 0xf5, 0x3d, 0x80, 0xcc, 0x12, 0x2e, 0xbd, -0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xba, 0xaf, 0x3f, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x41, -0xf0, 0x02, 0x2e, 0xd4, 0x75, 0xa8, 0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x91, -0x02, 0x24, 0xce, 0x02, 0x2e, 0x88, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, -0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, -0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, -0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x28, -0xcb, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, -0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, -0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, -0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, -0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x36, 0x12, 0x19, 0x21, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x36, 0x24, -0x03, 0xff, 0x12, 0x2d, 0x4f, 0x12, 0x19, 0x21, 0xe4, 0xf0, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, -0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x36, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x90, 0x12, 0x19, -0x62, 0x60, 0x2c, 0x12, 0x29, 0xda, 0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, -0x90, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x36, 0x90, 0xfa, 0x9c, -0x12, 0x14, 0xdf, 0xe0, 0xa3, 0x30, 0xe6, 0x33, 0x12, 0x19, 0x21, 0x74, 0x04, 0xf0, 0x22, 0x75, -0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x19, 0x62, 0x60, 0x16, 0x12, 0x29, 0xda, 0xef, -0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, -0xf0, 0x22, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, -0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, -0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xfb, 0x0f, 0x12, 0x18, 0x19, 0x80, -0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x31, 0x9d, 0xf5, 0x31, 0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0xd3, -0xe5, 0x31, 0x94, 0x00, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, -0x12, 0x19, 0x3e, 0x12, 0x19, 0x92, 0x12, 0x19, 0x8c, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x1e, -0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x13, 0xce, 0xff, 0x24, 0xfc, -0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x10, 0x9c, 0x12, 0x19, -0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, -0xff, 0x12, 0x2f, 0x6a, 0x22, 0x8b, 0x4b, 0x8a, 0x4c, 0x89, 0x4d, 0x8c, 0x4e, 0x8d, 0x4f, 0xd2, -0x00, 0x12, 0x2a, 0xa8, 0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x4e, 0x90, 0xff, 0xf1, 0xf0, 0x12, -0x2e, 0xd4, 0x50, 0xf2, 0x12, 0x26, 0x9a, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xc7, 0x12, -0x26, 0x9a, 0x50, 0xf8, 0xe4, 0xf5, 0x51, 0xe5, 0x50, 0x14, 0xff, 0xe5, 0x51, 0xc3, 0x9f, 0x50, -0x17, 0x12, 0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x05, 0x51, 0x74, 0x01, 0x25, 0x4d, 0xf5, -0x4d, 0xe4, 0x35, 0x4c, 0xf5, 0x4c, 0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, -0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x7f, 0x00, 0x22, 0xab, 0x4b, 0xaa, 0x4c, 0xa9, 0x4d, -0x12, 0x13, 0xb5, 0x90, 0xff, 0xf1, 0xf0, 0x02, 0x2e, 0xd4, 0x90, 0xff, 0xf1, 0xe5, 0x4f, 0xf0, -0x02, 0x2e, 0xd4, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 0xfa, -0xcb, 0xe4, 0x75, 0xf0, 0x09, 0x12, 0x14, 0x2f, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, -0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x12, -0x23, 0xee, 0x90, 0xff, 0xf7, 0xe5, 0x37, 0x12, 0x26, 0xfe, 0x90, 0xff, 0xf6, 0xe5, 0x37, 0xf0, -0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x06, 0x12, 0x26, 0xfe, 0xe5, 0x37, 0x30, 0xe0, 0x07, -0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, 0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, -0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, -0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x15, 0x6b, 0xa8, 0x6b, 0xa6, 0x07, 0x30, -0x08, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x6b, 0xe6, 0xff, 0xb4, 0x03, 0x0f, -0x78, 0x82, 0x76, 0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, -0x82, 0x76, 0xff, 0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x86, 0x76, 0xfa, -0x08, 0x76, 0x9a, 0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x20, 0xb7, 0x7b, -0x01, 0x7a, 0xff, 0x79, 0x48, 0x78, 0x6e, 0x12, 0x14, 0xf4, 0xa8, 0x6b, 0xe6, 0x24, 0xfd, 0x75, -0xf0, 0x08, 0xa4, 0xff, 0xae, 0xf0, 0x78, 0x70, 0x12, 0x20, 0xb7, 0x79, 0x08, 0x78, 0x71, 0x12, -0x14, 0xf4, 0x78, 0x73, 0xef, 0x12, 0x20, 0xb7, 0x05, 0x6b, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, -0xab, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe2, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, -0x79, 0xcb, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7e, 0x00, 0x90, 0xfa, -0xe0, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x52, -0x09, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe0, 0xe0, 0x70, 0x04, -0xa3, 0xe0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x65, -0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe2, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x65, 0xe0, -0x54, 0xef, 0xf0, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x90, 0xff, 0x93, 0x74, 0x2a, -0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, 0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, -0xe0, 0x44, 0x90, 0xf0, 0x12, 0x27, 0x8b, 0x12, 0x15, 0x35, 0x12, 0x2d, 0xa5, 0x7e, 0x07, 0x7f, -0xd0, 0x12, 0x11, 0x68, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0x82, 0xe4, 0x78, 0x7d, 0xf6, 0x78, -0x7d, 0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x74, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x7d, -0x06, 0x80, 0xec, 0x7f, 0x03, 0x12, 0x2c, 0x5b, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe4, 0x05, 0x7f, -0x04, 0x12, 0x2c, 0x5b, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, -0xe0, 0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x90, 0xef, 0xf6, 0x12, 0x27, -0x19, 0x12, 0x20, 0x59, 0x30, 0xe0, 0x25, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x7f, 0xf0, 0x78, 0x71, -0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, 0xe4, -0x12, 0x14, 0x0d, 0x80, 0xe9, 0x12, 0x20, 0x2d, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x20, 0x59, 0x30, -0xe1, 0x1e, 0x12, 0x20, 0x1b, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x2f, 0x15, 0x78, 0x6e, 0x12, 0x14, -0xeb, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x14, 0x0d, 0x12, 0x20, 0x1b, 0xe0, 0x44, 0x80, 0xf0, -0x12, 0x2f, 0x80, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x03, 0x6e, 0x01, 0xff, 0x48, -0x03, 0x71, 0x01, 0xff, 0x08, 0x02, 0x6c, 0x00, 0x00, 0x44, 0xfa, 0x94, 0x00, 0x00, 0x00, 0x00, -0x44, 0xfa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xae, 0x00, 0x00, 0x42, 0xfa, 0x7a, 0x00, -0x00, 0x42, 0xfa, 0x78, 0x00, 0x00, 0x42, 0xf9, 0x69, 0xff, 0xff, 0x42, 0xfa, 0x76, 0x00, 0x00, -0x43, 0xf9, 0x16, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x63, 0x20, 0x41, 0xf9, 0x64, 0x20, 0x41, 0xf9, -0x61, 0x00, 0x41, 0xf9, 0x62, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf9, 0x65, -0x00, 0x41, 0xf9, 0x15, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, 0x19, 0x82, -0xe5, 0x31, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x31, 0x94, -0x08, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x11, 0x7f, 0x08, 0xef, 0xe5, 0x31, 0x94, 0x08, 0xf5, 0x31, -0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0x80, 0x05, 0xaf, 0x31, 0x12, 0x19, 0x92, 0xe4, 0xfe, 0xee, -0xc3, 0x9f, 0x50, 0x19, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, -0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, 0xf0, 0x0e, 0x12, 0x18, 0x19, 0x80, 0xe2, 0xef, 0x54, 0x7f, -0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, 0x5f, 0x8a, 0x60, 0x89, 0x61, 0x12, 0x2a, 0x6e, 0x70, 0x05, -0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, 0x5f, 0xaa, 0x60, 0xa9, 0x61, 0x12, 0x2a, 0x62, 0x90, 0xfa, -0xc5, 0x12, 0x15, 0x06, 0xe5, 0x61, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x60, 0xfa, 0x90, 0xfa, 0xbf, -0x12, 0x15, 0x06, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x78, 0x91, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 0xff, -0x78, 0x91, 0xe6, 0xc3, 0x9f, 0x50, 0x12, 0x12, 0x2a, 0x40, 0xff, 0x12, 0x2a, 0x49, 0x12, 0x2a, -0x5c, 0x78, 0x91, 0x06, 0x12, 0x2a, 0x58, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x2f, -0x06, 0xe4, 0x93, 0xff, 0x78, 0x7a, 0xf6, 0x54, 0x0f, 0x12, 0x19, 0x07, 0xe0, 0x08, 0x76, 0x00, -0x08, 0xf6, 0x18, 0x12, 0x18, 0x42, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x7b, -0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, 0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, -0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, 0x22, 0x78, 0x7b, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, -0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, -0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0x00, 0x03, 0x12, 0x13, 0xce, 0x54, 0xf0, 0x24, 0xa0, 0x22, -0x90, 0xfa, 0xc5, 0x12, 0x14, 0xfd, 0x02, 0x13, 0xb5, 0x90, 0xfa, 0xbf, 0x12, 0x14, 0xfd, 0xef, -0x12, 0x13, 0xfb, 0x90, 0xfa, 0xc6, 0xe4, 0x22, 0x90, 0xfa, 0xc0, 0xe4, 0x75, 0xf0, 0x01, 0x02, -0x14, 0x2f, 0x90, 0x00, 0x08, 0x12, 0x14, 0x5b, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, -0x05, 0x12, 0x13, 0xce, 0x90, 0xfa, 0xbd, 0xf0, 0x22, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x22, -0x90, 0xfa, 0xd9, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, -0xd2, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xd4, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 0x25, 0x57, -0xf5, 0x57, 0xee, 0x35, 0x56, 0xf5, 0x56, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, -0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe2, 0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x3c, -0xaa, 0x3d, 0xa9, 0x3e, 0x02, 0x13, 0xfb, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x6a, -0xed, 0x70, 0x0f, 0xe5, 0x6a, 0xb4, 0x03, 0x05, 0x7f, 0x01, 0x02, 0x2e, 0xeb, 0x7f, 0x02, 0x02, -0x2e, 0xeb, 0xaf, 0x6a, 0x12, 0x27, 0x19, 0x74, 0x74, 0x25, 0x6a, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, -0xd2, 0x09, 0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x6a, 0xb4, -0x03, 0x07, 0x7f, 0x81, 0x12, 0x2e, 0xeb, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x2e, 0xeb, 0x30, 0x09, -0x07, 0x12, 0x18, 0x9b, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x22, 0x12, 0x0f, 0x89, 0x90, -0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, 0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, -0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, 0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x2c, 0x80, -0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0d, 0x12, 0x19, 0x3e, 0x53, 0x2c, 0x7f, 0x90, -0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, 0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0x9f, -0x12, 0x19, 0x46, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 0x8a, 0x12, 0x20, 0x9e, 0x30, 0xe1, -0x07, 0x7f, 0x13, 0x12, 0x2e, 0xa5, 0x80, 0x34, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 0x16, -0x78, 0x8a, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, 0x90, -0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x04, 0xf0, 0x78, 0x8a, -0xe6, 0xff, 0x12, 0x20, 0x59, 0xfd, 0x12, 0x2d, 0x21, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, -0x0f, 0x89, 0x78, 0x8f, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x27, 0x19, 0x90, 0xf9, 0x66, 0x12, 0x14, -0xfd, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, -0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x20, 0x4b, 0x12, 0x2f, 0x80, 0x78, -0x8f, 0xe6, 0xff, 0x12, 0x19, 0xbb, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, -0x8b, 0xef, 0xf6, 0x12, 0x2e, 0x4c, 0x12, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, -0x16, 0x78, 0x8b, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, -0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x14, 0xf0, 0xe0, 0x70, 0x02, -0xd2, 0xb3, 0x02, 0x10, 0x0c, 0x8f, 0x69, 0x12, 0x27, 0x19, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x3f, -0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, -0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0x74, -0x74, 0x25, 0x69, 0xf8, 0x74, 0xfb, 0x56, 0xf6, 0x7f, 0x00, 0x22, 0x8f, 0x37, 0xc2, 0x08, 0x12, -0x27, 0x19, 0x12, 0x20, 0x38, 0x78, 0x84, 0x12, 0x20, 0x1d, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x20, -0x70, 0x12, 0x20, 0x21, 0xe0, 0x20, 0xe0, 0xf6, 0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, -0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0xaf, 0x37, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, -0x89, 0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x24, 0x06, 0x12, 0x20, 0x23, 0xe0, 0xfd, 0x12, 0x20, -0x53, 0x90, 0x00, 0x03, 0x12, 0x20, 0x78, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x04, -0x12, 0x14, 0x0d, 0x12, 0x2f, 0x80, 0x7d, 0x02, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, -0xae, 0x05, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x35, -0xe4, 0x95, 0x34, 0x40, 0x02, 0xae, 0x35, 0xee, 0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, -0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, 0x12, 0x14, 0x0d, 0xaf, 0x06, 0x12, 0x2f, 0x6a, -0x22, 0x12, 0x0f, 0x89, 0x78, 0x8c, 0x12, 0x20, 0x9e, 0x30, 0xe2, 0x07, 0x7f, 0x13, 0x12, 0x2e, -0xa5, 0x80, 0x1b, 0x78, 0x8c, 0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x20, 0xe1, 0x07, 0x7f, 0x12, 0x12, -0x2e, 0xa5, 0x80, 0x0a, 0x78, 0x8c, 0xe6, 0xff, 0x12, 0x21, 0x6e, 0x12, 0x2e, 0xa5, 0x02, 0x10, -0x0c, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, 0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, -0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, 0x74, 0x74, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, -0x74, 0x95, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, -0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, 0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, -0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x80, 0xf0, 0x74, -0x74, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 0x64, -0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, -0xc3, 0xe5, 0x31, 0x9f, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x05, 0x12, 0x25, 0x9c, 0x80, 0x03, 0x12, -0x2f, 0x76, 0x02, 0x10, 0x0c, 0x90, 0xff, 0xfc, 0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, -0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, 0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, -0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0x80, 0xef, 0x22, 0x12, 0x0f, 0x89, 0x78, -0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, 0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, -0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x11, 0x9f, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x8e, 0x65, -0x8f, 0x66, 0xe5, 0x66, 0x15, 0x66, 0xae, 0x65, 0x70, 0x02, 0x15, 0x65, 0xd3, 0x94, 0x00, 0xee, -0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, 0x12, 0x0f, 0x62, 0x80, 0xe5, 0x22, 0x11, 0x1a, -0x2b, 0x1c, 0x23, 0x56, 0x2f, 0x5c, 0x2d, 0xcc, 0x2d, 0x7a, 0x2e, 0x6b, 0x2c, 0x8e, 0x2b, 0x66, -0x2b, 0xec, 0x2c, 0xf1, 0x2e, 0x2d, 0x1b, 0xe6, 0x2b, 0xaf, 0x28, 0x67, 0x0e, 0x12, 0x0f, 0x89, -0x78, 0x8d, 0x12, 0x20, 0x9e, 0x20, 0xe2, 0x07, 0x7f, 0x11, 0x12, 0x2e, 0xa5, 0x80, 0x0a, 0x78, -0x8d, 0xe6, 0xff, 0x12, 0x2c, 0x25, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x8f, 0x67, 0x12, 0x2c, -0x25, 0xaf, 0x67, 0x12, 0x27, 0x19, 0x12, 0x20, 0x38, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x67, -0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x67, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, -0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x05, 0x12, 0x29, 0x2d, 0x80, 0x06, 0x12, -0x19, 0x7a, 0x12, 0x19, 0x82, 0x02, 0x10, 0x0c, 0x12, 0x27, 0xfb, 0x12, 0x12, 0x3b, 0x90, 0xf8, -0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x11, 0xd8, 0x12, 0x26, 0xa3, 0x12, 0x12, 0x77, -0x12, 0x10, 0xfa, 0x80, 0xe3, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0xe4, 0xf5, 0x2a, 0xf5, -0x2b, 0xef, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 0xff, 0x12, 0x2f, 0x6a, 0x22, 0x90, 0xff, 0xf0, -0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, -0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, -0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, -0x18, 0xad, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, 0x18, 0xf7, 0xe0, 0x54, 0xdf, 0xf0, 0x22, -0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, -0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x84, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, -0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, 0x34, 0x30, 0x85, 0x35, 0x31, 0x90, 0xff, -0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x2f, -0x00, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, 0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, -0x38, 0x28, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x89, 0x7f, -0x02, 0x12, 0x10, 0x18, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x12, -0x18, 0x49, 0x12, 0x29, 0x2d, 0x22, 0x12, 0x19, 0x82, 0x12, 0x19, 0x3e, 0x12, 0x19, 0x7a, 0x22, -0xc2, 0x08, 0x22, +0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x12, 0x41, 0xad, 0x07, 0xaf, 0x02, +0x12, 0x12, 0x58, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x11, 0x66, 0x80, 0xc1, 0x8f, +0x24, 0x12, 0x2a, 0x06, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, +0x21, 0xf3, 0xe0, 0xfd, 0x12, 0x22, 0x8a, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x21, 0xf3, 0xed, 0xf0, +0x12, 0x22, 0x56, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xe0, 0xff, 0x12, 0x22, 0x99, 0x24, 0x09, 0x12, +0x21, 0xf3, 0xef, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x22, 0x09, 0xc0, +0x83, 0xc0, 0x82, 0xa3, 0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, +0x82, 0xe0, 0x33, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x80, 0x12, 0x22, 0x09, +0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0xff, 0x12, 0x22, 0x8a, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x21, +0xf3, 0xef, 0xf0, 0xed, 0x12, 0x22, 0x99, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xed, 0xf0, 0x12, 0x21, +0xfb, 0xe0, 0xff, 0x30, 0xe7, 0x19, 0x12, 0x22, 0x6e, 0x12, 0x21, 0xf3, 0xe0, 0x60, 0x09, 0x12, +0x21, 0xfb, 0xef, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x12, 0x21, 0xfb, 0xef, 0x54, 0xfd, 0xf0, 0x78, +0x7e, 0x12, 0x22, 0x09, 0xa3, 0xa3, 0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, +0xfd, 0x12, 0x22, 0x43, 0xa3, 0xe0, 0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, +0x05, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x31, 0x94, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x78, 0x80, +0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x24, 0x06, 0x12, 0x21, 0xf3, 0xe0, 0x60, 0x03, 0x43, 0x07, +0x04, 0x53, 0x07, 0xfc, 0x78, 0x80, 0x12, 0x22, 0x7a, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0x42, +0x07, 0x43, 0x07, 0x80, 0x12, 0x22, 0x8a, 0xf5, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xef, 0xf0, 0x12, +0x22, 0x99, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0xff, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xe0, +0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, 0x03, 0x43, 0x07, 0x20, 0xec, +0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, 0x12, 0x21, 0xfb, 0xe0, 0xfe, +0x54, 0x03, 0x60, 0x73, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x69, 0x78, 0x80, 0x12, 0x22, 0x6f, +0x12, 0x21, 0xf3, 0xe0, 0x12, 0x1b, 0x4c, 0x14, 0xa6, 0x00, 0x14, 0xda, 0x01, 0x14, 0xdf, 0x03, +0x14, 0xda, 0x05, 0x14, 0xdf, 0x07, 0x14, 0xda, 0x09, 0x14, 0xdf, 0x0b, 0x14, 0xda, 0x0d, 0x14, +0xdf, 0x0f, 0x00, 0x00, 0x14, 0xe7, 0xe5, 0x24, 0x64, 0x03, 0x70, 0x21, 0x90, 0xf9, 0x15, 0xe0, +0x30, 0xe2, 0x0d, 0x30, 0xb4, 0x05, 0x43, 0x07, 0x02, 0x80, 0x2c, 0x53, 0x07, 0xfd, 0x80, 0x27, +0x30, 0x95, 0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, +0x43, 0x07, 0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, +0x07, 0xfd, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x22, 0x78, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xef, +0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x12, 0x21, 0xfb, 0xe0, 0xfe, 0x54, +0x03, 0x70, 0x03, 0x02, 0x15, 0xd7, 0xee, 0x20, 0xe1, 0x03, 0x02, 0x15, 0xd4, 0x12, 0x22, 0x6e, +0x12, 0x21, 0xf3, 0xe0, 0x12, 0x1b, 0x4c, 0x15, 0x36, 0x00, 0x15, 0x6c, 0x01, 0x15, 0x6c, 0x03, +0x15, 0xa0, 0x05, 0x15, 0xa0, 0x07, 0x15, 0x86, 0x09, 0x15, 0x86, 0x0b, 0x15, 0xba, 0x0d, 0x15, +0xba, 0x0f, 0x00, 0x00, 0x15, 0xd7, 0xe5, 0x24, 0x64, 0x03, 0x70, 0x23, 0x90, 0xf9, 0x15, 0xe0, +0x30, 0xe2, 0x0f, 0x30, 0xb1, 0x06, 0x53, 0x07, 0x7f, 0x02, 0x15, 0xd7, 0x43, 0x07, 0x80, 0x02, +0x15, 0xd7, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x7d, 0x43, 0x07, 0x80, 0x80, 0x78, 0x30, +0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x70, 0x43, 0x07, 0x80, 0x80, 0x6b, 0xe5, 0x24, 0xb4, 0x03, +0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xdf, +0xf0, 0x53, 0x07, 0x7f, 0x80, 0x51, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x44, +0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x53, 0x07, 0x7f, 0x80, 0x37, +0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff, +0x9e, 0xe0, 0x54, 0xdf, 0xf0, 0x43, 0x07, 0x80, 0x80, 0x1d, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, +0xff, 0x9e, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x43, +0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x80, 0x12, 0x22, 0x3f, 0xe0, 0xfc, 0xa3, 0xe0, +0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, 0xec, 0x30, 0xe3, 0x05, +0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x10, 0x80, +0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, 0x03, 0x53, 0x07, 0xf7, +0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, 0xed, 0x30, 0xe6, 0x05, +0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, 0x43, 0x07, 0x02, 0x80, +0x03, 0x53, 0x07, 0xfd, 0x78, 0x7e, 0x12, 0x22, 0x3f, 0xa3, 0xef, 0xf0, 0x12, 0x31, 0xc7, 0x7f, +0x00, 0x22, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, 0xff, 0xf9, 0x74, +0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcc, 0xe4, 0xfd, 0x12, 0x22, 0xa0, 0x90, 0xfa, 0xcc, +0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0x12, 0x18, 0xe2, 0xe5, 0x23, 0x30, 0xe7, 0x02, 0xd2, +0x02, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x24, 0x90, 0xfa, 0xcc, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, +0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, +0x00, 0x7a, 0x00, 0x79, 0x23, 0x75, 0x2d, 0x00, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0xe5, +0x23, 0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x23, 0x64, 0x07, 0x60, 0x1e, 0xe5, 0x23, 0x64, +0x06, 0x60, 0x18, 0xe5, 0x23, 0x64, 0x14, 0x60, 0x12, 0xe5, 0x23, 0x64, 0x41, 0x60, 0x0c, 0xe5, +0x23, 0x64, 0x1a, 0x70, 0x46, 0xe5, 0x24, 0x64, 0x02, 0x70, 0x40, 0xe5, 0x23, 0xb4, 0x07, 0x16, +0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x02, 0xf0, 0xa3, +0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1e, 0xe5, 0x23, 0xb4, 0x41, 0x12, 0x90, 0xf9, 0x15, 0xe0, 0x44, +0x06, 0xf0, 0xa3, 0xe0, 0x44, 0x06, 0xf0, 0xd2, 0xb1, 0xd2, 0xb4, 0x80, 0x07, 0x90, 0xf9, 0x15, +0xe0, 0x44, 0x01, 0xf0, 0x90, 0xf9, 0x16, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x23, 0x64, 0x42, 0x60, +0x05, 0xe5, 0x23, 0xb4, 0x43, 0x0c, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x80, 0xf0, 0xa3, 0xe0, 0x44, +0x80, 0xf0, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x18, 0xe2, 0x90, 0xff, +0xf5, 0xe5, 0x23, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x33, 0xf5, 0x34, 0xf5, 0x32, 0x12, 0x1d, 0x84, +0x12, 0x1c, 0x30, 0x12, 0x1d, 0x8b, 0x90, 0xf9, 0x67, 0x12, 0x1b, 0x43, 0x90, 0xf9, 0x6c, 0x12, +0x1b, 0x43, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, +0x74, 0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x23, 0xe5, 0x23, +0x12, 0x1c, 0xa7, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x23, 0x12, 0x1c, 0xb5, 0xf5, 0x83, 0xe4, 0xf0, +0x05, 0x23, 0xe5, 0x23, 0xb4, 0x07, 0xe7, 0x78, 0x7a, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x31, +0x4d, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x31, 0x5a, 0xe4, 0x93, 0xff, +0x08, 0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x1c, 0x97, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, +0x08, 0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, +0x9f, 0x78, 0x7b, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x1c, 0x28, 0xce, 0xc3, 0x13, 0xce, +0x13, 0xd8, 0xf9, 0xff, 0xed, 0x12, 0x1c, 0xf8, 0xef, 0xf0, 0xed, 0x12, 0x1d, 0x1e, 0xe4, 0xf5, +0x23, 0xe5, 0x23, 0x90, 0x31, 0x47, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xe5, 0x23, 0x25, 0xe0, +0x24, 0x4e, 0xf5, 0x82, 0xe4, 0x34, 0x31, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, +0x53, 0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1c, 0x97, 0x12, 0x1d, 0x06, 0x24, 0x47, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0x12, 0x1c, 0x18, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, +0x1c, 0xf8, 0xef, 0xf0, 0x12, 0x1c, 0x1f, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d, +0x0b, 0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x1d, 0x1e, +0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, +0xf0, 0x02, 0x18, 0xb7, 0x78, 0x78, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1c, 0xea, 0x12, 0x1d, 0x06, +0x24, 0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x1c, 0x18, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, +0xf9, 0x12, 0x1d, 0x0b, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, +0x1c, 0x1f, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d, 0x0b, 0x24, 0x05, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x23, 0xe5, 0x23, 0x64, 0x04, 0x60, 0x03, 0x02, +0x17, 0xe1, 0x90, 0x31, 0x4c, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0x12, 0x1c, 0xe8, 0xe4, 0xf0, +0x90, 0x31, 0x4b, 0x93, 0xff, 0xf6, 0x12, 0x1c, 0x95, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, +0xf0, 0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, +0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x25, 0xd7, 0xe7, 0x09, 0xf6, 0x08, +0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, 0x82, 0x8c, 0x83, +0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x78, +0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, 0x09, 0xf0, 0xa3, +0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x58, +0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, 0xd2, 0x80, 0xfa, +0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, 0xa6, 0x80, 0xea, +0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, 0x82, 0x8a, 0x83, +0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, +0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, 0x89, 0x82, 0x8a, +0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, 0xfb, 0x22, 0x89, +0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xf0, +0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, 0x80, 0xdb, 0x89, +0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, 0xf0, 0xef, 0x60, +0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xb9, 0xf5, +0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, 0x19, +0x4c, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, +0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, +0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, +0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82, +0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, +0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, +0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, +0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, 0xf0, 0xf8, 0xa3, +0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0x38, +0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, +0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, +0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, +0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, +0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22, +0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x06, 0xf7, +0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, 0x19, 0x22, 0xf8, +0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0xe5, +0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, 0xf0, 0x22, 0xbb, +0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, 0x25, 0x82, 0xf5, +0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xf9, +0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, 0xe0, 0xfa, 0xa3, +0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, 0x83, 0xd0, 0x82, +0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, +0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, +0x80, 0xdf, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0xe5, 0x4c, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, +0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0x74, 0x11, 0x12, +0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x06, +0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, +0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a, 0x38, 0x04, 0x25, +0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a, +0x38, 0x04, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x04, 0xe0, 0xab, +0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, +0x37, 0xf5, 0x37, 0x90, 0xff, 0x05, 0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, +0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x22, 0xf5, 0x83, 0xe0, 0x54, +0x08, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, +0x78, 0x7b, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, 0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, +0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38, 0x6f, 0x22, 0xe0, 0x44, 0x04, 0xf0, 0x74, 0x12, +0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xe0, 0x22, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, +0x00, 0xc3, 0x90, 0xfa, 0xbd, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xbc, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, +0xb4, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0xef, 0x25, 0x4f, 0xf5, 0x4f, 0xee, 0x35, 0x4e, 0xf5, +0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb1, 0x90, 0xfa, 0xb4, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, +0xf5, 0x2e, 0x22, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, +0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x4d, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0x22, 0xe5, 0x4d, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, +0x22, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, +0x90, 0xfa, 0xbb, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x22, 0x75, 0x33, 0x00, 0x8f, 0x34, 0x90, 0xf9, +0x6c, 0x12, 0x1b, 0x3a, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, +0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, +0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, +0xa4, 0x22, 0x74, 0xaf, 0x25, 0x22, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, +0x08, 0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, +0xff, 0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, +0xfc, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x67, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, +0x65, 0xf0, 0x22, 0x12, 0x1b, 0x1c, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, +0xfa, 0x79, 0xb4, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, +0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x67, 0x02, 0x1b, 0x3a, 0x90, 0xff, 0xa4, 0xe0, +0x44, 0x02, 0xf0, 0x22, 0x75, 0x39, 0x01, 0x75, 0x3a, 0x09, 0x22, 0x7b, 0x01, 0x7a, 0xf9, 0x79, +0x6f, 0x22, 0xd3, 0xe5, 0x3c, 0x94, 0x08, 0xe5, 0x3b, 0x94, 0x01, 0x22, 0x90, 0xfa, 0xbb, 0xe0, +0xff, 0x90, 0xfa, 0xb7, 0xf0, 0x22, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, +0xe0, 0x54, 0xef, 0x22, 0x12, 0x10, 0x03, 0x78, 0x88, 0xef, 0xf6, 0x12, 0x2a, 0x06, 0x12, 0x22, +0x4a, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x21, 0xf3, 0xe0, 0xfd, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x0a, +0x12, 0x22, 0x52, 0x24, 0x0a, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x1a, 0x4a, 0x12, +0x22, 0x4a, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x53, 0x12, 0x22, 0x56, 0x24, +0x04, 0x12, 0x21, 0xf3, 0xe0, 0xf5, 0x54, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xf5, 0x55, +0xe5, 0x53, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x88, 0xf6, 0xd3, 0x94, 0x00, 0x40, 0x06, +0xe5, 0x54, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x88, 0xe6, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x0c, 0xef, +0x12, 0x1a, 0x4a, 0x78, 0x80, 0x12, 0x22, 0x09, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x53, +0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x53, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, 0x54, 0x20, +0xe5, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, 0x03, 0x43, 0x07, 0x02, +0xe5, 0x53, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x53, 0x30, 0xe2, 0x03, 0x43, 0x07, 0x20, +0xe5, 0x53, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x53, 0x30, 0xe1, 0x03, 0x43, 0x07, +0x80, 0xe5, 0x53, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x53, 0x30, 0xe6, 0x03, 0x43, 0x06, +0x08, 0xe5, 0x54, 0x20, 0xe4, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, +0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, 0x8f, 0xf0, +0x12, 0x1a, 0xef, 0xe5, 0x55, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, 0x12, 0x22, +0x2c, 0x90, 0x00, 0x08, 0xef, 0x12, 0x1a, 0x4a, 0x80, 0x0a, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x08, +0xe4, 0x12, 0x1a, 0x4a, 0xe5, 0x55, 0x54, 0x03, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x07, 0xef, 0x12, +0x1a, 0x4a, 0xe5, 0x55, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x1a, 0x4a, 0x90, +0x00, 0x07, 0x12, 0x1a, 0x0b, 0x70, 0x13, 0x12, 0x22, 0x2d, 0xe9, 0x24, 0x09, 0xf9, 0xe4, 0x3a, +0xfa, 0x12, 0x19, 0xf2, 0xff, 0xc3, 0x13, 0x12, 0x1a, 0x38, 0x12, 0x22, 0x78, 0x24, 0x08, 0x12, +0x21, 0xf3, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xe0, +0xfd, 0xee, 0xed, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0xef, 0x12, +0x31, 0xc7, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2f, 0x18, 0x02, 0x10, 0x86, 0x90, 0xfa, 0xe3, 0xe0, +0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, 0xfa, 0xd7, +0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0xff, 0x7e, 0x00, 0x90, 0xfa, +0xd3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, 0x12, 0x1a, +0x98, 0xff, 0x90, 0xfa, 0xd5, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, 0x01, 0x8e, +0x50, 0x8f, 0x51, 0x74, 0x0a, 0x25, 0x51, 0xf5, 0x51, 0xe4, 0x35, 0x50, 0xf5, 0x50, 0x90, 0xfa, +0xd8, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd6, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, 0xff, 0x90, +0xfa, 0xda, 0xf0, 0xc3, 0x90, 0xfa, 0xd4, 0xe0, 0x9f, 0x90, 0xfa, 0xd3, 0xe0, 0x94, 0x00, 0x50, +0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xda, 0xf0, 0x12, 0x1f, 0xfb, 0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, +0x2d, 0x5a, 0x90, 0xfa, 0xd3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, 0xfa, 0xd7, +0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, 0xfa, 0xda, +0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd4, 0xe0, 0x90, 0xfa, 0xda, 0xf0, 0x12, 0x1f, 0xfb, 0x60, 0x03, +0xe0, 0xff, 0x22, 0x12, 0x2d, 0x5a, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, +0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x7f, 0x00, 0x22, 0xaa, 0x50, 0xa9, 0x51, 0x7b, +0x01, 0x90, 0xfa, 0xd5, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xda, 0xe0, 0xf5, 0x4a, 0x12, +0x28, 0x9f, 0x90, 0xfa, 0xd9, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, 0xfe, 0x60, +0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x20, 0xbb, 0x24, 0x06, 0x60, 0x03, 0x02, 0x21, 0x03, 0x78, +0x71, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x33, +0x90, 0xfa, 0x91, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, 0x22, 0x78, +0x72, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x43, +0x90, 0xfa, 0x93, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xb0, 0x74, 0x01, 0xf0, 0x22, 0x90, +0xfa, 0x9d, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x21, 0x03, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, +0xca, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, +0xa6, 0x12, 0x22, 0x5d, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xca, 0xf0, 0x80, 0xe6, 0x90, 0xfa, +0xcb, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x2c, 0xb4, 0xef, 0x70, 0x57, 0x90, 0xfa, 0xcb, 0xe0, +0xff, 0x74, 0x34, 0x90, 0xfa, 0x95, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa7, 0xe0, 0xa3, +0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xca, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xca, +0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x22, 0x5d, 0x90, 0xff, 0xb6, +0xe0, 0x90, 0xfa, 0xca, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xcb, 0xe0, 0xff, 0x74, 0x44, 0xfe, 0x12, +0x2c, 0xb4, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xcb, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, 0x97, 0xf0, +0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, +0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, +0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc9, 0xf0, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0xef, +0x12, 0x1b, 0x4c, 0x21, 0xbb, 0x26, 0x21, 0xbb, 0x2e, 0x21, 0x5e, 0x30, 0x21, 0x5e, 0x32, 0x21, +0x6c, 0x38, 0x21, 0x7e, 0x3a, 0x21, 0xb0, 0x3e, 0x21, 0x9b, 0x44, 0x21, 0x90, 0x46, 0x21, 0xa6, +0x50, 0x21, 0xa6, 0x52, 0x21, 0xa6, 0x54, 0x21, 0xa6, 0x56, 0x00, 0x00, 0x21, 0xc0, 0x90, 0xfa, +0xc9, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x11, 0x16, 0x80, 0x62, 0x7c, 0x00, 0x7d, 0x01, +0x7f, 0x03, 0x12, 0x11, 0x16, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, 0x7c, 0x00, +0x7d, 0x01, 0x7f, 0x02, 0x12, 0x11, 0x16, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x3e, +0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x11, 0x16, 0x80, 0x33, 0x7c, 0x00, 0x7d, 0x01, 0x7f, +0x06, 0x12, 0x11, 0x16, 0x80, 0x28, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x12, 0x20, 0x18, 0x80, 0x1e, +0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x11, 0x16, 0x80, 0x13, 0x12, 0x27, 0x8d, 0x80, 0x0e, +0x90, 0xfa, 0xc9, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x2c, 0xb4, 0xd0, 0x07, +0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, +0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x24, +0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x74, 0x12, 0x25, 0x24, 0xf5, +0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0x22, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, +0x83, 0x22, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, +0xff, 0x7a, 0x31, 0x79, 0x99, 0x7e, 0x00, 0x7f, 0x0a, 0x02, 0x19, 0xcc, 0xff, 0x90, 0xf9, 0x6c, +0x02, 0x1b, 0x3a, 0x90, 0xf9, 0x67, 0x12, 0x1b, 0x3a, 0x90, 0x00, 0x04, 0x02, 0x1a, 0x0b, 0xe6, +0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, 0x78, 0x7e, 0xe6, 0xfe, 0x08, 0xe6, +0xff, 0x22, 0xed, 0x12, 0x1a, 0x4a, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, +0xfa, 0xcb, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, 0xf0, 0x4e, 0xf0, 0x22, 0x08, 0xe6, +0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x24, 0x09, 0x22, 0x78, 0x7e, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, +0x83, 0x22, 0xa6, 0x07, 0xe6, 0x24, 0x6e, 0xf8, 0xe6, 0x22, 0x78, 0x7e, 0xe6, 0xfa, 0x08, 0xe6, +0xfb, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, 0x8a, 0x83, 0xe5, 0x82, 0x22, +0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0x8d, 0x28, 0x90, 0xfa, 0xcf, 0xe4, 0xf0, 0xa3, 0x74, 0x02, +0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xce, 0x90, 0xfa, 0xcf, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, +0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xce, 0xe0, 0x65, 0x28, 0x60, 0x46, 0xa3, 0xe0, +0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x23, 0x2f, 0x90, 0xfa, 0xce, 0xe0, +0xff, 0x90, 0xfa, 0xd1, 0xe4, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0x12, 0x23, 0x2f, 0x90, 0xfa, 0xd1, +0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xcf, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xfa, 0xce, 0xe0, +0xa3, 0x75, 0xf0, 0x00, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x04, 0x12, 0x1a, +0x6c, 0x02, 0x22, 0xb1, 0x90, 0xfa, 0xd0, 0xe0, 0x24, 0x01, 0xff, 0x90, 0xfa, 0xcf, 0xe0, 0x34, +0x00, 0xab, 0x25, 0xaa, 0x26, 0xa9, 0x27, 0x8f, 0xf0, 0x12, 0x1a, 0xd0, 0x7f, 0x00, 0x22, 0x7b, +0x01, 0x7a, 0xfa, 0x79, 0xce, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1a, 0x6c, 0x85, +0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x25, 0xd7, 0x8f, 0x62, 0x12, 0x2a, 0x06, 0x12, 0x22, +0x4a, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x21, 0xf3, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x02, 0xf0, 0x08, +0x12, 0x22, 0x3f, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x22, 0x56, 0x24, 0x0b, 0x12, 0x21, 0xf3, +0xe0, 0x44, 0x01, 0xf0, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, +0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x62, 0x24, 0xfe, 0x44, 0x20, 0xfc, 0x4d, 0xf0, 0xe5, 0x82, 0x24, +0x04, 0x12, 0x21, 0xf3, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0x74, +0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x05, 0x12, 0x21, 0xf3, 0xc0, +0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x96, 0x25, 0x62, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, +0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, +0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0x44, 0x80, 0xf0, +0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x62, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, +0x10, 0x03, 0x7f, 0x02, 0x12, 0x12, 0x19, 0x78, 0x67, 0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, +0xb1, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe7, 0x07, 0x90, 0xff, 0x9e, 0xe4, 0xf0, 0x80, 0x36, 0xd2, +0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7c, +0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x7a, +0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, +0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, 0xe4, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, +0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, +0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7c, 0xe0, +0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x7a, 0xe0, +0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe4, 0xe0, +0xf5, 0xa8, 0x02, 0x10, 0x86, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x12, 0x2d, 0x3c, 0x90, 0xfa, +0xc0, 0x12, 0x1b, 0x43, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0x43, 0x90, 0xfa, +0xc4, 0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0x3a, 0xe9, 0x24, +0x01, 0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x43, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, +0x5e, 0x12, 0x2d, 0x48, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x82, 0xf6, 0x90, 0xfa, 0xbe, +0xe0, 0xff, 0x78, 0x82, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xc0, 0x12, 0x2d, 0x1d, 0xff, +0x78, 0x83, 0xf6, 0x90, 0xfa, 0xc3, 0x12, 0x2d, 0x1d, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x83, 0xf6, +0x12, 0x2d, 0x1a, 0x5e, 0x4f, 0xff, 0x78, 0x83, 0xf6, 0x12, 0x2d, 0x23, 0x75, 0xf0, 0x02, 0x12, +0x1a, 0x6c, 0x90, 0xfa, 0xc4, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1a, 0x6c, 0xab, 0x5c, 0xaa, 0x5d, +0xa9, 0x5e, 0x90, 0x00, 0x04, 0x12, 0x1a, 0x0b, 0x30, 0xe4, 0x03, 0x12, 0x2d, 0x32, 0x78, 0x82, +0x06, 0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbf, 0xf0, 0x22, 0x8b, 0x56, 0x8a, 0x57, 0x89, 0x58, 0x90, +0xfa, 0xbf, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x12, 0x19, 0xf2, 0x24, 0x6e, 0x60, +0x26, 0x14, 0x70, 0x70, 0x12, 0x2d, 0x09, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x24, 0x95, +0x80, 0x62, 0x12, 0x2d, 0x53, 0x12, 0x1f, 0x2c, 0x90, 0xfa, 0xbf, 0xef, 0xf0, 0x80, 0x55, 0x90, +0xfa, 0xbf, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2d, 0x09, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, +0x12, 0x2c, 0x5f, 0x80, 0x3f, 0xe5, 0x58, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x57, 0xfa, 0x7b, 0x01, +0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2d, 0x53, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0xfd, +0x90, 0x00, 0x08, 0x12, 0x1a, 0x98, 0xf5, 0x2e, 0x85, 0xf0, 0x2d, 0xd0, 0x01, 0xd0, 0x02, 0xd0, +0x03, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, +0xbf, 0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbf, 0xe0, 0x12, 0x2d, 0x53, 0x90, 0x00, 0x02, 0x12, 0x1a, +0x4a, 0x90, 0xfa, 0xbe, 0xe0, 0xff, 0x22, 0x8b, 0x29, 0x8a, 0x2a, 0x89, 0x2b, 0x8d, 0x2c, 0xe5, +0x2c, 0x70, 0x03, 0xaf, 0x2c, 0x22, 0x12, 0x2d, 0x82, 0x70, 0x16, 0x12, 0x2d, 0xa1, 0xe5, 0x2d, +0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0x1b, 0x50, 0xf2, 0x12, 0x26, 0x64, 0x40, 0x0b, 0x7f, 0x00, +0x22, 0x12, 0x2d, 0xa1, 0x12, 0x26, 0x64, 0x50, 0xf8, 0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, +0x2c, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, +0xf5, 0x2f, 0xe5, 0x2c, 0x14, 0xff, 0xe5, 0x2f, 0xc3, 0x9f, 0x50, 0x2a, 0x12, 0x31, 0x04, 0x40, +0x03, 0xaf, 0x2f, 0x22, 0xc3, 0xe5, 0x2c, 0x95, 0x2f, 0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, +0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2d, 0x94, 0x05, 0x2f, 0x74, 0x01, 0x25, 0x2b, 0xf5, 0x2b, 0xe4, +0x35, 0x2a, 0xf5, 0x2a, 0x80, 0xcc, 0x12, 0x31, 0x04, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2d, +0x94, 0xaf, 0x2c, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x2e, 0xf0, 0x02, 0x31, 0x1b, 0x12, 0x10, 0x03, +0x78, 0x84, 0x12, 0x22, 0x82, 0x30, 0xe1, 0x08, 0x7f, 0x13, 0x12, 0x30, 0xec, 0x02, 0x26, 0xfb, +0x78, 0x84, 0xe6, 0xf9, 0x24, 0x12, 0x12, 0x21, 0xff, 0xe0, 0xff, 0x30, 0xe7, 0x40, 0x54, 0x03, +0x60, 0x1e, 0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x44, 0x04, +0xf0, 0x80, 0x46, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x39, +0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x80, +0x28, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1b, 0xef, 0x54, +0x03, 0x60, 0x14, 0xe9, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, +0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x17, 0xe0, 0x04, 0xf0, 0xaf, +0x01, 0x12, 0x22, 0x33, 0xfd, 0x12, 0x2f, 0x49, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x75, 0xa8, +0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x8b, 0x02, 0x27, 0x48, 0x02, 0x30, 0xcf, +0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, +0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, +0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, +0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x2b, 0x4c, 0xe4, 0x7e, 0x01, 0x93, 0x60, +0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, +0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, +0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, +0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x22, +0x12, 0x1d, 0x12, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x22, 0x24, 0x03, 0xff, 0x12, 0x2f, 0x77, 0x12, +0x1d, 0x12, 0xe4, 0xf0, 0x05, 0x22, 0xe5, 0x22, 0xc3, 0x94, 0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x22, +0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x91, 0x12, 0x1d, 0x53, 0x60, 0x2c, 0x12, 0x2c, 0xb4, +0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x91, 0x12, 0x1b, 0x1c, 0xe4, 0xf0, +0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x22, 0x90, 0xfa, 0x9d, 0x12, 0x1b, 0x1c, 0xe0, 0xa3, 0x30, +0xe6, 0x33, 0x12, 0x1d, 0x12, 0x74, 0x04, 0xf0, 0x22, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, +0x95, 0x12, 0x1d, 0x53, 0x60, 0x16, 0x12, 0x2c, 0xb4, 0xef, 0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, +0x22, 0x90, 0xfa, 0x95, 0x12, 0x1b, 0x1c, 0xe4, 0xf0, 0xa3, 0xf0, 0x22, 0x05, 0x22, 0xe5, 0x22, +0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, +0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, +0x1c, 0x11, 0x12, 0x1a, 0x38, 0x0f, 0x12, 0x1c, 0x00, 0x80, 0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x3a, +0x9d, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39, 0xd3, 0xe5, 0x3a, 0x94, 0x00, 0xe5, 0x39, +0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, 0x12, 0x1d, 0x2f, 0x12, 0x1d, 0x84, +0x12, 0x1d, 0x76, 0x12, 0x19, 0xf2, 0x24, 0x6e, 0x60, 0x1e, 0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, +0x2d, 0x90, 0x00, 0x01, 0x12, 0x1a, 0x0b, 0xff, 0x24, 0xfc, 0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, +0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x11, 0x16, 0x12, 0x1d, 0x8b, 0x12, 0x25, 0x39, 0x12, 0x1c, +0xd9, 0x12, 0x1a, 0x0b, 0x60, 0x03, 0x02, 0x31, 0xbd, 0xe4, 0xff, 0x12, 0x31, 0xb1, 0x22, 0x8b, +0x45, 0x8a, 0x46, 0x89, 0x47, 0x8c, 0x48, 0x8d, 0x49, 0xd2, 0x00, 0x12, 0x2d, 0x82, 0x70, 0x16, +0x12, 0x2d, 0xa1, 0xe5, 0x48, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0x1b, 0x50, 0xf2, 0x12, 0x29, +0x14, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2d, 0xa1, 0x12, 0x29, 0x14, 0x50, 0xf8, 0xe4, 0xf5, +0x4b, 0xe5, 0x4a, 0x14, 0xff, 0xe5, 0x4b, 0xc3, 0x9f, 0x50, 0x17, 0x12, 0x29, 0x04, 0x40, 0x03, +0x7f, 0x18, 0x22, 0x05, 0x4b, 0x74, 0x01, 0x25, 0x47, 0xf5, 0x47, 0xe4, 0x35, 0x46, 0xf5, 0x46, +0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x29, 0x04, 0x40, 0x03, 0x7f, 0x18, +0x22, 0x7f, 0x00, 0x22, 0xab, 0x45, 0xaa, 0x46, 0xa9, 0x47, 0x12, 0x19, 0xf2, 0x90, 0xff, 0xf1, +0xf0, 0x02, 0x31, 0x1b, 0x90, 0xff, 0xf1, 0xe5, 0x49, 0xf0, 0x02, 0x31, 0x1b, 0x7b, 0x01, 0x7a, +0xfa, 0x79, 0xcc, 0xe4, 0xfd, 0x12, 0x22, 0xa0, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x09, 0x12, +0x1a, 0x6c, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, +0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xff, 0xf7, 0xe5, +0x23, 0x12, 0x29, 0x78, 0x90, 0xff, 0xf6, 0xe5, 0x23, 0xf0, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, +0x74, 0x06, 0x12, 0x29, 0x78, 0xe5, 0x23, 0x30, 0xe0, 0x07, 0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, +0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, +0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, +0x02, 0x25, 0xd7, 0x90, 0xff, 0x93, 0x74, 0x2a, 0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, +0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, 0xe0, 0x44, 0x90, 0xf0, 0xe4, 0x90, 0xf9, 0x15, +0xf0, 0xa3, 0xf0, 0x12, 0x2a, 0x78, 0x12, 0x16, 0x42, 0x12, 0x2f, 0xcd, 0x7e, 0x07, 0x7f, 0xd0, +0x12, 0x11, 0xe2, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0xfc, 0xe4, 0x78, 0x77, 0xf6, 0x78, 0x77, +0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x6e, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x77, 0x06, +0x80, 0xec, 0x7f, 0x03, 0x12, 0x2e, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x20, 0xe4, 0x05, 0x7f, 0x04, +0x12, 0x2e, 0xb3, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, 0xe0, +0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x15, 0x65, 0xa8, 0x65, 0xa6, 0x07, 0x30, 0x08, 0x05, 0x12, +0x11, 0x66, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x65, 0xe6, 0xff, 0xb4, 0x03, 0x0f, 0x78, 0x7c, 0x76, +0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, 0x7c, 0x76, 0xff, +0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x80, 0x76, 0xfa, 0x08, 0x76, 0x9b, +0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x22, 0x92, 0x7b, 0x01, 0x7a, 0xff, +0x79, 0x48, 0x78, 0x68, 0x12, 0x1b, 0x31, 0xa8, 0x65, 0xe6, 0x24, 0xfd, 0x75, 0xf0, 0x08, 0xa4, +0xff, 0xae, 0xf0, 0x78, 0x6a, 0x12, 0x22, 0x92, 0x79, 0x08, 0x78, 0x6b, 0x12, 0x1b, 0x31, 0x78, +0x6d, 0xef, 0x12, 0x22, 0x92, 0x05, 0x65, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xab, 0xf0, 0xe0, +0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcc, 0xe4, +0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x7e, 0x00, 0x90, 0xfa, 0xe1, 0xee, 0xf0, +0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcc, 0xe0, 0xb4, 0x52, 0x09, 0x90, 0xf9, +0x15, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe1, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, +0x01, 0x70, 0x10, 0x90, 0xfa, 0xcc, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x10, +0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe3, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x54, 0xef, 0xf0, +0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x12, 0x10, 0x03, 0x78, 0x8a, 0xef, 0xf6, 0x12, +0x2a, 0x06, 0x12, 0x22, 0x33, 0x30, 0xe0, 0x25, 0x12, 0x22, 0x07, 0xe0, 0x54, 0x7f, 0xf0, 0x78, +0x6b, 0x12, 0x1b, 0x28, 0x90, 0x00, 0x02, 0x12, 0x1a, 0x0b, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, +0xe4, 0x12, 0x1a, 0x4a, 0x80, 0xe9, 0x12, 0x22, 0x07, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x22, 0x33, +0x30, 0xe1, 0x1e, 0x12, 0x21, 0xe9, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x31, 0x5c, 0x78, 0x68, 0x12, +0x1b, 0x28, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x1a, 0x4a, 0x12, 0x21, 0xe9, 0xe0, 0x44, 0x80, +0xf0, 0x12, 0x31, 0xc7, 0xe4, 0xff, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x03, 0x68, 0x01, 0xff, +0x48, 0x03, 0x6b, 0x01, 0xff, 0x08, 0x02, 0x66, 0x00, 0x00, 0x44, 0xfa, 0x95, 0x00, 0x00, 0x00, +0x00, 0x44, 0xfa, 0x91, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xaf, 0x00, 0x00, 0x42, 0xfa, 0x7b, +0x00, 0x00, 0x42, 0xfa, 0x79, 0x00, 0x00, 0x42, 0xf9, 0x6a, 0xff, 0xff, 0x42, 0xfa, 0x77, 0x00, +0x00, 0x43, 0xf9, 0x18, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x65, 0x20, 0x41, 0xf9, 0x66, 0x20, 0x41, +0xf9, 0x63, 0x00, 0x41, 0xf9, 0x64, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf9, +0x15, 0x00, 0x00, 0x41, 0xf9, 0x17, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, +0x10, 0x03, 0x78, 0x85, 0xef, 0xf6, 0x12, 0x30, 0x93, 0x12, 0x30, 0xec, 0x78, 0x85, 0xe6, 0xff, +0x24, 0x12, 0x12, 0x21, 0xff, 0xe0, 0xfe, 0x30, 0xe7, 0x16, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff, +0x9e, 0xe0, 0x54, 0xfa, 0xf0, 0x80, 0x22, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf5, 0xf0, 0x80, 0x19, +0xee, 0x54, 0x03, 0x60, 0x14, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, +0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x14, 0xf0, 0xe0, +0x70, 0x02, 0xd2, 0xb3, 0x02, 0x10, 0x86, 0x12, 0x1d, 0x6c, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, +0xe5, 0x39, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x3a, 0x94, 0x08, 0xe5, 0x39, 0x94, 0x00, 0x40, +0x11, 0x7f, 0x08, 0xef, 0xe5, 0x3a, 0x94, 0x08, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39, +0x80, 0x05, 0xaf, 0x3a, 0x12, 0x1d, 0x84, 0xe4, 0xfe, 0xee, 0xc3, 0x9f, 0x50, 0x19, 0x12, 0x1c, +0x11, 0x12, 0x19, 0xf2, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, +0xf0, 0x0e, 0x12, 0x1c, 0x00, 0x80, 0xe2, 0xef, 0x54, 0x7f, 0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, +0x59, 0x8a, 0x5a, 0x89, 0x5b, 0x12, 0x2d, 0x48, 0x70, 0x05, 0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, +0x59, 0xaa, 0x5a, 0xa9, 0x5b, 0x12, 0x2d, 0x3c, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x43, 0xe5, 0x5b, +0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5a, 0xfa, 0x90, 0xfa, 0xc0, 0x12, 0x1b, 0x43, 0xe4, 0x90, 0xfa, +0xbf, 0xf0, 0x78, 0x8b, 0xf6, 0x90, 0xfa, 0xbe, 0xe0, 0xff, 0x78, 0x8b, 0xe6, 0xc3, 0x9f, 0x50, +0x12, 0x12, 0x2d, 0x1a, 0xff, 0x12, 0x2d, 0x23, 0x12, 0x2d, 0x36, 0x78, 0x8b, 0x06, 0x12, 0x2d, +0x32, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x31, 0x4d, 0xe4, 0x93, 0xff, 0x78, 0x74, +0xf6, 0x54, 0x0f, 0x12, 0x1c, 0xf8, 0xe0, 0x08, 0x76, 0x00, 0x08, 0xf6, 0x18, 0x12, 0x1c, 0x29, +0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x75, 0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, +0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, 0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, +0x22, 0x78, 0x75, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, +0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x90, +0x00, 0x03, 0x12, 0x1a, 0x0b, 0x54, 0xf0, 0x24, 0xa0, 0x22, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x3a, +0x02, 0x19, 0xf2, 0x90, 0xfa, 0xc0, 0x12, 0x1b, 0x3a, 0xef, 0x12, 0x1a, 0x38, 0x90, 0xfa, 0xc7, +0xe4, 0x22, 0x90, 0xfa, 0xc1, 0xe4, 0x75, 0xf0, 0x01, 0x02, 0x1a, 0x6c, 0x90, 0x00, 0x08, 0x12, +0x1a, 0x98, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0x90, 0xfa, +0xbe, 0xf0, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x22, 0x90, 0xfa, 0xda, 0xe0, 0xff, 0x7e, +0x00, 0xc3, 0x90, 0xfa, 0xd4, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xd3, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, +0xd5, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0xef, 0x25, 0x51, 0xf5, 0x51, 0xee, 0x35, 0x50, 0xf5, +0x50, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe3, +0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x29, 0xaa, 0x2a, 0xa9, 0x2b, 0x02, 0x1a, +0x38, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x64, 0xed, 0x70, 0x0f, 0xe5, 0x64, 0xb4, +0x03, 0x05, 0x7f, 0x01, 0x02, 0x31, 0x32, 0x7f, 0x02, 0x02, 0x31, 0x32, 0xaf, 0x64, 0x12, 0x2a, +0x06, 0x74, 0x6e, 0x25, 0x64, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, 0xd2, 0x09, 0x12, 0x1c, 0x83, 0xe0, +0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x64, 0xb4, 0x03, 0x07, 0x7f, 0x81, 0x12, 0x31, +0x32, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x31, 0x32, 0x30, 0x09, 0x07, 0x12, 0x1c, 0x83, 0xe0, 0x44, +0x80, 0xf0, 0x12, 0x31, 0xc7, 0x22, 0x12, 0x10, 0x03, 0x90, 0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, +0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, +0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x35, 0x80, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, +0xf0, 0x80, 0x0d, 0x12, 0x1d, 0x2f, 0x53, 0x35, 0x7f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, +0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0xb0, 0x12, 0x1d, 0x37, 0x02, 0x10, 0x86, +0x12, 0x10, 0x03, 0x78, 0x89, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x2a, 0x06, 0x90, 0xf9, 0x67, 0x12, +0x1b, 0x3a, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x80, 0xe6, 0xfe, 0x08, +0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x22, 0x25, 0x12, 0x31, 0xc7, +0x78, 0x89, 0xe6, 0xff, 0x12, 0x13, 0x3f, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x8f, 0x63, 0x12, +0x2a, 0x06, 0x12, 0x22, 0x07, 0xe0, 0x54, 0x3f, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x21, 0xf3, +0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x21, 0xf3, +0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x63, 0xf8, 0x74, 0xfb, 0x56, 0xf6, +0x7f, 0x00, 0x22, 0x8f, 0x23, 0xc2, 0x08, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x12, 0x78, 0x7e, 0x12, +0x21, 0xeb, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x22, 0x4a, 0x12, 0x21, 0xef, 0xe0, 0x20, 0xe0, 0xf6, +0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x31, 0xc7, +0xaf, 0x23, 0x12, 0x13, 0x3f, 0x22, 0x12, 0x10, 0x03, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x4a, 0x24, +0x06, 0x12, 0x21, 0xf1, 0xe0, 0xfd, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x03, 0x12, 0x22, 0x52, 0x24, +0x05, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x00, 0x04, 0x12, 0x1a, 0x4a, 0x12, 0x31, 0xc7, 0x7d, 0x02, +0xe4, 0xff, 0x12, 0x2f, 0x18, 0x02, 0x10, 0x86, 0xae, 0x05, 0x12, 0x1c, 0xde, 0xef, 0x12, 0x1a, +0x4a, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x3c, 0xe4, 0x95, 0x3b, 0x40, 0x02, 0xae, 0x3c, 0xee, +0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, 0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, +0x12, 0x1a, 0x4a, 0xaf, 0x06, 0x12, 0x31, 0xb1, 0x22, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, +0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, 0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, +0x74, 0x6e, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, 0x74, 0x96, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, +0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, 0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, +0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, +0x12, 0x21, 0xf3, 0xe0, 0x44, 0x80, 0xf0, 0x74, 0x6e, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, +0x00, 0x22, 0x12, 0x10, 0x03, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, +0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, 0xc3, 0xe5, 0x3a, 0x9f, 0xe5, 0x39, 0x94, 0x00, +0x40, 0x05, 0x12, 0x28, 0x16, 0x80, 0x03, 0x12, 0x31, 0xbd, 0x02, 0x10, 0x86, 0x90, 0xff, 0xfc, +0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, 0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, +0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, 0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, +0xf0, 0x80, 0xef, 0x22, 0x12, 0x10, 0x03, 0x78, 0x66, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, +0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x12, 0x19, +0x12, 0x1d, 0x46, 0x02, 0x10, 0x86, 0x8e, 0x5f, 0x8f, 0x60, 0xe5, 0x60, 0x15, 0x60, 0xae, 0x5f, +0x70, 0x02, 0x15, 0x5f, 0xd3, 0x94, 0x00, 0xee, 0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, +0x12, 0x0f, 0xdc, 0x80, 0xe5, 0x22, 0x11, 0x94, 0x2d, 0xf6, 0x23, 0xef, 0x31, 0xa3, 0x2f, 0xf4, +0x2f, 0xa2, 0x30, 0xb2, 0x2e, 0xe6, 0x26, 0x6d, 0x2b, 0xaf, 0x30, 0x55, 0x30, 0x74, 0x1d, 0xb4, +0x2e, 0x40, 0x2a, 0xe8, 0x0e, 0x12, 0x10, 0x03, 0x78, 0x86, 0x12, 0x22, 0x82, 0x20, 0xe1, 0x07, +0x7f, 0x12, 0x12, 0x30, 0xec, 0x80, 0x0a, 0x78, 0x86, 0xe6, 0xff, 0x12, 0x23, 0x49, 0x12, 0x30, +0xec, 0x02, 0x10, 0x86, 0x12, 0x10, 0x03, 0x78, 0x87, 0x12, 0x22, 0x82, 0x20, 0xe2, 0x07, 0x7f, +0x11, 0x12, 0x30, 0xec, 0x80, 0x0a, 0x78, 0x87, 0xe6, 0xff, 0x12, 0x2e, 0x7d, 0x12, 0x30, 0xec, +0x02, 0x10, 0x86, 0x8f, 0x61, 0x12, 0x2e, 0x7d, 0xaf, 0x61, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x12, +0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x61, 0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x61, 0x12, 0x13, +0x3f, 0x22, 0x12, 0x10, 0x03, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, +0x05, 0x12, 0x2c, 0x07, 0x80, 0x06, 0x12, 0x1d, 0x64, 0x12, 0x1d, 0x6c, 0x02, 0x10, 0x86, 0x12, +0x29, 0x93, 0x12, 0x12, 0xbb, 0x90, 0xf8, 0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x12, +0x58, 0x12, 0x29, 0x1d, 0x12, 0x12, 0xf7, 0x12, 0x11, 0x74, 0x80, 0xe3, 0x12, 0x1c, 0xde, 0xef, +0x12, 0x1a, 0x4a, 0xe4, 0xf5, 0x33, 0xf5, 0x34, 0xef, 0x60, 0x03, 0x02, 0x31, 0xbd, 0xe4, 0xff, +0x12, 0x31, 0xb1, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, +0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, +0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, +0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, 0x1c, 0x95, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, +0x1c, 0xe8, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, +0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x7e, 0x12, 0x22, +0x09, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, +0x3b, 0x39, 0x85, 0x3c, 0x3a, 0x90, 0xff, 0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, +0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x31, 0x47, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, +0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, 0x28, 0x38, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x12, 0x10, 0x03, 0x7f, 0x02, 0x12, 0x10, 0x92, 0x12, 0x1d, 0x46, 0x02, 0x10, +0x86, 0x75, 0x39, 0x00, 0x8f, 0x3a, 0x12, 0x1c, 0x30, 0x12, 0x2c, 0x07, 0x22, 0x12, 0x1d, 0x6c, +0x12, 0x1d, 0x2f, 0x12, 0x1d, 0x64, 0x22, 0xc2, 0x08, 0x22, }; #undef IMAGE_VERSION_NAME diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index f4567f166..d43b9e6cd 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -14,22 +14,12 @@ #ifndef IO_TABLES_H #define IO_TABLES_H -static struct usb_device_id edgeport_1port_id_table [] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, - { } -}; - static struct usb_device_id edgeport_2port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) }, { } }; @@ -41,12 +31,9 @@ static struct usb_device_id edgeport_4port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) }, { } }; @@ -54,9 +41,9 @@ static struct usb_device_id edgeport_8port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, { } }; @@ -69,7 +56,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, @@ -77,51 +63,18 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table_combined); -static struct usb_serial_device_type edgeport_1port_device = { - .owner = THIS_MODULE, - .name = "Edgeport 1 port adapter", - .short_name = "edgeport_1", - .id_table = edgeport_1port_id_table, - .num_interrupt_in = 1, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .shutdown = edge_shutdown, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, -}; - static struct usb_serial_device_type edgeport_2port_device = { .owner = THIS_MODULE, .name = "Edgeport 2 port adapter", diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 6b821b6ed..ace42c870 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -124,15 +124,11 @@ static struct usb_device_id edgeport_2port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, { } }; @@ -143,15 +139,11 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, { } }; @@ -278,7 +270,7 @@ static int TIReadDownloadMemory(struct usb_device *dev, int start_address, { int status = 0; __u8 read_length; - __u16 be_start_address; + __be16 be_start_address; dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length); @@ -395,7 +387,7 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address { int status = 0; int write_length; - __u16 be_start_address; + __be16 be_start_address; /* We can only send a maximum of 1 aligned byte page at a time */ @@ -1804,12 +1796,7 @@ static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs) tty = port->tty; if (tty) { /* let the tty driver wakeup if it has a special write_wakeup function */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - (tty->ldisc.write_wakeup)(tty); - } - - /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } } diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index 26a8c5a18..65073409f 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -18,14 +18,6 @@ #if !defined(_USBVEND_H) #define _USBVEND_H -#ifndef __KERNEL__ -#include "ionprag.h" /* Extra I/O Networks pragmas */ - -#include - -#include "iondef.h" /* Standard I/O Networks definitions */ -#endif - /************************************************************************ * * D e f i n e s / T y p e d e f s @@ -37,6 +29,7 @@ // #define USB_VENDOR_ID_ION 0x1608 // Our VID +#define USB_VENDOR_ID_TI 0x0451 // TI VID // // Definitions of USB product IDs (PID) @@ -48,36 +41,41 @@ // ION-device OEM IDs #define ION_OEM_ID_ION 0 // 00h Inside Out Networks -#define ION_OEM_ID_NLYNX 1 // 01h NLynx Systems +#define ION_OEM_ID_NLYNX 1 // 01h NLynx Systems #define ION_OEM_ID_GENERIC 2 // 02h Generic OEM #define ION_OEM_ID_MAC 3 // 03h Mac Version #define ION_OEM_ID_MEGAWOLF 4 // 04h Lupusb OEM Mac version (MegaWolf) #define ION_OEM_ID_MULTITECH 5 // 05h Multitech Rapidports +#define ION_OEM_ID_AGILENT 6 // 06h AGILENT board + - // ION-device Device IDs -// Product IDs - assigned to match middle digit of serial number +// Product IDs - assigned to match middle digit of serial number (No longer true) +#define ION_DEVICE_ID_80251_NETCHIP 0x020 // This bit is set in the PID if this edgeport hardware$ + // is based on the 80251+Netchip. -// The ION_DEVICE_ID_GENERATION_2 bit (0x20) will be ORed into the existing edgeport -// PIDs to identify 80251+Netchip hardware. This will guarantee that if a second -// generation edgeport device is plugged into a PC with an older (pre 2.0) driver, -// it will not enumerate. +#define ION_DEVICE_ID_GENERATION_1 0x00 // Value for 930 based edgeports +#define ION_DEVICE_ID_GENERATION_2 0x01 // Value for 80251+Netchip. +#define ION_DEVICE_ID_GENERATION_3 0x02 // Value for Texas Instruments TUSB5052 chip +#define ION_DEVICE_ID_GENERATION_4 0x03 // Watchport Family of products +#define ION_GENERATION_MASK 0x03 -#define ION_DEVICE_ID_GENERATION_2 0x020 // This bit is set in the PID if this edgeport hardware - // is based on the 80251+Netchip. +#define ION_DEVICE_ID_HUB_MASK 0x0080 // This bit in the PID designates a HUB device + // for example 8C would be a 421 4 port hub + // and 8D would be a 2 port embedded hub -#define EDGEPORT_DEVICE_ID_MASK 0x3df // Not including GEN_2 bit +#define EDGEPORT_DEVICE_ID_MASK 0x0ff // Not including OEM or GENERATION fields #define ION_DEVICE_ID_UNCONFIGURED_EDGE_DEVICE 0x000 // In manufacturing only #define ION_DEVICE_ID_EDGEPORT_4 0x001 // Edgeport/4 RS232 -// ION_DEVICE_ID_HUBPORT_7 0x002 // Hubport/7 (Placeholder, not used by software) +#define ION_DEVICE_ID_EDGEPORT_8R 0x002 // Edgeport with RJ45 no Ring #define ION_DEVICE_ID_RAPIDPORT_4 0x003 // Rapidport/4 #define ION_DEVICE_ID_EDGEPORT_4T 0x004 // Edgeport/4 RS232 for Telxon (aka "Fleetport") #define ION_DEVICE_ID_EDGEPORT_2 0x005 // Edgeport/2 RS232 #define ION_DEVICE_ID_EDGEPORT_4I 0x006 // Edgeport/4 RS422 #define ION_DEVICE_ID_EDGEPORT_2I 0x007 // Edgeport/2 RS422/RS485 -// ION_DEVICE_ID_HUBPORT_4 0x008 // Hubport/4 (Placeholder, not used by software) +#define ION_DEVICE_ID_EDGEPORT_8RR 0x008 // Edgeport with RJ45 with Data and RTS/CTS only // ION_DEVICE_ID_EDGEPORT_8_HANDBUILT 0x009 // Hand-built Edgeport/8 (Placeholder, used in middle digit of serial number only!) // ION_DEVICE_ID_MULTIMODEM_4X56 0x00A // MultiTech version of RP/4 (Placeholder, used in middle digit of serial number only!) #define ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT 0x00B // Edgeport/(4)21 Parallel port (USS720) @@ -90,41 +88,134 @@ #define ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) #define ION_DEVICE_ID_EDGEPORT_COMPATIBLE 0x013 // Edgeport Compatible, for NCR, Axiohm etc. testing #define ION_DEVICE_ID_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) +#define ION_DEVICE_ID_EDGEPORT_1 0x015 // Edgeport/1 RS232 +#define ION_DEVICE_ID_EPOS44 0x016 // Half of an EPOS/44 (TIUMP BASED) +#define ION_DEVICE_ID_EDGEPORT_42 0x017 // Edgeport/42 +#define ION_DEVICE_ID_EDGEPORT_412_8 0x018 // Edgeport/412 8 port part +#define ION_DEVICE_ID_EDGEPORT_412_4 0x019 // Edgeport/412 4 port part +#define ION_DEVICE_ID_EDGEPORT_22I 0x01A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 + +// Compact Form factor TI based devices 2c, 21c, 22c, 221c +#define ION_DEVICE_ID_EDGEPORT_2C 0x01B // Edgeport/2c is a TI based Edgeport/2 - Small I2c +#define ION_DEVICE_ID_EDGEPORT_221C 0x01C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_EDGEPORT_22C 0x01D // Edgeport/22c is a TI based Edgeport/2 with + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_EDGEPORT_21C 0x01E // Edgeport/21c is a TI based Edgeport/2 with lucent chip + // Small I2C + + +/* + * DANGER DANGER The 0x20 bit was used to indicate a 8251/netchip GEN 2 device. + * Since the MAC, Linux, and Optimal drivers still used the old code + * I suggest that you skip the 0x20 bit when creating new PIDs + */ + + +// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) +#define ION_DEVICE_ID_TI3410_EDGEPORT_1 0x040 // Edgeport/1 RS232 +#define ION_DEVICE_ID_TI3410_EDGEPORT_1I 0x041 // Edgeport/1i- RS422 model + +// Ti based software switchable RS232/RS422/RS485 devices +#define ION_DEVICE_ID_EDGEPORT_4S 0x042 // Edgeport/4s - software switchable model +#define ION_DEVICE_ID_EDGEPORT_8S 0x043 // Edgeport/8s - software switchable model + +// Usb to Ethernet dongle +#define ION_DEVICE_ID_EDGEPORT_E 0x0E0 // Edgeport/E Usb to Ethernet + +// Edgeport TI based devices +#define ION_DEVICE_ID_TI_EDGEPORT_4 0x0201 // Edgeport/4 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_2 0x0205 // Edgeport/2 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_4I 0x0206 // Edgeport/4i RS422 +#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 // Edgeport/2i RS422/RS485 +#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C // Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) +#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D // Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) +#define ION_DEVICE_ID_TI_EDGEPORT_8 0x020F // Edgeport/8 (single-CPU) +#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 // Edgeport/1 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 // Edgeport/42 4 hub 2 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_22I 0x021A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B // Edgeport/2c RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_221C 0x021C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_TI_EDGEPORT_22C 0x021D // Edgeport/22c is a TI based Edgeport/2 with + // 2 external hub ports - Large I2C +#define ION_DEVICE_ID_TI_EDGEPORT_21C 0x021E // Edgeport/21c is a TI based Edgeport/2 with lucent chip + +// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) +#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1 0x240 // Edgeport/1 RS232 +#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I 0x241 // Edgeport/1i- RS422 model + +// Ti based software switchable RS232/RS422/RS485 devices +#define ION_DEVICE_ID_TI_EDGEPORT_4S 0x242 // Edgeport/4s - software switchable model +#define ION_DEVICE_ID_IT_EDGEPORT_8S 0x243 // Edgeport/8s - software switchable model + + +/************************************************************************ + * + * Generation 4 devices + * + ************************************************************************/ + +// Watchport based on 3410 both 1-wire and binary products (16K I2C) +#define ION_DEVICE_ID_WP_UNSERIALIZED 0x300 // Watchport based on 3410 both 1-wire and binary products +#define ION_DEVICE_ID_WP_PROXIMITY 0x301 // Watchport/P Discontinued +#define ION_DEVICE_ID_WP_MOTION 0x302 // Watchport/M +#define ION_DEVICE_ID_WP_MOISTURE 0x303 // Watchport/W +#define ION_DEVICE_ID_WP_TEMPERATURE 0x304 // Watchport/T +#define ION_DEVICE_ID_WP_HUMIDITY 0x305 // Watchport/H + +#define ION_DEVICE_ID_WP_POWER 0x306 // Watchport +#define ION_DEVICE_ID_WP_LIGHT 0x307 // Watchport +#define ION_DEVICE_ID_WP_RADIATION 0x308 // Watchport +#define ION_DEVICE_ID_WP_ACCELERATION 0x309 // Watchport/A +#define ION_DEVICE_ID_WP_DISTANCE 0x30A // Watchport/D Discontinued +#define ION_DEVICE_ID_WP_PROX_DIST 0x30B // Watchport/D uses distance sensor + // Default to /P function + +#define ION_DEVICE_ID_PLUS_PWR_HP4CD 0x30C // 5052 Plus Power HubPort/4CD+ (for Dell) +#define ION_DEVICE_ID_PLUS_PWR_HP4C 0x30D // 5052 Plus Power HubPort/4C+ +#define ION_DEVICE_ID_PLUS_PWR_PCI 0x30E // 3410 Plus Power PCI Host Controller 4 port + + +// +// Definitions for AXIOHM USB product IDs +// +#define USB_VENDOR_ID_AXIOHM 0x05D9 // Axiohm VID + +#define AXIOHM_DEVICE_ID_MASK 0xffff +#define AXIOHM_DEVICE_ID_EPIC_A758 0xA758 +#define AXIOHM_DEVICE_ID_EPIC_A794 0xA794 +#define AXIOHM_DEVICE_ID_EPIC_A225 0xA225 + + +// +// Definitions for NCR USB product IDs +// +#define USB_VENDOR_ID_NCR 0x0404 // NCR VID + +#define NCR_DEVICE_ID_MASK 0xffff +#define NCR_DEVICE_ID_EPIC_0202 0x0202 +#define NCR_DEVICE_ID_EPIC_0203 0x0203 +#define NCR_DEVICE_ID_EPIC_0310 0x0310 +#define NCR_DEVICE_ID_EPIC_0311 0x0311 +#define NCR_DEVICE_ID_EPIC_0312 0x0312 + + +// +// Definitions for SYMBOL USB product IDs +// +#define USB_VENDOR_ID_SYMBOL 0x05E0 // Symbol VID +#define SYMBOL_DEVICE_ID_MASK 0xffff +#define SYMBOL_DEVICE_ID_KEYFOB 0x0700 + + +// +// Definitions for other product IDs #define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device -// BlackBox OEM devices -#define ION_DEVICE_ID_BB_EDGEPORT_4 0x001 // Edgeport/4 RS232 -#define ION_DEVICE_ID_BB_EDGEPORT_4T 0x004 // Edgeport/4 RS232 for Telxon (aka "Fleetport") -#define ION_DEVICE_ID_BB_EDGEPORT_2 0x005 // Edgeport/2 RS232 -#define ION_DEVICE_ID_BB_EDGEPORT_4I 0x006 // Edgeport/4 RS422 -#define ION_DEVICE_ID_BB_EDGEPORT_2I 0x007 // Edgeport/2 RS422/RS485 -#define ION_DEVICE_ID_BB_EDGEPORT_421 0x00C // Edgeport/421 Hub+RS232+Parallel -#define ION_DEVICE_ID_BB_EDGEPORT_21 0x00D // Edgeport/21 RS232+Parallel -#define ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU 0x00E // Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB) -#define ION_DEVICE_ID_BB_EDGEPORT_8 0x00F // Edgeport/8 (single-CPU) -#define ION_DEVICE_ID_BB_EDGEPORT_2_DIN 0x010 // Edgeport/2 RS232 with Apple DIN connector -#define ION_DEVICE_ID_BB_EDGEPORT_4_DIN 0x011 // Edgeport/4 RS232 with Apple DIN connector -#define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) -#define ION_DEVICE_ID_BB_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) - - -/* Edgeport TI based devices */ -#define ION_DEVICE_ID_TI_EDGEPORT_4 0x0201 /* Edgeport/4 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_2 0x0205 /* Edgeport/2 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_4I 0x0206 /* Edgeport/4i RS422 */ -#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 /* Edgeport/2i RS422/RS485 */ -#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C /* Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) */ -#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D /* Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) */ -#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 /* Edgeport/1 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 /* Edgeport/42 4 hub 2 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_22 0x021A /* Edgeport/22 Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */ -#define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B /* Edgeport/2c RS232 */ - -#define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT 0x0240 /* Edgeport/421 in boot mode */ -#define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN 0x0241 /* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ -#define ION_DEVICE_ID_TI_EDGEPORT_21_BOOT 0x0242 /* Edgeport/21 in boot mode */ -#define ION_DEVICE_ID_TI_EDGEPORT_21_DOWN 0x0243 /*Edgeport/42 in download mode: first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ +#define GENERATION_ID_FROM_USB_PRODUCT_ID( ProductId ) \ + ( (__u16) ((ProductId >> 8) & (ION_GENERATION_MASK)) ) #define MAKE_USB_PRODUCT_ID( OemId, DeviceId ) \ ( (__u16) (((OemId) << 10) || (DeviceId)) ) @@ -143,7 +234,7 @@ // TxCredits value below which driver won't bother sending (to prevent too many small writes). // Send only if above 25% -#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit) (max(((InitialCredit) / 4), EDGE_FW_BULK_MAX_PACKET_SIZE)) +#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max( ((InitialCredit) / 4), (MaxPacketSize) )) #define EDGE_FW_BULK_MAX_PACKET_SIZE 64 // Max Packet Size for Bulk In Endpoint (EP1) #define EDGE_FW_BULK_READ_BUFFER_SIZE 1024 // Size to use for Bulk reads @@ -158,8 +249,8 @@ // Definitions of I/O Networks vendor-specific requests // for default endpoint // -// bmRequestType = 00100000 Set vendor-specific, to device -// bmRequestType = 10100000 Get vendor-specific, to device +// bmRequestType = 01000000 Set vendor-specific, to device +// bmRequestType = 11000000 Get vendor-specific, to device // // These are the definitions for the bRequest field for the // above bmRequestTypes. @@ -184,11 +275,87 @@ #define USB_REQUEST_ION_ENABLE_SUSPEND 9 // Enable/Disable suspend feature // (wValue != 0: Enable; wValue = 0: Disable) +#define USB_REQUEST_ION_SEND_IOSP 10 // Send an IOSP command to the edgeport over the control pipe +#define USB_REQUEST_ION_RECV_IOSP 11 // Receive an IOSP command from the edgeport over the control pipe + + +#define USB_REQUEST_ION_DIS_INT_TIMER 0x80 // Sent to Axiohm to enable/ disable + // interrupt token timer + // wValue = 1, enable (default) + // wValue = 0, disable // // Define parameter values for our vendor-specific commands // +// +// Edgeport Compatiblity Descriptor +// +// This descriptor is only returned by Edgeport-compatible devices +// supporting the EPiC spec. True ION devices do not return this +// descriptor, but instead return STALL on receipt of the +// GET_EPIC_DESC command. The driver interprets a STALL to mean that +// this is a "real" Edgeport. +// + +struct edge_compatibility_bits +{ + // This __u32 defines which Vendor-specific commands/functionality + // the device supports on the default EP0 pipe. + + __u32 VendEnableSuspend : 1; // 0001 Set if device supports ION_ENABLE_SUSPEND + __u32 VendUnused : 31; // Available for future expansion, must be 0 + + // This __u32 defines which IOSP commands are supported over the + // bulk pipe EP1. + + // xxxx Set if device supports: + __u32 IOSPOpen : 1; // 0001 OPEN / OPEN_RSP (Currently must be 1) + __u32 IOSPClose : 1; // 0002 CLOSE + __u32 IOSPChase : 1; // 0004 CHASE / CHASE_RSP + __u32 IOSPSetRxFlow : 1; // 0008 SET_RX_FLOW + __u32 IOSPSetTxFlow : 1; // 0010 SET_TX_FLOW + __u32 IOSPSetXChar : 1; // 0020 SET_XON_CHAR/SET_XOFF_CHAR + __u32 IOSPRxCheck : 1; // 0040 RX_CHECK_REQ/RX_CHECK_RSP + __u32 IOSPSetClrBreak : 1; // 0080 SET_BREAK/CLEAR_BREAK + __u32 IOSPWriteMCR : 1; // 0100 MCR register writes (set/clr DTR/RTS) + __u32 IOSPWriteLCR : 1; // 0200 LCR register writes (wordlen/stop/parity) + __u32 IOSPSetBaudRate : 1; // 0400 setting Baud rate (writes to LCR.80h and DLL/DLM register) + __u32 IOSPDisableIntPipe : 1; // 0800 Do not use the interrupt pipe for TxCredits or RxButesAvailable + __u32 IOSPRxDataAvail : 1; // 1000 Return status of RX Fifo (Data available in Fifo) + __u32 IOSPTxPurge : 1; // 2000 Purge TXBuffer and/or Fifo in Edgeport hardware + __u32 IOSPUnused : 18; // Available for future expansion, must be 0 + + // This __u32 defines which 'general' features are supported + + __u32 TrueEdgeport : 1; // 0001 Set if device is a 'real' Edgeport + // (Used only by driver, NEVER set by an EPiC device) + __u32 GenUnused : 31; // Available for future expansion, must be 0 + +}; + +struct edge_compatibility_descriptor +{ + __u8 Length; // Descriptor Length (per USB spec) + __u8 DescType; // Descriptor Type (per USB spec, =DEVICE type) + __u8 EpicVer; // Version of EPiC spec supported + // (Currently must be 1) + __u8 NumPorts; // Number of serial ports supported + __u8 iDownloadFile; // Index of string containing download code filename + // 0=no download, FF=download compiled into driver. + __u8 Unused[ 3 ]; // Available for future expansion, must be 0 + // (Currently must be 0). + __u8 MajorVersion; // Firmware version: xx. + __u8 MinorVersion; // yy. + __le16 BuildNumber; // zzzz (LE format) + + // The following structure contains __u32s, with each bit + // specifying whether the EPiC device supports the given + // command or functionality. + + struct edge_compatibility_bits Supports; + +}; // Values for iDownloadFile #define EDGE_DOWNLOAD_FILE_NONE 0 // No download requested @@ -272,30 +439,30 @@ struct edge_manuf_descriptor { __u8 NumPorts; // F08 Number of ports __u8 DescDate[3]; // F09 MM/DD/YY when descriptor template was compiler, - // so host can track changes to USB-only descriptors. + // so host can track changes to USB-only descriptors. __u8 SerNumLength; // F0C USB string descriptor len __u8 SerNumDescType; // F0D USB descriptor type (=STRING type) - __u16 SerialNumber[MAX_SERIALNUMBER_LEN]; // F0E "01-01-000100" Unicode Serial Number + __le16 SerialNumber[MAX_SERIALNUMBER_LEN]; // F0E "01-01-000100" Unicode Serial Number __u8 AssemblyNumLength; // F26 USB string descriptor len __u8 AssemblyNumDescType; // F27 USB descriptor type (=STRING type) - __u16 AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F28 "350-1000-01-A " assembly number + __le16 AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F28 "350-1000-01-A " assembly number __u8 OemAssyNumLength; // F44 USB string descriptor len __u8 OemAssyNumDescType; // F45 USB descriptor type (=STRING type) - __u16 OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F46 "xxxxxxxxxxxxxx" OEM assembly number + __le16 OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F46 "xxxxxxxxxxxxxx" OEM assembly number __u8 ManufDateLength; // F62 USB string descriptor len __u8 ManufDateDescType; // F63 USB descriptor type (=STRING type) - __u16 ManufDate[6]; // F64 "MMDDYY" manufacturing date + __le16 ManufDate[6]; // F64 "MMDDYY" manufacturing date __u8 Reserved3[0x4D]; // F70 -- unused, set to 0 -- __u8 UartType; // FBD Uart Type __u8 IonPid; // FBE Product ID, == LSB of USB DevDesc.PID - // (Note: Edgeport/4s before 11/98 will have - // 00 here instead of 01) + // (Note: Edgeport/4s before 11/98 will have + // 00 here instead of 01) __u8 IonConfig; // FBF Config byte for ION manufacturing use // FBF end of structure, total len = 3C0h @@ -312,7 +479,7 @@ struct edge_manuf_descriptor { // both 00 and 01 values mean '654. #define MANUF_UART_EXAR_654_EARLY 0 // Exar 16C654 in Edgeport/4s before 11/98 #define MANUF_UART_EXAR_654 1 // Exar 16C654 -#define MANUF_UART_EXAR_2852 2 // Exar 16C2852 +#define MANUF_UART_EXAR_2852 2 // Exar 16C2852 // // Note: The CpuRev and BoardRev values do not conform to manufacturing @@ -334,25 +501,22 @@ struct edge_manuf_descriptor { #define MANUF_BOARD_REV_GENERATION_2 0x20 // Second generaiton edgeport - - // Values of bottom 5 bits of CpuRev & BoardRev for // Implementation 1 (ie, 251+Netchip-based) #define MANUF_CPU_REV_1 1 // C251TB Rev 1 (Need actual Intel rev here) #define MANUF_BOARD_REV_A 1 // First rev of 251+Netchip design - - #define MANUF_SERNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->SerialNumber) #define MANUF_ASSYNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->AssemblyNumber) #define MANUF_OEMASSYNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->OemAssyNumber) #define MANUF_MANUFDATE_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->ManufDate) -#define MANUF_ION_CONFIG_MASTER 0x80 // 1=Master mode, 0=Normal -#define MANUF_ION_CONFIG_DIAG 0x40 // 1=Run h/w diags, 0=norm -#define MANUF_ION_CONFIG_DIAG_NO_LOOP 0x20 // As above but no ext loopback test - +#define MANUF_ION_CONFIG_DIAG_NO_LOOP 0x20 // As below but no ext loopback test +#define MANUF_ION_CONFIG_DIAG 0x40 // 930 based device: 1=Run h/w diags, 0=norm + // TIUMP Device : 1=IONSERIAL needs to run Final Test +#define MANUF_ION_CONFIG_MASTER 0x80 // 930 based device: 1=Master mode, 0=Normal + // TIUMP Device : 1=First device on a multi TIUMP Device // // This structure describes parameters for the boot code, and @@ -368,19 +532,19 @@ struct edge_boot_descriptor { __u8 DescVer; // C2 Desc version/format __u8 Reserved1; // C3 -- unused, set to 0 -- - __u16 BootCodeLength; // C4 Boot code goes from FF:0000 to FF:(len-1) + __le16 BootCodeLength; // C4 Boot code goes from FF:0000 to FF:(len-1) // (LE format) __u8 MajorVersion; // C6 Firmware version: xx. __u8 MinorVersion; // C7 yy. - __u16 BuildNumber; // C8 zzzz (LE format) + __le16 BuildNumber; // C8 zzzz (LE format) __u16 EnumRootDescTable; // CA Root of ROM-based descriptor table __u8 NumDescTypes; // CC Number of supported descriptor types __u8 Reserved4; // CD Fix Compiler Packing - __u16 Capabilities; // CE-CF Capabilities flags (LE format) + __le16 Capabilities; // CE-CF Capabilities flags (LE format) __u8 Reserved2[0x28]; // D0 -- unused, set to 0 -- __u8 UConfig0; // F8 930-defined CPU configuration byte 0 __u8 UConfig1; // F9 930-defined CPU configuration byte 1 @@ -398,23 +562,29 @@ struct edge_boot_descriptor { #define BOOT_CAP_RESET_CMD 0x0001 // If set, boot correctly supports ION_RESET_DEVICE - /************************************************************************ T I U M P D E F I N I T I O N S ***********************************************************************/ +// Chip definitions in I2C +#define UMP5152 0x52 +#define UMP3410 0x10 + + //************************************************************************ // TI I2C Format Definitions //************************************************************************ -#define I2C_DESC_TYPE_INFO_BASIC 1 -#define I2C_DESC_TYPE_FIRMWARE_BASIC 2 -#define I2C_DESC_TYPE_DEVICE 3 -#define I2C_DESC_TYPE_CONFIG 4 -#define I2C_DESC_TYPE_STRING 5 -#define I2C_DESC_TYPE_FIRMWARE_BLANK 0xf2 - -#define I2C_DESC_TYPE_MAX 5 -// 3410 may define types 6, 7 for other firmware downloads +#define I2C_DESC_TYPE_INFO_BASIC 0x01 +#define I2C_DESC_TYPE_FIRMWARE_BASIC 0x02 +#define I2C_DESC_TYPE_DEVICE 0x03 +#define I2C_DESC_TYPE_CONFIG 0x04 +#define I2C_DESC_TYPE_STRING 0x05 +#define I2C_DESC_TYPE_FIRMWARE_AUTO 0x07 // for 3410 download +#define I2C_DESC_TYPE_CONFIG_KLUDGE 0x14 // for 3410 +#define I2C_DESC_TYPE_WATCHPORT_VERSION 0x15 // firmware version number for watchport +#define I2C_DESC_TYPE_WATCHPORT_CALIBRATION_DATA 0x16 // Watchport Calibration Data + +#define I2C_DESC_TYPE_FIRMWARE_BLANK 0xf2 // Special section defined by ION #define I2C_DESC_TYPE_ION 0 // Not defined by TI @@ -428,7 +598,9 @@ struct ti_i2c_desc __u8 Data[0]; // Data starts here }__attribute__((packed)); -struct ti_i2c_firmware_rec +// for 5152 devices only (type 2 record) +// for 3410 the version is stored in the WATCHPORT_FIRMWARE_VERSION descriptor +struct ti_i2c_firmware_rec { __u8 Ver_Major; // Firmware Major version number __u8 Ver_Minor; // Firmware Minor version number @@ -436,6 +608,14 @@ struct ti_i2c_firmware_rec }__attribute__((packed)); +struct watchport_firmware_version +{ +// Added 2 bytes for version number + __u8 Version_Major; // Download Version (for Watchport) + __u8 Version_Minor; +}__attribute__((packed)); + + // Structure of header of download image in fw_down.h struct ti_i2c_image_header { @@ -461,6 +641,15 @@ struct ti_basic_descriptor } __attribute__((packed)); +// CPU / Board Rev Definitions +#define TI_CPU_REV_5052 2 // 5052 based edgeports +#define TI_CPU_REV_3410 3 // 3410 based edgeports + +#define TI_BOARD_REV_TI_EP 0 // Basic ti based edgeport +#define TI_BOARD_REV_COMPACT 1 // Compact board +#define TI_BOARD_REV_WATCHPORT 2 // Watchport + + #define TI_GET_CPU_REVISION(x) (__u8)((((x)>>4)&0x0f)) #define TI_GET_BOARD_REVISION(x) (__u8)(((x)&0x0f)) @@ -469,20 +658,30 @@ struct ti_basic_descriptor #define TI_MAX_I2C_SIZE ( 16 * 1024 ) -/* TI USB 5052 definitions */ +#define TI_MANUF_VERSION_0 0 + +// IonConig2 flags +#define TI_CONFIG2_RS232 0x01 +#define TI_CONFIG2_RS422 0x02 +#define TI_CONFIG2_RS485 0x04 +#define TI_CONFIG2_SWITCHABLE 0x08 + +#define TI_CONFIG2_WATCHPORT 0x10 + + struct edge_ti_manuf_descriptor { __u8 IonConfig; // Config byte for ION manufacturing use __u8 IonConfig2; // Expansion - __u8 Version; // Verqsion + __u8 Version; // Version __u8 CpuRev_BoardRev; // CPU revision level (0xF0) and Board Rev Level (0x0F) __u8 NumPorts; // Number of ports for this UMP __u8 NumVirtualPorts; // Number of Virtual ports __u8 HubConfig1; // Used to configure the Hub __u8 HubConfig2; // Used to configure the Hub __u8 TotalPorts; // Total Number of Com Ports for the entire device (All UMPs) - __u8 Reserved; + __u8 Reserved; // Reserved }__attribute__((packed)); -#endif // if !defined() +#endif // if !defined(_USBVEND_H) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 42119dd44..8fbce2732 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -127,6 +127,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E335_ID) }, { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, + { USB_DEVICE(HTC_VENDOR_ID, HTC_HIMALAYA_ID) }, { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A600_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A620_PRODUCT_ID) }, @@ -188,6 +189,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) usb_set_serial_port_data(port, priv); priv->active = 0; priv->queue_len = 0; + priv->free_len = 0; INIT_LIST_HEAD(&priv->queue); INIT_LIST_HEAD(&priv->freelist); diff --git a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h index e9bedde0d..b997a9596 100644 --- a/drivers/usb/serial/ipaq.h +++ b/drivers/usb/serial/ipaq.h @@ -78,6 +78,7 @@ #define HTC_VENDOR_ID 0x0bb4 #define HTC_PRODUCT_ID 0x00ce +#define HTC_HIMALAYA_ID 0x0a02 #define NEC_VENDOR_ID 0x0409 #define NEC_PRODUCT_ID 0x00d5 diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index cb42cc7c3..3d1571695 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -449,6 +449,10 @@ static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) */ tty = port->tty; + /* + * FIXME: must not do this in IRQ context, + * must honour TTY_DONT_FLIP + */ tty->ldisc.receive_buf( tty, data+1, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index fd6c1b838..cd441d783 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -186,13 +186,7 @@ static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) wake_up_interruptible( &port->write_wait ); /* wake up line discipline */ - if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup ) - (tty->ldisc.write_wakeup)(tty); - - /* wake up other tty processes */ - wake_up_interruptible( &tty->write_wait ); - /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ + tty_wakeup(tty); } static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index b4961f0d2..212906c74 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -579,11 +579,7 @@ static void mct_u232_write_bulk_callback (struct urb *urb, struct pt_regs *regs) if (write_blocking) { wake_up_interruptible(&port->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - + tty_wakeup(tty); } else { /* from generic_write_bulk_callback */ schedule_work(&port->work); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index af0d230c6..c61e56829 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -659,7 +659,7 @@ static void pl2303_break_ctl (struct usb_serial_port *port, int break_state) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__); + dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2656807d7..03e8a7e1c 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: @@ -755,68 +805,7 @@ void usb_serial_port_softint(void *private) if (!tty) return; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg("%s - write wakeup call.", __FUNCTION__); - (tty->ldisc.write_wakeup)(tty); - } - - 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); + tty_wakeup(tty); } static void port_release(struct device *dev) @@ -859,7 +848,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 +1198,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/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index b27741bf5..1b759018e 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -668,8 +668,7 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) if (port->tty->driver->flush_buffer) port->tty->driver->flush_buffer(port->tty); - if (port->tty->ldisc.flush_buffer) - port->tty->ldisc.flush_buffer(port->tty); + tty_ldisc_flush(port->tty); firm_report_tx_done(port); diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 58baacc9a..94798eb1a 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -50,16 +50,19 @@ * in that routine. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "datafab.h" -#include -#include -#include - static int datafab_determine_lun(struct us_data *us, struct datafab_info *info); @@ -388,7 +391,7 @@ static int datafab_id_device(struct us_data *us, static int datafab_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, + struct scsi_cmnd * srb, int sense_6) { static unsigned char rw_err_page[12] = { @@ -483,7 +486,7 @@ static int datafab_handle_mode_sense(struct us_data *us, if (sense_6) ptr[0] = i - 1; else - ((u16 *) ptr)[0] = cpu_to_be16(i - 2); + ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); usb_stor_set_xfer_buf(ptr, i, srb); return USB_STOR_TRANSPORT_GOOD; @@ -498,7 +501,7 @@ static void datafab_info_destructor(void *extra) // Transport for the Datafab MDCFE-B // -int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) +int datafab_transport(struct scsi_cmnd * srb, struct us_data *us) { struct datafab_info *info; int rc; @@ -540,8 +543,8 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) // build the reply // we need the last sector, not the number of sectors - ((u32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((u32 *) ptr)[1] = cpu_to_be32(info->ssize); + ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); + ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); return USB_STOR_TRANSPORT_GOOD; @@ -625,12 +628,12 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) if (srb->cmnd[0] == MODE_SENSE) { US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n"); - return datafab_handle_mode_sense(us, srb, TRUE); + return datafab_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n"); - return datafab_handle_mode_sense(us, srb, FALSE); + return datafab_handle_mode_sense(us, srb, 0); } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { diff --git a/drivers/usb/storage/datafab.h b/drivers/usb/storage/datafab.h index c9343f6e4..32e3f271e 100644 --- a/drivers/usb/storage/datafab.h +++ b/drivers/usb/storage/datafab.h @@ -24,7 +24,7 @@ #ifndef _USB_DATAFAB_MDCFE_B_H #define _USB_DATAFAB_MDCFE_B_H -extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int datafab_transport(struct scsi_cmnd *srb, struct us_data *us); struct datafab_info { unsigned long sectors; // total sector count diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c index d4f278ca7..d76483706 100644 --- a/drivers/usb/storage/debug.c +++ b/drivers/usb/storage/debug.c @@ -44,9 +44,15 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include + #include "debug.h" +#include "scsi.h" + -void usb_stor_show_command(Scsi_Cmnd *srb) +void usb_stor_show_command(struct scsi_cmnd *srb) { char *what = NULL; int i; diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index d5d6b3c76..c4f4bcf36 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -46,13 +46,13 @@ #include #include -#include -#include "usb.h" + +struct scsi_cmnd; #define USB_STORAGE "usb-storage: " #ifdef CONFIG_USB_STORAGE_DEBUG -void usb_stor_show_command(Scsi_Cmnd *srb); +void usb_stor_show_command(struct scsi_cmnd *srb); void usb_stor_show_sense( unsigned char key, unsigned char asc, unsigned char ascq ); #define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x ) diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c index ae135fd3c..12c15f19a 100644 --- a/drivers/usb/storage/dpcm.c +++ b/drivers/usb/storage/dpcm.c @@ -30,6 +30,10 @@ */ #include +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" @@ -41,7 +45,7 @@ * Transport for the Microtech DPCM-USB * */ -int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) +int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) { int ret; diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h index e6e5637d6..81b464cfc 100644 --- a/drivers/usb/storage/dpcm.h +++ b/drivers/usb/storage/dpcm.h @@ -29,6 +29,6 @@ #ifndef _MICROTECH_DPCM_USB_H #define _MICROTECH_DPCM_USB_H -extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us); #endif diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 4b1ff0ad2..1dbb6301d 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -29,12 +29,16 @@ */ #include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "freecom.h" -#include "linux/hdreg.h" #ifdef CONFIG_USB_STORAGE_DEBUG static void pdump (void *, int); @@ -55,14 +59,14 @@ struct freecom_cb_wrap { struct freecom_xfer_wrap { u8 Type; /* Command type. */ u8 Timeout; /* Timeout in seconds. */ - u32 Count; /* Number of bytes to transfer. */ + __le32 Count; /* Number of bytes to transfer. */ u8 Pad[58]; } __attribute__ ((packed)); struct freecom_ide_out { u8 Type; /* Type + IDE register. */ u8 Pad; - u16 Value; /* Value to write. */ + __le16 Value; /* Value to write. */ u8 Pad2[60]; }; @@ -74,7 +78,7 @@ struct freecom_ide_in { struct freecom_status { u8 Status; u8 Reason; - u16 Count; + __le16 Count; u8 Pad[60]; }; @@ -105,7 +109,7 @@ struct freecom_status { #define FCM_STATUS_PACKET_LENGTH 4 static int -freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, +freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, unsigned int ipipe, unsigned int opipe, int count) { struct freecom_xfer_wrap *fxfr = @@ -139,7 +143,7 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, } static int -freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, +freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, int unsigned ipipe, unsigned int opipe, int count) { struct freecom_xfer_wrap *fxfr = @@ -176,7 +180,7 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, * Transport for the Freecom USB/IDE adaptor. * */ -int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) +int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) { struct freecom_cb_wrap *fcb; struct freecom_status *fst; @@ -302,7 +306,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) * move in. */ switch (us->srb->sc_data_direction) { - case SCSI_DATA_READ: + case DMA_FROM_DEVICE: /* catch bogus "read 0 length" case */ if (!length) break; @@ -334,7 +338,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("Transfer happy\n"); break; - case SCSI_DATA_WRITE: + case DMA_TO_DEVICE: /* catch bogus "write 0 length" case */ if (!length) break; @@ -364,7 +368,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) break; - case SCSI_DATA_NONE: + case DMA_NONE: /* Easy, do nothing. */ break; diff --git a/drivers/usb/storage/freecom.h b/drivers/usb/storage/freecom.h index 8c0ada8bb..1b012d62d 100644 --- a/drivers/usb/storage/freecom.h +++ b/drivers/usb/storage/freecom.h @@ -29,7 +29,7 @@ #ifndef _FREECOM_USB_H #define _FREECOM_USB_H -extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int freecom_transport(struct scsi_cmnd *srb, struct us_data *us); extern int usb_stor_freecom_reset(struct us_data *us); extern int freecom_init (struct us_data *us); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 43cc9c5e0..8aa136b4b 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -44,6 +44,16 @@ /* Include files */ +#include +#include +#include +#include +#include + +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" @@ -51,11 +61,6 @@ #include "scsiglue.h" #include "isd200.h" -#include -#include -#include -#include -#include /* Timeout defines (in Seconds) */ @@ -290,8 +295,8 @@ struct isd200_info { */ struct read_capacity_data { - unsigned long LogicalBlockAddress; - unsigned long BytesPerBlock; + __be32 LogicalBlockAddress; + __be32 BytesPerBlock; }; /* @@ -349,7 +354,7 @@ struct sense_data { * RETURNS: * void */ -static void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) +static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; @@ -427,7 +432,7 @@ static int isd200_action( struct us_data *us, int action, ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; srb->request_buffer = pointer; srb->request_bufflen = value; break; @@ -439,7 +444,7 @@ static int isd200_action( struct us_data *us, int action, ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_RESET: @@ -448,7 +453,7 @@ static int isd200_action( struct us_data *us, int action, ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_REENABLE: @@ -457,7 +462,7 @@ static int isd200_action( struct us_data *us, int action, ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_SOFT_RESET: @@ -466,14 +471,14 @@ static int isd200_action( struct us_data *us, int action, ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; srb->request_buffer = (void *) info->id; srb->request_bufflen = sizeof(struct hd_driveid); break; @@ -535,7 +540,7 @@ static int isd200_read_regs( struct us_data *us ) * the device and receive the response. */ static void isd200_invoke_transport( struct us_data *us, - Scsi_Cmnd *srb, + struct scsi_cmnd *srb, union ata_cdb *ataCdb ) { int need_auto_sense = 0; @@ -839,7 +844,7 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, unsigned long endTime; struct isd200_info *info = (struct isd200_info *)us->extra; unsigned char *regs = info->RegsBuf; - int recheckAsMaster = FALSE; + int recheckAsMaster = 0; if ( detect ) endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; @@ -847,7 +852,7 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; /* loop until we detect !BSY or timeout */ - while(TRUE) { + while(1) { #ifdef CONFIG_USB_STORAGE_DEBUG char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ? "Master" : "Slave"; @@ -899,9 +904,9 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, itself okay as a master also */ if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && - (recheckAsMaster == FALSE)) { + !recheckAsMaster) { US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n"); - recheckAsMaster = TRUE; + recheckAsMaster = 1; master_slave = ATA_ADDRESS_DEVHEAD_STD; } else { US_DEBUGP(" Identified ATAPI device\n"); @@ -948,15 +953,15 @@ static int isd200_manual_enum(struct us_data *us) if (retStatus == ISD200_GOOD) { int isslave; /* master or slave? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, FALSE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0); if (retStatus == ISD200_GOOD) - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, FALSE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0); if (retStatus == ISD200_GOOD) { retStatus = isd200_srst(us); if (retStatus == ISD200_GOOD) /* ata or atapi? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, TRUE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1); } isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; @@ -1011,7 +1016,8 @@ static int isd200_get_inquiry_data( struct us_data *us ) } else { /* ATA Command Identify successful */ int i; - __u16 *src, *dest; + __be16 *src; + __u16 *dest; ide_fix_driveid(id); US_DEBUGP(" Identify Data Structure:\n"); @@ -1063,17 +1069,17 @@ static int isd200_get_inquiry_data( struct us_data *us ) } /* Fill in vendor identification fields */ - src = (__u16*)id->model; + src = (__be16*)id->model; dest = (__u16*)info->InquiryData.VendorId; for (i=0;i<4;i++) dest[i] = be16_to_cpu(src[i]); - src = (__u16*)(id->model+8); + src = (__be16*)(id->model+8); dest = (__u16*)info->InquiryData.ProductId; for (i=0;i<8;i++) dest[i] = be16_to_cpu(src[i]); - src = (__u16*)id->fw_rev; + src = (__be16*)id->fw_rev; dest = (__u16*)info->InquiryData.ProductRevisionLevel; for (i=0;i<2;i++) dest[i] = be16_to_cpu(src[i]); @@ -1121,15 +1127,15 @@ static int isd200_get_inquiry_data( struct us_data *us ) * Translate SCSI commands to ATA commands. * * RETURNS: - * TRUE if the command needs to be sent to the transport layer - * FALSE otherwise + * 1 if the command needs to be sent to the transport layer + * 0 otherwise */ -static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, +static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, union ata_cdb * ataCdb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct hd_driveid *id = info->id; - int sendToTransport = TRUE; + int sendToTransport = 1; unsigned char sectnum, head; unsigned short cylinder; unsigned long lba; @@ -1147,7 +1153,7 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, sizeof(info->InquiryData), srb); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; break; case MODE_SENSE: @@ -1167,7 +1173,7 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1185,7 +1191,7 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1209,15 +1215,14 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, sizeof(readCapacityData), srb); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; case READ_10: US_DEBUGP(" ATA OUT - SCSIOP_READ\n"); - lba = *(unsigned long *)&srb->cmnd[2]; - lba = cpu_to_be32(lba); + lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; if (id->capability & CAPABILITY_LBA) { @@ -1249,8 +1254,7 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, case WRITE_10: US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n"); - lba = *(unsigned long *)&srb->cmnd[2]; - lba = cpu_to_be32(lba); + lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; if (id->capability & CAPABILITY_LBA) { @@ -1293,7 +1297,7 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, } else { US_DEBUGP(" Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1319,14 +1323,14 @@ static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; default: US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); srb->result = DID_ERROR << 16; - sendToTransport = FALSE; + sendToTransport = 0; break; } @@ -1424,9 +1428,9 @@ int isd200_Initialization(struct us_data *us) * */ -void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us) +void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) { - int sendToTransport = TRUE; + int sendToTransport = 1; union ata_cdb ataCdb; /* Make sure driver was initialized */ diff --git a/drivers/usb/storage/isd200.h b/drivers/usb/storage/isd200.h index 70ebe1c39..0a35f4fa7 100644 --- a/drivers/usb/storage/isd200.h +++ b/drivers/usb/storage/isd200.h @@ -25,7 +25,7 @@ #ifndef _USB_ISD200_H #define _USB_ISD200_H -extern void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us); +extern void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us); extern int isd200_Initialization(struct us_data *us); #endif diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index ac9c908c4..24464ece5 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -47,15 +47,19 @@ * in that routine. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "jumpshot.h" -#include -#include -#include static inline int jumpshot_bulk_read(struct us_data *us, unsigned char *data, @@ -319,7 +323,7 @@ static int jumpshot_id_device(struct us_data *us, } static int jumpshot_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, + struct scsi_cmnd * srb, int sense_6) { static unsigned char rw_err_page[12] = { @@ -409,7 +413,7 @@ static int jumpshot_handle_mode_sense(struct us_data *us, if (sense_6) ptr[0] = i - 1; else - ((u16 *) ptr)[0] = cpu_to_be16(i - 2); + ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); usb_stor_set_xfer_buf(ptr, i, srb); return USB_STOR_TRANSPORT_GOOD; @@ -426,7 +430,7 @@ static void jumpshot_info_destructor(void *extra) // Transport for the Lexar 'Jumpshot' // -int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) +int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us) { struct jumpshot_info *info; int rc; @@ -471,8 +475,8 @@ int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) // build the reply // - ((u32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((u32 *) ptr)[1] = cpu_to_be32(info->ssize); + ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); + ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); return USB_STOR_TRANSPORT_GOOD; @@ -551,12 +555,12 @@ int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) if (srb->cmnd[0] == MODE_SENSE) { US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n"); - return jumpshot_handle_mode_sense(us, srb, TRUE); + return jumpshot_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n"); - return jumpshot_handle_mode_sense(us, srb, FALSE); + return jumpshot_handle_mode_sense(us, srb, 0); } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { diff --git a/drivers/usb/storage/jumpshot.h b/drivers/usb/storage/jumpshot.h index 8147197cd..19bac9d15 100644 --- a/drivers/usb/storage/jumpshot.h +++ b/drivers/usb/storage/jumpshot.h @@ -24,7 +24,7 @@ #ifndef _USB_JUMPSHOT_H #define _USB_JUMPSHOT_H -extern int jumpshot_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us); struct jumpshot_info { unsigned long sectors; // total sector count diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 1c56f4944..99ed4d9bc 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -45,6 +45,8 @@ */ #include +#include +#include #include "protocol.h" #include "usb.h" #include "debug.h" @@ -59,7 +61,7 @@ * Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us */ -static void fix_inquiry_data(Scsi_Cmnd *srb) +static void fix_inquiry_data(struct scsi_cmnd *srb) { unsigned char databuf[3]; unsigned int index, offset; @@ -91,10 +93,10 @@ static void fix_inquiry_data(Scsi_Cmnd *srb) * Fix-up the return data from a READ CAPACITY command. My Feiya reader * returns a value that is 1 too large. */ -static void fix_read_capacity(Scsi_Cmnd *srb) +static void fix_read_capacity(struct scsi_cmnd *srb) { unsigned int index, offset; - u32 c; + __be32 c; unsigned long capacity; /* verify that it's a READ CAPACITY command */ @@ -120,11 +122,11 @@ static void fix_read_capacity(Scsi_Cmnd *srb) * Protocol routines ***********************************************************************/ -void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ for (; srb->cmd_len<12; srb->cmd_len++) @@ -141,11 +143,11 @@ void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) } } -void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ @@ -166,12 +168,12 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) } -void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us) { /* fix some commands -- this is a form of mode translation * UFI devices only accept 12 byte long commands * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ @@ -213,7 +215,8 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) } } -void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, + struct us_data *us) { /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); @@ -241,7 +244,7 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) * pick up from where this one left off. */ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, unsigned int *offset, enum xfer_buf_dir dir) { unsigned int cnt; @@ -327,7 +330,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, /* Store the contents of buffer into srb's transfer buffer and set the * SCSI residue. */ void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb) + unsigned int buflen, struct scsi_cmnd *srb) { unsigned int index = 0, offset = 0; diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h index c1fcb528a..7aa460d3b 100644 --- a/drivers/usb/storage/protocol.h +++ b/drivers/usb/storage/protocol.h @@ -41,9 +41,8 @@ #ifndef _PROTOCOL_H_ #define _PROTOCOL_H_ -#include -#include "scsi.h" -#include "usb.h" +struct scsi_cmnd; +struct us_data; /* Sub Classes */ @@ -60,18 +59,19 @@ #define US_SC_DEVICE 0xff /* Use device's value */ /* Protocol handling routines */ -extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*, + struct us_data*); -/* Scsi_Cmnd transfer buffer access utilities */ +/* struct scsi_cmnd transfer buffer access utilities */ enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF}; extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, unsigned int *offset, enum xfer_buf_dir dir); extern void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb); + unsigned int buflen, struct scsi_cmnd *srb); #endif diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index d003abe67..c18cd06ea 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -44,17 +44,23 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "scsiglue.h" -#include "usb.h" -#include "debug.h" -#include "transport.h" -#include "protocol.h" #include #include + +#include +#include #include +#include +#include #include +#include "scsiglue.h" +#include "usb.h" +#include "debug.h" +#include "transport.h" +#include "protocol.h" + /*********************************************************************** * Host functions ***********************************************************************/ @@ -92,17 +98,15 @@ static int slave_configure(struct scsi_device *sdev) * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Devices using Genesys Logic chips cause a lot of trouble for - * high-speed transfers; they die unpredictably when given more - * than 64 KB of data at a time. If we detect such a device, - * reduce the maximum transfer size to 64 KB = 128 sectors. */ - -#define USB_VENDOR_ID_GENESYS 0x05e3 // Needs a standard location - + /* According to the technical support people at Genesys Logic, + * devices using their chips have problems transferring more than + * 32 KB at a time. In practice people have found that 64 KB + * works okay and that's what Windows does. But we'll be + * conservative; people can always use the sysfs interface to + * increase max_sectors. */ if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS && - us->pusb_dev->speed == USB_SPEED_HIGH && - sdev->request_queue->max_sectors > 128) - blk_queue_max_sectors(sdev->request_queue, 128); + sdev->request_queue->max_sectors > 64) + blk_queue_max_sectors(sdev->request_queue, 64); /* We can't put these settings in slave_alloc() because that gets * called before the device type is known. Consequently these @@ -146,7 +150,8 @@ static int slave_configure(struct scsi_device *sdev) /* queue a command */ /* This is always called with scsi_lock(srb->host) held */ -static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +static int queuecommand(struct scsi_cmnd *srb, + void (*done)(struct scsi_cmnd *)) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; @@ -176,7 +181,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) /* Command abort */ /* This is always called with scsi_lock(srb->host) held */ -static int command_abort( Scsi_Cmnd *srb ) +static int command_abort(struct scsi_cmnd *srb ) { struct Scsi_Host *host = srb->device->host; struct us_data *us = (struct us_data *) host->hostdata[0]; @@ -223,7 +228,7 @@ static int command_abort( Scsi_Cmnd *srb ) /* This invokes the transport reset mechanism to reset the state of the * device */ /* This is always called with scsi_lock(srb->host) held */ -static int device_reset( Scsi_Cmnd *srb ) +static int device_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; int result; @@ -258,7 +263,7 @@ static int device_reset( Scsi_Cmnd *srb ) /* It refuses to work if there's more than one interface in * the device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ -static int bus_reset( Scsi_Cmnd *srb ) +static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; int result; @@ -444,10 +449,10 @@ struct scsi_host_template usb_stor_host_template = { * periodically someone should test to see which setting is more * optimal. */ - .use_clustering = TRUE, + .use_clustering = 1, /* emulated HBA */ - .emulated = TRUE, + .emulated = 1, /* we do our own delay after a device or bus reset */ .skip_settle_delay = 1, diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h index e5dc7613b..70df2a7bc 100644 --- a/drivers/usb/storage/scsiglue.h +++ b/drivers/usb/storage/scsiglue.h @@ -41,17 +41,15 @@ #ifndef _SCSIGLUE_H_ #define _SCSIGLUE_H_ -#include -#include "scsi.h" #include -#include "usb.h" + +struct us_data; +struct scsi_cmnd; extern void usb_stor_report_device_reset(struct us_data *us); extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_invalidCDB[18]; extern struct scsi_host_template usb_stor_host_template; -extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); -extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); #endif diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index f96bb7535..ff81b40c2 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -41,16 +41,19 @@ * EF: compute checksum (?) */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "sddr09.h" -#include -#include -#include -#include #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) @@ -1401,7 +1404,7 @@ sddr09_init(struct us_data *us) { /* * Transport for the Sandisk SDDR-09 */ -int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) +int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) { static unsigned char sensekey = 0, sensecode = 0; static unsigned char havefakesense = 0; @@ -1486,11 +1489,11 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) capacity = (info->lbact << info->blockshift) - 1; - ((u32 *) ptr)[0] = cpu_to_be32(capacity); + ((__be32 *) ptr)[0] = cpu_to_be32(capacity); // Report page size - ((u32 *) ptr)[1] = cpu_to_be32(info->pagesize); + ((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize); usb_stor_set_xfer_buf(ptr, 8, srb); return USB_STOR_TRANSPORT_GOOD; @@ -1507,7 +1510,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) "mode page 0x%x\n", modepage); memcpy(ptr, mode_page_01, sizeof(mode_page_01)); - ((u16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); + ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0; usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); return USB_STOR_TRANSPORT_GOOD; @@ -1581,13 +1584,13 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) if (srb->request_bufflen == 0) return USB_STOR_TRANSPORT_GOOD; - if (srb->sc_data_direction == SCSI_DATA_WRITE || - srb->sc_data_direction == SCSI_DATA_READ) { - unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE) + if (srb->sc_data_direction == DMA_TO_DEVICE || + srb->sc_data_direction == DMA_FROM_DEVICE) { + unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) ? us->send_bulk_pipe : us->recv_bulk_pipe; US_DEBUGP("SDDR09: %s %d bytes\n", - (srb->sc_data_direction == SCSI_DATA_WRITE) ? + (srb->sc_data_direction == DMA_TO_DEVICE) ? "sending" : "receiving", srb->request_bufflen); diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h index 685123939..c9d78d618 100644 --- a/drivers/usb/storage/sddr09.h +++ b/drivers/usb/storage/sddr09.h @@ -29,7 +29,7 @@ /* Sandisk SDDR-09 stuff */ -extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); struct sddr09_card_info { unsigned long capacity; /* Size of card in bytes */ diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index eb9615318..10270f42a 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -24,15 +24,19 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "sddr55.h" -#include -#include -#include #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) @@ -74,7 +78,7 @@ static int sddr55_bulk_transport(struct us_data *us, int direction, unsigned char *data, unsigned int len) { struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - unsigned int pipe = (direction == SCSI_DATA_READ) ? + unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; if (!len) @@ -99,7 +103,7 @@ static int sddr55_status(struct us_data *us) command[5] = 0xB0; command[7] = 0x80; result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); US_DEBUGP("Result for send_command in status %d\n", result); @@ -110,7 +114,7 @@ static int sddr55_status(struct us_data *us) } result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 4); + DMA_FROM_DEVICE, status, 4); /* expect to get short transfer if no card fitted */ if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) { @@ -139,7 +143,7 @@ static int sddr55_status(struct us_data *us) /* now read status */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 2); + DMA_FROM_DEVICE, status, 2); if (result != USB_STOR_XFER_GOOD) { set_sense_info (4, 0, 0); /* hardware error */ @@ -215,7 +219,7 @@ static int sddr55_read_data(struct us_data *us, /* send command */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); US_DEBUGP("Result for send_command in read_data %d\n", result); @@ -227,7 +231,7 @@ static int sddr55_read_data(struct us_data *us, /* read data */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, buffer, len); + DMA_FROM_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -236,7 +240,7 @@ static int sddr55_read_data(struct us_data *us, /* now read status */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 2); + DMA_FROM_DEVICE, status, 2); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -390,7 +394,7 @@ static int sddr55_write_data(struct us_data *us, /* send command */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for send_command in write_data %d\n", @@ -404,7 +408,7 @@ static int sddr55_write_data(struct us_data *us, /* send the data */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, buffer, len); + DMA_TO_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for send_data in write_data %d\n", @@ -417,7 +421,7 @@ static int sddr55_write_data(struct us_data *us, } /* now read status */ - result = sddr55_bulk_transport(us, SCSI_DATA_READ, status, 6); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for get_status in write_data %d\n", @@ -483,7 +487,7 @@ static int sddr55_read_deviceID(struct us_data *us, memset(command, 0, 8); command[5] = 0xB0; command[7] = 0x84; - result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); + result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); US_DEBUGP("Result of send_control for device ID is %d\n", result); @@ -492,7 +496,7 @@ static int sddr55_read_deviceID(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; result = sddr55_bulk_transport(us, - SCSI_DATA_READ, content, 4); + DMA_FROM_DEVICE, content, 4); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -502,7 +506,7 @@ static int sddr55_read_deviceID(struct us_data *us, if (content[0] != 0xff) { result = sddr55_bulk_transport(us, - SCSI_DATA_READ, content, 2); + DMA_FROM_DEVICE, content, 2); } return USB_STOR_TRANSPORT_GOOD; @@ -624,21 +628,21 @@ static int sddr55_read_map(struct us_data *us) { command[6] = numblocks * 2 / 256; command[7] = 0x8A; - result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); + result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); return -1; } - result = sddr55_bulk_transport(us, SCSI_DATA_READ, buffer, numblocks * 2); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); return -1; } - result = sddr55_bulk_transport(us, SCSI_DATA_READ, command, 2); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); @@ -734,7 +738,7 @@ static void sddr55_card_info_destructor(void *extra) { /* * Transport for the Sandisk SDDR-55 */ -int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) +int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) { int result; static unsigned char inquiry_response[8] = { @@ -834,8 +838,8 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) capacity /= PAGESIZE; capacity--; - ((u32 *) ptr)[0] = cpu_to_be32(capacity); - ((u32 *) ptr)[1] = cpu_to_be32(PAGESIZE); + ((__be32 *) ptr)[0] = cpu_to_be32(capacity); + ((__be32 *) ptr)[1] = cpu_to_be32(PAGESIZE); usb_stor_set_xfer_buf(ptr, 8, srb); sddr55_read_map(us); diff --git a/drivers/usb/storage/sddr55.h b/drivers/usb/storage/sddr55.h index 6dc0da6d2..d6bd32f6c 100644 --- a/drivers/usb/storage/sddr55.h +++ b/drivers/usb/storage/sddr55.h @@ -28,7 +28,7 @@ /* Sandisk SDDR-55 stuff */ -extern int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us); extern int sddr55_reset(struct us_data *us); #endif diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index b0af06e4f..c98fa3938 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -39,16 +39,20 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "shuttle_usbat.h" -#include -#include -#include - #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) @@ -275,7 +279,7 @@ static int usbat_rw_block_test(struct us_data *us, int minutes) { int result; - unsigned int pipe = (direction == SCSI_DATA_READ) ? + unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, @@ -315,9 +319,9 @@ static int usbat_rw_block_test(struct us_data *us, } else cmdlen = 8; - command[cmdlen-8] = (direction==SCSI_DATA_WRITE ? 0x40 : 0xC0); + command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); command[cmdlen-7] = access | - (direction==SCSI_DATA_WRITE ? 0x05 : 0x04); + (direction==DMA_TO_DEVICE ? 0x05 : 0x04); command[cmdlen-6] = data_reg; command[cmdlen-5] = status_reg; command[cmdlen-4] = timeout; @@ -355,7 +359,7 @@ static int usbat_rw_block_test(struct us_data *us, //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", - // direction == SCSI_DATA_WRITE ? "out" : "in", + // direction == DMA_TO_DEVICE ? "out" : "in", // len, use_sg); result = usb_stor_bulk_transfer_sg(us, @@ -388,7 +392,7 @@ static int usbat_rw_block_test(struct us_data *us, * the bulk output pipe only the first time. */ - if (direction==SCSI_DATA_READ && i==0) { + if (direction==DMA_FROM_DEVICE && i==0) { if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; @@ -399,7 +403,7 @@ static int usbat_rw_block_test(struct us_data *us, */ result = usbat_read(us, USBAT_ATA, - direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, + direction==DMA_TO_DEVICE ? 0x17 : 0x0E, status); if (result!=USB_STOR_XFER_GOOD) @@ -410,7 +414,7 @@ static int usbat_rw_block_test(struct us_data *us, return USB_STOR_TRANSPORT_FAILED; US_DEBUGP("Redoing %s\n", - direction==SCSI_DATA_WRITE ? "write" : "read"); + direction==DMA_TO_DEVICE ? "write" : "read"); } else if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -420,7 +424,7 @@ static int usbat_rw_block_test(struct us_data *us, } US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", - direction==SCSI_DATA_WRITE ? "Writing" : "Reading"); + direction==DMA_TO_DEVICE ? "Writing" : "Reading"); return USB_STOR_TRANSPORT_FAILED; } @@ -520,7 +524,7 @@ static int usbat_write_user_io(struct us_data *us, static int usbat_handle_read10(struct us_data *us, unsigned char *registers, unsigned char *data, - Scsi_Cmnd *srb) + struct scsi_cmnd *srb) { int result = USB_STOR_TRANSPORT_GOOD; unsigned char *buffer; @@ -537,7 +541,7 @@ static int usbat_handle_read10(struct us_data *us, result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, + DMA_FROM_DEVICE, srb->request_buffer, srb->request_bufflen, srb->use_sg, 1); @@ -606,7 +610,7 @@ static int usbat_handle_read10(struct us_data *us, result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, + DMA_FROM_DEVICE, buffer, len, 0, 1); @@ -803,7 +807,7 @@ int init_8200e(struct us_data *us) /* * Transport for the HP 8200e */ -int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) +int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) { int result; unsigned char *status = us->iobuf; @@ -847,12 +851,12 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) if (srb->cmnd[0] == TEST_UNIT_READY) transferred = 0; - if (srb->sc_data_direction == SCSI_DATA_WRITE) { + if (srb->sc_data_direction == DMA_TO_DEVICE) { result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_WRITE, + DMA_TO_DEVICE, srb->request_buffer, len, srb->use_sg, 10); @@ -900,7 +904,7 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) // If there is response data to be read in // then do it here. - if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) { + if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { // How many bytes to read in? Check cylL register diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h index e9c4aead5..9855c1d32 100644 --- a/drivers/usb/storage/shuttle_usbat.h +++ b/drivers/usb/storage/shuttle_usbat.h @@ -53,7 +53,7 @@ #define USBAT_UIO_ADPRST 0x01 // Reset SCM chip /* HP 8200e stuff */ -extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); extern int init_8200e(struct us_data *us); #endif diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 232155854..42f784321 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -46,15 +46,20 @@ */ #include +#include +#include +#include + +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "scsiglue.h" #include "usb.h" #include "debug.h" -#include -#include -#include /*********************************************************************** * Data transfer routines @@ -260,9 +265,7 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) USB_ENDPOINT_HALT, endp, NULL, 0, 3*HZ); - /* reset the toggles and endpoint flags */ - usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe)); + /* reset the endpoint toggle */ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); @@ -522,7 +525,7 @@ int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, * This is used by the protocol layers to actually send the message to * the device and receive the response. */ -void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; @@ -569,7 +572,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && - srb->sc_data_direction != SCSI_DATA_READ) { + srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } @@ -629,7 +632,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) /* set the transfer direction */ old_sc_data_direction = srb->sc_data_direction; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; /* use the new buffer we have */ old_request_buffer = srb->request_buffer; @@ -749,7 +752,7 @@ void usb_stor_stop_transport(struct us_data *us) * Control/Bulk/Interrupt transport */ -int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = srb->request_bufflen; unsigned int pipe = 0; @@ -778,7 +781,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (transfer_length) { - pipe = srb->sc_data_direction == SCSI_DATA_READ ? + pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, @@ -849,7 +852,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) /* * Control/Bulk transport */ -int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = srb->request_bufflen; int result; @@ -877,7 +880,7 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, @@ -908,6 +911,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) int result; /* issue the command */ + us->iobuf[0] = 0; result = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | @@ -918,7 +922,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) result, us->iobuf[0]); /* if we have a successful request, return the result */ - if (result == 1) + if (result >= 0) return us->iobuf[0]; /* @@ -939,7 +943,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) return -1; } -int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; @@ -952,7 +956,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(transfer_length); - bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; + bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0; bcb->Tag = srb->serial_number; bcb->Lun = srb->device->lun; if (us->flags & US_FL_SCM_MULT_TARG) @@ -977,8 +981,14 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* DATA STAGE */ /* send/receive data payload, if there is any */ + + /* Genesys Logic interface chips need a 100us delay between the + * command phase and the data phase */ + if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS) + udelay(100); + if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 123b041ab..153efd623 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -44,7 +44,8 @@ #include #include #include "usb.h" -#include "scsi.h" + +struct scsi_cmnd; /* Protocols */ @@ -82,9 +83,9 @@ /* command block wrapper */ struct bulk_cb_wrap { - __u32 Signature; /* contains 'USBC' */ + __le32 Signature; /* contains 'USBC' */ __u32 Tag; /* unique per command id */ - __u32 DataTransferLength; /* size of data */ + __le32 DataTransferLength; /* size of data */ __u8 Flags; /* direction in bit 0 */ __u8 Lun; /* LUN normally 0 */ __u8 Length; /* of of the CDB */ @@ -98,9 +99,9 @@ struct bulk_cb_wrap { /* command status wrapper */ struct bulk_cs_wrap { - __u32 Signature; /* should = 'USBS' */ + __le32 Signature; /* should = 'USBS' */ __u32 Tag; /* same as original command */ - __u32 Residue; /* amount not transferred */ + __le32 Residue; /* amount not transferred */ __u8 Status; /* see below */ __u8 Filler[18]; }; @@ -150,16 +151,16 @@ struct bulk_cs_wrap { #define US_CBI_ADSC 0 -extern int usb_stor_CBI_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_CBI_transport(struct scsi_cmnd *, struct us_data*); -extern int usb_stor_CB_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*); extern int usb_stor_CB_reset(struct us_data*); -extern int usb_stor_Bulk_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*); extern int usb_stor_Bulk_max_lun(struct us_data*); extern int usb_stor_Bulk_reset(struct us_data*); -extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*); extern void usb_stor_stop_transport(struct us_data*); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 195e98f95..4fe25f6b0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -45,11 +45,6 @@ * */ -UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, - "Mitsumi", - "CD-R/RW Drive", - US_SC_8020, US_PR_CBI, NULL, 0), - UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, "Mitsumi", "USB FDD", @@ -373,6 +368,15 @@ UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN), +/* Reported by Johann Cardon + * This entry is needed only because the device reports + * bInterfaceClass = 0xff (vendor-specific) + */ +UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999, + "Y-E Data", + "Silicon Media R/W", + US_SC_DEVICE, US_PR_DEVICE, NULL, 0), + /* Fabrizio Fellini */ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, "Fujifilm", @@ -384,11 +388,15 @@ UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, "USB Hard Disk", US_SC_RBC, US_PR_CB, NULL, 0 ), -/* Submitted by Jol Bourquard */ +/* Submitted by Joel Bourquard + * Some versions of this device need the SubClass and Protocol overrides + * while others don't. + */ UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110, "In-System", "PyroGate External CD-ROM Enclosure (FCD-523)", - US_SC_SCSI, US_PR_BULK, NULL, 0 ), + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_NEED_OVERRIDE ), #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, @@ -482,6 +490,13 @@ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, US_FL_SINGLE_LUN ), #endif +/* Reported by Darsen Lu */ +UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, + "SigmaTel", + "USBMSC Audio Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Submitted by Benny Sjostrand */ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, "Minolta", @@ -510,11 +525,13 @@ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN ), +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk", "ImageMate SDDR-31", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_SER ), +#endif UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", @@ -685,7 +702,7 @@ UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100, "Trumpion", "t33520 USB Flash Card Controller", US_SC_DEVICE, US_PR_BULK, NULL, - US_FL_MODE_XLATE), + US_FL_NEED_OVERRIDE | US_FL_MODE_XLATE), /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index ad22739be..9579bdf49 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -50,6 +50,11 @@ #include #include #include + +#include +#include +#include + #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -133,7 +138,9 @@ static struct usb_device_id storage_usb_ids [] = { { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) }, +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, +#endif /* Terminating entry */ { } @@ -207,8 +214,10 @@ static struct us_unusual_dev us_unusual_dev_list[] = { .useTransport = US_PR_BULK}, { .useProtocol = US_SC_8070, .useTransport = US_PR_BULK}, +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) { .useProtocol = US_SC_SCSI, .useTransport = US_PR_BULK}, +#endif /* Terminating entry */ { NULL } @@ -322,7 +331,7 @@ static int usb_stor_control_thread(void * __us) /* reject the command if the direction indicator * is UNKNOWN */ - if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { + if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } @@ -423,6 +432,13 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", + us->pusb_dev->descriptor.idVendor, + us->pusb_dev->descriptor.idProduct, + us->pusb_dev->descriptor.bcdDevice); + US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", + intf->cur_altsetting->desc.bInterfaceSubClass, + intf->cur_altsetting->desc.bInterfaceProtocol); /* Store our private data in the interface */ usb_set_intfdata(intf, us); @@ -453,11 +469,6 @@ static void get_device_info(struct us_data *us, int id_index) struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; struct usb_device_id *id = &storage_usb_ids[id_index]; - if (unusual_dev->vendorName) - US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); - if (unusual_dev->productName) - US_DEBUGP("Product: %s\n", unusual_dev->productName); - /* Store the entries */ us->unusual_dev = unusual_dev; us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ? @@ -528,6 +539,8 @@ static void get_device_info(struct us_data *us, int id_index) } if (strlen(us->serial) == 0) strcpy(us->serial, "None"); + + US_DEBUGP("Vendor: %s, Product: %s\n", us->vendor, us->product); } /* Get the transport settings */ @@ -715,8 +728,6 @@ static int get_pipes(struct us_data *us) ep_int = ep; } } - US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n", - ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0); if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); @@ -880,9 +891,6 @@ static int storage_probe(struct usb_interface *intf, int result; US_DEBUGP("USB Mass Storage device detected\n"); - US_DEBUGP("altsetting is %d, id_index is %d\n", - intf->cur_altsetting->desc.bAlternateSetting, - id_index); /* Allocate the us_data structure and initialize the mutexes */ us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 35d01444a..785f30be6 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -48,10 +48,9 @@ #include #include #include -#include "scsi.h" -#include struct us_data; +struct scsi_cmnd; /* * Unusual device list definitions @@ -102,9 +101,9 @@ struct us_unusual_dev { #define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */ -typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*); typedef int (*trans_reset)(struct us_data*); -typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*); typedef void (*extra_data_destructor)(void *); /* extra data destructor */ /* we allocate one of these for every device that we remember */ @@ -144,7 +143,7 @@ struct us_data { /* SCSI interfaces */ struct Scsi_Host *host; /* our dummy host data */ - Scsi_Cmnd *srb; /* current srb */ + struct scsi_cmnd *srb; /* current srb */ /* thread information */ int pid; /* control thread */ @@ -180,4 +179,8 @@ extern void fill_inquiry_response(struct us_data *us, #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) + +/* Vendor ID list for devices that require special handling */ +#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */ + #endif diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index f893cc078..d3a3fd9b1 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -1,42 +1,15 @@ /* - * USB Skeleton driver - 1.1 + * USB Skeleton driver - 2.0 * - * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * * 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, version 2. * - * - * This driver is to be used as a skeleton driver to be able to create a - * USB driver quickly. The design of it is based on the usb-serial and - * dc2xx drivers. - * - * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help - * in debugging this driver. - * - * - * History: - * - * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev() - * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and - * disconnect. Fix transfer amount in read(). Use - * macros instead of magic numbers in probe(). Change - * size variables to size_t. Show how to eliminate - * DMA bounce buffer. - * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array. - * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device - * driver. - * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do - * not have both a bulk in and bulk out endpoint. - * Thanks to Holger Waechtler for the fix. - * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. - * Thanks to Pete Zaitcev for the fix. - * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux - * 2001_08_21 - 0.4 - more small bug fixes. - * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel - * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people - * 2001_05_01 - 0.1 - first version + * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c + * but has been rewritten to be easy to read and use, as no locks are now + * needed anymore. * */ @@ -46,31 +19,10 @@ #include #include #include -#include -#include +#include #include #include -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) - - -/* Version Information */ -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" -#define DRIVER_DESC "USB Skeleton Driver" - -/* Module parameters */ -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - /* Define these values to match your devices */ #define USB_SKEL_VENDOR_ID 0xfff0 @@ -79,11 +31,8 @@ MODULE_PARM_DESC(debug, "Debug enabled or not"); /* table of devices that work with this driver */ static struct usb_device_id skel_table [] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, - /* "Gadget Zero" firmware runs under Linux */ - { USB_DEVICE(0x0525, 0xa4a0) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE (usb, skel_table); @@ -92,413 +41,195 @@ MODULE_DEVICE_TABLE (usb, skel_table); /* Structure to hold all of our device specific stuff */ struct usb_skel { - struct usb_device * udev; /* save off the usb device pointer */ + struct usb_device * udev; /* the usb device for this device */ struct usb_interface * interface; /* the interface for this device */ - unsigned char minor; /* the starting minor number for this device */ - unsigned char num_ports; /* the number of ports this device has */ - char num_interrupt_in; /* number of interrupt in endpoints we have */ - char num_bulk_in; /* number of bulk in endpoints we have */ - char num_bulk_out; /* number of bulk out endpoints we have */ - unsigned char * bulk_in_buffer; /* the buffer to receive data */ size_t bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ - - unsigned char * bulk_out_buffer; /* the buffer to send data */ - size_t bulk_out_size; /* the size of the send buffer */ - struct urb * write_urb; /* the urb used to send data */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - atomic_t write_busy; /* true iff write urb is busy */ - struct completion write_finished; /* wait for the write to finish */ - - int open; /* if the port is open or not */ - int present; /* if the device is not disconnected */ - struct semaphore sem; /* locks this structure */ -}; - - -/* prevent races between open() and disconnect() */ -static DECLARE_MUTEX (disconnect_sem); - -/* local function prototypes */ -static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos); -static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos); -static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int skel_open (struct inode *inode, struct file *file); -static int skel_release (struct inode *inode, struct file *file); - -static int skel_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void skel_disconnect (struct usb_interface *interface); - -static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs); - -/* - * File operations needed when we register this driver. - * This assumes that this driver NEEDS file operations, - * of course, which means that the driver is expected - * to have a node in the /dev directory. If the USB - * device were for a network interface then the driver - * would use "struct net_driver" instead, and a serial - * device would use "struct tty_driver". - */ -static struct file_operations skel_fops = { - /* - * The owner field is part of the module-locking - * mechanism. The idea is that the kernel knows - * which module to increment the use-counter of - * BEFORE it calls the device's open() function. - * This also means that the kernel can decrement - * the use-counter again before calling release() - * or should the open() function fail. - */ - .owner = THIS_MODULE, - - .read = skel_read, - .write = skel_write, - .ioctl = skel_ioctl, - .open = skel_open, - .release = skel_release, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core - */ -static struct usb_class_driver skel_class = { - .name = "usb/skel%d", - .fops = &skel_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, - .minor_base = USB_SKEL_MINOR_BASE, -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver skel_driver = { - .owner = THIS_MODULE, - .name = "skeleton", - .probe = skel_probe, - .disconnect = skel_disconnect, - .id_table = skel_table, + struct kref kref; }; +#define to_skel_dev(d) container_of(d, struct usb_skel, kref) +static struct usb_driver skel_driver; -/** - * usb_skel_debug_data - */ -static inline void usb_skel_debug_data (const char *function, int size, const unsigned char *data) -{ - int i; +static void skel_delete(struct kref *kref) +{ + struct usb_skel *dev = to_skel_dev(kref); - if (!debug) - return; - - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} - - -/** - * skel_delete - */ -static inline void skel_delete (struct usb_skel *dev) -{ + usb_put_dev(dev->udev); kfree (dev->bulk_in_buffer); - usb_buffer_free (dev->udev, dev->bulk_out_size, - dev->bulk_out_buffer, - dev->write_urb->transfer_dma); - usb_free_urb (dev->write_urb); kfree (dev); } - -/** - * skel_open - */ -static int skel_open (struct inode *inode, struct file *file) +static int skel_open(struct inode *inode, struct file *file) { - struct usb_skel *dev = NULL; + struct usb_skel *dev; struct usb_interface *interface; int subminor; int retval = 0; - dbg("%s", __FUNCTION__); - subminor = iminor(inode); - /* prevent disconnects */ - down (&disconnect_sem); - - interface = usb_find_interface (&skel_driver, subminor); + interface = usb_find_interface(&skel_driver, subminor); if (!interface) { err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval = -ENODEV; - goto exit_no_device; + goto exit; } dev = usb_get_intfdata(interface); if (!dev) { retval = -ENODEV; - goto exit_no_device; + goto exit; } - /* lock this device */ - down (&dev->sem); - - /* increment our usage count for the driver */ - ++dev->open; + /* increment our usage count for the device */ + kref_get(&dev->kref); /* save our object in the file's private structure */ file->private_data = dev; - /* unlock this device */ - up (&dev->sem); - -exit_no_device: - up (&disconnect_sem); +exit: return retval; } - -/** - * skel_release - */ -static int skel_release (struct inode *inode, struct file *file) +static int skel_release(struct inode *inode, struct file *file) { struct usb_skel *dev; - int retval = 0; dev = (struct usb_skel *)file->private_data; - if (dev == NULL) { - dbg ("%s - object is NULL", __FUNCTION__); + if (dev == NULL) return -ENODEV; - } - dbg("%s - minor %d", __FUNCTION__, dev->minor); - - /* lock our device */ - down (&dev->sem); - - if (dev->open <= 0) { - dbg ("%s - device not opened", __FUNCTION__); - retval = -ENODEV; - goto exit_not_opened; - } - - /* wait for any bulk writes that might be going on to finish up */ - if (atomic_read (&dev->write_busy)) - wait_for_completion (&dev->write_finished); - - --dev->open; - - if (!dev->present && !dev->open) { - /* the device was unplugged before the file was released */ - up (&dev->sem); - skel_delete (dev); - return 0; - } - -exit_not_opened: - up (&dev->sem); - - return retval; + /* decrement the count on our device */ + kref_put(&dev->kref, skel_delete); + return 0; } - -/** - * skel_read - */ -static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct usb_skel *dev; int retval = 0; dev = (struct usb_skel *)file->private_data; - - dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - up (&dev->sem); - return -ENODEV; - } - + /* do a blocking bulk read to get data from the device */ - retval = usb_bulk_msg (dev->udev, - usb_rcvbulkpipe (dev->udev, - dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, - min (dev->bulk_in_size, count), - &count, HZ*10); + retval = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, + min(dev->bulk_in_size, count), + &count, HZ*10); /* if the read was successful, copy the data to userspace */ if (!retval) { - if (copy_to_user (buffer, dev->bulk_in_buffer, count)) + if (copy_to_user(buffer, dev->bulk_in_buffer, count)) retval = -EFAULT; else retval = count; } - /* unlock the device */ - up (&dev->sem); return retval; } - -/** - * skel_write - * - * A device driver has to decide how to report I/O errors back to the - * user. The safest course is to wait for the transfer to finish before - * returning so that any errors will be reported reliably. skel_read() - * works like this. But waiting for I/O is slow, so many drivers only - * check for errors during I/O initiation and do not report problems - * that occur during the actual transfer. That's what we will do here. - * - * A driver concerned with maximum I/O throughput would use double- - * buffering: Two urbs would be devoted to write transfers, so that - * one urb could always be active while the other was waiting for the - * user to send more data. - */ -static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos) +static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) { struct usb_skel *dev; - ssize_t bytes_written = 0; - int retval = 0; - dev = (struct usb_skel *)file->private_data; + dev = (struct usb_skel *)urb->context; - dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); + /* sync/async unlink faults aren't errors */ + if (urb->status && + !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) { + dbg("%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); + } - /* lock this object */ - down (&dev->sem); + /* free up our allocated buffer */ + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); +} - /* verify that the device wasn't unplugged */ - if (!dev->present) { - retval = -ENODEV; - goto exit; - } +static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) +{ + struct usb_skel *dev; + int retval = 0; + struct urb *urb = NULL; + char *buf = NULL; + + dev = (struct usb_skel *)file->private_data; /* verify that we actually have some data to write */ - if (count == 0) { - dbg("%s - write request of 0 bytes", __FUNCTION__); + if (count == 0) goto exit; - } - /* wait for a previous write to finish up; we don't use a timeout - * and so a nonresponsive device can delay us indefinitely. - */ - if (atomic_read (&dev->write_busy)) - wait_for_completion (&dev->write_finished); + /* create a urb, and a buffer for it, and copy the data to the urb */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + retval = -ENOMEM; + goto error; + } - /* we can only write as much as our buffer will hold */ - bytes_written = min (dev->bulk_out_size, count); + buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error; + } - /* copy the data from userspace into our transfer buffer; - * this is the only copy required. - */ - if (copy_from_user(dev->write_urb->transfer_buffer, buffer, - bytes_written)) { + if (copy_from_user(buf, user_buffer, count)) { retval = -EFAULT; - goto exit; + goto error; } - usb_skel_debug_data (__FUNCTION__, bytes_written, - dev->write_urb->transfer_buffer); - - /* this urb was already set up, except for this write size */ - dev->write_urb->transfer_buffer_length = bytes_written; + /* initialize the urb properly */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + buf, count, skel_write_bulk_callback, dev); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* send the data out the bulk port */ - /* a character device write uses GFP_KERNEL, - unless a spinlock is held */ - init_completion (&dev->write_finished); - atomic_set (&dev->write_busy, 1); - retval = usb_submit_urb(dev->write_urb, GFP_KERNEL); + retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - atomic_set (&dev->write_busy, 0); - err("%s - failed submitting write urb, error %d", - __FUNCTION__, retval); - } else { - retval = bytes_written; + err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); + goto error; } + /* release our reference to this urb, the USB core will eventually free it entirely */ + usb_free_urb(urb); + exit: - /* unlock the device */ - up (&dev->sem); + return count; +error: + usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); + usb_free_urb(urb); return retval; } +static struct file_operations skel_fops = { + .owner = THIS_MODULE, + .read = skel_read, + .write = skel_write, + .open = skel_open, + .release = skel_release, +}; -/** - * skel_ioctl - */ -static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usb_skel *dev; - - dev = (struct usb_skel *)file->private_data; - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - up (&dev->sem); - return -ENODEV; - } - - dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __FUNCTION__, - dev->minor, cmd, arg); - - /* fill in your device specific stuff here */ - - /* unlock the device */ - up (&dev->sem); - - /* return that we did not understand this ioctl call */ - return -ENOTTY; -} - - -/** - * skel_write_bulk_callback +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core */ -static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_skel *dev = (struct usb_skel *)urb->context; - - dbg("%s - minor %d", __FUNCTION__, dev->minor); - - /* sync/async unlink faults aren't errors */ - if (urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET)) { - dbg("%s - nonzero write bulk status received: %d", - __FUNCTION__, urb->status); - } - - /* notify anyone waiting that the write has finished */ - atomic_set (&dev->write_busy, 0); - complete (&dev->write_finished); -} - +static struct usb_class_driver skel_class = { + .name = "usb/skel%d", + .fops = &skel_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + .minor_base = USB_SKEL_MINOR_BASE, +}; -/** - * skel_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(interface); struct usb_skel *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; @@ -506,28 +237,21 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i int i; int retval = -ENOMEM; - /* See if the device offered us matches what we can accept */ - if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || - (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { - return -ENODEV; - } - /* allocate memory for our device state and initialize it */ - dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); + dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - err ("Out of memory"); - return -ENOMEM; + err("Out of memory"); + goto error; } - memset (dev, 0x00, sizeof (*dev)); + memset(dev, 0x00, sizeof(*dev)); + kref_init(&dev->kref); - init_MUTEX (&dev->sem); - dev->udev = udev; + dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; /* set up the endpoint information */ - /* check out the endpoints */ /* use only the first bulk-in and bulk-out endpoints */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -539,9 +263,9 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i buffer_size = endpoint->wMaxPacketSize; dev->bulk_in_size = buffer_size; dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); + err("Could not allocate bulk_in_buffer"); goto error; } } @@ -551,153 +275,85 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk out endpoint */ - /* a probe() may sleep and has no restrictions on memory allocations */ - dev->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->write_urb) { - err("No free urbs available"); - goto error; - } dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; - - /* on some platforms using this kind of buffer alloc - * call eliminates a dma "bounce buffer". - * - * NOTE: you'd normally want i/o buffers that hold - * more than one packet, so that i/o delays between - * packets don't hurt throughput. - */ - buffer_size = endpoint->wMaxPacketSize; - dev->bulk_out_size = buffer_size; - dev->write_urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | - URB_ASYNC_UNLINK); - dev->bulk_out_buffer = usb_buffer_alloc (udev, - buffer_size, GFP_KERNEL, - &dev->write_urb->transfer_dma); - if (!dev->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); - goto error; - } - usb_fill_bulk_urb(dev->write_urb, udev, - usb_sndbulkpipe(udev, - endpoint->bEndpointAddress), - dev->bulk_out_buffer, buffer_size, - skel_write_bulk_callback, dev); } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Couldn't find both bulk-in and bulk-out endpoints"); + err("Could not find both bulk-in and bulk-out endpoints"); goto error; } - /* allow device read, write and ioctl */ - dev->present = 1; + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); /* we can register the device now, as it is ready */ - usb_set_intfdata (interface, dev); - retval = usb_register_dev (interface, &skel_class); + retval = usb_register_dev(interface, &skel_class); if (retval) { /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); - usb_set_intfdata (interface, NULL); + err("Not able to get a minor for this device."); + usb_set_intfdata(interface, NULL); goto error; } - dev->minor = interface->minor; - /* let the user know what node this device is now attached to */ - info ("USB Skeleton device now attached to USBSkel-%d", dev->minor); + info("USB Skeleton device now attached to USBSkel-%d", interface->minor); return 0; error: - skel_delete (dev); + if (dev) + kref_put(&dev->kref, skel_delete); return retval; } - -/** - * skel_disconnect - * - * Called by the usb core when the device is removed from the system. - * - * This routine guarantees that the driver will not submit any more urbs - * by clearing dev->udev. It is also supposed to terminate any currently - * active urbs. Unfortunately, usb_bulk_msg(), used in skel_read(), does - * not provide any way to do this. But at least we can cancel an active - * write. - */ static void skel_disconnect(struct usb_interface *interface) { struct usb_skel *dev; - int minor; + int minor = interface->minor; - /* prevent races with open() */ - down (&disconnect_sem); + /* prevent skel_open() from racing skel_disconnect() */ + lock_kernel(); - dev = usb_get_intfdata (interface); - usb_set_intfdata (interface, NULL); - - down (&dev->sem); - - minor = dev->minor; + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); /* give back our minor */ - usb_deregister_dev (interface, &skel_class); + usb_deregister_dev(interface, &skel_class); - /* terminate an ongoing write */ - if (atomic_read (&dev->write_busy)) { - usb_unlink_urb (dev->write_urb); - wait_for_completion (&dev->write_finished); - } - - /* prevent device read, write and ioctl */ - dev->present = 0; - - up (&dev->sem); + unlock_kernel(); - /* if the device is opened, skel_release will clean this up */ - if (!dev->open) - skel_delete (dev); - - up (&disconnect_sem); + /* decrement our usage count */ + kref_put(&dev->kref, skel_delete); info("USB Skeleton #%d now disconnected", minor); } +static struct usb_driver skel_driver = { + .owner = THIS_MODULE, + .name = "skeleton", + .probe = skel_probe, + .disconnect = skel_disconnect, + .id_table = skel_table, +}; - -/** - * usb_skel_init - */ static int __init usb_skel_init(void) { int result; /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); - if (result) { - err("usb_register failed. Error number %d", - result); - return result; - } + if (result) + err("usb_register failed. Error number %d", result); - info(DRIVER_DESC " " DRIVER_VERSION); - return 0; + return result; } - -/** - * usb_skel_exit - */ static void __exit usb_skel_exit(void) { /* deregister this driver with the USB subsystem */ usb_deregister(&skel_driver); } - module_init (usb_skel_init); module_exit (usb_skel_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 5e9bcf5a8..6a3cfbdc6 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c @@ -199,6 +199,15 @@ static int mc68x328fb_check_var(struct fb_var_screeninfo *var, */ switch (var->bits_per_pixel) { case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; + var->transp.offset = 0; + var->transp.length = 0; + break; case 8: var->red.offset = 0; var->red.length = 8; @@ -430,6 +439,13 @@ int __init mc68x328fb_setup(char *options) int __init mc68x328fb_init(void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("68328fb", &option)) + return -ENODEV; + mc68x328fb_setup(option); +#endif /* * initialize the default mode from the LCD controller registers */ @@ -452,8 +468,12 @@ int __init mc68x328fb_init(void) get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR; + if (fb_info.var.bits_per_pixel == 1) { + fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; + fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; + } fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; fb_alloc_cmap(&fb_info.cmap, 256, 0); @@ -471,6 +491,8 @@ int __init mc68x328fb_init(void) return 0; } +module_init(mc68x328fb_init); + #ifdef MODULE static void __exit mc68x328fb_cleanup(void) @@ -478,7 +500,6 @@ static void __exit mc68x328fb_cleanup(void) unregister_framebuffer(&fb_info); } -module_init(mc68x328fb_init); module_exit(mc68x328fb_cleanup); MODULE_LICENSE("GPL"); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 798ba0032..ab23abe01 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -38,6 +38,17 @@ config FB (e.g. an accelerated X server) and that are not frame buffer device-aware may cause unexpected results. If unsure, say N. +config FB_MODE_HELPERS + bool "Enable Video Mode Handling Helpers" + depends on FB + default y + ---help--- + This enables functions for handling video modes using the + Generalized Timing Formula and the EDID parser. A few drivers rely + on this feature such as the radeonfb, rivafb, and the i810fb. If + your driver does not take advantage of this feature, choosing Y will + just increase the kernel size by about 5K. + config FB_CIRRUS tristate "Cirrus Logic support" depends on FB && (ZORRO || PCI) @@ -68,6 +79,19 @@ config FB_PM2_FIFO_DISCONNECT help Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2). +config FB_ARMCLCD + tristate "ARM PrimeCell PL110 support" + depends on FB && ARM && ARM_AMBA + help + This framebuffer device driver is for the ARM PrimeCell PL110 + Colour LCD controller. ARM PrimeCells provide the building + blocks for System on a Chip devices. + + If you want to compile this as a module (=code which can be + inserted into and removed from the running kernel), say M + here and read . The module + will be called amba-clcd. + config FB_ACORN bool "Acorn VIDC support" depends on FB && ARM && ARCH_ACORN @@ -392,40 +416,21 @@ config FB_PVR2 (). Please see the file . -config FB_E1355 +config FB_EPSON1355 bool "Epson 1355 framebuffer support" - depends on FB && SUPERH + depends on FB && (SUPERH || ARCH_CEIVA) help Build in support for the SED1355 Epson Research Embedded RAMDAC LCD/CRT Controller (since redesignated as the S1D13505) as a framebuffer. Product specs at . -config E1355_REG_BASE - hex "Register Base Address" - depends on FB_E1355 - default "a8000000" - help - Epson SED1355/S1D13505 LCD/CRT controller register base address. - See the manuals at - for - discussion. - -config E1355_FB_BASE - hex "Framebuffer Base Address" - depends on FB_E1355 - default "a8200000" - help - Epson SED1355/S1D13505 LCD/CRT controller memory base address. See - the manuals at - for - discussion. - config FB_RIVA tristate "nVidia Riva support" depends on FB && PCI select I2C_ALGOBIT if FB_RIVA_I2C select I2C if FB_RIVA_I2C + select FB_MODE_HELPERS help This driver supports graphics boards with the nVidia Riva/Geforce chips. @@ -457,7 +462,10 @@ config FB_RIVA_DEBUG config FB_I810 tristate "Intel 810/815 support (EXPERIMENTAL)" - depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI + depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + select AGP + select AGP_INTEL + select FB_MODE_HELPERS help This driver supports the on-board graphics built in to the Intel 810 and 815 chipsets. Say Y if you have and plan to use such a board. @@ -661,6 +669,7 @@ config FB_RADEON depends on FB && PCI select I2C_ALGOBIT if FB_RADEON_I2C select I2C if FB_RADEON_I2C + select FB_MODE_HELPERS help Choose this option if you want to use an ATI Radeon graphics card as a framebuffer device. There are both PCI and AGP versions. You @@ -766,6 +775,7 @@ config FB_SIS_315 config FB_NEOMAGIC tristate "NeoMagic display support" depends on FB && PCI + select FB_MODE_HELPERS help This driver supports notebooks with NeoMagic PCI chips. Say Y if you have such a graphics card. diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 52e37a0fc..b88f69ae1 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -13,80 +13,88 @@ ifeq ($(CONFIG_FB),y) obj-$(CONFIG_PPC) += macmodes.o endif -obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +# Hardware specific drivers go first +obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CYBER) += cyberfb.o +obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PM2) += pm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PM3) += pm3fb.o -obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_ATARI) += atafb.o -obj-$(CONFIG_FB_68328) += 68328fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o + +obj-$(CONFIG_FB_MATROX) += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_ATY128) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_RADEON) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_KYRO) += kyro/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o + +obj-$(CONFIG_FB_I810) += cfbcopyarea.o cfbfillrect.o cfbimgblt.o \ + vgastate.o obj-$(CONFIG_FB_RADEON_OLD) += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o vgastate.o -obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VIRGE) += virgefb.o +obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o +ifneq ($(CONFIG_FB_3DFX_ACCEL),y) +obj-$(CONFIG_FB_3DFX) += cfbfillrect.o cfbcopyarea.o +endif obj-$(CONFIG_FB_CONTROL) += controlfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_CYBER) += cyberfb.o -obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_GBE) += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o -obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o cfbimgblt.o -obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o -obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_TRIDENT) += tridentfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o -obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ - cfbimgblt.o vgastate.o -obj-$(CONFIG_FB_VIRGE) += virgefb.o -obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_STI) += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o - -obj-$(CONFIG_FB_MATROX) += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o -obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_ATY128) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_RADEON) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_I810) += i810/ cfbfillrect.o cfbcopyarea.o \ - cfbimgblt.o vgastate.o - -obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ATARI) += atafb.o +obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_HGA) += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_E1355) += epson1355fb.o +obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_KYRO) += kyro/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_68328) += 68328fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_GBE) += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PXA) += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o + +# Platform or fallback drivers go here +obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ + cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o -obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ - cfbfillrect.o -obj-$(CONFIG_FB_PXA) += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o +# the test framebuffer is last +obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 0c3aa4a7f..f7bfbc722 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -1010,7 +1010,7 @@ static void __init acornfb_init_fbinfo(void) first = 0; fb_info.fbops = &acornfb_ops; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; fb_info.pseudo_palette = current_par.pseudo_palette; strcpy(fb_info.fix.id, "Acorn"); @@ -1291,6 +1291,11 @@ acornfb_init(void) unsigned long size; u_int h_sync, v_sync; int rc, i; + char *option = NULL; + + if (fb_get_options("acornfb", &option)) + return -ENODEV; + acornfb_setup(option); acornfb_init_fbinfo(); @@ -1456,6 +1461,8 @@ acornfb_init(void) return 0; } +module_init(acornfb_init); + MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c new file mode 100644 index 000000000..d6af37b7a --- /dev/null +++ b/drivers/video/amba-clcd.c @@ -0,0 +1,515 @@ +/* + * linux/drivers/video/amba-clcd.c + * + * Copyright (C) 2001 ARM Limited, by David A Rusling + * Updated to 2.5, Deep Blue Solutions Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * ARM PrimeCell PL110 Color LCD Controller + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define to_clcd(info) container_of(info, struct clcd_fb, fb) + +/* This is limited to 16 characters when displayed by X startup */ +static const char *clcd_name = "CLCD FB"; + +/* + * Unfortunately, the enable/disable functions may be called either from + * process or IRQ context, and we _need_ to delay. This is _not_ good. + */ +static inline void clcdfb_sleep(unsigned int ms) +{ + if (in_atomic()) { + mdelay(ms); + } else { + msleep(ms); + } +} + +static inline void clcdfb_set_start(struct clcd_fb *fb) +{ + unsigned long ustart = fb->fb.fix.smem_start; + unsigned long lstart; + + ustart += fb->fb.var.yoffset * fb->fb.fix.line_length; + lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2; + + writel(ustart, fb->regs + CLCD_UBAS); + writel(lstart, fb->regs + CLCD_LBAS); +} + +static void clcdfb_disable(struct clcd_fb *fb) +{ + u32 val; + + if (fb->board->disable) + fb->board->disable(fb); + + val = readl(fb->regs + CLCD_CNTL); + if (val & CNTL_LCDPWR) { + val &= ~CNTL_LCDPWR; + writel(val, fb->regs + CLCD_CNTL); + + clcdfb_sleep(20); + } + if (val & CNTL_LCDEN) { + val &= ~CNTL_LCDEN; + writel(val, fb->regs + CLCD_CNTL); + } + + /* + * Disable CLCD clock source. + */ + clk_disable(fb->clk); +} + +static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) +{ + /* + * Enable the CLCD clock source. + */ + clk_enable(fb->clk); + + /* + * Bring up by first enabling.. + */ + cntl |= CNTL_LCDEN; + writel(cntl, fb->regs + CLCD_CNTL); + + clcdfb_sleep(20); + + /* + * and now apply power. + */ + cntl |= CNTL_LCDPWR; + writel(cntl, fb->regs + CLCD_CNTL); + + /* + * finally, enable the interface. + */ + if (fb->board->enable) + fb->board->enable(fb); +} + +static int +clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) +{ + int ret = 0; + + memset(&var->transp, 0, sizeof(var->transp)); + memset(&var->red, 0, sizeof(var->red)); + memset(&var->green, 0, sizeof(var->green)); + memset(&var->blue, 0, sizeof(var->blue)); + + switch (var->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + var->red.length = 8; + var->red.offset = 0; + var->green.length = 8; + var->green.offset = 0; + var->blue.length = 8; + var->blue.offset = 0; + break; + case 16: + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + if (fb->panel->cntl & CNTL_BGR) { + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + } else { + var->red.offset = 0; + var->green.offset = 5; + var->blue.offset = 10; + } + break; + case 24: + if (fb->panel->cntl & CNTL_LCDTFT) { + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + + if (fb->panel->cntl & CNTL_BGR) { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + } else { + var->red.offset = 0; + var->green.offset = 8; + var->blue.offset = 16; + } + break; + } + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + int ret = -EINVAL; + + if (fb->board->check) + ret = fb->board->check(fb, var); + if (ret == 0) + ret = clcdfb_set_bitfields(fb, var); + + return ret; +} + +static int clcdfb_set_par(struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + struct clcd_regs regs; + + fb->fb.fix.line_length = fb->fb.var.xres_virtual * + fb->fb.var.bits_per_pixel / 8; + + if (fb->fb.var.bits_per_pixel <= 8) + fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + + fb->board->decode(fb, ®s); + + clcdfb_disable(fb); + + writel(regs.tim0, fb->regs + CLCD_TIM0); + writel(regs.tim1, fb->regs + CLCD_TIM1); + writel(regs.tim2, fb->regs + CLCD_TIM2); + writel(regs.tim3, fb->regs + CLCD_TIM3); + + clcdfb_set_start(fb); + + clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000); + + fb->clcd_cntl = regs.cntl; + + clcdfb_enable(fb, regs.cntl); + +#ifdef DEBUG + printk(KERN_INFO "CLCD: Registers set to\n" + KERN_INFO " %08x %08x %08x %08x\n" + KERN_INFO " %08x %08x %08x %08x\n", + readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1), + readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3), + readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS), + readl(fb->regs + CLCD_IENB), readl(fb->regs + CLCD_CNTL)); +#endif + + return 0; +} + +static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) +{ + unsigned int mask = (1 << bf->length) - 1; + + return (val >> (16 - bf->length) & mask) << bf->offset; +} + +/* + * Set a single color register. The values supplied have a 16 bit + * magnitude. Return != 0 for invalid regno. + */ +static int +clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + + if (regno < 16) + fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | + convert_bitfield(blue, &fb->fb.var.blue) | + convert_bitfield(green, &fb->fb.var.green) | + convert_bitfield(red, &fb->fb.var.red); + + if (fb->fb.var.bits_per_pixel == 8 && regno < 256) { + int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); + u32 val, mask, newval; + + newval = (red >> 11) & 0x001f; + newval |= (green >> 6) & 0x03e0; + newval |= (blue >> 1) & 0x7c00; + + /* + * 3.2.11: if we're configured for big endian + * byte order, the palette entries are swapped. + */ + if (fb->clcd_cntl & CNTL_BEBO) + regno ^= 1; + + if (regno & 1) { + newval <<= 16; + mask = 0x0000ffff; + } else { + mask = 0xffff0000; + } + + val = readl(fb->regs + hw_reg) & mask; + writel(val | newval, fb->regs + hw_reg); + } + + return regno > 255; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int clcdfb_blank(int blank_mode, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + + if (blank_mode != 0) { + clcdfb_disable(fb); + } else { + clcdfb_enable(fb, fb->clcd_cntl); + } + return 0; +} + +static struct fb_ops clcdfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = clcdfb_check_var, + .fb_set_par = clcdfb_set_par, + .fb_setcolreg = clcdfb_setcolreg, + .fb_blank = clcdfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int clcdfb_register(struct clcd_fb *fb) +{ + int ret; + + fb->clk = clk_get(&fb->dev->dev, "CLCDCLK"); + if (IS_ERR(fb->clk)) { + ret = PTR_ERR(fb->clk); + goto out; + } + + ret = clk_use(fb->clk); + if (ret) + goto free_clk; + + fb->fb.fix.mmio_start = fb->dev->res.start; + fb->fb.fix.mmio_len = SZ_4K; + + fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); + if (!fb->regs) { + printk(KERN_ERR "CLCD: unable to remap registers\n"); + ret = -ENOMEM; + goto unuse_clk; + } + + fb->fb.fbops = &clcdfb_ops; + fb->fb.flags = FBINFO_FLAG_DEFAULT; + fb->fb.pseudo_palette = fb->cmap; + + strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id)); + fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fb->fb.fix.type_aux = 0; + fb->fb.fix.xpanstep = 0; + fb->fb.fix.ypanstep = 0; + fb->fb.fix.ywrapstep = 0; + fb->fb.fix.accel = FB_ACCEL_NONE; + + fb->fb.var.xres = fb->panel->mode.xres; + fb->fb.var.yres = fb->panel->mode.yres; + fb->fb.var.xres_virtual = fb->panel->mode.xres; + fb->fb.var.yres_virtual = fb->panel->mode.yres; + fb->fb.var.bits_per_pixel = fb->panel->bpp; + fb->fb.var.grayscale = fb->panel->grayscale; + fb->fb.var.pixclock = fb->panel->mode.pixclock; + fb->fb.var.left_margin = fb->panel->mode.left_margin; + fb->fb.var.right_margin = fb->panel->mode.right_margin; + fb->fb.var.upper_margin = fb->panel->mode.upper_margin; + fb->fb.var.lower_margin = fb->panel->mode.lower_margin; + fb->fb.var.hsync_len = fb->panel->mode.hsync_len; + fb->fb.var.vsync_len = fb->panel->mode.vsync_len; + fb->fb.var.sync = fb->panel->mode.sync; + fb->fb.var.vmode = fb->panel->mode.vmode; + fb->fb.var.activate = FB_ACTIVATE_NOW; + fb->fb.var.nonstd = 0; + fb->fb.var.height = fb->panel->height; + fb->fb.var.width = fb->panel->width; + fb->fb.var.accel_flags = 0; + + fb->fb.monspecs.hfmin = 0; + fb->fb.monspecs.hfmax = 100000; + fb->fb.monspecs.vfmin = 0; + fb->fb.monspecs.vfmax = 400; + fb->fb.monspecs.dclkmin = 1000000; + fb->fb.monspecs.dclkmax = 100000000; + + /* + * Make sure that the bitfields are set appropriately. + */ + clcdfb_set_bitfields(fb, &fb->fb.var); + + /* + * Allocate colourmap. + */ + fb_alloc_cmap(&fb->fb.cmap, 256, 0); + + /* + * Ensure interrupts are disabled. + */ + writel(0, fb->regs + CLCD_IENB); + + fb_set_var(&fb->fb, &fb->fb.var); + + printk(KERN_INFO "CLCD: %s hardware, %s display\n", + fb->board->name, fb->panel->mode.name); + + ret = register_framebuffer(&fb->fb); + if (ret == 0) + goto out; + + printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); + + iounmap(fb->regs); + unuse_clk: + clk_unuse(fb->clk); + free_clk: + clk_put(fb->clk); + out: + return ret; +} + +static int clcdfb_probe(struct amba_device *dev, void *id) +{ + struct clcd_board *board = dev->dev.platform_data; + struct clcd_fb *fb; + int ret; + + if (!board) + return -EINVAL; + + ret = amba_request_regions(dev, NULL); + if (ret) { + printk(KERN_ERR "CLCD: unable to reserve regs region\n"); + goto out; + } + + fb = (struct clcd_fb *) kmalloc(sizeof(struct clcd_fb), GFP_KERNEL); + if (!fb) { + printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); + ret = -ENOMEM; + goto free_region; + } + memset(fb, 0, sizeof(struct clcd_fb)); + + fb->dev = dev; + fb->board = board; + + ret = fb->board->setup(fb); + if (ret) + goto free_fb; + + ret = clcdfb_register(fb); + if (ret == 0) { + amba_set_drvdata(dev, fb); + goto out; + } + + fb->board->remove(fb); + free_fb: + kfree(fb); + free_region: + amba_release_regions(dev); + out: + return ret; +} + +static int clcdfb_remove(struct amba_device *dev) +{ + struct clcd_fb *fb = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + clcdfb_disable(fb); + unregister_framebuffer(&fb->fb); + iounmap(fb->regs); + clk_unuse(fb->clk); + clk_put(fb->clk); + + fb->board->remove(fb); + + kfree(fb); + + amba_release_regions(dev); + + return 0; +} + +static struct amba_id clcdfb_id_table[] = { + { + .id = 0x00041110, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver clcd_driver = { + .drv = { + .name = "clcd-pl110", + }, + .probe = clcdfb_probe, + .remove = clcdfb_remove, + .id_table = clcdfb_id_table, +}; + +int __init amba_clcdfb_init(void) +{ + if (fb_get_options("ambafb", NULL)) + return -ENODEV; + + return amba_driver_register(&clcd_driver); +} + +module_init(amba_clcdfb_init); + +static void __exit amba_clcdfb_exit(void) +{ + amba_driver_unregister(&clcd_driver); +} + +module_exit(amba_clcdfb_exit); + +MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 95ea71c9b..baa4fa06b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -1307,6 +1307,8 @@ static int amifb_set_par(struct fb_info *info) info->fix.ywrapstep = 1; info->fix.xpanstep = 0; info->fix.ypanstep = 0; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | + FBINFO_READS_FAST; /* override SCROLL_REDRAW */ } else { info->fix.ywrapstep = 0; if (par->vmode & FB_VMODE_SMOOTH_XPAN) @@ -1314,6 +1316,7 @@ static int amifb_set_par(struct fb_info *info) else info->fix.xpanstep = 16<fix.ypanstep = 1; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; } return 0; } @@ -2254,6 +2257,13 @@ int __init amifb_init(void) u_long chipptr; u_int defmode; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("amifb", &option)) + return -ENODEV; + amifb_setup(option); +#endif if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) return -ENXIO; @@ -2382,7 +2392,7 @@ default_chipset: fb_info.fbops = &amifb_ops; fb_info.par = ¤tpar; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.flags = FBINFO_DEFAULT; if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { @@ -3811,14 +3821,11 @@ static void ami_rebuild_copper(void) } +module_init(amifb_init); + #ifdef MODULE MODULE_LICENSE("GPL"); -int init_module(void) -{ - return amifb_init(); -} - void cleanup_module(void) { unregister_framebuffer(&fb_info); diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index 1563b0d27..bda3ed9ba 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c @@ -524,7 +524,7 @@ static void __init init_asiliant(struct fb_info *p, unsigned long addr) p->fix.smem_start = addr; p->var = asiliantfb_var; p->fbops = &asiliantfb_ops; - p->flags = FBINFO_FLAG_DEFAULT; + p->flags = FBINFO_DEFAULT; fb_alloc_cmap(&p->cmap, 256, 0); @@ -609,9 +609,14 @@ static struct pci_driver asiliantfb_driver = { int __init asiliantfb_init(void) { + if (fb_get_options("asiliantfb", NULL)) + return -ENODEV; + return pci_module_init(&asiliantfb_driver); } +module_init(asiliantfb_init); + static void __exit asiliantfb_exit(void) { pci_unregister_driver(&asiliantfb_driver); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 1c7bcd80f..f2d82d005 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -2439,6 +2439,14 @@ static int aty128_pci_resume(struct pci_dev *pdev) int __init aty128fb_init(void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("aty128fb", &option)) + return -ENODEV; + aty128fb_setup(option); +#endif + return pci_module_init(&aty128fb_driver); } @@ -2447,8 +2455,9 @@ static void __exit aty128fb_exit(void) pci_unregister_driver(&aty128fb_driver); } -#ifdef MODULE module_init(aty128fb_init); + +#ifdef MODULE module_exit(aty128fb_exit); MODULE_AUTHOR("(c)1999-2003 Brad Douglas "); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 37177bece..2d753a150 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -1902,7 +1902,7 @@ static int __init aty_init(struct fb_info *info, const char *name) return 1; } -int __init atyfb_init(void) +int __init atyfb_do_init(void) { #if defined(CONFIG_PCI) unsigned long addr, res_start, res_size; @@ -1917,12 +1917,14 @@ int __init atyfb_init(void) char prop[128]; int node, len, j; u32 mem, chip_id; +#else + u16 tmp; +#endif +#ifdef __sparc__ /* Do not attach when we have a serial console. */ if (!con_is_present()) return -ENXIO; -#else - u16 tmp; #endif while ((pdev = @@ -2377,6 +2379,19 @@ int __init atyfb_init(void) return 0; } +int __init atyfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("atyfb", &option)) + return -ENODEV; + atyfb_setup(option); +#endif + return atyfb_do_init(); +} + + #ifndef MODULE int __init atyfb_setup(char *options) { @@ -2445,6 +2460,7 @@ int __init atyfb_setup(char *options) } return 0; } +module_init(atyfb_init); #endif /* !MODULE */ #ifdef CONFIG_ATARI diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index bd3b24caa..325b83b30 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -282,7 +282,7 @@ static void __devexit radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_d static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) { - void *rom; + void __iomem *rom; struct resource *r; u16 dptr; u8 rom_type; @@ -395,13 +395,13 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo) * if we end up having conflicts */ u32 segstart; - unsigned char *rom_base = NULL; + void __iomem *rom_base = NULL; for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { - rom_base = (char *)ioremap(segstart, 0x10000); + rom_base = ioremap(segstart, 0x10000); if (rom_base == NULL) return -ENOMEM; - if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) + if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa) break; iounmap(rom_base); rom_base = NULL; @@ -1702,68 +1702,6 @@ int radeonfb_set_par(struct fb_info *info) } - -static ssize_t radeonfb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - struct inode *inode = file->f_dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct radeonfb_info *rinfo = info->par; - - if (p >= rinfo->mapped_vram) - return 0; - if (count >= rinfo->mapped_vram) - count = rinfo->mapped_vram; - if (count + p > rinfo->mapped_vram) - count = rinfo->mapped_vram - p; - radeonfb_sync(info); - if (count) { - char *base_addr; - - base_addr = info->screen_base; - count -= copy_to_user(buf, base_addr+p, count); - if (!count) - return -EFAULT; - *ppos += count; - } - return count; -} - -static ssize_t radeonfb_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned long p = *ppos; - struct inode *inode = file->f_dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct radeonfb_info *rinfo = info->par; - int err; - - if (p > rinfo->mapped_vram) - return -ENOSPC; - if (count >= rinfo->mapped_vram) - count = rinfo->mapped_vram; - err = 0; - if (count + p > rinfo->mapped_vram) { - count = rinfo->mapped_vram - p; - err = -ENOSPC; - } - radeonfb_sync(info); - if (count) { - char *base_addr; - - base_addr = info->screen_base; - count -= copy_from_user(base_addr+p, buf, count); - *ppos += count; - err = -EFAULT; - } - if (count) - return count; - return err; -} - - static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = radeonfb_check_var, @@ -1776,8 +1714,6 @@ static struct fb_ops radeonfb_ops = { .fb_fillrect = radeonfb_fillrect, .fb_copyarea = radeonfb_copyarea, .fb_imageblit = radeonfb_imageblit, - .fb_read = radeonfb_read, - .fb_write = radeonfb_write, .fb_cursor = soft_cursor, }; @@ -1795,8 +1731,8 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; info->fbops = &radeonfb_ops; - info->screen_base = (char *)rinfo->fb_base; - + info->screen_base = rinfo->fb_base; + info->screen_size = rinfo->mapped_vram; /* Fill fix common fields */ strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); info->fix.smem_start = rinfo->fb_base_phys; @@ -1932,7 +1868,7 @@ static int radeon_set_backlight_level(int level, void *data) #undef SET_MC_FB_FROM_APERTURE static void fixup_memory_mappings(struct radeonfb_info *rinfo) { - u32 save_crtc_gen_cntl, save_crtc2_gen_cntl; + u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0; u32 save_crtc_ext_cntl; u32 aper_base, aper_size; u32 agp_base; @@ -2069,19 +2005,22 @@ static int radeonfb_pci_register (struct pci_dev *pdev, struct fb_info *info; struct radeonfb_info *rinfo; u32 tmp; + int ret; RTRACE("radeonfb_pci_register BEGIN\n"); /* Enable device in PCI config */ - if (pci_enable_device(pdev) != 0) { + ret = pci_enable_device(pdev); + if (ret < 0) { printk(KERN_ERR "radeonfb: Cannot enable PCI device\n"); - return -ENODEV; + goto err_out; } info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev); if (!info) { printk (KERN_ERR "radeonfb: could not allocate memory\n"); - return -ENODEV; + ret = -ENOMEM; + goto err_disable; } rinfo = info->par; rinfo->info = info; @@ -2106,23 +2045,19 @@ static int radeonfb_pci_register (struct pci_dev *pdev, rinfo->mmio_base_phys = pci_resource_start (pdev, 2); /* request the mem regions */ - if (!request_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0), "radeonfb")) { - printk (KERN_ERR "radeonfb: cannot reserve FB region\n"); - goto free_rinfo; - } - - if (!request_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2), "radeonfb")) { - printk (KERN_ERR "radeonfb: cannot reserve MMIO region\n"); - goto release_fb; + ret = pci_request_regions(pdev, "radeonfb"); + if (ret < 0) { + printk( KERN_ERR "radeonfb: cannot reserve PCI regions." + " Someone already got them?\n"); + goto err_release_fb; } /* map the regions */ - rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE); + rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); if (!rinfo->mmio_base) { - printk (KERN_ERR "radeonfb: cannot map MMIO\n"); - goto release_mmio; + printk(KERN_ERR "radeonfb: cannot map MMIO\n"); + ret = -EIO; + goto err_release_pci; } /* On PPC, the firmware sets up a memory mapping that tends @@ -2226,33 +2161,24 @@ static int radeonfb_pci_register (struct pci_dev *pdev, RTRACE("radeonfb: probed %s %ldk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); - rinfo->mapped_vram = MAX_MAPPED_VRAM; - if (rinfo->video_ram < rinfo->mapped_vram) - rinfo->mapped_vram = rinfo->video_ram; - for (;;) { - rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys, - rinfo->mapped_vram); - if (rinfo->fb_base == 0 && rinfo->mapped_vram > MIN_MAPPED_VRAM) { - rinfo->mapped_vram /= 2; - continue; - } - memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); - break; - } + rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram); - if (!rinfo->fb_base) { + do { + rinfo->fb_base = ioremap (rinfo->fb_base_phys, + rinfo->mapped_vram); + } while ( rinfo->fb_base == 0 && + ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) ); + + if (rinfo->fb_base) + memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); + else { printk (KERN_ERR "radeonfb: cannot map FB\n"); - goto unmap_rom; + ret = -EIO; + goto err_unmap_rom; } RTRACE("radeonfb: mapped %ldk videoram\n", rinfo->mapped_vram/1024); - - /* Argh. Scary arch !!! */ -#ifdef CONFIG_PPC64 - rinfo->fb_base = IO_TOKEN_TO_ADDR(rinfo->fb_base); -#endif - /* * Check for required workaround for PLL accesses */ @@ -2330,9 +2256,10 @@ static int radeonfb_pci_register (struct pci_dev *pdev, printk("radeonfb: Power Management enabled for Mobility chipsets\n"); } - if (register_framebuffer(info) < 0) { + ret = register_framebuffer(info); + if (ret < 0) { printk (KERN_ERR "radeonfb: could not register framebuffer\n"); - goto unmap_fb; + goto err_unmap_fb; } #ifdef CONFIG_MTRR @@ -2358,30 +2285,30 @@ static int radeonfb_pci_register (struct pci_dev *pdev, RTRACE("radeonfb_pci_register END\n"); return 0; -unmap_fb: - iounmap ((void*)rinfo->fb_base); -unmap_rom: +err_unmap_fb: + iounmap(rinfo->fb_base); +err_unmap_rom: if (rinfo->mon1_EDID) kfree(rinfo->mon1_EDID); if (rinfo->mon2_EDID) kfree(rinfo->mon2_EDID); if (rinfo->mon1_modedb) fb_destroy_modedb(rinfo->mon1_modedb); + fb_dealloc_cmap(&info->cmap); #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); - iounmap ((void*)rinfo->mmio_base); -release_mmio: - release_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2)); -release_fb: - release_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0)); -free_rinfo: + iounmap(rinfo->mmio_base); +err_release_pci: + pci_release_regions(pdev); +err_release_fb: framebuffer_release(info); - return -ENODEV; +err_disable: + pci_disable_device(pdev); +err_out: + return ret; } @@ -2410,13 +2337,10 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) unregister_framebuffer(info); - iounmap ((void*)rinfo->mmio_base); - iounmap ((void*)rinfo->fb_base); + iounmap(rinfo->mmio_base); + iounmap(rinfo->fb_base); - release_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2)); - release_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0)); + pci_release_regions(pdev); if (rinfo->mon1_EDID) kfree(rinfo->mon1_EDID); @@ -2427,7 +2351,9 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); + pci_disable_device(pdev); } @@ -2442,9 +2368,17 @@ static struct pci_driver radeonfb_driver = { #endif /* CONFIG_PM */ }; +int __init radeonfb_setup (char *options); int __init radeonfb_init (void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("radeonfb", &option)) + return -ENODEV; + radeonfb_setup(option); +#endif return pci_module_init (&radeonfb_driver); } @@ -2489,9 +2423,9 @@ int __init radeonfb_setup (char *options) return 0; } +module_init(radeonfb_init); #ifdef MODULE -module_init(radeonfb_init); module_exit(radeonfb_exit); #endif diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index 94ff455d0..e6c01642c 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -55,7 +55,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ u8 *pedid = NULL; u8 *pmt = NULL; u8 *tmp; - int i, mt; + int i, mt = MT_NONE; RTRACE("analyzing OF properties...\n"); pmt = (u8 *)get_property(dp, "display-type", NULL); @@ -72,7 +72,9 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ else if (strcmp(pmt, "NONE")) { printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n", pmt); return MT_NONE; - } + } else + return MT_NONE; + for (i = 0; propnames[i] != NULL; ++i) { pedid = (u8 *)get_property(dp, propnames[i], NULL); if (pedid != NULL) @@ -645,15 +647,23 @@ static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) rinfo->panel_info.fbk_divider = 0xad; rinfo->panel_info.use_bios_dividers = 1; } + /* Aluminium PowerBook 15" */ + if (machine_is_compatible("PowerBook5,4")) { + rinfo->panel_info.ref_divider = rinfo->pll.ref_div; + rinfo->panel_info.post_divider = 0x2; + rinfo->panel_info.fbk_divider = 0x8e; + rinfo->panel_info.use_bios_dividers = 1; + } /* Aluminium PowerBook 17" */ - if (machine_is_compatible("PowerBook5,3")) { + if (machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook5,5")) { rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x4; rinfo->panel_info.fbk_divider = 0x80; rinfo->panel_info.use_bios_dividers = 1; } /* iBook G4 */ - if (machine_is_compatible("PowerBook6,3") | + if (machine_is_compatible("PowerBook6,3") || machine_is_compatible("PowerBook6,5")) { rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x6; diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 87223df80..447eb5841 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -262,14 +262,14 @@ struct radeonfb_info { unsigned long mmio_base_phys; unsigned long fb_base_phys; - unsigned long mmio_base; - unsigned long fb_base; + void __iomem *mmio_base; + void __iomem *fb_base; - unsigned long fb_local_base; + unsigned long fb_local_base; struct pci_dev *pdev; - u8 *bios_seg; + void __iomem *bios_seg; int fp_bios_start; u32 pseudo_palette[17]; diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index b3ab23b07..65b65addf 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -323,7 +323,7 @@ static void bw2_init_one(struct sbus_dev *sdev) resp = &res; all->info.var.xres = all->info.var.xres_virtual = 1152; all->info.var.yres = all->info.var.yres_virtual = 900; - all->info.bits_per_pixel = 1; + all->info.var.bits_per_pixel = 1; linebytes = 1152 / 8; } else #else @@ -337,6 +337,10 @@ static void bw2_init_one(struct sbus_dev *sdev) all->info.var.xres); } #endif + all->info.var.red.length = all->info.var.green.length = + all->info.var.blue.length = all->info.var.bits_per_pixel; + all->info.var.red.offset = all->info.var.green.offset = + all->info.var.blue.offset = 0; all->par.regs = (struct bw2_regs *) sbus_ioremap(resp, BWTWO_REGISTER_OFFSET, @@ -347,7 +351,7 @@ static void bw2_init_one(struct sbus_dev *sdev) all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT; all->info.fbops = &bw2_ops; #if defined(CONFIG_SPARC32) if (sdev) @@ -382,6 +386,9 @@ int __init bw2_init(void) struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("bw2fb", &option)) + return -ENODEV; + #ifdef CONFIG_SUN4 bw2_init_one(NULL); #endif @@ -412,8 +419,9 @@ bw2_setup(char *arg) return 0; } -#ifdef MODULE module_init(bw2_init); + +#ifdef MODULE module_exit(bw2_exit); #endif diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 9c32d2b40..b4b286a4c 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -43,8 +43,9 @@ #define BYTES_PER_LONG 8 #endif -static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, unsigned long n) +static void bitcpy(unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, + unsigned long n) { unsigned long first, last; int shift = dst_idx-src_idx, left, right; @@ -185,8 +186,8 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, } } -static void bitcpy_rev(unsigned long *dst, int dst_idx, - const unsigned long *src, int src_idx, unsigned long n) +static void bitcpy_rev(unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, unsigned long n) { unsigned long first, last; int shift = dst_idx-src_idx, left, right; @@ -344,7 +345,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) int x2, y2, old_dx, old_dy, vxres, vyres; unsigned long next_line = p->fix.line_length; int dst_idx = 0, src_idx = 0, rev_copy = 0; - unsigned long *dst = NULL, *src = NULL; + unsigned long __iomem *dst = NULL, *src = NULL; if (p->state != FBINFO_STATE_RUNNING) return; @@ -394,7 +395,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) rev_copy = 1; } - dst = src = (unsigned long *)((unsigned long)p->screen_base & + dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(BYTES_PER_LONG-1)); dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1); dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel; diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 20f3acfd8..4a94bf85e 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -119,7 +119,7 @@ static inline unsigned long pixel_to_pat(const struct fb_info *p, * Unaligned 32-bit pattern fill using 32/64-bit memory accesses */ -void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +void bitfill32(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n) { unsigned long val = pat; unsigned long first, last; @@ -178,7 +178,7 @@ void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) * used for the next 32/64-bit word */ -void bitfill(unsigned long *dst, int dst_idx, unsigned long pat, int left, +void bitfill(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left, int right, u32 n) { unsigned long first, last; @@ -228,7 +228,7 @@ void bitfill(unsigned long *dst, int dst_idx, unsigned long pat, int left, } } -void bitfill32_rev(unsigned long *dst, int dst_idx, u32 pat, u32 n) +void bitfill32_rev(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n) { unsigned long val = pat, dat; unsigned long first, last; @@ -300,7 +300,7 @@ void bitfill32_rev(unsigned long *dst, int dst_idx, u32 pat, u32 n) * used for the next 32/64-bit word */ -void bitfill_rev(unsigned long *dst, int dst_idx, unsigned long pat, int left, +void bitfill_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left, int right, u32 n) { unsigned long first, last, dat; @@ -364,7 +364,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) u32 bpp = p->var.bits_per_pixel; unsigned long x2, y2, vxres, vyres; unsigned long height, width, fg; - unsigned long *dst; + unsigned long __iomem *dst; int dst_idx, left; if (p->state != FBINFO_STATE_RUNNING) @@ -397,7 +397,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) else fg = rect->color; - dst = (unsigned long *)((unsigned long)p->screen_base & + dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(BYTES_PER_LONG-1)); dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8; dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; @@ -407,7 +407,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) p->fbops->fb_sync(p); if (!left) { u32 pat = pixel_to_pat32(p, fg); - void (*fill_op32)(unsigned long *dst, int dst_idx, u32 pat, + void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n) = NULL; switch (rect->rop) { @@ -429,7 +429,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp); int right = bpp-left; int r; - void (*fill_op)(unsigned long *dst, int dst_idx, + void (*fill_op)(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left, int right, u32 n) = NULL; diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 31da88e32..4c123abaa 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -87,21 +87,22 @@ static u32 cfb_tab32[] = { #endif static inline void color_imageblit(const struct fb_image *image, - struct fb_info *p, u8 *dst1, + struct fb_info *p, u8 __iomem *dst1, u32 start_index, u32 pitch_index) { /* Draw the penguin */ - u32 *dst, *dst2, color = 0, val, shift; + u32 __iomem *dst, *dst2; + u32 color = 0, val, shift; int i, n, bpp = p->var.bits_per_pixel; u32 null_bits = 32 - bpp; u32 *palette = (u32 *) p->pseudo_palette; const u8 *src = image->data; - dst2 = (u32 *) dst1; + dst2 = (u32 __iomem *) dst1; for (i = image->height; i--; ) { n = image->width; - dst = (u32 *) dst1; + dst = (u32 __iomem *) dst1; shift = 0; val = 0; @@ -136,7 +137,7 @@ static inline void color_imageblit(const struct fb_image *image, dst1 += p->fix.line_length; if (pitch_index) { dst2 += p->fix.line_length; - dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1)); + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); start_index += pitch_index; start_index &= 32 - 1; @@ -145,25 +146,26 @@ static inline void color_imageblit(const struct fb_image *image, } static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, - u8 *dst1, u32 fgcolor, + u8 __iomem *dst1, u32 fgcolor, u32 bgcolor, u32 start_index, u32 pitch_index) { u32 shift, color = 0, bpp = p->var.bits_per_pixel; - u32 *dst, *dst2, val, pitch = p->fix.line_length; + u32 __iomem *dst, *dst2; + u32 val, pitch = p->fix.line_length; u32 null_bits = 32 - bpp; u32 spitch = (image->width+7)/8; const u8 *src = image->data, *s; u32 i, j, l; - dst2 = (u32 *) dst1; + dst2 = (u32 __iomem *) dst1; for (i = image->height; i--; ) { shift = val = 0; l = 8; j = image->width; - dst = (u32 *) dst1; + dst = (u32 __iomem *) dst1; s = src; /* write leading bits */ @@ -201,7 +203,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * src += spitch; if (pitch_index) { dst2 += pitch; - dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1)); + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); start_index += pitch_index; start_index &= 32 - 1; } @@ -218,14 +220,14 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * * beginning and end of a scanline is dword aligned */ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, - u8 *dst1, u32 fgcolor, + u8 __iomem *dst1, u32 fgcolor, u32 bgcolor) { u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; u32 ppw = 32/bpp, spitch = (image->width + 7)/8; u32 bit_mask, end_mask, eorx, shift; const char *s = image->data, *src; - u32 *dst; + u32 __iomem *dst; u32 *tab = NULL; int i, j, k; @@ -253,7 +255,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * k = image->width/ppw; for (i = image->height; i--; ) { - dst = (u32 *) dst1, shift = 8; src = s; + dst = (u32 __iomem *) dst1, shift = 8; src = s; for (j = k; j--; ) { shift -= ppw; @@ -273,7 +275,7 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) u32 width = image->width, height = image->height; u32 dx = image->dx, dy = image->dy; int x2, y2, vxres, vyres; - u8 *dst1; + u8 __iomem *dst1; if (p->state != FBINFO_STATE_RUNNING) return; @@ -325,7 +327,7 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) else slow_imageblit(image, p, dst1, fgcolor, bgcolor, start_index, pitch_index); - } else if (image->depth <= bpp) + } else color_imageblit(image, p, dst1, start_index, pitch_index); } diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index e0fc4c02c..c43322b2d 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -550,7 +550,7 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node) all->par.mode = MDI_8_PIX; all->par.ramsize = (is_8mb ? 0x800000 : 0x400000); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; all->info.fbops = &cg14_ops; all->info.currcon = -1; all->info.par = &all->par; @@ -584,6 +584,9 @@ int __init cg14_init(void) struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("cg14fb", NULL)) + return -ENODEV; + #ifdef CONFIG_SPARC32 { int root, node; @@ -626,8 +629,9 @@ cg14_setup(char *arg) return 0; } -#ifdef MODULE module_init(cg14_init); + +#ifdef MODULE module_exit(cg14_exit); #endif diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index dd0163cc3..078394109 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -398,7 +398,7 @@ static void cg3_init_one(struct sbus_dev *sdev) sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, sizeof(struct cg3_regs), "cg3 regs"); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT; all->info.fbops = &cg3_ops; #ifdef CONFIG_SPARC32 all->info.screen_base = (char *) @@ -444,6 +444,9 @@ int __init cg3_init(void) struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("cg3fb", NULL)) + return -ENODEV; + for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "cgthree") || !strcmp(sdev->prom_name, "cgRDI")) @@ -473,8 +476,9 @@ cg3_setup(char *arg) return 0; } -#ifdef MODULE module_init(cg3_init); + +#ifdef MODULE module_exit(cg3_exit); #endif diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 469ac2060..be87a66f1 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -712,7 +712,8 @@ static void cg6_init_one(struct sbus_dev *sdev) sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET, sizeof(u32), "cgsix fhc"); - all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; all->info.fbops = &cg6_ops; #ifdef CONFIG_SPARC32 all->info.screen_base = (char *) @@ -759,6 +760,9 @@ int __init cg6_init(void) struct sbus_bus *sbus; struct sbus_dev *sdev; + if (fb_get_options("cg6fb", NULL)) + return -ENODEV; + for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "cgsix") || !strcmp(sdev->prom_name, "cgthree+")) @@ -788,8 +792,9 @@ cg6_setup(char *arg) return 0; } -#ifdef MODULE module_init(cg6_init); + +#ifdef MODULE module_exit(cg6_exit); #endif diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index c804352c0..4ee5a25db 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -362,7 +362,7 @@ static void __init init_chips(struct fb_info *p, unsigned long addr) p->var = chipsfb_var; p->fbops = &chipsfb_ops; - p->flags = FBINFO_FLAG_DEFAULT; + p->flags = FBINFO_DEFAULT; fb_alloc_cmap(&p->cmap, 256, 0); @@ -462,9 +462,14 @@ static struct pci_driver chipsfb_driver = { int __init chips_init(void) { + if (fb_get_options("chipsfb", NULL)) + return -ENODEV; + return pci_module_init(&chipsfb_driver); } +module_init(chips_init); + static void __exit chipsfb_exit(void) { pci_unregister_driver(&chipsfb_driver); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 82c26b15c..8132b3bf2 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -752,6 +752,12 @@ int cirrusfb_check_var(struct fb_var_screeninfo *var, switch (var->bits_per_pixel) { case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; break; case 8: @@ -2600,6 +2606,14 @@ int __init cirrusfb_init(void) { int error = 0; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cirrusfb", &option)) + return -ENODEV; + cirrusfb_setup(option); +#endif + #ifdef CONFIG_ZORRO error |= zorro_module_init(&cirrusfb_zorro_driver); #endif @@ -2657,8 +2671,9 @@ void __exit cirrusfb_exit (void) #endif } -#ifdef MODULE module_init(cirrusfb_init); + +#ifdef MODULE module_exit(cirrusfb_exit); #endif diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index a982e7520..8692e0029 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -364,6 +364,9 @@ int __init clps711xfb_init(void) { int err = -ENOMEM; + if (fb_get_options("clps711xfb", NULL)) + return -ENODEV; + cfb = kmalloc(sizeof(*cfb), GFP_KERNEL); if (!cfb) goto out; @@ -372,7 +375,7 @@ int __init clps711xfb_init(void) strcpy(cfb->fix.id, "clps711x"); cfb->fbops = &clps7111fb_ops; - cfb->flags = FBINFO_FLAG_DEFAULT; + cfb->flags = FBINFO_DEFAULT; clps711x_guess_lcd_params(cfb); @@ -432,9 +435,7 @@ static void __exit clps711xfb_exit(void) } } -#ifdef MODULE module_init(clps711xfb_init); -#endif module_exit(clps711xfb_exit); MODULE_AUTHOR("Russell King "); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 5bc0ef0ab..85e796b70 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC default y help Saying Y here will allow you to use Linux in text mode through a @@ -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 @@ -67,7 +67,7 @@ config SGI_NEWPORT_CONSOLE # bool 'IODC console' CONFIG_IODC_CONSOLE config STI_CONSOLE tristate "STI text console" - depends on PARISC + depends on PARISC && FRAMEBUFFER_CONSOLE default y help The STI console is the builtin display/keyboard on HP-PARISC diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 2fcb51a57..2fba5cfcb 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -314,6 +314,28 @@ static int search_for_mapped_con(void) return 0; } +static int fbcon_takeover(void) +{ + int err, i; + + if (!num_registered_fb) + return -ENODEV; + + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + + err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + if (err) { + for (i = first_fb_vc; i <= last_fb_vc; i++) { + con2fb_map[i] = -1; + } + info_idx = -1; + } + + return err; +} + /** * set_con2fb_map - map console to frame buffer device * @unit: virtual console number to map @@ -322,7 +344,7 @@ static int search_for_mapped_con(void) * Maps a virtual console @unit to a frame buffer device * @newidx. */ -int set_con2fb_map(int unit, int newidx) +static int set_con2fb_map(int unit, int newidx) { struct vc_data *vc = vc_cons[unit].d; int oldidx = con2fb_map[unit]; @@ -338,8 +360,7 @@ int set_con2fb_map(int unit, int newidx) if (!search_for_mapped_con()) { info_idx = newidx; - fb_console_init(); - return 0; + return fbcon_takeover(); } if (oldidx != -1) @@ -405,6 +426,87 @@ int set_con2fb_map(int unit, int newidx) /* * Accelerated handlers. */ +static inline int get_color(struct vc_data *vc, struct fb_info *info, + u16 c, int is_fg) +{ + int depth = fb_get_color_depth(info); + int color = 0; + + if (depth != 1) + color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) + : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); + + switch (depth) { + case 1: + { + /* 0 or 1 */ + int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; + int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; + + color = (is_fg) ? fg : bg; + break; + } + case 2: + /* + * Scale down 16-colors to 4 colors. Default 4-color palette + * is grayscale. + */ + color /= 4; + break; + case 3: + /* + * Last 8 entries of default 16-color palette is a more intense + * version of the first 8 (i.e., same chrominance, different + * luminance). + */ + color &= 7; + break; + } + + return color; +} + +#define FBCON_ATTRIBUTE_UNDERLINE 1 +#define FBCON_ATTRIBUTE_REVERSE 2 +#define FBCON_ATTRIBUTE_BOLD 4 + +static inline int get_attribute(struct fb_info *info, u16 c) +{ + int attribute = 0; + + if (fb_get_color_depth(info) == 1) { + if (attr_underline(c)) + attribute |= FBCON_ATTRIBUTE_UNDERLINE; + if (attr_reverse(c)) + attribute |= FBCON_ATTRIBUTE_REVERSE; + if (attr_bold(c)) + attribute |= FBCON_ATTRIBUTE_BOLD; + } + + return attribute; +} + +static inline void update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + u8 c; + + offset = cellsize - (offset * width); + for (i = 0; i < cellsize; i++) { + c = src[i]; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) + c = 0xff; + if (attribute & FBCON_ATTRIBUTE_BOLD) + c |= c >> 1; + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + dst[i] = c; + } +} + void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, int sx, int dy, int dx, int height, int width) { @@ -455,13 +557,19 @@ void accel_putcs(struct vc_data *vc, struct fb_info *info, unsigned int shift_low = 0, mod = vc->vc_font.width % 8; unsigned int shift_high = 8, pitch, cnt, size, k; unsigned int idx = vc->vc_font.width >> 3; + unsigned int attribute = get_attribute(info, scr_readw(s)); struct fb_image image; - u8 *src, *dst; + u8 *src, *dst, *buf = NULL; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + image.fg_color = get_color(vc, info, scr_readw(s), 1); + image.bg_color = get_color(vc, info, scr_readw(s), 0); - image.fg_color = attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, - scr_readw(s)); - image.bg_color = attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, - scr_readw(s)); image.dx = xx * vc->vc_font.width; image.dy = yy * vc->vc_font.height; image.height = vc->vc_font.height; @@ -491,6 +599,12 @@ void accel_putcs(struct vc_data *vc, struct fb_info *info, while (k--) { src = vc->vc_font.data + (scr_readw(s++)& charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + move_unaligned(info, &info->pixmap, dst, pitch, src, idx, image.height, shift_high, shift_low, mod); @@ -503,6 +617,12 @@ void accel_putcs(struct vc_data *vc, struct fb_info *info, while (k--) { src = vc->vc_font.data + (scr_readw(s++)& charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + move_aligned(info, &info->pixmap, dst, pitch, src, idx, image.height); dst += width; @@ -512,6 +632,9 @@ void accel_putcs(struct vc_data *vc, struct fb_info *info, image.dx += cnt * vc->vc_font.width; count -= cnt; } + + if (buf) + kfree(buf); } void accel_clear_margins(struct vc_data *vc, struct fb_info *info, @@ -550,6 +673,47 @@ void accel_clear_margins(struct vc_data *vc, struct fb_info *info, * Low Level Operations */ /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ +static int var_to_display(struct display *disp, + struct fb_var_screeninfo *var, + struct fb_info *info) +{ + disp->xres_virtual = var->xres_virtual; + disp->yres_virtual = var->yres_virtual; + disp->bits_per_pixel = var->bits_per_pixel; + disp->grayscale = var->grayscale; + disp->nonstd = var->nonstd; + disp->accel_flags = var->accel_flags; + disp->height = var->height; + disp->width = var->width; + disp->red = var->red; + disp->green = var->green; + disp->blue = var->blue; + disp->transp = var->transp; + disp->mode = fb_match_mode(var, &info->modelist); + if (disp->mode == NULL) + /* This should not happen */ + return -EINVAL; + return 0; +} + +static void display_to_var(struct fb_var_screeninfo *var, + struct display *disp) +{ + fb_videomode_to_var(var, disp->mode); + var->xres_virtual = disp->xres_virtual; + var->yres_virtual = disp->yres_virtual; + var->bits_per_pixel = disp->bits_per_pixel; + var->grayscale = disp->grayscale; + var->nonstd = disp->nonstd; + var->accel_flags = disp->accel_flags; + var->height = disp->height; + var->width = disp->width; + var->red = disp->red; + var->green = disp->green; + var->blue = disp->blue; + var->transp = disp->transp; +} + static const char *fbcon_startup(void) { const char *display_desc = "frame buffer device"; @@ -723,6 +887,9 @@ static void fbcon_init(struct vc_data *vc, int init) info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + if (var_to_display(p, &info->var, info)) + return; + /* If we are not the first console on this fb, copy the font from that console */ t = &fb_display[display_fg]; @@ -737,7 +904,7 @@ static void fbcon_init(struct vc_data *vc, int init) } if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); - vc->vc_can_do_color = info->var.bits_per_pixel != 1; + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; @@ -780,9 +947,15 @@ static void fbcon_init(struct vc_data *vc, int init) if (logo) { /* Need to make room for the logo */ - int cnt; + int cnt, erase = vc->vc_video_erase_char; int step; + /* + * remove underline attribute from erase character + * if black and white framebuffer. + */ + if (fb_get_color_depth(info) == 1) + erase &= ~0x400; logo_height = fb_prepare_logo(info); logo_lines = (logo_height + vc->vc_font.height - 1) / vc->vc_font.height; @@ -796,8 +969,7 @@ static void fbcon_init(struct vc_data *vc, int init) save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); if (save) { int i = cols < new_cols ? cols : new_cols; - scr_memsetw(save, vc->vc_video_erase_char, - logo_lines * new_cols * 2); + scr_memsetw(save, erase, logo_lines * new_cols * 2); r = q - step; for (cnt = 0; cnt < logo_lines; cnt++, r += i) scr_memcpyw(save + cnt * new_cols, r, 2 * i); @@ -817,7 +989,7 @@ static void fbcon_init(struct vc_data *vc, int init) } } scr_memsetw((unsigned short *) vc->vc_origin, - vc->vc_video_erase_char, + erase, vc->vc_size_row * logo_lines); if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { @@ -926,55 +1098,6 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, accel_clear(vc, info, real_y(p, sy), sx, height, width); } -static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) -{ - struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int width = (vc->vc_font.width + 7) >> 3; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; - struct display *p = &fb_display[vc->vc_num]; - unsigned int size, pitch; - struct fb_image image; - u8 *src, *dst; - - if (!info->fbops->fb_blank && console_blanked) - return; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) - return; - - image.dx = xpos * vc->vc_font.width; - image.dy = real_y(p, ypos) * vc->vc_font.height; - image.width = vc->vc_font.width; - image.height = vc->vc_font.height; - image.fg_color = attr_fgcol(fgshift, c); - image.bg_color = attr_bgcol(bgshift, c); - image.depth = 1; - - src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width; - - pitch = width + scan_align; - pitch &= ~scan_align; - size = pitch * vc->vc_font.height; - size += buf_align; - size &= ~buf_align; - - dst = fb_get_buffer_offset(info, &info->pixmap, size); - image.data = dst; - - if (info->pixmap.outbuf) - fb_iomove_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height); - else - fb_sysmove_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height); - - info->fbops->fb_imageblit(info, &image); -} - static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { @@ -992,17 +1115,22 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, accel_putcs(vc, info, s, count, real_y(p, ypos), xpos); } +static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) +{ + fbcon_putcs(vc, (const unsigned short *) &c, 1, ypos, xpos); +} + static void fbcon_cursor(struct vc_data *vc, int mode) { + struct fb_cursor cursor; struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; struct display *p = &fb_display[vc->vc_num]; int w = (vc->vc_font.width + 7) >> 3, c; - int y = real_y(p, vc->vc_y); - struct fb_cursor cursor; - + int y = real_y(p, vc->vc_y), fg, bg; + int attribute; + u8 *src; + if (mode & CM_SOFTBACK) { mode &= ~CM_SOFTBACK; if (softback_lines) { @@ -1015,8 +1143,22 @@ static void fbcon_cursor(struct vc_data *vc, int mode) fbcon_set_origin(vc); c = scr_readw((u16 *) vc->vc_pos); - - cursor.image.data = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; + if (info->cursor.data) + kfree(info->cursor.data); + info->cursor.data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } + + cursor.image.data = src; cursor.set = FB_CUR_SETCUR; cursor.image.depth = 1; @@ -1031,11 +1173,13 @@ static void fbcon_cursor(struct vc_data *vc, int mode) case CM_MOVE: case CM_DRAW: info->cursor.enable = 1; - - if (info->cursor.image.fg_color != attr_fgcol(fgshift, c) || - info->cursor.image.bg_color != attr_bgcol(bgshift, c)) { - cursor.image.fg_color = attr_fgcol(fgshift, c); - cursor.image.bg_color = attr_bgcol(bgshift, c); + fg = get_color(vc, info, c, 1); + bg = get_color(vc, info, c, 0); + + if (info->cursor.image.fg_color != fg || + info->cursor.image.bg_color != bg) { + cursor.image.fg_color = fg; + cursor.image.bg_color = bg; cursor.set |= FB_CUR_SETCMAP; } @@ -1058,17 +1202,19 @@ static void fbcon_cursor(struct vc_data *vc, int mode) cursor.set |= FB_CUR_SETHOT; } - if ((cursor.set & FB_CUR_SETSIZE) || ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) + if ((cursor.set & FB_CUR_SETSIZE) || + ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) || info->cursor.mask == NULL) { char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); int cur_height, size, i = 0; + u8 msk = 0xff; - if (!mask) return; + if (!mask) + return; if (info->cursor.mask) kfree(info->cursor.mask); info->cursor.mask = mask; - p->cursor_shape = vc->vc_cursor_type & 0x0f; cursor.set |= FB_CUR_SETSHAPE; @@ -1095,10 +1241,10 @@ static void fbcon_cursor(struct vc_data *vc, int mode) } size = (vc->vc_font.height - cur_height) * w; while (size--) - mask[i++] = 0; + mask[i++] = ~msk; size = cur_height * w; while (size--) - mask[i++] = 0xff; + mask[i++] = msk; } info->cursor.rop = ROP_XOR; info->fbops->fb_cursor(info, &cursor); @@ -1126,6 +1272,8 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc) int rows, cols, charcnt = 256; info->var.xoffset = info->var.yoffset = p->yscroll = 0; + if (var_to_display(p, &info->var, info)) + return; t = &fb_display[display_fg]; if (!vc->vc_font.data) { vc->vc_font.data = p->fontdata = t->fontdata; @@ -1139,7 +1287,7 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc) if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); - vc->vc_can_do_color = info->var.bits_per_pixel != 1; + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; @@ -1813,7 +1961,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var = info->var; - int err; int x_diff, y_diff; + int x_diff, y_diff; int fw = vc->vc_font.width; int fh = vc->vc_font.height; @@ -1822,15 +1970,31 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, x_diff = info->var.xres - var.xres; y_diff = info->var.yres - var.yres; if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { - char mode[40]; + struct fb_videomode *mode; DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); - snprintf(mode, 40, "%ix%i", var.xres, var.yres); - err = fb_find_mode(&var, info, mode, info->monspecs.modedb, - info->monspecs.modedb_len, NULL, - info->var.bits_per_pixel); - if (!err || width > var.xres/fw || height > var.yres/fh) + mode = fb_find_best_mode(&var, &info->modelist); + if (mode == NULL) + return -EINVAL; + fb_videomode_to_var(&var, mode); + if (width > var.xres/fw || height > var.yres/fh) return -EINVAL; + /* + * The following can probably have any value... Do we need to + * set all of them? + */ + var.bits_per_pixel = p->bits_per_pixel; + var.xres_virtual = p->xres_virtual; + var.yres_virtual = p->yres_virtual; + var.accel_flags = p->accel_flags; + var.width = p->width; + var.height = p->height; + var.red = p->red; + var.green = p->green; + var.blue = p->blue; + var.transp = p->transp; + var.nonstd = p->nonstd; + DPRINTK("resize now %ix%i\n", var.xres, var.yres); if (CON_IS_VISIBLE(vc)) { var.activate = FB_ACTIVATE_NOW | @@ -1838,6 +2002,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_MODESWITCH; } + var_to_display(p, &info->var, info); } updatescrollmode(p, info, vc); return 0; @@ -1847,6 +2012,7 @@ static int fbcon_switch(struct vc_data *vc) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var; int i; if (softback_top) { @@ -1872,8 +2038,6 @@ static int fbcon_switch(struct vc_data *vc) conp2->vc_top = 0; logo_shown = -1; } - if (info) - info->var.yoffset = p->yscroll = 0; /* * FIXME: If we have multiple fbdev's loaded, we need to @@ -1888,7 +2052,18 @@ static int fbcon_switch(struct vc_data *vc) registered_fb[i]->currcon = vc->vc_num; } - fbcon_resize(vc, vc->vc_cols, vc->vc_rows); + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + fb_videomode_to_var(&var, p->mode); + display_to_var(&var, p); + var.activate = FB_ACTIVATE_NOW; + + /* + * make sure we don't unnecessarily trip the memcmp() + * in fb_set_var() + */ + info->var.activate = var.activate; + info->var.yoffset = info->var.xoffset = p->yscroll = 0; + fb_set_var(info, &var); if (info->flags & FBINFO_MISC_MODESWITCH) { if (info->fbops->fb_set_par) @@ -1896,6 +2071,10 @@ static int fbcon_switch(struct vc_data *vc) info->flags &= ~FBINFO_MISC_MODESWITCH; } + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + updatescrollmode(p, info, vc); + switch (p->scrollmode) { case SCROLL_WRAP_MOVE: scrollback_phys_max = p->vrows - vc->vc_rows; @@ -2290,26 +2469,31 @@ static struct fb_cmap palette_cmap = { static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - int i, j, k; + int i, j, k, depth; u8 val; - if (!vc->vc_can_do_color - || (!info->fbops->fb_blank && console_blanked)) + if (!info->fbops->fb_blank && console_blanked) return -EINVAL; - for (i = j = 0; i < 16; i++) { - k = table[i]; - val = vc->vc_palette[j++]; - palette_red[k] = (val << 8) | val; - val = vc->vc_palette[j++]; - palette_green[k] = (val << 8) | val; - val = vc->vc_palette[j++]; - palette_blue[k] = (val << 8) | val; - } - if (info->var.bits_per_pixel <= 4) - palette_cmap.len = 1 << info->var.bits_per_pixel; - else + depth = fb_get_color_depth(info); + if (depth > 3) { + for (i = j = 0; i < 16; i++) { + k = table[i]; + val = vc->vc_palette[j++]; + palette_red[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_green[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_blue[k] = (val << 8) | val; + } palette_cmap.len = 16; - palette_cmap.start = 0; + palette_cmap.start = 0; + /* + * If framebuffer is capable of less than 16 colors, + * use default palette of fbcon. + */ + } else + fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); + return fb_set_cmap(&palette_cmap, info); } @@ -2516,10 +2700,9 @@ static void fbcon_modechanged(struct fb_info *info) p = &fb_display[vc->vc_num]; info->var.xoffset = info->var.yoffset = p->yscroll = 0; - vc->vc_can_do_color = info->var.bits_per_pixel != 1; - vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (CON_IS_VISIBLE(vc)) { + var_to_display(p, &info->var, info); cols = info->var.xres / vc->vc_font.width; rows = info->var.yres / vc->vc_font.height; vc_resize(vc->vc_num, cols, rows); @@ -2542,10 +2725,52 @@ static void fbcon_modechanged(struct fb_info *info) } } +static int fbcon_mode_deleted(struct fb_info *info, + struct fb_videomode *mode) +{ + struct fb_info *fb_info; + struct display *p; + int i, j, found = 0; + + /* before deletion, ensure that mode is not in use */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + j = (int) con2fb_map[i]; + if (j == -1) + continue; + fb_info = registered_fb[j]; + if (fb_info != info) + continue; + p = &fb_display[i]; + if (!p || !p->mode) + continue; + if (fb_mode_is_equal(p->mode, mode)) { + found = 1; + break; + } + } + return found; +} + +static int fbcon_fb_registered(int idx) +{ + int ret = 0; + + if (info_idx == -1) { + info_idx = idx; + ret = fbcon_takeover(); + } + + return ret; +} + static int fbcon_event_notify(struct notifier_block *self, unsigned long action, void *data) { - struct fb_info *info = (struct fb_info *) data; + struct fb_event *event = (struct fb_event *) data; + struct fb_info *info = event->info; + struct fb_videomode *mode; + struct fb_con2fbmap *con2fb; + int ret = 0; switch(action) { case FB_EVENT_SUSPEND: @@ -2557,9 +2782,24 @@ static int fbcon_event_notify(struct notifier_block *self, case FB_EVENT_MODE_CHANGE: fbcon_modechanged(info); break; + case FB_EVENT_MODE_DELETE: + mode = (struct fb_videomode *) event->data; + ret = fbcon_mode_deleted(info, mode); + break; + case FB_EVENT_FB_REGISTERED: + ret = fbcon_fb_registered(info->node); + break; + case FB_EVENT_SET_CONSOLE_MAP: + con2fb = (struct fb_con2fbmap *) event->data; + ret = set_con2fb_map(con2fb->console - 1, con2fb->framebuffer); + break; + case FB_EVENT_GET_CONSOLE_MAP: + con2fb = (struct fb_con2fbmap *) event->data; + con2fb->framebuffer = con2fb_map[con2fb->console - 1]; + break; } - return 0; + return ret; } /* @@ -2595,60 +2835,43 @@ const struct consw fb_con = { static struct notifier_block fbcon_event_notifier = { .notifier_call = fbcon_event_notify, }; -static int fbcon_event_notifier_registered; -/* can't be __init as it can be called by set_con2fb_map() later */ -int fb_console_init(void) +int __init fb_console_init(void) { - int err, i; + int i; + + acquire_console_sem(); + fb_register_client(&fbcon_event_notifier); + release_console_sem(); for (i = 0; i < MAX_NR_CONSOLES; i++) con2fb_map[i] = -1; - if (!num_registered_fb) - return -ENODEV; - - if (info_idx == -1) { + if (num_registered_fb) { for (i = 0; i < FB_MAX; i++) { if (registered_fb[i] != NULL) { info_idx = i; break; } } + fbcon_takeover(); } - for (i = first_fb_vc; i <= last_fb_vc; i++) - con2fb_map[i] = info_idx; - err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, - fbcon_is_default); - if (err) { - for (i = first_fb_vc; i <= last_fb_vc; i++) { - con2fb_map[i] = -1; - } - return err; - } - acquire_console_sem(); - if (!fbcon_event_notifier_registered) { - fb_register_client(&fbcon_event_notifier); - fbcon_event_notifier_registered = 1; - } - release_console_sem(); + return 0; } +module_init(fb_console_init); + #ifdef MODULE void __exit fb_console_exit(void) { acquire_console_sem(); - if (fbcon_event_notifier_registered) { - fb_unregister_client(&fbcon_event_notifier); - fbcon_event_notifier_registered = 0; - } + fb_unregister_client(&fbcon_event_notifier); release_console_sem(); give_up_console(&fb_con); } -module_init(fb_console_init); module_exit(fb_console_exit); #endif diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 71643f5ad..a89001a40 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -33,12 +33,21 @@ struct display { short yscroll; /* Hardware scrolling */ int vrows; /* number of virtual rows */ int cursor_shape; + u32 xres_virtual; + u32 yres_virtual; + u32 height; + u32 width; + u32 bits_per_pixel; + u32 grayscale; + u32 nonstd; + u32 accel_flags; + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + struct fb_videomode *mode; }; -/* drivers/video/console/fbcon.c */ -extern signed char con2fb_map[MAX_NR_CONSOLES]; -extern int set_con2fb_map(int unit, int newidx); - /* * Attribute Decoding */ @@ -56,8 +65,8 @@ extern int set_con2fb_map(int unit, int newidx); /* Monochrome */ #define attr_bold(s) \ ((s) & 0x200) -#define attr_reverse(s, inverse) \ - (((s) & 0x800) ^ (inverse ? 0x800 : 0)) +#define attr_reverse(s) \ + ((s) & 0x800) #define attr_underline(s) \ ((s) & 0x400) #define attr_blink(s) \ diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 8ad33fa31..22896d692 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -556,6 +556,11 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro int __init control_init(void) { struct device_node *dp; + char *option = NULL; + + if (fb_get_options("controlfb", &option)) + return -ENODEV; + control_setup(option); dp = find_devices("control"); if (dp != 0 && !control_of_init(dp)) @@ -564,6 +569,7 @@ int __init control_init(void) return -ENXIO; } +module_init(control_init); /* Work out which banks of VRAM we have installed. */ /* danj: I guess the card just ignores writes to nonexistant VRAM... */ @@ -1010,7 +1016,7 @@ static void __init control_init_info(struct fb_info *info, struct fb_info_contro info->par = &p->par; info->fbops = &controlfb_ops; info->pseudo_palette = p->pseudo_palette; - info->flags = FBINFO_FLAG_DEFAULT; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; info->screen_base = (char *) p->frame_buffer + CTRLFB_OFF; fb_alloc_cmap(&info->cmap, 256, 0); diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 0afebb72c..4dca34fdf 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1166,7 +1166,7 @@ static struct fb_videomode __devinitdata cyber2000fb_default_mode = { .vmode = FB_VMODE_NONINTERLACED }; -static char igs_regs[] __devinitdata = { +static char igs_regs[] = { EXT_CRT_IRQ, 0, EXT_CRT_TEST, 0, EXT_SYNC_CTL, 0, @@ -1281,7 +1281,7 @@ cyberpro_alloc_fb_info(unsigned int id, char *name) cfb->fb.var.accel_flags = FB_ACCELF_TEXT; cfb->fb.fbops = &cyber2000fb_ops; - cfb->fb.flags = FBINFO_FLAG_DEFAULT; + cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; cfb->fb.pseudo_palette = (void *)(cfb + 1); fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0); @@ -1289,7 +1289,7 @@ cyberpro_alloc_fb_info(unsigned int id, char *name) return cfb; } -static void __devinit +static void cyberpro_free_fb_info(struct cfb_info *cfb) { if (cfb) { @@ -1712,11 +1712,21 @@ static struct pci_driver cyberpro_driver = { * I don't think we can use the "module_init" stuff here because * the fbcon stuff may not be initialised yet. Hence the #ifdef * around module_init. + * + * Tony: "module_init" is now required */ int __init cyber2000fb_init(void) { int ret = -1, err; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cyber2000fb", NULL)) + return -ENODEV; + cyber2000fb_setup(option); +#endif + #ifdef CONFIG_ARCH_SHARK err = cyberpro_vl_probe(); if (!err) { @@ -1738,9 +1748,7 @@ static void __exit cyberpro_exit(void) pci_unregister_driver(&cyberpro_driver); } -#ifdef MODULE module_init(cyber2000fb_init); -#endif module_exit(cyberpro_exit); MODULE_AUTHOR("Russell King"); diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 11ba053b5..1dbb82dca 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -239,6 +239,9 @@ static int __devinit dnfb_probe(struct device *device) info->fbops = &dn_fb_ops; info->fix = dnfb_fix; info->var = dnfb_var; + info->var.red.length = 1; + info->var.red.offset = 0; + info->var.green = info->var.blue = info->var.red; info->screen_base = (u_char *) info->fix.smem_start; err = fb_alloc_cmap(&info->cmap, 2, 0); @@ -281,6 +284,9 @@ int __init dnfb_init(void) { int ret; + if (fb_get_options("dnfb", NULL)) + return -ENODEV; + ret = driver_register(&dnfb_driver); if (!ret) { @@ -291,4 +297,6 @@ int __init dnfb_init(void) return ret; } +module_init(dnfb_init); + MODULE_LICENSE("GPL"); diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index a998ee9d8..6cb54f809 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c @@ -1,541 +1,771 @@ /* - * linux/drivers/video/epson1355fb.c - * -- Support for the Epson SED1355 LCD/CRT controller + * linux/drivers/video/epson1355fb.c -- Epson S1D13505 frame buffer for 2.5. * - * Copyright (C) 2000 Philipp Rumpf + * Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller + * (previously known as SED1355) * - * based on linux/drivers/video/skeletonfb.c, which was + * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html + * + * + * Copyright (C) Hewlett-Packard Company. All rights reserved. + * + * Written by Christopher Hoover + * + * Adapted from: + * + * linux/drivers/video/skeletonfb.c + * Modified to new api Jan 2001 by James Simmons (jsimmons@infradead.org) * Created 28 Dec 1997 by Geert Uytterhoeven * + * linux/drivers/video/epson1355fb.c (2.4 driver) + * Copyright (C) 2000 Philipp Rumpf + * * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ -/* TODO (roughly in order of priority): - * 16 bpp support - * crt support - * hw cursor support - * SwivelView + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * + * Noteworthy Issues + * ----------------- + * + * This driver is complicated by the fact that this is a 16-bit chip + * and, on at least one platform (ceiva), we can only do 16-bit reads + * and writes to the framebuffer. We hide this from user space + * except in the case of mmap(). + * + * + * To Do + * ----- + * + * - Test 8-bit pseudocolor mode + * - Allow setting bpp, virtual resolution + * - Implement horizontal panning + * - (maybe) Implement hardware cursor */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include #include +#include #include -#include